Domanda

Dato un handle a una chiave del Registro di Windows, come ad esempio quelli che sono impostati per :: RegOpenKeyEx (), è possibile determinare il percorso completo di quella chiave?

Mi rendo conto che in una semplice applicazione tutto quello che dovete fare è guardare fino 5 o 10 linee e leggere ... ma in un'applicazione complessa come quella che io sono il debug, la chiave che mi interessa può essere aperto da una serie di chiamate.

È stato utile?

Soluzione

Usa LoadLibrary e la funzione NtQueryKey esportato come nel seguente frammento di codice.

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

Questo stamperà il percorso della chiave sulla console:

  

percorso chiave per 00000FDC è   '\ Registry \ Machine \ SOFTWARE \ Microsoft'.

Altri suggerimenti

Nominalmente non perché è solo una maniglia e non v'è alcuna API che io sappia per farvi fare questo nel di normale API di Windows.

Tuttavia, l'API Native ha un sacco di funzioni, alcune delle quali può dare handle aperti per i file dati e simili quindi c'è forse qualcosa di simile per il Registro. Quella e Regmon da SysInternals può fare qualcosa di simile, ma si dovrà Google ho paura: /

È possibile utilizzare RegSaveKey e scrivere in un file, poi guarda il file.

In alternativa è possibile mantenere una mappa globale di HKEYs per LPCWSTRs e aggiungere voci quando vengono aperti e fare le ricerche ogni volta.

Si può anche essere in grado di fare qualcosa con il comando reg! In WinDBG / NTSD, ma non si può semplicemente dare il HKEY. Dovrete fare qualche altro inganno per ottenere le informazioni che si desidera fuori di esso.

Per ntsd/windbg:

!handle yourhandle 4

Ero entusiasta di trovare questo articolo e la sua soluzione ben voluto. Fino a quando ho scoperto che NTDLL.DLL del mio sistema non ha avuto NtQueryKeyType.

Dopo un po 'di caccia in giro, mi sono imbattuto in ZwQueryKey nei forum DDK.

E 'in C #, ma qui è la soluzione che funziona per 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;
}

Ho sempre e solo provato durante l'esecuzione come amministratore, che può essere richiesta.

Il risultato è un po 'stranamente formattato: \REGISTRY\MACHINE\SOFTWARE\company\product per esempio, invece di HKEY_LOCAL_MACHINE\SOFTWARE\company\product

.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top