Bad counter path, pdhAddCounter; performance monitor in windows - c++

I'm trying to count the number of processes on windoes 2008 server using pdh.h.
CONST PWSTR COUNTER_PATH = L"\\System\\Processes";
HQUERY hQuery = NULL;
HCOUNTER hCounter;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
pdhStatus = PdhOpenQuery(NULL, 0, &hQuery);
pdhStatus = PdhAddCounter(hQuery, (LPCSTR)COUNTER_PATH, 0, &hCounter);
I got the COUNTER_PATH name from here, and the example can be found in here. But somehow I'm getting 0xC0000BC0 (PDH_CSTATUS_BAD_COUNTERNAME) error message at PdhAddCounter. Can anybody pick up any mistake I made? I'm not sure what I'm missing here. Is there anything wrong with COUNTER_PATH?

You're casting COUNTER_PATH to a LPCSTR in PdhAddCounter which you shouldn't be doing.
PdhAddCounter's second parameter is a LPCTSTR which is the same as CONST PWSTR.

Related

LookupAccountName Always Fails With Error 122 (ERROR_INSUFFICIENT_BUFFER)

Perhaps somebody can enlighten me here.
I'm attempting to automate a WiFi connection process where the SSID is determined by a serial number. Since this is always different, I figured I need to save a temporary profile each time I wish to connect.
WlanSaveTemporaryProfile() wants a LPCWSTR strAllUserProfileSecurity to define permissions for this profile. So far the rabbit hole has led me to try using LookupAccountNameW(). I have tried to AllocateAndInitializeSid() to no avail. I tried plugging in an empty buffer with the same result. In both cases, I get an error 122, which says the buffer was too small.
Any aid here is sincerely appreciated.
Here's the relevant code. Mostly constructed from examples in Microsoft's documentation.
DWORD GetStringSecurityDescriptor(
PWCHAR ps_securityDescriptor, /* This needs to be populated when this function completes. */
PULONG pul_securityDescriptorLen,
LPWSTR ps_accountName
)
{
DWORD dw_result = NULL;
DWORD dw_lastError = NULL;
DWORD dw_bufferSizeOfUserAccount = NULL;
/* Create a security descriptor for the profile. */
SECURITY_DESCRIPTOR secDesc;
bool success = InitializeSecurityDescriptor(&secDesc, SECURITY_DESCRIPTOR_REVISION);
if (!success)
{
wprintf(L"Security Descriptor Initialization Failed.\n");
}
PSID p_userSid = NULL;
/* Attempt 2: Straight up malloc the memory. Doesn't work any better.*/
//p_userSid = malloc(100);
/* Attempt 1: Allocate and Initialize an SID for LookupAccountNameW(). */
SID_IDENTIFIER_AUTHORITY auth = SECURITY_WORLD_SID_AUTHORITY;
BOOL b_sidReady = AllocateAndInitializeSid(
&auth,
6,
SECURITY_NULL_RID,
SECURITY_WORLD_RID,
SECURITY_LOCAL_RID,
SECURITY_LOCAL_LOGON_RID,
SECURITY_CREATOR_OWNER_RID,
SECURITY_CREATOR_GROUP_RID,
0, 0,
&p_userSid
);
LPDWORD buf = &dw_bufferSizeOfUserAccount;
WCHAR domainName[1000] = { 0 }; // Perhaps DNLEN + 1 was too small?
DWORD domainNameLen = 1000;
SID_NAME_USE use = SidTypeUser;
// Currently failing. dw_bufferSizeOfUserAccount still recieves a 28, so that wasn't it.
success = LookupAccountNameW(
NULL,
ps_accountName,
p_userSid,
buf,
domainName,
&domainNameLen,
&use);
if (!success)
{
dw_lastError = GetLastError();
switch (dw_lastError)
{
case ERROR_INSUFFICIENT_BUFFER: // LookupAccountNameW() always ends up here.
wprintf(L"The data area passed to a system call is too small.\n");
FreeSid(p_userSid);
return dw_lastError;
default:
wprintf(L"Looking up Account Name failed. See Error 0x%x.\n", dw_lastError);
FreeSid(p_userSid);
return dw_lastError;
}
}
// ... more code irrelevant to this problem...
}
Great thanks to Georgy Firsov!
I missed a statement in the documentation.
By calculating the size of the SID and storing it in dw_bufferSizeOfUserAccount, the function ran successfully.
dw_bufferSizeOfUserAccount = GetLengthSid(p_userSid);

How to get the logged-on user's SID in Windows

I need to get the string format SID of the logged-on user. I already have the username and am trying to use LookupAccountName to get the SID. This works partly - I do get a SID but it is only a partial match to the user's actual SID.
I do not want the SID of the process owner as the process may be elevated (impersonating), but rather I want the SID of the user who is logged on where the process is running.
The code needs to work with non-elevated privileges.
This is my code so far
LPCTSTR wszAccName = TEXT("hardcoded username for testing");
LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024);
DWORD cchDomainName = 1024;
SID_NAME_USE eSidType;
SID sid;
DWORD cbSid = 1024;
if (!LookupAccountName(NULL, wszAccName, &sid, &cbSid, wszDomainName, &cchDomainName, &eSidType)) {
return GetLastError();
}
if (!ConvertSidToStringSid(&sid, &pszSidBuffer)) {
return GetLastError();
}
This yields a SID like "S-1-5-21-1-1234567890-9-1000"
But the user's actual SID is like "S-1-5-21-3214321539-1234567890-2233445522-1000"
(as per the process owner and the registry key under HKEY_USERS).
Note how the SIDs are the same except for the 5th and 7th components, which are only 1 digit each but should be longer.
How do I get the user's actual/complete SID?
Also, I'm a total C/C++ newbie (and the code above is not production quality at all). And I'm using /NODEFAULTLIB in order to avoid linking VC runtimes. Sorry about that.
Your code doesn't provide a properly-sized buffer for the SID returned by LookupAccountName(). This results in stack corruption and undefined behaviour, which might conceivably explain why you're not getting the SID you were expecting. (Although I rather suspect that you're actually passing in the wrong username, or an improperly formatted username.)
Anyway, to fix the most obvious problem, the code should look more like this:
#include <Windows.h>
#include <Sddl.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
LPCTSTR wszAccName = TEXT("domainname\\username");
LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024);
DWORD cchDomainName = 1024;
SID_NAME_USE eSidType;
LPTSTR sidstring;
char sid_buffer[1024];
DWORD cbSid = 1024;
SID * sid = (SID *)sid_buffer;
if (!LookupAccountName(NULL, wszAccName, sid_buffer, &cbSid, wszDomainName, &cchDomainName, &eSidType)) {
return GetLastError();
}
if (!ConvertSidToStringSid(sid, &sidstring)) {
return GetLastError();
}
printf("%ws\n", sidstring);
return 0;
}
That's still not the correct way to do it, of course; you are supposed to call LookupAccountName() twice, once to determine the buffer length and then a second time to retrieve the actual information. But it demonstrates what you've done wrong, and is good enough for testing purposes.

Find what is the channel using Windows API

I am trying to get the Channel using the windows API. So far, I have tried to use the wlan_intf_opcode_channel_number with the WlanQueryInterface function.
I am not too sure what the reply means on that thread and was hoping someone could clarify.
ULONG channel = 0;
DWORD dwSizeChannel = sizeof(channel);
dwResult = WlanQueryInterface(
hClient,
InterfaceGuid,
wlan_intf_opcode_channel_number,
NULL,
&dwSizeChannel,
(PVOID*)&channel,
NULL);
I am not sure what to do after here. Any help would be appreciated!
After checking i found out that i always get the same value as channel has befor calling the WlanQueryInterface
The MS docs for the op-code seems to be wrong. If you try something similar here:
ULONG *channel = NULL;
DWORD dwSizeChannel = sizeof(*channel);
DWORD rc = WlanQueryInterface (
hClient, InterfaceGuid,
wlan_intf_opcode_channel_number,
NULL, &dwSizeChannel, &channel, NULL);
if (rc == ERROR_SUCCESS && channel) {
printf ("Channel: %lu\n", *channel):
WlanFreeMemory (channel);
}
I do get the expected Channel: 5.
The same goes for wlan_intf_opcode_current_operation_mode and possibly other op-codes that's simply an ULONG.
I tried out WlanQueryInterface with the inputs from the documentation:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms706765(v=vs.85).aspx
When query based on "wlan_intf_opcode_channel_number" was triggered, I got the data as "13". And the frequency could be made out as 2472Mhz from the WLAN information provided by the following wikipedia link:
https://en.wikipedia.org/wiki/List_of_WLAN_channels
Hope this helps.

RSSI using Windows API

I am trying to get the RSSI using the windows API. So far, I have found this thread saying to use the wlan_intf_opcode_rssi with the WlanQueryInterface function. I am not too sure what the reply means on that thread and was hoping someone could clarify.
All i have managed to understand from the other thread is this:
WlanQueryInterface(hClient,
&pInfo->InterfaceGuid,
wlan_intf_opcode_rssi,
NULL,
&connectInfoSize,
(PVOID*)&pConnectInfo,
&opCode);
I am not sure what to do after here. Any help would be appreciated!
You're passing the wrong type of argument to WlanQueryInterface. MSDN says that the return type for wlan_intf_opcode_rssi is LONG, so you need to pass a pointer to a LONG variable, like this:
LONG rssi = 0;
DWORD dwSizeRssi = sizeof(rssi);
dwResult = WlanQueryInterface(hClient,
&pIfInfo->InterfaceGuid,
wlan_intf_opcode_rssi,
NULL,
&dwSizeRssi,
(PVOID *)&rssi,
&opCode);
if (dwResult == ERROR_SUCCESS)
{
wprintf(L"RSSI = %u \n", rssi);
}

EnumProcessModulesEx fails returning error code 299 (ERROR_PARTIAL_COPY)

I am calling the function EnumProcessModulesEx and it fails. I running on a 64-bit machine. Here is the code below:
wchar_t* dest = new wchar_t[100];
int index = SendMessage(processes, LB_GETCURSEL, 0, 0);
SendMessage(processes, LB_GETTEXT, index, (LPARAM)dest);
HMODULE module;
unsigned long cbneeded;
EnableTokenPrivilege(hWnd, SE_DEBUG_NAME);
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, _wtoi(dest));
int errorcode = GetLastError();
BOOL ret = EnumProcessModulesEx(h, &module, sizeof module, &cbneeded, LIST_MODULES_ALL);
int err = GetLastError();
wchar_t* name = new wchar_t[MAX_PATH];
GetModuleBaseName(h, module, name, sizeof name);
MessageBox(hWnd, name, L"Process Name", 0);
delete dest;
delete name;
Most probably you are trying to open 32bit process from 64bit application or vice versa. You can only work with processes of the same kind.
BOOL ret = EnumProcessModulesEx(h, &module, sizeof module, &cbneeded, LIST_MODULES_ALL);
The 3rd argument is supposed to be the size of the array of HMODULES you pass in the 2nd argument. You only pass 1, not big enough. Note the lpcbNeeded, it tells you how large the array needs to be to not get the error.
If the target platform is x86, then you can try to change it to x64.
You can read the document: https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules
If this function is called from a 32-bit application running on WOW64, it can only enumerate the modules of a 32-bit process. If the process is a 64-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).
Well, what does GetLastError return? EDIT: my bad, I failed hard..
Do error-checking and make sure it's not SendMessage, EnableTokenPrivilege, or OpenProcess that's giving you the error.