2009-06-01 5 views
18

Dato un handle per una chiave del Registro di sistema di Windows, come quelli impostati da :: RegOpenKeyEx(), è possibile determinare il percorso completo per quella chiave?Determina il percorso della chiave di registro dall'handle HKEY in C++

Mi rendo conto che in una semplice applicazione tutto quello che devi fare è cercare 5 o 10 righe e leggere ... ma in un'applicazione complessa come quella di cui sto eseguendo il debug, la chiave a cui sono interessato può essere aperto da una serie di chiamate.

risposta

29

Utilizzare la funzione esportata LoadLibrary e NtQueryKey come nel seguente snippet 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'.

+0

Fantastico, stavo guardando esattamente questo! –

+0

[ZwQueryKey in MSDN] (http://msdn.microsoft.com/en-us/library/ff567060 (v = vs.85) .aspx). – Naszta

+0

Un'altra cosa: in un'applicazione (in modalità utente) dovresti usare 'NtQueryKey' invece di' ZwQueryKey'. – Naszta

1

Nominalmente no perché è solo un handle e non esiste alcuna API che io conosca per consentirvi di farlo nelle normali API di Windows.

TUTTAVIA l'API nativa ha molte funzioni alcune delle quali possono darti maniglie aperte per determinati file e simili, quindi potrebbe esserci qualcosa di simile per il Registro. Quello e RegMon di SysInternals possono fare qualcosa di simile, ma tu dovrò Google ho paura:/

1

Puoi usare RegSaveKey e scriverlo in un file, quindi guardare il file.

In alternativa è possibile mantenere una mappa globale di HKEY a LPCWSTR e aggiungere voci quando vengono aperte e effettuate ricerche ogni volta.

Si può anche essere in grado di fare qualcosa con il comando! Reg in WinDBG/NTSD, ma non si può semplicemente dargli l'HKEY. Dovrai fare qualche altro trucco per ottenere le informazioni che desideri.

+0

nota: questa funzione richiede diritti UAC. – sergiol

0

Per ntsd/windbg:

!handle yourhandle 4

0

ero entusiasta di trovare questo articolo e la sua soluzione ben voluto. Fino a quando ho trovato che il mio NTDLL.DLL del mio sistema non aveva NtQueryKeyType.

Dopo aver cercato in giro, ho incontrato 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 richiesto.

Il risultato è un po 'stranamente formattato: \REGISTRY\MACHINE\SOFTWARE\company\product ad esempio, anziché HKEY_LOCAL_MACHINE\SOFTWARE\company\product.

+0

Questo è il nome del formato NT – paulm