2009-06-01 13 views
18

Étant donné un handle vers une clé de Registre Windows, tels que ceux définis par :: RegOpenKeyEx(), est-il possible de déterminer le chemin d'accès complet à cette clé?Déterminer le chemin vers la clé de registre à partir du handle HKEY en C++

Je me rends compte que dans une application simple tout ce que vous avez à faire est de chercher 5 ou 10 lignes et lire ... mais dans une application complexe comme celle que je débogue, la clé qui m'intéresse peut être ouvert à partir d'une série d'appels.

Répondre

29

Utilisez la fonction exportée LoadLibrary et NtQueryKey comme dans l'extrait de code suivant.

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

Ce imprimera le chemin de clé sur la console:

chemin clé pour 00000FDC est '\ REGISTRY \ MACHINE \ SOFTWARE \ Microsoft.

+0

Génial, je cherchais exactement ça! –

+0

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

+0

Encore une chose: dans une application (en mode utilisateur), vous devriez utiliser 'NtQueryKey' au lieu de' ZwQueryKey'. – Naszta

1

Nominalement non parce que c'est juste une poignée et il n'y a pas d'API que je connaisse pour vous permettre de le faire dans l'API Windows normale. Cependant, l'API native a beaucoup de fonctions dont certaines peuvent vous donner des poignées ouvertes pour des fichiers donnés et ainsi de suite, donc il peut y avoir quelque chose de similaire pour le registre. Cela et RegMon par SysInternals peut faire quelque chose comme ça, mais vous aurez à Google J'ai peur:/

1

Vous pouvez utiliser RegSaveKey et l'écrire dans un fichier, puis regardez le fichier. Vous pouvez également conserver une carte globale de HKEY à LPCWSTRs et ajouter des entrées lorsque vous les ouvrez et effectuez des recherches à chaque fois.

Vous pouvez également faire quelque chose avec la commande! Reg dans WinDBG/NTSD, mais vous ne pouvez pas lui donner le HKEY. Vous devrez faire d'autres trucs pour obtenir l'info que vous voulez en sortir.

+0

note: cette fonction nécessite des droits UAC. – sergiol

0

Pour ntsd/windbg:

!handle yourhandle 4

0

j'étais heureux de trouver cet article et sa solution bien aimé. Jusqu'à ce que je trouve que NTDLL.DLL de mon système n'avait pas NtQueryKeyType. Après quelques recherches, j'ai couru sur ZwQueryKey dans les forums DDK.

Il est en C#, mais voici la solution qui fonctionne pour moi:

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

Je ne l'ai jamais essayé lors de l'exécution en tant qu'administrateur, ce qui peut être nécessaire.

Le résultat est un peu bizarrement formaté: \REGISTRY\MACHINE\SOFTWARE\company\product par exemple, au lieu de HKEY_LOCAL_MACHINE\SOFTWARE\company\product.

+0

Ceci est des noms de format NT – paulm

Questions connexes