2009-06-01 4 views
18

Dando un identificador a una clave del registro de Windows, como las que establece :: RegOpenKeyEx(), ¿es posible determinar la ruta completa a esa clave?Determinar la ruta a la clave de registro desde el controlador HKEY en C++

Me doy cuenta de que en una aplicación simple todo lo que tienes que hacer es buscar 5 o 10 líneas y leer ... pero en una aplicación compleja como la que estoy depurando, la clave que me interesa puede ser abierto desde una serie de llamadas.

Respuesta

29

Uso LoadLibrary y NtQueryKey función exportada como en el siguiente fragmento de código.

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

Esto imprimirá el camino tecla de la consola:

ruta clave para 00000FDC es '\ REGISTRY \ MACHINE \ SOFTWARE \ Microsoft'.

+0

Impresionante, estaba buscando Exactamente eso! –

+0

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

+0

Una cosa más: en una aplicación (en modo de usuario) debe usar 'NtQueryKey' en lugar de' ZwQueryKey'. – Naszta

1

Nominalmente no, porque es solo un identificador y no hay una API que conozca para permitirle hacer esto en las API normales de Windows.

SIN EMBARGO, la API nativa tiene muchas funciones, algunas de las cuales pueden darle identificadores abiertos para archivos determinados y similares, por lo que tal vez haya algo similar para el Registro. Eso y RegMon by SysInternals pueden hacer algo como esto, pero tendrás que Google. Temo:/

1

Puedes usar RegSaveKey y escribirlo en un archivo, luego mirar el archivo.

O bien, puede mantener un mapa global de HKEYs en LPCWSTRs y agregar entradas cuando los abre y realiza búsquedas cada vez.

También puede hacer algo con el comando! Reg en WinDBG/NTSD, pero no puede simplemente darle el HKEY. Tendrás que hacer otros trucos para obtener la información que deseas.

+0

nota: esa función requiere derechos de UAC. – sergiol

0

Para ntsd/windbg:

!handle yourhandle 4

0

tenía ganas de encontrar este artículo y su solución muy querido. Hasta que encontré que NTDLL.DLL de mi sistema no tenía NtQueryKeyType.

Después de buscar algo, me encontré con ZwQueryKey en los foros de DDK.

Es en C#, pero aquí es la solución que funciona para mí:

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

He intentado sólo alguna vez que mientras se ejecuta como administrador, que pueda ser requerida.

El resultado es un formato extrañamente extraño: \REGISTRY\MACHINE\SOFTWARE\company\product por ejemplo, en lugar de HKEY_LOCAL_MACHINE\SOFTWARE\company\product.

+0

Esto es nombres de formato NT – paulm

Cuestiones relacionadas