从C ++中的HKEY句柄确定注册表项的路径

时间:2009-06-01 22:06:14

标签: c++ registry handle

给定Windows注册表项的句柄,例如:: RegOpenKeyEx()设置的句柄,是否可以确定该键的完整路径?

我意识到在一个简单的应用程序中你所要做的就是查找5行或10行并阅读...但是在我正在调试的复杂应用程序中,我可以打开我感兴趣的键来自一系列电话。

5 个答案:

答案 0 :(得分:30)

使用LoadLibraryNtQueryKey导出的功能,如以下代码段所示。

#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;
}

这将在控制台上打印关键路径:

  

00000FDC的关键路径是   '\ REGISTRY \ MACHINE \ SOFTWARE \ Microsoft的。

答案 1 :(得分:1)

名义上没有,因为它只是一个句柄,我知道没有API可以让你在普通的Windows API中执行此操作。

然而,Native API具有许多功能,其中一些功能可以为给定文件等提供处理打开,因此注册表可能有类似的功能。那个和SysInternals的RegMon可能会做这样的事情,但你不得不谷歌我害怕:/

答案 2 :(得分:1)

您可以使用RegSaveKey并将其写入文件,然后查看该文件。

或者,您可以将HKEY的全局映射保存到LPCWSTR,并在打开它们时添加条目并随时进行查找。

你也可以在WinDBG / NTSD中使用!reg命令做一些事情,但你不能只给它HKEY。你将不得不做一些其他的技巧来获得你想要的信息。

答案 3 :(得分:0)

ntsd/windbg

!handle yourhandle 4

答案 4 :(得分:0)

我很高兴能找到这篇文章及其备受欢迎的解决方案。 直到我发现我的系统的NTDLL.DLL没有NtQueryKeyType。

经过一番狩猎,我在DDK论坛上遇到了ZwQueryKey。

它在C#中,但这是适用于我的解决方案:

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;
}

我只是在以管理员身份运行时尝试过,这可能是必需的。

结果格式有点奇怪:\REGISTRY\MACHINE\SOFTWARE\company\product例如,而不是HKEY_LOCAL_MACHINE\SOFTWARE\company\product