WMI:monitor registry change - c++

In my project ,i want to monitor sofeware installation and unstallation in my system, so i use WMI event mechanism,but now i encounter a problem and have a question.
problem:
i want to monitor HKLM'SOFTWARE\Microsoft\Windows\currentversion\unistall',but code[1] works error(ExecNotificationQueryAnsync failed with =0x80041058).while code[2] works ok,what's wrong?
[1]
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * FROM RegistryTreeChangeEvent WITHIN 1 " "WHERE Hive='HKEY_LOCAL_MACHINE'" "AND RootPath='software\\Microsoft\\Windows\\currentversion\\unistall'"
),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
[2]
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * FROM RegistryTreeChangeEvent WITHIN 1 " "WHERE Hive='HKEY_LOCAL_MACHINE'" "AND RootPath='software'"
),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
question:in My event consumer ,i want to get the software's name ,how can i do ?
thanks!!

Just use
SELECT * FROM RegistryTreeChangeEvent WITHIN 1 " "WHERE Hive='HKEY_LOCAL_MACHINE'" "AND RootPath='software\\\\Microsoft\\\\Windows\\\\currentversion\\\\unistall'"

Related

Why DACL entries of a file printed via win32 API is not matching up with DACL information in the file properties?

Here is the minimal code for reference
ULONG result = GetSecurityInfo(Hfile
, SE_FILE_OBJECT
, OWNER_SECURITY_INFORMATION |GROUP_SECURITY_INFORMATION| DACL_SECURITY_INFORMATION
, &sidowner
, &sidgroup
, &pdacl
, NULL
, &psd);
This is how I extracted the access control entries from DACL
BOOL b = GetAce(pdacl, i, (LPVOID*)&ace);
if (((ACCESS_ALLOWED_ACE*)ace)->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) {
sid = (PSID)&((ACCESS_ALLOWED_ACE*)ace)->SidStart;
LookupAccountSid(NULL, sid, oname, &namelen, doname, &domainnamelen, &peUse);
wcout << "domianName/AccoutName : " << doname << "/" << oname << endl;
mask = ((ACCESS_ALLOWED_ACE*)ace)->Mask;
cout << "Allowed" << endl;
}
output:
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Users
Allowed
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
SYNCHRONIZE
As we can see from the above output Administrators have multiple entries and ACE of "System" and "Authenticated users" are not found. "Users" only have read rights in file properties but in the output, it is printed that the "Users" have "Write access" as well.
I did a lot of research and read through many books but nothing seems to give a clear-cut answer
edit:
Here's the output using the CACLS command.
C:\Users\Administrator>cacls e:/hello.txt
e:\hello.txt BUILTIN\Administrators:F
NT AUTHORITY\SYSTEM:F
NT AUTHORITY\Authenticated Users:C
BUILTIN\Users:R
The first part of the question:
The reason why the program prints the name same account name repeatedly is because the LookupAccountSid function does not have enough data area. since the namelen and domainlen are IN\OUT arguments the function returns the size of the domain name and account name every time after execution. So to solve this the namelen and domainlen have to be reassigned every time.
LookupAccountSid(NULL, sid, oname, &namelen, doname, &domainnamelen, &peUse);
wcout << "domianName/AccoutName : " << doname << "/" << oname << endl;
namelen = 100; domainnamelen = 100; //This should solve the problem
Here is the link to the docs for the LookupAccountSid function
The second part of the question
The reason why the output from the program shows the users have FILE_GENERIC_WRITE permission even though the CACLS seem to show that users only have read and execute permission to the given file path is that in the program the code that checks if the users have the write permissions is done by the following.
if (FILE_GENERIC_WRITE & ace->Mask) {
wcout << " FILE_GENERIC_WRITE" << "\n";
}
The problem is the FILE_GENERIC_WRITE consists of multiple permissions like STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE and when the code is written like this (FILE_GENERIC_WRITE & ace->Mask) it only checks if at least one of the permissions is present or not.
A special thanks to #user253751 and #Werner Henze for patiently explaining the solution

How can I determine the primary key of a table in postgres with C++ and libpqxx?

My task is to determine the primary key of a postgres table with libpqxx (dynamically), but I don't know how to bind the value correctly. I get syntax error.
std::string sql =
"SELECT c.column_name, c.data_type "\
"FROM information_schema.table_constraints tc"
"JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)"
"JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema "
"AND tc.table_name = c.table_name AND ccu.column_name = c.column_name "
"WHERE constraint_type = 'PRIMARY KEY' and tc.table_name = '$1';";
C->prepare("determine_primary_key", sql.c_str());
pqxx::prepare::invocation w_invocation = W->prepared("determine_primary_key");
std::vector<std::string > vect;
vect.push_back("postgres_table_name");
prep_dynamic(vect, w_invocation);
pqxx::result r = w_invocation.exec();
From the documentation for pqxx, the prepared() method is deprecated. So using your code snippet I would make the following changes to use the new exec_prepared() statement and pull in your parameter:
std::string sql =
"SELECT c.column_name, c.data_type "\
"FROM information_schema.table_constraints tc"
"JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)"
"JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema "
"AND tc.table_name = c.table_name AND ccu.column_name = c.column_name "
"WHERE constraint_type = 'PRIMARY KEY' and tc.table_name = '$1';";
C->prepare("determine_primary_key", sql.c_str());
pqxx::result r = W->exec_prepared("determine_primary_key", "<your_table_name_here>");
But, if you are still using the older version of pqxx and need to keep using prepared() you can do the following:
std::string sql =
"SELECT c.column_name, c.data_type "\
"FROM information_schema.table_constraints tc"
"JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)"
"JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema "
"AND tc.table_name = c.table_name AND ccu.column_name = c.column_name "
"WHERE constraint_type = 'PRIMARY KEY' and tc.table_name = '$1';";
C->prepare("determine_primary_key", sql.c_str());
pqxx::result r = W->prepared("determine_primary_key")("<your_table_name_here>").exec();
You can check the libpqxx documentation to get more info on prepared() and exec_prepared().

Boost Log Time Zone

I've been learning the Boost Log library
http://www.boost.org/doc/libs/develop/libs/log/doc/html/index.html
but I've been unable to figure out how to display the user's time zone. There is a %q and %Q format option that looks promising but doesn't seem to work (I'm using MSVC++ 2013). Using this format "%Y-%m-%d %H:%M:%S.%f%Q", I get the following output:
1 [2015-08-18 21:27:16.860724] main.cpp#11, Test App Started.
but I would have expected
1 [2015-08-18 21:27:16.860724-08.00] main.cpp#11, Test App Started.
as explained in:
http://www.boost.org/doc/libs/develop/libs/log/doc/html/log/detailed/expressions.html#log.detailed.expressions.formatters
Here's the code I've been trying and a few commented out lines that I have also tried with no luck:
void Log::init() const
{
boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::utc_clock());
// boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::local_clock());
boost::log::register_simple_formatter_factory<Severity, char>("Severity");
// boost::log::register_formatter_factory("TimeStamp", boost::make_shared<timestamp_formatter_factory>());
boost::log::add_common_attributes();
boost::log::add_file_log
(
boost::log::keywords::file_name = "appname_%N.log",
boost::log::keywords::rotation_size = 10 * 1024 * 1024,
boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
boost::log::keywords::format =
boost::log::expressions::stream
<< boost::log::expressions::attr<unsigned>("LineID") << " "
<< "[" << boost::log::expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S.%f%Q"<< "]" << " "
<< "<" << boost::log::expressions::attr<Severity>("Severity") << _NSTR(">") << _NSTR(" ")
<< boost::log::expressions::smessage
// "%LineID% [%TimeStamp(format=\"%Y-%m-%d %H:%M:%S.%f%Q\")%] <%Severity%>: %%Message%"
);
const auto severity = boost::log::expressions::attr<Severity>("Severity");
boost::log::core::get()->set_filter
(
severity >= severityThreshold_
);
}
Any suggestions on what I might be doing wrong?
Both utc_clock and local_clock produce values of type boost::posix_time::ptime, which do not have information of a time zone. The difference between the clocks is what time ptime represents - UTC or local time according to the time zone set on the machine. The formatter has no use for %Q and %q and replaces them with an empty string.
The time zone is present in the boost::local_time::local_date_time type, the %Q and %q placeholders will work for it. The library does not have a clock attribute that produces local_date_time, so you will have to write one yourself. See here for an example.

Which method made the call to IWbemObjectSink::Indicate method

I am developing an application in C++ using VS2010. In my code,I have two WQL queries as follows:
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * "
"FROM __InstanceDeletionEvent WITHIN 1 "
"WHERE TargetInstance ISA 'Win32_Process' "),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
hres1 = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * "
"FROM __InstanceCreationEvent WITHIN 1 "
"WHERE TargetInstance ISA 'Win32_Process'"),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
On cretion or deletion of processes I get its name printed into the console from the IWbemObjectSink::Indicate method. When the name of the process is printed, I need to know whether it was created or deleted. How will I know this? Is there some way to know which asynchronous method made the call to Indicate method?
Thankyou
__InstanceDeletionEvent and __InstanceCreationEvent are subclasses of __InstanceOperationEvent. Hence, you should be querying for instances of __InstanceOperationEvent. Then you will Get the Class from the object in your Sink Class (e.g., pStubSink) to know from which instance is being created. Look at this example to get an idea about how to handle a similar situation: http://blogs.technet.com/b/heyscriptingguy/archive/2005/04/04/how-can-i-monitor-for-different-types-of-events-with-just-one-script.aspx
UPDATE1:
__InstanceOperationEvent is superclass of: __InstanceDeletionEvent, __InstanceCreationEvent and __InstanceModificationEvent.
pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE Targetinstance ISA 'Win32_Process'"),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
In your Indicate function:
Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hr = S_OK;
for (int i = 0; i < lObjectCount; i++)
{
_variant_t myVariant;
hr = apObjArray[i]->Get(_bstr_t(L"__Class"), 0, &myVariant, 0, 0);
if (SUCCEEDED(hr))
{
std::wstring classOrigin(myVariant.bstrVal);
if (0 == classOrigin.compare(L"__InstanceDeletionEvent") )
{
std::wcout << L"DELETION" << std::endl;
}
else if (0 == classOrigin.compare(L"__InstanceCreationEvent"))
{
std::wcout << L"CREATION" << std::endl;
}
}
}
}
myVariant will say which is the class that generated the event (read note).
NOTE: This will result in a constant call to your pStubSink because Processes are constantly being modificated (__InstanceModificationEvent, e.g., changes in memory/CPU).
UPDATE2: You could also have two different Queries (and consecuently Sink objects), one for creation and one for deletion (e.g., pStubSinkCreation, pStubSinkDeletion). In this way you (1) would know exactly when it comes from Creation and when from Deletion; and (2) would avoid to be receiving constantly the __InstanceModificationEvent.

Passing A Variable To SQL

I have a variable that is an IP address. It is saved as text in my Access 2010 database. I am trying to run this query with ipSrc and the query always fails. My guess is that its seeing ipSrc as ipSrc and not as the actual IP address. I tried it with 'ipSrc' and just plain ipSrc and both reurn fail. Also tried ""ipSrc"", failed as well. This failed to. '&ipSrc'. Here is the statement.
SQLCHAR* query = (SQLCHAR*)"SELECT tblIP.[IPAddress], tblIP.[IPType], tblIP.[IPStatus], tblIP.[IPMax] FROM tblIP WHERE tblIP.[IPAddress]= ipSrc AND tblIP.[IPType]=3 AND tblIP.[IPStatus]=1 AND tblIP.[IPMax]=0;";
and here is the definition of ipSrc.
translate_ip(ip_header->source_ip, ipSrc);
Using printf it prints out as an actual IP address.
printf("\n Source IP: %s", ipSrc);
There's no way for the code to know, from what you have there, that ipSrc should be treated specially, it's just going to pass it through as-is.
You can probably try to construct the query string dynamically as a C++ string, and then use that to populate the query. Something like:
std::string strqry =
"SELECT tblIP.[IPAddress], "
+ " tblIP.[IPType], "
+ " tblIP.[IPStatus], "
+ " tblIP.[IPMax] "
+ "FROM tblIP "
+ "WHERE tblIP.[IPAddress] = '" + ipSrc + "' "
+ "AND tblIP.[IPType] = 3 "
+ "AND tblIP.[IPStatus] = 1 "
+ "AND tblIP.[IPMax] = 0"
+ ";";
SQLCHAR *query = (SQLCHAR *)(strqry.c_str());
// Now use query
And make sure you have control over the ipSrc value. Otherwise, you're subject to SQL injection attacks (in which case you'll want to use prepared/parameterised statements).