LoadAccelerators for a specific resource language - c++

I want to call LoadAccelerators but for a specific language in the resources. Is there a way to do it?

I did some reverse engineering and here's how to load it from memory for a specific LCID:
#pragma pack(push, 1) // exact fit - no padding
struct ACCEL_MEM{
BYTE fVirt;
BYTE byteReserved;
WORD wKey;
WORD wCmd;
WORD wReserved;
};
#pragma pack(pop)
HACCEL LoadAcceleratorsIndirectWithLCID(UINT nResourceID, LCID lcid)
{
//Open accelerators table with the 'nResourceID'
//'nResourceID' = Resource ID to use
//'lcid' = LCID to load resources for, or NULL to use the one from current thread
//RETURN:
// = HACCEL loaded -- must be removed with DestroyAcceleratorTable(), or
// = NULL if error
ASSERT(nResourceID);
HACCEL hAccel = NULL;
HINSTANCE hInst = ::GetModuleHandle(NULL);
if(hInst)
{
//Do we have a LCID?
if(lcid == NULL)
lcid = ::GetThreadLocale();
//Get language ID
LANGID langid = LANGIDFROMLCID(lcid);
//Try to load for specified resource
HRSRC hResource = ::FindResourceEx(hInst, RT_ACCELERATOR, MAKEINTRESOURCE(nResourceID), langid);
if(hResource == NULL)
{
//If failed, use default lcid
hResource = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_ACCELERATOR);
}
if(hResource)
{
HGLOBAL hglb = LoadResource(hInst, hResource);
if(hglb)
{
LPVOID lpsz = LockResource(hglb);
DWORD dwcbSz = ::SizeofResource(hInst, hResource);
if(lpsz &&
dwcbSz)
{
ACCEL_MEM* pMem = (ACCEL_MEM*)lpsz;
//Count items in the table
int nCnt = 0;
ACCEL_MEM* pTest = pMem;
for(;; pTest++)
{
nCnt++;
if(pTest->fVirt & 0x80)
break;
}
//Reserve mem
ACCEL* pAccels = new ACCEL[nCnt];
//Parse data
for(int i = 0; i < nCnt; i++)
{
pAccels[i].fVirt = pMem[i].fVirt & 0x7f;
pAccels[i].key = pMem[i].wKey;
pAccels[i].cmd = pMem[i].wCmd;
}
//Create accel table
hAccel = ::CreateAcceleratorTable(pAccels, nCnt);
//Free mem
delete[] pAccels;
pAccels = NULL;
}
}
}
}
return hAccel;
}

You put your language-specific resources in a DLL. At run time, you load that DLL and specify the DLL's handle as the hInstance when you call LoadAccelerators.

Related

How to get all (non-disabled) user SIDs via Windows API?

I'm looking for a way to retrieve all user SIDs on a system via the Windows API.
Retrieving all user SIDs can be done with via wmic useraccount get sid. Is there a way of getting this information via the Windows API instead?
Additionally, the wmic command returns the SIDs of all accounts, including disabled accounts - wmic useraccount get disabled,sid will show which accounts are disabled. It would be a bonus if a solution could advise on how to retrieve the SIDs of accounts that are not disabled, but this is not crucial.
You could use the function:
NET_API_STATUS NET_API_FUNCTION NetUserEnum(
LPCWSTR servername,
DWORD level,
DWORD filter,
LPBYTE *bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
PDWORD resume_handle
);
with servername = NULL to enumerate local computer accounts, then use:
BOOL LookupAccountNameW(
LPCWSTR lpSystemName,
LPCWSTR lpAccountName,
PSID Sid,
LPDWORD cbSid,
LPWSTR ReferencedDomainName,
LPDWORD cchReferencedDomainName,
PSID_NAME_USE peUse
);
to retrieve SID's.
Refer to https://learn.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netuserenum and https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupaccountnamew for details and examples.
In function NetUserEnum, setting the parameter level=1 will return detailed information about user accounts, and the bufptr parameter will point to an array of USER_INFO_1 structures.
Examining the member usri1_flags of structure USER_INFO_1 with mask UF_ACCOUNTDISABLE give the status of account.
Following RbMm comment, note that specifying in function NetUserEnum the parameter level=3, the bufptr parameter will point to an array of USER_INFO_3 structures, that contains user RID's.
The member usri3_user_id contains the relative ID (RID) of the user, and the member usri3_primary_group_id contains the RID of the Primary Global Group for the user. Using these values you don't need to call LookupAccountNameW.
The efficiency is boosted using suggestions from RbMm in the comments below.
There are several ways.
A simple one is with NetQueryDisplayInformation
Test sample (Windows 10, VS 2015) =>
NET_API_STATUS NetStatus;
DWORD dwIndex = 0;
DWORD dwEntriesRequested = 0xFFFFFFFF;
DWORD dwPreferredMaximumLength = 0xFFFFFFFF;
DWORD dwReturnedEntryCount;
PVOID pNDU = NULL;
do {
NetStatus = NetQueryDisplayInformation(NULL, 1, dwIndex, dwEntriesRequested, dwPreferredMaximumLength, &dwReturnedEntryCount, &pNDU);
if (NetStatus != NERR_Success && NetStatus != ERROR_MORE_DATA)
break;
for (int i = 0; i < dwReturnedEntryCount; i++)
{
PNET_DISPLAY_USER NetDisplayUser = (PNET_DISPLAY_USER)(((LPBYTE)pNDU) + sizeof(NET_DISPLAY_USER) * i);
PSID pSID = ConvertNameToSID(NetDisplayUser->usri1_name);
LPWSTR pszSid = NULL;
ConvertSidToStringSid(pSID, &pszSid);
BOOL bIsAccountDisabled = ((NetDisplayUser->usri1_flags & UF_ACCOUNTDISABLE) != 0) ? TRUE : FALSE;
WCHAR wsBuffer[MAX_PATH];
wsprintf(wsBuffer, L"%4.4ld %-20.20ws SID : %ws - Disabled : %ws - Comment : %ws\n",
NetDisplayUser->usri1_next_index,
NetDisplayUser->usri1_name,
pszSid,
(bIsAccountDisabled ? L"True" : L"False"),
NetDisplayUser->usri1_comment
);
LocalFree(pSID);
OutputDebugString(wsBuffer);
dwIndex = NetDisplayUser->usri1_next_index;
}
NetApiBufferFree(pNDU);
} while (NetStatus == ERROR_MORE_DATA);
PSID ConvertNameToSID(LPTSTR lpszName)
{
WCHAR wszDomainName[256];
DWORD dwSizeDomain = sizeof(wszDomainName) / sizeof(TCHAR);
DWORD dwSizeSid = 0;
SID_NAME_USE sidName;
LookupAccountName(NULL, lpszName, NULL, &dwSizeSid, wszDomainName, &dwSizeDomain, &sidName);
PSID pSid;
pSid = (PSID)LocalAlloc(LPTR, dwSizeSid);
LookupAccountName(NULL, lpszName, pSid, &dwSizeSid, wszDomainName, &dwSizeDomain, &sidName);
return pSid;
}
for enumerate user accounts in SAM (Security Account Manager) database we can use or NetQueryDisplayInformation (more fast) or NetUserEnum (if we need more detail user information). or SAM api (fastest, include ntsam.h and link with samlib.lib )
note that if we have user (RID) we not need use LookupAccountName - this is very not efficient in this case (many heavy remote calls internal - LsaOpenPolicy, LsaLookupNames2, LsaClose . internal LsaLookupNames2 use anyway SAM api SamLookupNamesInDomain).
really all what we need - first get domain SID and than append user RID to it. get domain SID we can by LsaQueryInformationPolicy with PolicyAccountDomainInformation for SID of the account domain (computer) - always exist and with PolicyDnsDomainInformation or PolicyPrimaryDomainInformation for get SID of the primary domain (exist only if computer part of Domain)
void PrintUsersInDomain(PUNICODE_STRING ServerName, PSID DomainSid)
{
PWSTR szServerName = 0;
if (ServerName)
{
if (ULONG Length = ServerName->Length)
{
szServerName = ServerName->Buffer;
// if not null terminated
if (Length + sizeof(WCHAR) < ServerName->MaximumLength || *(PWSTR)((PBYTE)szServerName + Length))
{
szServerName = (PWSTR)alloca(Length + sizeof(WCHAR));
memcpy(szServerName, ServerName->Buffer, Length);
*(PWSTR)((PBYTE)szServerName + Length) = 0;
}
}
}
UCHAR SubAuthorityCount = *GetSidSubAuthorityCount(DomainSid);
ULONG DestinationSidLength = GetSidLengthRequired(SubAuthorityCount + 1);
PSID UserSid = alloca(DestinationSidLength);
CopySid(DestinationSidLength, UserSid, DomainSid);
++*GetSidSubAuthorityCount(UserSid);
PULONG pRid = GetSidSubAuthority(UserSid, SubAuthorityCount);
PVOID Buffer;
ULONG Index = 0, ReturnedEntryCount;
NET_API_STATUS status;
do
{
switch (status = NetQueryDisplayInformation(szServerName, 1, Index,
64, MAX_PREFERRED_LENGTH, &ReturnedEntryCount, &Buffer))
{
case NOERROR:
case ERROR_MORE_DATA:
if (ReturnedEntryCount)
{
PNET_DISPLAY_USER pndu = (PNET_DISPLAY_USER)Buffer;
do
{
//if (!(pndu->usri1_flags & UF_ACCOUNTDISABLE))
{
*pRid = pndu->usri1_user_id;
PWSTR szSid;
if (ConvertSidToStringSidW(UserSid, &szSid))
{
DbgPrint("\t[%08x] %S %S\n", pndu->usri1_flags, pndu->usri1_name, szSid);
LocalFree(szSid);
}
}
Index = pndu->usri1_next_index;
} while (pndu++, --ReturnedEntryCount);
}
NetApiBufferFree(Buffer);
}
} while (status == ERROR_MORE_DATA);
}
void PrintUsersInDomain_fast(PUNICODE_STRING ServerName, PSID DomainSid)
{
SAM_HANDLE ServerHandle, DomainHandle = 0;
//SAM_SERVER_ENUMERATE_DOMAINS|SAM_SERVER_LOOKUP_DOMAIN
NTSTATUS status = SamConnect(ServerName, &ServerHandle, SAM_SERVER_LOOKUP_DOMAIN, 0);
DbgPrint("SamConnect(%wZ) = %x\n", ServerName, status);
if (0 <= status)
{
status = SamOpenDomain(ServerHandle, DOMAIN_READ|DOMAIN_EXECUTE, DomainSid, &DomainHandle);
SamCloseHandle(ServerHandle);
}
if (0 <= status)
{
UCHAR SubAuthorityCount = *GetSidSubAuthorityCount(DomainSid);
ULONG DestinationSidLength = GetSidLengthRequired(SubAuthorityCount + 1);
PSID UserSid = alloca(DestinationSidLength);
CopySid(DestinationSidLength, UserSid, DomainSid);
++*GetSidSubAuthorityCount(UserSid);
PULONG pRid = GetSidSubAuthority(UserSid, SubAuthorityCount);
PVOID Buffer;
ULONG Index = 0, TotalAvailable, TotalReturned, ReturnedEntryCount;
do
{
if (0 <= (status = SamQueryDisplayInformation(DomainHandle,
DomainDisplayUser,
Index,
2,
0x10000,
&TotalAvailable,
&TotalReturned,
&ReturnedEntryCount,
&Buffer)))
{
if (ReturnedEntryCount)
{
PSAM_DISPLAY_USER psdu = (PSAM_DISPLAY_USER)Buffer;
do
{
//if (!(psdu->AccountControl & USER_ACCOUNT_DISABLED))
{
*pRid = psdu->Rid;
PWSTR szSid;
if (ConvertSidToStringSidW(UserSid, &szSid))
{
DbgPrint("\t[%08x] %wZ %S\n", psdu->AccountControl, &psdu->AccountName, szSid);
LocalFree(szSid);
}
}
Index = psdu->Index;
} while (psdu++, --ReturnedEntryCount);
}
SamFreeMemory(Buffer);
}
} while (status == STATUS_MORE_ENTRIES);
SamCloseHandle(DomainHandle);
}
}
void PrintUsers()
{
LSA_HANDLE PolicyHandle;
LSA_OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(ObjectAttributes) };
NTSTATUS status;
if (0 <= (status = LsaOpenPolicy(0, &ObjectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle)))
{
union {
PVOID buf;
PPOLICY_DNS_DOMAIN_INFO pddi;
PPOLICY_ACCOUNT_DOMAIN_INFO padi;
};
if (0 <= LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation, &buf))
{
DbgPrint("DomainName=<%wZ>\n", &padi->DomainName);
if (padi->DomainSid)
{
PrintUsersInDomain_fast(&padi->DomainName, padi->DomainSid);
PrintUsersInDomain(&padi->DomainName, padi->DomainSid);
}
LsaFreeMemory(buf);
}
if (0 <= LsaQueryInformationPolicy(PolicyHandle, PolicyDnsDomainInformation, &buf))
{
DbgPrint("DomainName=<%wZ>\n", &pddi->Name);
if (pddi->Sid)
{
PrintUsersInDomain_fast(&pddi->Name, pddi->Sid);
PrintUsersInDomain(&pddi->Name, pddi->Sid);
}
LsaFreeMemory(buf);
}
LsaClose(PolicyHandle);
}
}
typedef struct SAM_DISPLAY_USER {
ULONG Index;
ULONG Rid;
ULONG AccountControl; /* User account control bits */
UNICODE_STRING AccountName;
UNICODE_STRING AdminComment;
UNICODE_STRING FullName;
} *PSAM_DISPLAY_USER;

How to validate credentials with CredUIPromptForWindowsCredentials

I don't know why I can't unpack the authentification buffer used in CredUIPromptForWindowsCredentials with CredUnPackAuthenticationBufferW, I always get ERROR_INSUFFICIENT_BUFFER error.
I will appreciate your help.
std::wstring caption = L"Caption";
std::wstring msg= L"Msg";
CREDUI_INFOW credui = {};
credui.cbSize = sizeof(credui);
credui.hwndParent = nullptr;
credui.pszMessageText = msg.c_str();
credui.pszCaptionText = caption.c_str();
credui.hbmBanner = nullptr;
ULONG authPackage = 0;
LPVOID outCredBuffer = nullptr;
ULONG outCredSize = 0;
BOOL save = false;
LPWSTR pszUserName = nullptr;
DWORD pcchlMaxUserName = 0;
LPWSTR pszDomainName = nullptr;
DWORD pcchMaxDomainName = 0;
LPWSTR pszPassword = nullptr;
DWORD pcchMaxPassword = 0;
DWORD result = CredUIPromptForWindowsCredentialsW(&credui,
0,
&authPackage,
nullptr,
0,
&outCredBuffer,
&outCredSize,
&save,
CREDUIWIN_ENUMERATE_ADMINS);
std::cout <<CredUnPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS
,outCredBuffer
,outCredSize
,pszUserName
,&pcchlMaxUserName
,pszDomainName
,&pcchMaxDomainName
,pszPassword
,&pcchMaxPassword) << std::endl;
std::cout << GetLastError() << std::endl; // out put 122 == ERROR_INSUFFICIENT_BUFFER
this is typical winapi pattern - api must return some information in the memory buffer. but instead allocate buffer yourself - it obligate caller to allocate buffer.
so caller must allocate buffer itself and pass it pointer and size to api.
api check buffer size - if it large enough fill information to buffer, otherwise return ERROR_INSUFFICIENT_BUFFER (assume that no another errors) or sometime ERROR_MORE_DATA. which which concrete error reurned ERROR_INSUFFICIENT_BUFFER or ERROR_MORE_DATA usual direct documented for api call. different between this 2 errors: ERROR_INSUFFICIENT_BUFFER - mean no any info filled to buffer at all, when ERROR_MORE_DATA mean some data is returned, but incomplete.
and api return to user, via some out parameter, required buffer size in this case. frequently this is done via the same inout parameter - pointer to DWORD. in input specifies the size of user allocated buffer, in output - specifies the required size of buffer or size of returned data
frequently which buffer size is required - unknown at begin. so we need or call api with 0 size buffers(s) first, or allocate some, supposedly sufficient buffer size. if buffer will be insuffient - reallocate or extend it and call api again. for some api (like CredUnPackAuthenticationBufferW) the required output buffer does not change with time (if input parameters not changed), but usual output buffer size may change between calls - even second call with buffer size returned by first call can fail with buffer size error (because returned data may grow between calls). in this case need call api in do/while(error == ERROR_INSUFFICIENT_BUFFER/ERROR_MORE_DATA) loop. but even in case output buffer does not change with time we can better do this is loop with single api call inside, instead 2 api calls.
for concrete case code can look like
ULONG cred()
{
CREDUI_INFO ci = { sizeof(ci) };
BOOL bSave = FALSE;
PVOID pvOutAuthBuffer;
ULONG ulOutAuthBufferSize;
ULONG ulAuthPackage = 0;
ULONG dwError = CredUIPromptForWindowsCredentials(
&ci, NOERROR, &ulAuthPackage, 0, 0,
&pvOutAuthBuffer, &ulOutAuthBufferSize,
&bSave, CREDUIWIN_ENUMERATE_ADMINS );
if (dwError == NOERROR)
{
ULONG cchUserName = 0;
ULONG cchPassword = 0;
ULONG cchDomain = 0;
static volatile UCHAR guz = 0;
PWSTR stack = (PWSTR)alloca(guz);
PWSTR szUserName = 0, szPassword = 0, szDomainName = 0;
ULONG cchNeed, cchAllocated = 0;
do
{
if (cchAllocated < (cchNeed = cchUserName + cchPassword + cchDomain))
{
szUserName = (PWSTR)alloca((cchNeed - cchAllocated) * sizeof(WCHAR));
cchAllocated = (ULONG)(stack - szUserName);
szPassword = szUserName + cchUserName;
szDomainName = szPassword + cchPassword;
}
dwError = CredUnPackAuthenticationBuffer(
CRED_PACK_PROTECTED_CREDENTIALS,
pvOutAuthBuffer, ulOutAuthBufferSize,
szUserName, &cchUserName,
szDomainName, &cchDomain,
szPassword, &cchPassword)
? NOERROR : GetLastError();
if (dwError == NOERROR)
{
DbgPrint("%S#%S %S\n", szDomainName, szUserName, szPassword);
break;
}
} while (dwError == ERROR_INSUFFICIENT_BUFFER);
CoTaskMemFree(pvOutAuthBuffer);
}
return dwError;
}
#RbMm - you're right! I tested it with LogonUser, and it works perfectly. Thanks.
And for a ready solution, I got this :
bool Authenticate_ADMIN_User(std::wstring caption, std::wstring msg, int maxReAsks = 0)
{
CREDUI_INFOW credui = {};
credui.cbSize = sizeof(credui);
credui.hwndParent = nullptr;
credui.pszMessageText = msg.c_str();
credui.pszCaptionText = caption.c_str();
credui.hbmBanner = nullptr;
ULONG authPackage = 0,
outCredSize = 0;
LPVOID outCredBuffer = nullptr;
BOOL save = false;
DWORD err = 0;
int tries = 0;
bool reAsk = false;
do
{
tries++;
if(CredUIPromptForWindowsCredentialsW(&credui,
err,
&authPackage,
nullptr,
0,
&outCredBuffer,
&outCredSize,
&save,
CREDUIWIN_ENUMERATE_ADMINS)
!= ERROR_SUCCESS)
return false;
ULONG cchUserName = 0;
ULONG cchPassword = 0;
ULONG cchDomain = 0;
ULONG cchNeed, cchAllocated = 0;
static volatile UCHAR guz = 0;
PWSTR stack = (PWSTR)alloca(guz);
PWSTR szUserName = nullptr, szPassword = nullptr, szDomainName = nullptr;
BOOL ret;
do{
if (cchAllocated < (cchNeed = cchUserName + cchPassword + cchDomain))
{
szUserName = (PWSTR)alloca((cchNeed - cchAllocated) * sizeof(WCHAR));
cchAllocated = (ULONG)(stack - szUserName);
szPassword = szUserName + cchUserName;
szDomainName = szPassword + cchPassword;
}
ret = CredUnPackAuthenticationBuffer(
CRED_PACK_PROTECTED_CREDENTIALS , outCredBuffer, outCredSize, szUserName, &cchUserName,
szDomainName, &cchDomain, szPassword,
&cchPassword);
}while(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
SecureZeroMemory(outCredBuffer, outCredSize);
CoTaskMemFree(outCredBuffer);
HANDLE handle = nullptr;
if (LogonUser(szUserName,
szDomainName,
szPassword,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&handle))
{
CloseHandle(handle);
return true;
}
else
{
err = ERROR_LOGON_FAILURE;
reAsk = true;
}
}while(reAsk && tries < maxReAsks);
return false;
}

Enumerating process handles, weird issue

I scan for opened handles to my process and print them in the console.
I start my process
I attach cheat engine
I run the enumeration of opened handles
I see which process has a handle to my process
The weird issue at this point is as follows, check the code:
array<Accessor^>^ AntiCheat::ScanHandles()
{
List<Accessor^>^ accessorList = gcnew List<Accessor^>();
if (!EnableDebugPrivilege(true))
printf("EnableDebugPrivilege failed: %d\n", GetLastError());
tNtQuerySystemInformation oNtQuerySystemInformation = (tNtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
PSYSTEM_HANDLE_INFORMATION handleInfo = new SYSTEM_HANDLE_INFORMATION;
SYSTEM_INFORMATION_CLASS infoClass = (SYSTEM_INFORMATION_CLASS)16; // SystemHandleInformation
DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);
DWORD needed = 0;
NTSTATUS status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
while (!NT_SUCCESS(status))
{
if (needed == 0)
return nullptr;
// The previously supplied buffer wasn't enough.
delete handleInfo;
size = needed + 1024;
handleInfo = (PSYSTEM_HANDLE_INFORMATION)new BYTE[size];
status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
}
HANDLE currentProcess = GetCurrentProcess();
DWORD currentProcessId = GetProcessId(currentProcess);
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
//printf(".");
SYSTEM_HANDLE handle = handleInfo->Handles[i];
HANDLE procHandle = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, handle.dwProcessId);
if (GetLastError() == ERROR_ACCESS_DENIED)
continue;
HANDLE dupl = 0;
if (!DuplicateHandle(procHandle, (HANDLE)handle.wValue, currentProcess, &dupl, 0, false, DUPLICATE_SAME_ACCESS))
continue;
DWORD procId = GetProcessId(dupl);
if (procId == currentProcessId)
{
printf("accessing us\n");
char processName[MAX_PATH];
GetModuleFileNameEx((HMODULE)procHandle, NULL, processName, MAX_PATH);
accessorList->Add(gcnew Accessor(gcnew String(processName), handle.GrantedAccess));
}
CloseHandle(dupl);
}
return accessorList->ToArray();
}
If I uncomment the line with printf(".");, I see 3 opened handles to my process (cheatengine). If it's commented (runs way faster), there is no opened handle. However I don't know why this affects my code. Im surprised, does anyone know why this happens? Or how to find out how to find the handles without my printf("."); line?
Another issue is: each time I call the function, the number of allocated bytes duplicates. And I don't know why.
I see logic problems with your code.
You are not ignoring array items where handle.dwProcessId equals currentProcessId, so you end up opening handles to your own process. Since you are only interested in looking for other processes, you should be ignoring items where handle.dwProcessId is equal to currentProcessId.
You are not checking if OpenProcess() fails for any reason other than ERROR_ACCESS_DENIED. Do not call GetLastError() unless OpenProcess() actually returns NULL first.
You are not closing an opened handle if DuplicateHandle() fails. And why are you duplicating each source handle just to call GetProcessId() on it? You already have their process IDs from the array, so the whole DuplicateHandle()+GetProcessId() is completely unnecessary.
You are taking the wrong approach anyway. Have a look at this discussion:
Enumerating the processes referencing an object
Use NtQuerySystemInformation with SystemInformationClass set to SystemHandleInformation. This fills in an array of SYSTEM_HANDLE_INFORMATION structures, which are defined as:
typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION;
Search for the entry corresponding to the handle you opened with ProcessID equal to GetCurrentProcessId(), then find all entries with the same Object pointer.
Although the discussion shows the wrong declaration for SYSTEM_HANDLE_INFORMATION. The following article shows the correct one:
HOWTO: Enumerate handles
#define SystemHandleInformation 16
typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
/* The following structure is actually called SYSTEM_HANDLE_TABLE_ENTRY_INFO, but SYSTEM_HANDLE is shorter. */
typedef struct _SYSTEM_HANDLE
{
ULONG ProcessId;
BYTE ObjectTypeNumber;
BYTE Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG HandleCount; /* Or NumberOfHandles if you prefer. */
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
With that said, try something more like this:
array<Accessor^>^ AntiCheat::ScanHandles()
{
List<Accessor^>^ accessorList = gcnew List<Accessor^>();
if (!EnableDebugPrivilege(true))
printf("EnableDebugPrivilege failed: %d\n", GetLastError());
tNtQuerySystemInformation oNtQuerySystemInformation = (tNtQuerySystemInformation) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
DWORD currentProcessId = GetCurrentProcessId();
HANDLE currentProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, currentProcessId);
PVOID currentProcessAddr = nullptr;
DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);
DWORD needed = 0;
PSYSTEM_HANDLE_INFORMATION handleInfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[size];
SYSTEM_INFORMATION_CLASS infoClass = (SYSTEM_INFORMATION_CLASS) 16; // SystemHandleInformation
NTSTATUS status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
// The previously supplied buffer wasn't enough.
delete[] handleInfo;
size += 1024;
handleInfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[size];
status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
}
if (status != 0)
{
delete[] handleInfo;
return nullptr;
}
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
SYSTEM_HANDLE &handle = handleInfo->Handles[i];
if ((handle.dwProcessId == currentProcessId) &&
(currentProcess == (HANDLE)handle.wValue))
{
currentProcessAddr = handle.pAddress;
break;
}
}
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
SYSTEM_HANDLE &handle = handleInfo->Handles[i];
if ((handle.dwProcessId != currentProcessId) &&
(handle.pAddress == currentProcessAddr))
{
printf("accessing us\n");
HANDLE procHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, handle.dwProcessId);
if (procHandle != 0)
{
char processName[MAX_PATH+1];
DWORD len = GetModuleFileNameEx((HMODULE)procHandle, NULL, processName, MAX_PATH);
CloseHandle(procHandle);
processName[len] = '\0';
accessorList->Add(gcnew Accessor(gcnew String(processName), handle.GrantedAccess));
}
else
accessorList->Add(gcnew Accessor(gcnew String("unknown"), handle.GrantedAccess));
}
}
CloseHandle(currentProcess);
delete[] handleInfo;
return accessorList->ToArray();
}

AddFontMemResourceEx

The following code should work to load a font from a binary resource stored in my executable to system memory according to all of the examples I have found but it is not working. "myfont" is the name of the ttf associated with IDR_FONT in the resource file.
DWORD Count ;
HRSRC Resource = FindResource(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_FONT),"BINARY") ;
DWORD Length = SizeofResource(GetModuleHandle(NULL),Resource) ;
HGLOBAL Address = LoadResource(GetModuleHandle(NULL),Resource) ;
HANDLE Handle = AddFontMemResourceEx(Address,Length,0,&Count) ;
if(Handle==0)
{
MessageBox(hWnd,"Font load failed", "Error",NULL);
}
LOGFONT logfont; //set window font
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfEscapement = 0;
memcpy(logfont.lfFaceName, "myfont", LF_FACESIZE);
logfont.lfHeight = 14;
logfont.lfItalic = FALSE;
logfont.lfOrientation = 0;
logfont.lfOutPrecision = OUT_TT_PRECIS;
logfont.lfQuality = PROOF_QUALITY;
logfont.lfStrikeOut = FALSE;
logfont.lfUnderline = FALSE;
logfont.lfWeight = FW_DONTCARE;
hFont = CreateFontIndirect(&logfont);
Any ideas what I am doing incorrectly?
There are two problems with your code.
You are not checking any of the API functions for failure. Most likely, your call to FindResource() is failing because "BINARY" is not a standard resource type. User-defined resources should use RCDATA instead:
HRSRC Resource = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_FONT), RT_RCDATA);
Or maybe FONT if it is an actual standard FONT resource:
HRSRC Resource = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_FONT), RT_FONT);
The actual name of the resource type depends on the content of the .RC file you used to add the resource to the executable, though.
The other problem, and more importatly, is that you are not actually accessing the raw data of the resource so you can pass the real font data to AddFontMemResourceEx(). You need to use LockResource() for that.
Try something more like this instead:
HANDLE AddResourceFont(LPCTSTR ResID, DWORD *Installed)
{
if (Installed) *Installed = 0;
HMODULE hMod = GetModuleHandle(NULL);
DWORD Count, ErrorCode;
HRSRC Resource = FindResource(hMod, ResID, RT_RCDATA); // or RT_FONT or whatever your actual resource type is
if (!Resource)
{
ErrorCode = GetLastError();
//...
return NULL;
}
DWORD Length = SizeofResource(hMod, Resource);
if ((Length == 0) && (GetLastError() != 0))
{
ErrorCode = GetLastError();
//...
return NULL;
}
HGLOBAL Address = LoadResource(hMod, Resource);
if (!Address)
{
ErrorCode = GetLastError();
//...
return NULL;
}
PVOID FontData = LockResource(Address);
if (!FontData)
{
ErrorCode = GetLastError();
//...
return NULL;
}
HANDLE Handle = AddFontMemResourceEx(FontData, Length, 0, &Count);
if (!Handle)
{
ErrorCode = GetLastError();
//...
return NULL;
}
if (Installed) *Installed = Count;
return Handle;
}
.
DWORD Count = 0;
HANDLE hFont = AddResourceFont(MAKEINTRESOURCE(IDR_FONT), &Count);
if (hFont)
{
//...
RemoveFontMemResourceEx(hFont);
}

Working with transparent PNG in Windows mobile 6.x using C++

I have been trying to add to resource and use some semi transparent PNG files in my windows mobile 6.x application. After days of looking around and experimenting with different methods, I decided to dynamically load and use gdiplus.dll and use the flat APIs. everything works except function GdipCreateHBITMAPFromBitmap returns NotImplemented (6). any idea how to fix this problem? I have 3 files that I am attaching here.
GdiPlusDynamic.cpp:
#include "GdiPlusDynamic.h"
#include "GdiPlusDynamicTools.h"
#include <string>
TAutoStream::TAutoStream(HGLOBAL m_hBuffer)
{
pStream = NULL;
switch(::CreateStreamOnHGlobal(m_hBuffer, TRUE, &pStream))
{
case E_NOINTERFACE:
throw std::wstring(L"The specified interface is not supported");
break;
case E_OUTOFMEMORY:
throw std::wstring(L"Not enough memory");
break;
default:
break;
}
}
TAutoStream::~TAutoStream(void)
{
if(NULL != pStream)
pStream->Release();
}
IStream* TAutoStream::get(void)
{
return pStream;
}
AutoGlobal::AutoGlobal(UINT uFlags, SIZE_T dwBytes) : len(0)
{
m_hBuffer = ::GlobalAlloc(uFlags, dwBytes);
if(IsOk())
{
memset(m_hBuffer, 0, dwBytes);
len = dwBytes;
}
}
AutoGlobal::~AutoGlobal(void)
{
if(IsOk())
::GlobalFree(m_hBuffer);
}
bool AutoGlobal::IsOk(void)
{
return (NULL != m_hBuffer);
}
HGLOBAL AutoGlobal::get(void)
{
return m_hBuffer;
}
TAutoLockedBuff::TAutoLockedBuff(UINT uFlags, SIZE_T dwBytes) : AutoGlobal(uFlags, dwBytes)
{
pBuffer = NULL;
if(AutoGlobal::IsOk())
pBuffer = GlobalLock(m_hBuffer);
}
TAutoLockedBuff::~TAutoLockedBuff(void)
{
if(IsOk())
GlobalUnlock(m_hBuffer);
}
bool TAutoLockedBuff::IsOk(void)
{
return (AutoGlobal::IsOk() && (NULL != pBuffer));
}
void TAutoLockedBuff::CopyFrom(const void* pSrcData, SIZE_T srcLen)
{
if(IsOk())
CopyMemory(pBuffer, pSrcData, min(srcLen, len));
}
TDynamicGdiPlus::TDynamicGdiPlus(void) : everythigOK(false)
{
GdiplusStartupInput dpStartupInfo;
token = 0;
pGdiplusStartup = NULL;
pGdiplusShutdown = NULL;
pGdipCreateBitmapFromStream = NULL;
pGdipCreateHBITMAPFromBitmap = NULL;
pGdipFree = NULL;
hGdiPlus = ::LoadLibrary(L"gdiplus.dll");
if(NULL == hGdiPlus)
throw std::wstring(L"Unable to load 'gdiplus.dll'");
pGdiplusStartup = (TGdiplusStartup)GetProcAddress(hGdiPlus, L"GdiplusStartup");
if(NULL == pGdiplusStartup)
throw std::wstring(L"Unable to get the address of 'GdiplusStartup'");
pGdiplusShutdown = (TGdiplusShutdown)GetProcAddress(hGdiPlus, L"GdiplusShutdown");
if(NULL == pGdiplusShutdown)
throw std::wstring(L"Unable to get the address of 'GdiplusShutdown'");
pGdipCreateBitmapFromStream = (TGdipCreateBitmapFromStream)GetProcAddress(hGdiPlus, L"GdipCreateBitmapFromStreamICM");
if(NULL == pGdipCreateBitmapFromStream)
throw std::wstring(L"Unable to get the address of 'GdipCreateBitmapFromStreamICM'");
pGdipCreateHBITMAPFromBitmap = (TGdipCreateHBITMAPFromBitmap)GetProcAddress(hGdiPlus, L"GdipCreateHBITMAPFromBitmap");
if(NULL == pGdipCreateHBITMAPFromBitmap)
throw std::wstring(L"Unable to get the address of 'GdipCreateHBITMAPFromBitmap'");
pGdipFree = (TGdipFree)GetProcAddress(hGdiPlus, L"GdipFree");
if(NULL == pGdipFree)
throw std::wstring(L"Unable to get the address of 'GdipFree'");
if(Status::Ok != pGdiplusStartup(&token, &dpStartupInfo, NULL))
throw std::wstring(L"Unable to start 'GDI Plus'");
else
everythigOK = true;
}
TDynamicGdiPlus::~TDynamicGdiPlus(void)
{
if((0 != token) && (NULL != pGdiplusShutdown))
pGdiplusShutdown(token);
if(NULL != hGdiPlus)
FreeLibrary(hGdiPlus);
}
HBITMAP TDynamicGdiPlus::LoadImageFromResource(HINSTANCE hInst, LPCTSTR lpName, LPCTSTR lpType)
{
HBITMAP retVal = NULL;
if(everythigOK)
{
HRSRC hResource = ::FindResource(hInst, lpName, lpType);
if (NULL != hResource)
{
DWORD imageSize = ::SizeofResource(hInst, hResource);
if (0 < imageSize)
{
const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));
if (NULL != pResourceData)
{
TAutoLockedBuff m_Buffer(GMEM_MOVEABLE, imageSize + 1);
void* pBmp;
m_Buffer.CopyFrom(pResourceData, imageSize);
TAutoStream m_Stream(m_Buffer.get());
pGdipCreateBitmapFromStream(m_Stream.get(), &pBmp);
if (NULL != pBmp)
{
pGdipCreateHBITMAPFromBitmap(pBmp, &retVal, 0x00FFFFFF); // this returns NotImplemented
pGdipFree(pBmp);
if(NULL == retVal)
throw std::wstring(L"Unable to extract HBITMAP from Gdiplus::Bitmap");
}
else
throw std::wstring(L"Unable to extract Gdiplus::Bitmap from stream");
}
else
throw std::wstring(L"Unable to lock resource");
}
else
throw std::wstring(L"Size of resource is 0");
}
else
throw std::wstring(L"Unable to find resource");
}
return retVal;
}
GdiPlusDynamic.h
#pragma once
typedef enum {
Ok = 0,
GenericError = 1,
InvalidParameter = 2,
OutOfMemory = 3,
ObjectBusy = 4,
InsufficientBuffer = 5,
NotImplemented = 6,
Win32Error = 7,
WrongState = 8,
Aborted = 9,
FileNotFound = 10,
ValueOverflow = 11,
AccessDenied = 12,
UnknownImageFormat = 13,
FontFamilyNotFound = 14,
FontStyleNotFound = 15,
NotTrueTypeFont = 16,
UnsupportedGdiplusVersion = 17,
GdiplusNotInitialized = 18,
PropertyNotFound = 19,
PropertyNotSupported = 20,
ProfileNotFound = 21
} Status;
enum DebugEventLevel
{
DebugEventLevelFatal,
DebugEventLevelWarning
};
// Callback function that GDI+ can call, on debug builds, for assertions
// and warnings.
typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);
// Notification functions which the user must call appropriately if
// "SuppressBackgroundThread" (below) is set.
typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);
struct GdiplusStartupInput
{
UINT32 GdiplusVersion; // Must be 1 (or 2 for the Ex version)
DebugEventProc DebugEventCallback; // Ignored on free builds
BOOL SuppressBackgroundThread; // FALSE unless you're prepared to call
// the hook/unhook functions properly
BOOL SuppressExternalCodecs; // FALSE unless you want GDI+ only to use
// its internal image codecs.
GdiplusStartupInput(
DebugEventProc debugEventCallback = NULL,
BOOL suppressBackgroundThread = FALSE,
BOOL suppressExternalCodecs = FALSE)
{
GdiplusVersion = 1;
DebugEventCallback = debugEventCallback;
SuppressBackgroundThread = suppressBackgroundThread;
SuppressExternalCodecs = suppressExternalCodecs;
}
};
struct GdiplusStartupOutput
{
// The following 2 fields are NULL if SuppressBackgroundThread is FALSE.
// Otherwise, they are functions which must be called appropriately to
// replace the background thread.
//
// These should be called on the application's main message loop - i.e.
// a message loop which is active for the lifetime of GDI+.
// "NotificationHook" should be called before starting the loop,
// and "NotificationUnhook" should be called after the loop ends.
NotificationHookProc NotificationHook;
NotificationUnhookProc NotificationUnhook;
};
typedef Status (WINAPI *TGdiplusStartup)(ULONG_PTR* token, const GdiplusStartupInput *input, GdiplusStartupOutput *output);
typedef void (WINAPI *TGdiplusShutdown)(ULONG_PTR token);
typedef Status (WINAPI *TGdipCreateBitmapFromStream)(IStream* stream, void **bitmap);
typedef Status (WINAPI *TGdipCreateHBITMAPFromBitmap)(void* bitmap, HBITMAP* hbmReturn, DWORD background);
typedef void (WINAPI *TGdipFree)(void* ptr);
class TDynamicGdiPlus
{
private:
bool everythigOK;
protected:
HMODULE hGdiPlus;
TGdiplusStartup pGdiplusStartup;
TGdiplusShutdown pGdiplusShutdown;
TGdipCreateBitmapFromStream pGdipCreateBitmapFromStream;
TGdipCreateHBITMAPFromBitmap pGdipCreateHBITMAPFromBitmap;
TGdipFree pGdipFree;
ULONG_PTR token;
public:
TDynamicGdiPlus(void);
virtual ~TDynamicGdiPlus(void);
HBITMAP LoadImageFromResource(HINSTANCE hInst, LPCTSTR lpName, LPCTSTR lpType);
};
and GdiPlusDynamicTools.h
#pragma once
class TAutoStream
{
protected:
IStream* pStream;
public:
TAutoStream(HGLOBAL m_hBuffer);
virtual ~TAutoStream(void);
IStream* get(void);
};
class AutoGlobal
{
protected:
HGLOBAL m_hBuffer;
SIZE_T len;
public:
AutoGlobal(UINT uFlags, SIZE_T dwBytes);
virtual ~AutoGlobal(void);
bool IsOk(void);
HGLOBAL get(void);
};
class TAutoLockedBuff : public AutoGlobal
{
protected:
void* pBuffer;
public:
TAutoLockedBuff(UINT uFlags, SIZE_T dwBytes);
virtual ~TAutoLockedBuff(void);
bool IsOk(void);
void CopyFrom(const void* pSrcData, SIZE_T srcLen);
};
You can use IImagingFactory service instead GDI+
This service can render png, bmp with alpha channel.
We use this service for real project under Windows Mobile 6.x
This code mockup:
CComPtr<IImagingFactory> spImageFactory;
spImageFactory.CoCreateInstance(__uuidof(ImagingFactory);
HRSRC hRes = FindResource(hInstance, MAKEINTRESOURCE(resID), _T("PNG"));
DWORD imageSize = SizeOfResource(hInstance, hRes);
HGLOBAL hGlobal = LoadResource(hInstance, hRes);
CComPtr<IImage> spImage;
spImageFactory->CreateImageFromBuffer(LockResource(hGlobal, imageSize), BufferDisposalFlagNone, &spImage);
ImageInfo info = {0};
spImage->GetImageInfo(&info);
CRect rect(x, y, x+info.Width, y+info.Height);
spImage->Draw(hDc, &rect, NULL);