2014-09-11 12 views
7

Ich erstelle eine Benutzermodus-CMD-Anwendung, die VS 2013 in C++ verwendet, und ich versuche, die nativen Registrierungsbearbeitungsfunktionen darin zu verwenden. Ich versuche, einen bestimmten Schlüssel mit 'NtOpenKey' zu öffnen, aber es schlägt immer mit 'STATUS_OBJECT_NAME_NOT_FOUND' fehl und ich bin sicher, dass das 'Objekt' an seinem Platz ist, also muss der Grund woanders sein. Ich möchte die systemeigenen Registrierungs-APIs verwenden, weil sie mit "Hidden Registry Keys" umgehen können - siehe here für weitere Informationen. Hier ist ein Ausschnitt aus meinem Code:NtOpenKey schlägt mit 0xC0000034 fehl - wie behebt man das?

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

//.... 
} 

Und 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 
); 

HINWEIS: Es ist für pädagogische prupose so bitte mich nicht fragen, warum ich WIN32 API nicht.

+5

"Objektname nicht gefunden", das ist natürlich ein * sehr * häufiges Problem. Warum auf der Erde machst du das, es fügt nichts zu RegOpenKeyEx() hinzu, nur Elend und selbstverschuldete Verwirrung portierend. –

+1

Es ist für Bildungs-Prupose - also bitte versuchen Sie mir zu helfen, damit umzugehen. – AnArrayOfFunctions

+1

Dies erzieht niemanden, es ist schädlich. Dies ist kein Forum. –

Antwort

19

NB: den Kernel-API vom Benutzermodus verwendet, ist ungestützten. Ich empfehle dringend, dies zu tun, es sei denn, es gibt einen zwingenden Grund, warum es notwendig ist.

Hier ist das Problem:

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

Vom documentation for UNICODE_STRING:

Wenn die Zeichenfolge nullterminierte ist, Länge enthält nicht die Hinternullzeichen.

So sollten Sie so etwas wie

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

geschrieben werden sagen: Ihr Code einen Schlüssel mit dem Namen L „Ventil \ 0“ anstelle des Schlüssel mit dem Namen L „Ventil“ zu öffnen versuchen.


Nachtrag: es umstritten ist, ob so genannte „versteckte“ Schlüssel (ein unglücklicher Name IMO, die Schlüssel zu Win32-Code sichtbar sind, können sie einfach nicht manipuliert werden) tatsächlich möglich sind , also hier funktioniert Code zu erstellen:

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

Ab Windows 7, zumindest, dies noch funktioniert. (Sie erhalten eine Kopie von ntdll.lib benötigen, das von dem DDK/WDK, um diesen Code zu bauen.)

Bitte nicht diesen Code in der Produktion tun oder auf anderen Maschinen der Menschen.

+4

Nebenbei, mit viel Arbeit können Sie dies auf eine unterstützte Weise tun. Erstellen Sie einen Treiber. Diese API wird vom Treiber unterstützt. Übertragen Sie Ihre Kommunikation von User-Space zu Ihrem Treiber und lassen Sie diese Arbeit machen. – Yakk