NtOpenKey失败了0xC0000034 - 如何解决这个问题?

时间:2014-09-11 15:31:56

标签: c++ winapi wdk

我正在使用C ++中的VS 2013创建用户模式CMD应用程序,并且我尝试使用其中的本机注册表编辑功能。我试图用NtOpenKey' NtOpenKey'但它始终因“STATUS_OBJECT_NAME_NOT_FOUND”而失败。而且我确定'对象'在它的位置,所以原因必须在其他地方。我想使用本机注册表API,因为他们可以处理隐藏的注册表项' - 查看here了解更多信息。以下是我的代码片段:

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

//....
}

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

注意:这是教育用途,所以请不要问我为什么不使用WIN32 API。

1 个答案:

答案 0 :(得分:19)

NB: 在用户模式下使用内核API 不支持 。我强烈建议不要这样做,除非有充分理由说明为什么有必要。

问题在于:

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

来自documentation for UNICODE_STRING

  

如果字符串以null结尾,则Length不包括尾随空字符。

所以你应该说像

这样的话
UNICODE_STRING uStrTmp = { sizeof(strRegSteam) - sizeof(wchar_t), 
                           sizeof(strRegSteam), 
                           strRegSteam };

如上所述,您的代码试图打开名为L“Valve \ 0”的键,而不是名为L“Valve”的键。


附录: 有争议的是所谓的“隐藏”密钥(一个不幸的名称IMO;密钥对Win32代码可见,他们根本无法实际上是可行的,所以这里是创建一个的工作代码:

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

至于Windows 7,至少,这仍然有效。 (您需要一份ntdll.lib,可以从DDK / WDK获得,以构建此代码。)

在生产代码或其他人的机器上执行此操作。