2014-09-11 11 views
7

Tworzę aplikację CMD w trybie użytkownika przy użyciu VS 2013 w C++ i próbuję użyć w niej rodzimych funkcji edycji rejestru. Próbuję otworzyć określony klucz za pomocą "NtOpenKey", ale zawsze kończy się to niepowodzeniem z "STATUS_OBJECT_NAME_NOT_FOUND" i jestem pewien, że "obiekt" jest na swoim miejscu, więc powód musi być gdzie indziej. Chcę używać macierzystego rejestru API, ponieważ mogą obsługiwać "Ukryte klucze rejestru" - spójrz na here, aby uzyskać więcej informacji. Oto fragment mojego kodu:NtOpenKey kończy się niepowodzeniem z 0xC0000034 - jak to naprawić?

#include <Windows.h> 
#include <tchar.h> 

#include <wininet.h> 

#include <iostream> 

#include <stdio.h> 
#include <string.h> 
#include <assert.h> 

#include "Nt_Funcs_declr.h" //here I have manually included the native api declarations as normally I'm denied to use them but they're exported in ntdll.dll so basically it is possible 

#include <zlib.h> 

//Obitain Steam folder path 

wchar_t *GetSteamPathBuffer() 
{ 
    //Open the Sofware Steam registry 

    OBJECT_ATTRIBUTES objAttrs; 

    objAttrs.Length = sizeof(OBJECT_ATTRIBUTES); 

    objAttrs.RootDirectory = NULL; 

    wchar_t strRegSteam [] = L"\\Registry\\Machine\\SOFTWARE\\Valve"; 

    UNICODE_STRING uStrTmp = { sizeof(strRegSteam), sizeof(strRegSteam), strRegSteam }; 

    objAttrs.ObjectName = &uStrTmp; 

    objAttrs.Attributes = OBJ_CASE_INSENSITIVE; // 

    objAttrs.SecurityDescriptor = NULL; 

    objAttrs.SecurityQualityOfService = NULL; 

    HANDLE pKey; 

    ULONG tmmp = NtOpenKey(&pKey, GENERIC_READ, &objAttrs); //here it fails with 'STATUS_OBJECT_NAME_NOT_FOUND' 
    if(tmmp) 
    { 
     cout << "Error: " << GetLastError(); 
     return NULL; 
    } 

//.... 
} 

I Nt_Funcs_declr.h:

#pragma once 


//NTDLL import declarations 

#define STATUS_BUFFER_TOO_SMALL   ((NTSTATUS)0xC0000023L) 

// 
// Unicode strings are counted 16-bit character strings. If they are 
// NULL terminated, Length does not include trailing NULL. 
// 

typedef struct _UNICODE_STRING { 
    USHORT Length; 
    USHORT MaximumLength; 
#ifdef MIDL_PASS 
    [size_is(MaximumLength/2), length_is((Length)/2)] USHORT * Buffer; 
#else // MIDL_PASS 
    _Field_size_bytes_part_(MaximumLength, Length) PWCH Buffer; 
#endif // MIDL_PASS 
} UNICODE_STRING; 
typedef UNICODE_STRING *PUNICODE_STRING; 
typedef const UNICODE_STRING *PCUNICODE_STRING; 

// 
// Valid values for the Attributes field 
// 

#define OBJ_INHERIT    0x00000002L 
#define OBJ_PERMANENT   0x00000010L 
#define OBJ_EXCLUSIVE   0x00000020L 
#define OBJ_CASE_INSENSITIVE 0x00000040L 
#define OBJ_OPENIF    0x00000080L 
#define OBJ_OPENLINK   0x00000100L 
#define OBJ_KERNEL_HANDLE  0x00000200L 
#define OBJ_FORCE_ACCESS_CHECK 0x00000400L 
#define OBJ_VALID_ATTRIBUTES 0x000007F2L 

typedef struct _OBJECT_ATTRIBUTES { 
    ULONG Length; 
    HANDLE RootDirectory; 
    PUNICODE_STRING ObjectName; 
    ULONG Attributes; 
    PVOID SecurityDescriptor;  // Points to type SECURITY_DESCRIPTOR 
    PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE 
} OBJECT_ATTRIBUTES; 
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; 
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES; 


extern "C" 
NTSYSAPI 
NTSTATUS 
NTAPI 
NtOpenKey(
_Out_ PHANDLE KeyHandle, 
_In_ ACCESS_MASK DesiredAccess, 
_In_ POBJECT_ATTRIBUTES ObjectAttributes 
); 

typedef enum _KEY_INFORMATION_CLASS { 
    KeyBasicInformation, 
    KeyNodeInformation, 
    KeyFullInformation, 
    KeyNameInformation, 
    KeyCachedInformation, 
    KeyFlagsInformation, 
    KeyVirtualizationInformation, 
    KeyHandleTagsInformation, 
    KeyTrustInformation, 
    MaxKeyInfoClass // MaxKeyInfoClass should always be the last enum 
} KEY_INFORMATION_CLASS; 

extern "C" 
NTSYSAPI 
NTSTATUS 
NTAPI 
NtQueryKey(
_In_ HANDLE KeyHandle, 
_In_ KEY_INFORMATION_CLASS KeyInformationClass, 
_Out_writes_bytes_opt_(Length) PVOID KeyInformation, 
_In_ ULONG Length, 
_Out_ PULONG ResultLength 
); 

typedef enum _KEY_VALUE_INFORMATION_CLASS { 
    KeyValueBasicInformation, 
    KeyValueFullInformation, 
    KeyValuePartialInformation, 
    KeyValueFullInformationAlign64, 
    KeyValuePartialInformationAlign64, 
    MaxKeyValueInfoClass // MaxKeyValueInfoClass should always be the last enum 
} KEY_VALUE_INFORMATION_CLASS; 

typedef struct _KEY_VALUE_PARTIAL_INFORMATION { 
    ULONG TitleIndex; 
    ULONG Type; 
    ULONG DataLength; 
    _Field_size_bytes_(DataLength) UCHAR Data[1]; // Variable size 
} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; 

extern "C" 
NTSYSAPI 
NTSTATUS 
NTAPI 
NtQueryValueKey(
_In_ HANDLE KeyHandle, 
_In_ PUNICODE_STRING ValueName, 
_In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 
_Out_writes_bytes_opt_(Length) PVOID KeyValueInformation, 
_In_ ULONG Length, 
_Out_ PULONG ResultLength 
); 

UWAGA: To dla prupose edukacyjnego więc proszę nie pytaj mnie dlaczego nie używam API Win32.

+5

"nie znaleziono nazwy obiektu", co oczywiście jest * bardzo * częstym problemem. Dlaczego, na Boga, robisz to, to nie dodaje niczego do RegOpenKeyEx(), tylko przenosi nędzę i samookaleczone zamieszanie. –

+1

To jest na edukacyjną próbę - więc lepiej postaraj się mi pomóc. – AnArrayOfFunctions

+1

To nikogo nie kształci, jest szkodliwe. To nie jest forum. –

Odpowiedz

19

Uwaga: pomocą API jądra z trybu użytkownika jest niepodparta. Zdecydowanie odradzam robienie tego, chyba że istnieje przekonujący powód, dla którego jest to konieczne.

Oto problem:

UNICODE_STRING uStrTmp = { sizeof(strRegSteam), sizeof(strRegSteam), strRegSteam }; 

Z documentation for UNICODE_STRING:

Jeśli łańcuch jest zakończony zerem, długość nie obejmuje tyłu znak null.

Należy więc mówić coś takiego

UNICODE_STRING uStrTmp = { sizeof(strRegSteam) - sizeof(wchar_t), 
          sizeof(strRegSteam), 
          strRegSteam }; 

Jak napisano, Twój kod został próbując otworzyć klucz o nazwie L „Valve \ 0” zamiast klucz o nazwie L „zawór”.


Uzupełnienie: zostało zakwestionowane, czy tak zwane „ukryte” klucze (niefortunna nazwa IMO; klawisze są widoczne w kodzie Win32, oni po prostu nie mogą być manipulowane) są rzeczywiście możliwe , więc tutaj działa kod:

#include <Windows.h> 

#include <stdio.h> 

typedef struct _UNICODE_STRING { 
    USHORT Length; 
    USHORT MaximumLength; 
    PWCH Buffer; 
} UNICODE_STRING; 
typedef UNICODE_STRING *PUNICODE_STRING; 
typedef const UNICODE_STRING *PCUNICODE_STRING; 

typedef struct _OBJECT_ATTRIBUTES { 
    ULONG Length; 
    HANDLE RootDirectory; 
    PUNICODE_STRING ObjectName; 
    ULONG Attributes; 
    PVOID SecurityDescriptor;   
    PVOID SecurityQualityOfService; 
} OBJECT_ATTRIBUTES; 
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; 
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES; 

#define OBJ_CASE_INSENSITIVE 0x00000040L 

#pragma comment(lib, "ntdll.lib") 

__declspec(dllimport) NTSTATUS NTAPI NtCreateKey(
    __out PHANDLE KeyHandle, 
    __in ACCESS_MASK DesiredAccess, 
    __in POBJECT_ATTRIBUTES ObjectAttributes, 
    __reserved ULONG TitleIndex, 
    __in_opt PUNICODE_STRING Class, 
    __in ULONG CreateOptions, 
    __out_opt PULONG Disposition 
    ); 

NTSYSAPI NTSTATUS NTAPI NtOpenKey(
    __out PHANDLE KeyHandle, 
    __in ACCESS_MASK DesiredAccess, 
    __in POBJECT_ATTRIBUTES ObjectAttributes 
    ); 

NTSYSAPI NTSTATUS NTAPI NtDeleteKey(
    __out HANDLE KeyHandle 
    ); 

int main(int argc, char ** argv) 
{ 
    HANDLE pKey; 
    NTSTATUS result; 

    OBJECT_ATTRIBUTES objAttrs; 
    wchar_t strSoftwareKey [] = L"\\Registry\\Machine\\SOFTWARE\\Test\0Key"; 

// If you use this string instead, the key functions normally, proving that the 
// issue isn't because we're using UTF-16 rather than ANSI strings: 
// 
// wchar_t strSoftwareKey [] = L"\\Registry\\Machine\\SOFTWARE\\Test\u2D80Key"; 

    UNICODE_STRING uStrSoftwareKey = { 
     sizeof(strSoftwareKey) - sizeof(wchar_t), 
     sizeof(strSoftwareKey), 
     strSoftwareKey }; 

    objAttrs.Length = sizeof(OBJECT_ATTRIBUTES); 
    objAttrs.RootDirectory = NULL; 
    objAttrs.ObjectName = &uStrSoftwareKey; 
    objAttrs.Attributes = OBJ_CASE_INSENSITIVE; 
    objAttrs.SecurityDescriptor = NULL; 
    objAttrs.SecurityQualityOfService = NULL; 

    result = NtCreateKey(&pKey, GENERIC_ALL, &objAttrs, 0, NULL, 0, NULL); 
    if(result) 
    { 
     printf("NtCreateKey: %x\n", result); 
     return NULL; 
    } 

#if 0 // enable this section to delete the key 
     // you won't be able to use regedit! 
    result = NtDeleteKey(pKey); 
    if(result) 
    { 
     printf("NtDeleteKey: %x\n", result); 
     return NULL; 
    } 
#endif 
} 

Od wersji Windows 7 to nadal działa. (Musisz kopię ntdll.lib, dostępnego z DDK/WDK, w celu zbudowania tego kodu.)

Proszę nie zrobić to w kodzie produkcyjnym lub na maszynach innych ludzi.

+4

Na marginesie, z dużą ilością pracy możesz to zrobić w obsługiwany sposób. Utwórz sterownik. Ze sterownika ten interfejs API jest obsługiwany. Przekaż swoją komunikację z przestrzeni użytkownika do sterownika i poproś ją o wykonanie tej pracy. – Yakk

Powiązane problemy