Construct if statement on TCHAR array - c++

I have this code which prints the computer name.
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain(void)
{
TCHAR buffer[256] = TEXT("");
TCHAR szDescription[8][32] = { TEXT("NetBIOS"),
TEXT("DNS hostname"),
TEXT("DNS domain"),
TEXT("DNS fully-qualified"),
TEXT("Physical NetBIOS"),
TEXT("Physical DNS hostname"),
TEXT("Physical DNS domain"),
TEXT("Physical DNS fully-qualified") };
int cnf = 0;
DWORD dwSize = sizeof(buffer);
if (!GetComputerNameEx((COMPUTER_NAME_FORMAT)0, buffer, &dwSize))
{
_tprintf(TEXT("GetComputerNameEx failed (%d)\n"), GetLastError());
return;
}
else _tprintf(TEXT("%s: %s\n"), szDescription[0], buffer);
if (buffer == TEXT("DESKTOP-SURPO18")) _tprintf(TEXT("CORRECT"));
dwSize = _countof(buffer);
ZeroMemory(buffer, dwSize);
}
I just want to create or construct a simple if statement like if(buffer == text("MyComputerName")) tprint(TEXT("CORRECT")); but it's not working. Or can you suggest other simplest way of code like I posted above that work with if statement easily using a computer name? Thank you.

Related

Error code 122 using SetupDiGetDeviceRegistryPropertyW to get the required size

I want to get the Device ID of a USB stick by using the Setup API, but first I am trying to understand some of the functions I have to use. The SetupDiGetDeviceRegistryProperty documentation says I can send NULL to the buffer and buffer size to get the required size, but I am getting the 122 error code, which means:
The data area passed to a system call is too small
Can anyone tell me what am I doing wrong?
Here is my code so far:
#include <Windows.h>
#include <wchar.h>
#include <SetupAPI.h>
#pragma comment(lib, "Setupapi.lib")
int wmain(int argc, wchar_t *arv[])
{
// SetupDiGetClassDevs
HDEVINFO hDeviceInfo;
DWORD filterDevInfo = DIGCF_ALLCLASSES;
hDeviceInfo = SetupDiGetClassDevsW(NULL, NULL, NULL, filterDevInfo);
if (hDeviceInfo != INVALID_HANDLE_VALUE)
{
// SetupDiEnumDeviceInfo
DWORD memberIndex = 0;
SP_DEVINFO_DATA devInfoData;
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(
hDeviceInfo,
memberIndex,
&devInfoData))
{
fwprintf(stderr, L"Error on enum: %u\n", GetLastError());
return 1;
}
// SetupDiGetDeviceRegistryProperty
DWORD propertyRetrieved = SPDRP_DEVICEDESC;
DWORD requiredSize;
// First call to get the required size for the buffer
if (!SetupDiGetDeviceRegistryPropertyW(
hDeviceInfo,
&devInfoData,
propertyRetrieved,
NULL,
NULL,
0,
&requiredSize))
{
fwprintf(stderr, L"Error on registry property: %u\n", GetLastError());
return 1;
}
}
else
{
wprintf(L"Error code: %u\n", GetLastError());
return 1;
}
return 0;
}

How can a program read its own image from memory via ReadProcessMemory?

I am trying to make an executable which can read itself from memory using ReadProcessMemory api of windows.
Then, I will use this to calculate the checksum of executable.
This is my code :
#define PSAPI_VERSION 1
#include <string>
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <psapi.h>
#include <Wincrypt.h>
#define BUFSIZE 1024
#define MD5LEN 16
// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS
#pragma comment(lib, "psapi.lib")
int main(void)
{
HWND hMyProcess = (HWND)(GetCurrentProcess());
HMODULE hModule = (HMODULE)GetModuleHandle(NULL);
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
MODULEINFO moduleInfo;
if(hModule != NULL && hMyProcess != NULL){
// if (GetModuleInformation())
GetModuleBaseName(hMyProcess, hModule, szProcessName, MAX_PATH);
printf("%s\n", szProcessName);
if (GetModuleInformation(hMyProcess, hModule, &moduleInfo, sizeof(moduleInfo))){
printf("lpBaseOfDLL : %x\n", moduleInfo.lpBaseOfDll);
printf("Entry Point : %x\n", moduleInfo.EntryPoint);
printf("SizeOfImage : %x\n", moduleInfo.SizeOfImage);
}
}
// Till here working fine, problem lies below
// read process memory
TCHAR *hexEXE;
SIZE_T *lpNumberOfBytesRead;
if(ReadProcessMemory(hMyProcess, moduleInfo.lpBaseOfDll,
hexEXE, moduleInfo.SizeOfImage, 0)){
//printf("%s\n", hexEXE);
printf("Read memory\n");
printf("%d \n",strlen(hexEXE));
}
// will be implemented later, taken from --> https://msdn.microsoft.com/en-us/library/aa382380(VS.85).aspx
DWORD dwStatus = 0;
BOOL bResult = FALSE;
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
/*if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT)){
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
//CloseHandle(hFile);
return dwStatus;
}
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)){
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
//CloseHandle(hFile);
CryptReleaseContext(hProv, 0);
return dwStatus;
}*/
return 0;
}
Problem :
I am not able to read the my own process's memory, it's the first time I'm using WinAPI, so perhaps I am using the function in some wrong way.
The program just hangs and it shows "Windows has encountered some problem..."
Possible Reasons of Error :
I think the handle to the process ( hMyProcess ) I'm getting earlier isn't with the required privileges ( PROCESS_VM_READ ), how do I verify it and if it isn't then how do I get the correct privileges.
TCHAR *hexEXE;
SIZE_T *lpNumberOfBytesRead;
hexEXE = malloc (moduleInfo.SizeOfImage);
if(ReadProcessMemory(hMyProcess, moduleInfo.lpBaseOfDll,
hexEXE, moduleInfo.SizeOfImage, 0)){
//printf("%s\n", hexEXE);
printf("Read memory\n");
//hexEXE is not a string. Don't use it in strlen.
//printf("%d \n",strlen(hexEXE));
print("%d \n", moduleInfo.SizeOfImage);
}
The ReadProcessMemory need a memory to store the image. So, the "hexEXE" need be assign to a memory buffer.
Sorry for the extended discussion, but I got it running by changing the code to instead of using ReadProcessMemory directly iterating over the memory through a for loop like this :
long *baseAddress = (long *)moduleInfo.lpBaseOfDll;
printf("%d %x\n",baseAddress, baseAddress);
for (int i = 0; i < moduleInfo.SizeOfImage; ++i){
long *addressToRead = baseAddress+i;
printf("%x : %x\n", addressToRead, *addressToRead);
}
Here's the output :
Further thoughts
However, I don't understand why am I not able to get it using ReadProcessMemory.

Changing IP in C++ by using addIPAdress()

Like in the title - I've been working on code in C++ that changes my IP address. The program works "alright" and shows it added new IP, however the old IP stay the same and doesn't change.
So what I have to fix in my code to get rid off of the problem
If entire script is wrong I would really appreciate an example of program which would work.
The code:
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
int main()
{
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
DWORD dwRetVal;
UINT IPAddress;
UINT IPMask;
ULONG NTEContext = 0;
ULONG NTEInstance = 0;
LPVOID lpMsgBuf;
pIPAddrTable = (MIB_IPADDRTABLE *)malloc(sizeof(MIB_IPADDRTABLE));
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
pIPAddrTable = (MIB_IPADDRTABLE *)malloc(dwSize);
}
if ((dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)) == NO_ERROR) {
printf("\tAddress: %ld\n", pIPAddrTable->table[0].dwAddr);
printf("\tMask: %ld\n", pIPAddrTable->table[0].dwMask);
}
else {
printf("Call to GetIpAddrTable failed.\n");
}
IPAddress = inet_addr("192.168.0.2");
IPMask = inet_addr("255.255.255.0");
if ((dwRetVal = AddIPAddress(IPAddress,
IPMask,
pIPAddrTable->table[0].dwIndex,
&NTEContext, &NTEInstance)) == NO_ERROR) {
printf("\tIP address added.\n");
}
else {
printf("Error adding IP address.\n");
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)& lpMsgBuf, 0, NULL)) {
printf("\tError: %s", lpMsgBuf);
}
LocalFree(lpMsgBuf);
}
system("c:\\windows\\system32\\ipconfig");
system("pause");
}
Footnote: Program was modified from an example from Microsoft https://msdn.microsoft.com/en-us/library/windows/desktop/aa365875(v=vs.85).aspx Though, it contains error which makes my VS to reach breakpoints caused by 'GlobalFree(pIPAddrTable);'
If anyone interested I'm inviting for a C++ project on GitHub
All is conformant with MSDN documentation. The page on AddIpAddress states:
The AddIPAddress function is used to add a new IPv4 address entry on a local computer. The IPv4 address added by the AddIPAddress function is not persistent...
That means that calling this function will have no effect on pre-existing network addresses and just add a temporary new one.
If you want the change the static network address, you should try to use the EnableStatic method of the Win32_NetworkAdapterConfiguration class.

Debug content of shared memory

I got two processes. In process A, application Alpha is prepared for using shared memory. In process B, my windows console application with a main method accesses this shared memory. It works, I can connect to the memory. Unfortunately if I store the memory content in a variable (here pBuf) and inspect the variable via MsVisualStudioDebugger, there is only one letter in the buffer - what went wrong? How am I able to look in the memory/file to get a clue, what objects are stored in the memory? Thanks in advance.
Here is the code of my console app:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#pragma comment(lib, "user32.lib")
using namespace std;
#define BUF_SIZE 256
TCHAR szName[] = TEXT("SIMITSHM"); // Name des SHMs;
int main(void){
std::cout << "*** start SharedMemory ***\n";
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szName);
if (hMapFile == NULL){
MessageBox(NULL, TEXT("Could not open file mapping object"), TEXT("FEHLER"), MB_OK);
return 1;
}
pBuf = (LPTSTR) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
if (pBuf == NULL){
MessageBox(NULL, TEXT("Could not map view of file"), TEXT("FEHLER"), MB_OK);
CloseHandle(hMapFile);
return 1;
}
MessageBox(NULL, pBuf, TEXT("SIMIT-SHM"), MB_OK); // content of memory
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
std::cout << "*** close app by typing a number. ***\n";
int a = 0;
cin >> a;
return 0;
}
UPDATE: after doing more research on this issue, I guess the problem is the casting of the return value of MapViewOfFile()-function.
UPDATE-2: Thanks Hans! I was able to look the pBuf content as a hexdump, see:
UPDATE-3: Thanks Hans! Due to your advice I was able to use fwrite() to put the shared-memory-content in a file on my local machine. Moreover I am able to see some familiar names, i.e. names like EingangMotor1 which I configured in application-Alpha and it seems this content was stored in shared memory. Now I hope to play around with application-Alpha, recognize the related changes in shared-memory and afterwards hopefully I will be able to change the values of the shared memory variable values, so application-Alpha will change its behaviour on the fly.
UPDATE-4: current code - thanks in advance for feedback, which lines needs to be improved.
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <strsafe.h>
#include <fstream>
#include <sstream>
#include <vector>
#pragma comment(lib, "user32.lib")
using namespace std;
#define BUF_SIZE 256
TCHAR szName[] = TEXT("SIMITSHM"); // Name des SHMs;
int main(void){
std::cout << "*** Start SharedMemory ***\n";
HANDLE hMapFile;
FILE * pBuf;
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szName);
if (hMapFile == NULL){
MessageBox(NULL, TEXT("Could not open file mapping object"), TEXT("ERROR"), MB_OK);
return 1;
}
// MapViewOfFile return a pointer to void, so you need to cast it to a suitable structure
pBuf = (FILE*) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
if (pBuf == NULL){
MessageBox(NULL, TEXT("Could not map view of file"), TEXT("ERROR"), MB_OK);
CloseHandle(hMapFile);
return 1;
}
// write file
FILE * pFile;
pFile = fopen ("shm-main-simit-content-fwrite.txt","w");
fwrite(pBuf, 50, 20, pFile);
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
std::cout << "*** close app by typing a number. ***\n";
int a = 0;
cin >> a;
return 0;
}
Yes, you certainly have a type mismatch. That file is very unlikely to contain a properly zero-terminated C string. Using the TCHAR macros adds to the randomness, there is no point in using them anymore. The last non-Unicode version of Windows died 10 years ago.
Answering the question: use Debug + Windows + Memory + Memory 1 and put "pBuf" in the Address box. You'll see a raw hex dump of the shared memory content.

Determine path to registry key from HKEY handle in C++

Given a handle to a Windows Registry Key, such as the ones that are set by ::RegOpenKeyEx(), is it possible to determine the full path to that key?
I realize that in a simple application all you have to do is look up 5 or 10 lines and read... but in a complex app like the one I'm debugging, the key I'm interested in can be opened from a series of calls.
Use LoadLibrary and NtQueryKey exported function as in the following code snippet.
#include <windows.h>
#include <string>
typedef LONG NTSTATUS;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#ifndef STATUS_BUFFER_TOO_SMALL
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#endif
std::wstring GetKeyPathFromKKEY(HKEY key)
{
std::wstring keyPath;
if (key != NULL)
{
HMODULE dll = LoadLibrary(L"ntdll.dll");
if (dll != NULL) {
typedef DWORD (__stdcall *NtQueryKeyType)(
HANDLE KeyHandle,
int KeyInformationClass,
PVOID KeyInformation,
ULONG Length,
PULONG ResultLength);
NtQueryKeyType func = reinterpret_cast<NtQueryKeyType>(::GetProcAddress(dll, "NtQueryKey"));
if (func != NULL) {
DWORD size = 0;
DWORD result = 0;
result = func(key, 3, 0, 0, &size);
if (result == STATUS_BUFFER_TOO_SMALL)
{
size = size + 2;
wchar_t* buffer = new (std::nothrow) wchar_t[size/sizeof(wchar_t)]; // size is in bytes
if (buffer != NULL)
{
result = func(key, 3, buffer, size, &size);
if (result == STATUS_SUCCESS)
{
buffer[size / sizeof(wchar_t)] = L'\0';
keyPath = std::wstring(buffer + 2);
}
delete[] buffer;
}
}
}
FreeLibrary(dll);
}
}
return keyPath;
}
int _tmain(int argc, _TCHAR* argv[])
{
HKEY key = NULL;
LONG ret = ERROR_SUCCESS;
ret = RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft", &key);
if (ret == ERROR_SUCCESS)
{
wprintf_s(L"Key path for %p is '%s'.", key, GetKeyPathFromKKEY(key).c_str());
RegCloseKey(key);
}
return 0;
}
This will print the key path on the console:
Key path for 00000FDC is
'\REGISTRY\MACHINE\SOFTWARE\Microsoft'.
I was excited to find this article and its well liked solution.
Until I found that my system's NTDLL.DLL did not have NtQueryKeyType.
After some hunting around, I ran across ZwQueryKey in the DDK forums.
It is in C#, but here is the solution that works for me:
enum KEY_INFORMATION_CLASS
{
KeyBasicInformation, // A KEY_BASIC_INFORMATION structure is supplied.
KeyNodeInformation, // A KEY_NODE_INFORMATION structure is supplied.
KeyFullInformation, // A KEY_FULL_INFORMATION structure is supplied.
KeyNameInformation, // A KEY_NAME_INFORMATION structure is supplied.
KeyCachedInformation, // A KEY_CACHED_INFORMATION structure is supplied.
KeyFlagsInformation, // Reserved for system use.
KeyVirtualizationInformation, // A KEY_VIRTUALIZATION_INFORMATION structure is supplied.
KeyHandleTagsInformation, // Reserved for system use.
MaxKeyInfoClass // The maximum value in this enumeration type.
}
[StructLayout(LayoutKind.Sequential)]
public struct KEY_NAME_INFORMATION
{
public UInt32 NameLength; // The size, in bytes, of the key name string in the Name array.
public char[] Name; // An array of wide characters that contains the name of the key.
// This character string is not null-terminated.
// Only the first element in this array is included in the
// KEY_NAME_INFORMATION structure definition.
// The storage for the remaining elements in the array immediately
// follows this element.
}
[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int ZwQueryKey(IntPtr hKey, KEY_INFORMATION_CLASS KeyInformationClass, IntPtr lpKeyInformation, int Length, out int ResultLength);
public static String GetHKeyName(IntPtr hKey)
{
String result = String.Empty;
IntPtr pKNI = IntPtr.Zero;
int needed = 0;
int status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, IntPtr.Zero, 0, out needed);
if ((UInt32)status == 0xC0000023) // STATUS_BUFFER_TOO_SMALL
{
pKNI = Marshal.AllocHGlobal(sizeof(UInt32) + needed + 4 /*paranoia*/);
status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, pKNI, needed, out needed);
if (status == 0) // STATUS_SUCCESS
{
char[] bytes = new char[2 + needed + 2];
Marshal.Copy(pKNI, bytes, 0, needed);
// startIndex == 2 skips the NameLength field of the structure (2 chars == 4 bytes)
// needed/2 reduces value from bytes to chars
// needed/2 - 2 reduces length to not include the NameLength
result = new String(bytes, 2, (needed/2)-2);
}
}
Marshal.FreeHGlobal(pKNI);
return result;
}
I've only ever tried it while running as Administrator, which may be required.
The result is a bit oddly formatted: \REGISTRY\MACHINE\SOFTWARE\company\product for example, instead of HKEY_LOCAL_MACHINE\SOFTWARE\company\product.
Nominally no because it's just a handle and there is no API that I know of to let you do this in the normal Windows API's.
HOWEVER the Native API has lots of functions some of which can give you handles open for given files and the like so there maybe something similar for the Registry. That and RegMon by SysInternals may do something like this but you'll have to Google I'm afraid :/
You can use RegSaveKey and write it to a file, then look at the file.
Alternatively you can keep a global map of HKEYs to LPCWSTRs and add entries when you open them and do lookups whenever.
You may also be able to do something with the !reg command in WinDBG / NTSD, but you can't just give it the HKEY. You'll have to do some other trickery to get the info you want out of it.
Since std::wstring allows to construct string from pointer and count of characters, and the kernel string always return the count of bytes, it is not necessary to terminated the string with NUL. I do not suggest that to add size or to offset the pointer by constant number directly, it's better to use the real data type like the structure types instead, and std::vector<UCHAR> instead of new for dynamic memory allocating. I modified the code from highly upvoted answer as the followings.
The legacy way, obtaining the function pointer from ntdll.dll dynamically:
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#include <string>
#include <vector>
#define REG_KEY_PATH_LENGTH 1024
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
KeyLayerInformation,
MaxKeyInfoClass
} KEY_INFORMATION_CLASS;
typedef struct _KEY_NAME_INFORMATION {
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
typedef NTSTATUS (NTAPI *PFN_NtQueryKey)(
__in HANDLE /* KeyHandle */,
__in KEY_INFORMATION_CLASS /* KeyInformationClass */,
__out_opt PVOID /* KeyInformation */,
__in ULONG /* Length */,
__out ULONG * /* ResultLength */
);
std::wstring RegQueryKeyPath(HKEY hKey)
{
std::wstring keyPath;
if (hKey != NULL)
{
HMODULE hinstDLL = GetModuleHandleW(L"ntdll.dll");
if (hinstDLL != NULL)
{
FARPROC pfn = GetProcAddress(hinstDLL, "NtQueryKey");
if (pfn != NULL)
{
NTSTATUS Status;
std::vector<UCHAR> Buffer(FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + sizeof(WCHAR) * REG_KEY_PATH_LENGTH);
KEY_NAME_INFORMATION *pkni;
ULONG Length;
TryAgain:
Status = reinterpret_cast<PFN_NtQueryKey>(pfn)(hKey, KeyNameInformation, Buffer.data(), Buffer.size(), &Length);
switch (Status) {
case STATUS_BUFFER_TOO_SMALL:
case STATUS_BUFFER_OVERFLOW:
Buffer.resize(Length);
goto TryAgain;
case STATUS_SUCCESS:
pkni = reinterpret_cast<KEY_NAME_INFORMATION *>(Buffer.data());
keyPath.assign(pkni->Name, pkni->NameLength / sizeof(WCHAR));
default:
break;
}
}
}
}
return keyPath;
}
If you are using Visual Studio 2015 or above, ntdll.lib is included by default, so I suggest that linking to ntdll.dll statically:
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll")
#include <string>
#include <vector>
#define REG_KEY_PATH_LENGTH 1024
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
KeyLayerInformation,
MaxKeyInfoClass
} KEY_INFORMATION_CLASS;
typedef struct _KEY_NAME_INFORMATION {
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
EXTERN_C NTSYSAPI NTSTATUS NTAPI NtQueryKey(
__in HANDLE /* KeyHandle */,
__in KEY_INFORMATION_CLASS /* KeyInformationClass */,
__out_opt PVOID /* KeyInformation */,
__in ULONG /* Length */,
__out ULONG * /* ResultLength */
);
std::wstring RegQueryKeyPath(HKEY hKey)
{
std::wstring keyPath;
NTSTATUS Status;
std::vector<UCHAR> Buffer(FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + sizeof(WCHAR) * REG_KEY_PATH_LENGTH);
KEY_NAME_INFORMATION *pkni;
ULONG Length;
TryAgain:
Status = NtQueryKey(hKey, KeyNameInformation, Buffer.data(), Buffer.size(), &Length);
switch (Status) {
case STATUS_BUFFER_TOO_SMALL:
case STATUS_BUFFER_OVERFLOW:
Buffer.resize(Length);
goto TryAgain;
case STATUS_SUCCESS:
pkni = reinterpret_cast<KEY_NAME_INFORMATION *>(Buffer.data());
keyPath.assign(pkni->Name, pkni->NameLength / sizeof(WCHAR));
default:
break;
}
return keyPath;
}
Note that NtQueryKey returned STATUS_BUFFER_OVERFLOW but not STATUS_BUFFER_TOO_SMALL on Windows 10 if the supplied buffer is insufficient.
For ntsd/windbg:
!handle yourhandle 4