2017-09-14 3 views
2

BUTObtenir poignée à clé avec NtCreateKey/NtOpenKey

Je suis en train de faire une fonction qui permettra de créer une sous-clé donnée dans la ruche de Registre HKCU, ou ouvrir la sous-clé si elle existe déjà, retourne TRUE.

NOTES

Soit RegSidPath représentent un chemin de registre HKCU complet avec un user SID qui y est annexé tel que \\Registry\\User\\S-1-5-20-xxxxxx-xxxxxx-xxxxxxxx-1050

Soit KeyToCreate représentent un chemin de registre spécifique tel que \\Software\\MyCompany\\MySoftware\\MySubKey

CODE

J'ai la fonction suivante:

BOOL CreateHKCUKey(PWCHAR RegSidPath, PWCHAR KeyToCreate) { 

UNICODE_STRING uString; 
RtlInitUnicodeString(&uString, RegSidPath); 

OBJECT_ATTRIBUTES ObjAttributes; 
InitializeObjectAttributes(&ObjAttributes, &uString, OBJ_CASE_INSENSITIVE, 0, 0); 

HANDLE BaseKeyHandle = NULL; 
NTSTATUS Status = NtOpenKey(&BaseKeyHandle, KEY_CREATE_SUB_KEY, &ObjAttributes); 
if (NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) { 

    UNICODE_STRING KeyString = { 0 }; 
    do { 
     PWCHAR NextSubKey = StrStrW((KeyString.Length == 0 ? KeyToCreate : KeyString.Buffer) + 1, L"\\"); 
     DWORD CurrentKeyLength = lstrlenW(KeyToCreate) - lstrlenW(NextSubKey); 
     PWCHAR CurrentSubKey = PWCHAR(GlobalAlloc(GPTR, CurrentKeyLength + sizeof(WCHAR))); 
     if (CurrentSubKey != ERROR) { 
      memcpy(CurrentSubKey, KeyToCreate, CurrentKeyLength * sizeof(WCHAR)); 
      CurrentSubKey[CurrentKeyLength] = UNICODE_NULL; 

      RtlInitUnicodeString(&KeyString, CurrentSubKey); 

      OBJECT_ATTRIBUTES KeyAttributes; 
      InitializeObjectAttributes(&KeyAttributes, &KeyString, OBJ_CASE_INSENSITIVE, &BaseKeyHandle, 0); 

      HANDLE CurrentHiveEntry = NULL; 
      Status = NtOpenKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes); 
      if (RtlNtStatusToDosError(Status) == ERROR_BAD_PATHNAME) { 
       InitializeObjectAttributes(&KeyAttributes, &KeyString, OBJ_CASE_INSENSITIVE, &CurrentHiveEntry, 0); 

       DWORD DefaultDisposition; 
       Status = NtCreateKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &DefaultDisposition); 
       if (NT_SUCCESS(Status)) { 
        if (StrCmpNW(KeyString.Buffer + uString.Length, KeyString.Buffer, lstrlenW(KeyToCreate) == 0)) 
         return TRUE; 
        else continue; 
       } else break; 
      } else break; 
      BaseKeyHandle = CurrentHiveEntry; 
     } 
    } while (TRUE); 
} 
NtClose(BaseKeyHandle); 
return FALSE; 
} 

PROBLÈME

Chaque fois que le code arrive à cette partie de la fonction

Status = NtOpenKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes); 
     if (RtlNtStatusToDosError(Status) == ERROR_BAD_PATHNAME) { 

La valeur de retour est toujours ERROR_BAD_PATHNAME (161) même si la sous-clé en cours existe déjà.

QUESTION

Quelle est la raison, et ce que je fais mal? Y a-t-il quelque chose que j'ai fait qui ne soit pas correct, et comment puis-je le réparer?

+0

Au point d'échec, quelle est la valeur de 'CurrentSubKey'? En outre, la seule erreur que vous vérifiez est 'ERROR_BAD_PATHNAME', si la boucle précédente a échoué avec un autre code d'erreur, alors' BaseKeyHandle' ne pointera pas là où vous l'attendez. (Oh, et vous fuyez les poignées.) –

+0

@HarryJohnston '\\ Software' - que puis-je faire pour déboguer l'erreur –

+2

Pourquoi avez-vous besoin de l'API NT pour cela? – Anders

Répondre

1
NTSTATUS CreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, PWCHAR RegSidPath, PWCHAR KeyToCreate, PULONG Disposition) 
{ 
    UNICODE_STRING ObjectName; 
    RtlInitUnicodeString(&ObjectName, RegSidPath); 

    OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName ,OBJ_CASE_INSENSITIVE }; 

    NTSTATUS status = ZwOpenKey(&oa.RootDirectory, KEY_CREATE_SUB_KEY, &oa); 

    if (0 <= status) 
    { 
     ObjectName.Buffer = KeyToCreate; 

     do 
     { 
      ACCESS_MASK Access; 

      if (KeyToCreate = wcschr(++ObjectName.Buffer, '\\')) 
      { 
       ObjectName.Length = (USHORT)RtlPointerToOffset(ObjectName.Buffer, KeyToCreate); 
       Access = KEY_CREATE_SUB_KEY; 
      } 
      else 
      { 
       ObjectName.Length = (USHORT)wcslen(ObjectName.Buffer) * sizeof(WCHAR); 
       Access = DesiredAccess; 
      } 

      ObjectName.MaximumLength = ObjectName.Length; 

      status = ZwCreateKey(KeyHandle, Access, &oa, 0, 0, 0, Disposition); 

      NtClose(oa.RootDirectory); 

      oa.RootDirectory = *KeyHandle; 

     } while (0 <= status && (ObjectName.Buffer = KeyToCreate)); 
    } 

    return status; 
} 

et utiliser comme

HANDLE hKey; 
    NTSTATUS status = CreateKey(&hKey, KEY_ALL_ACCESS, 
    L"\\REGISTRY\\USER\\S-***", 
    L"\\Software\\MyCompany\\MySoftware\\MySubKey", 0); 
1

À moins que vous écrivez un pilote, utilisez RegCreateKeyEx() à la place. Il gère toute la logique de création de clés intermédiaires pour vous si elles n'existent pas déjà. 1 appel de fonction, pas de bouclage nécessaire.

HKEY hKey; 
DWORD dwDisposition; 
LONG lRet = RegCreateKeyExW(HKEY_USERS, L"S-1-5-20-xxxxxx-xxxxxx-xxxxxxxx-1050\\Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition); 
if (lRet == 0) 
{ 
    ... 
    RegCloseKey(hKey); 
} 

Cependant, pour accéder à la ruche HKEY_CURRENT_USER d'un utilisateur spécifique, la solution préférée consiste à utiliser RegOpenCurrentUser() ou LoadUserProfile() au lieu d'accéder HKEY_USERS directement:

// impersonate the desired user first, then... 

HKEY hRootKey; 
LONG lRet = RegOpenCurrentUser(samDesired, &hRootKey); 
if (lRet == 0) 
{ 
    HKEY hKey; 
    DWORD dwDisposition; 
    lRet = RegCreateKeyExW(hRootKey, L"Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition); 
    if (lRet == 0) 
    { 
     ... 
     RegCloseKey(hKey); 
    } 
    RegCloseKey(hRootKey); 
} 

// stop impersonating... 

// obtain token to desired user first, then... 

PROFILEINFO profile = {0}; 
profile.dwSize = sizeof(profile); 
profile.dwFlags = PI_NOUI; 

if (LoadUserProfile(hToken, &profile)) 
{ 
    HKEY hKey; 
    DWORD dwDisposition; 
    LONG lRet = RegCreateKeyExW((HKEY)profile.hProfile, L"Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition); 
    if (lRet == 0) 
    { 
     ... 
     RegCloseKey(hKey); 
    } 
    UnloadUserProfile(hToken, profile.hProfile); 
} 

// release token ... 
+0

Je sais comment utiliser Advapi32, merci, mais je cherchais des appels NTAPI. Ce dernier est très bien documenté partout ailleurs. –