Search code examples
c++registryhandle

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.


Solution

  • 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'.