NtOpenKey与0xC0000034一起失败-如何修复此问题? 我在C++中使用VS 2013创建用户模式CMD应用程序,我尝试使用它的本地注册表编辑功能。我试图用“NtOpenKey”打开某个键,但总是用“STATUS\u OBJECT\u NAME\u NOT\u FOUND”失败,我确信“OBJECT”在它的位置,所以原因一定在其他地方。我想使用本机注册表API,因为它们可以处理“隐藏的注册表项”——查看更多信息。以下是我的代码片段: #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; } //.... }

NtOpenKey与0xC0000034一起失败-如何修复此问题? 我在C++中使用VS 2013创建用户模式CMD应用程序,我尝试使用它的本地注册表编辑功能。我试图用“NtOpenKey”打开某个键,但总是用“STATUS\u OBJECT\u NAME\u NOT\u FOUND”失败,我确信“OBJECT”在它的位置,所以原因一定在其他地方。我想使用本机注册表API,因为它们可以处理“隐藏的注册表项”——查看更多信息。以下是我的代码片段: #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; } //.... },c++,winapi,wdk,C++,Winapi,Wdk,注意:这是出于教育目的,所以请不要问我为什么不使用WIN32 API。NB:从用户模式使用内核API是不受支持的。我强烈建议不要这样做,除非有令人信服的理由说明有必要这样做 问题是: UNICODE_STRING uStrTmp = { sizeof(strRegSteam), sizeof(strRegSteam), strRegSteam }; 从: 如果字符串以null结尾,则长度不包括尾随的null字符 所以你应该这样说 UNICODE_STRING uStrTmp = { sizeo

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

NB:从用户模式使用内核API是不受支持的。我强烈建议不要这样做,除非有令人信服的理由说明有必要这样做

问题是:

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

如果字符串以null结尾,则长度不包括尾随的null字符

所以你应该这样说

UNICODE_STRING uStrTmp = { sizeof(strRegSteam) - sizeof(wchar_t), 
                           sizeof(strRegSteam), 
                           strRegSteam };
如前所述,您的代码试图打开名为L“Valve\0”的键,而不是名为L“Valve”的键


附录:关于所谓的“隐藏”键(在我看来,这是一个不幸的名字;这些键对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
}
#包括
#包括
typedef结构\u UNICODE\u字符串{
USHORT长度;
USHORT最大长度;
PWCH缓冲器;
}UNICODE_字符串;
typedef UNICODE_字符串*PUNICODE_字符串;
typedef const UNICODE_字符串*PCUNICODE_字符串;
类型定义结构_对象_属性{
乌龙长度;
处理根目录;
PUNICODE_字符串ObjectName;
乌龙属性;
PVOID安全描述符;
PVOID安全性服务质量;
}对象属性;
typedef对象属性*POBJECT属性;
typedef CONST OBJECT_属性*PCOBJECT_属性;
#定义不区分大小写的对象0x00000040L
#pragma注释(lib,“ntdll.lib”)
__declspec(dllimport)NTSTATUS NTAPI NtCreateKey(
__拿出幻影钥匙柄,
__在ACCESS_MASK DesiredAccess中,
__在POBJECT_属性ObjectAttributes中,
__保留ULONG TitleIndex,
__在字符串类中,
__在ULONG CreateOptions中,
__不选普龙性格
);
NTSYSAPI NTSTATUS NTAPI NtOpenKey(
__拿出幻影钥匙柄,
__在ACCESS_MASK DesiredAccess中,
__在POBJECT_属性中ObjectAttributes
);
NTSYSAPI NTSTATUS NTAPI NtDeleteKey(
__外把手钥匙把手
);
int main(int argc,字符**argv)
{
处理pKey;
状态结果;
对象属性objAttrs;
wchar\u t strSoftwareKey[]=L“\\Registry\\Machine\\SOFTWARE\\Test\0Key”;
//如果改为使用此字符串,则键可以正常工作,从而证明
//问题并不是因为我们使用的是UTF-16而不是ANSI字符串:
//
//wchar\u t strSoftwareKey[]=L“\\Registry\\Machine\\SOFTWARE\\Test\u2D80Key”;
UNICODE_字符串和SoftwareKey={
sizeof(strSoftwareKey)-sizeof(wchar_t),
sizeof(strSoftwareKey),
strSoftwareKey};
objAttrs.Length=sizeof(对象属性);
objAttrs.RootDirectory=NULL;
objAttrs.ObjectName=&ustSoftwareKey;
Attributes=OBJ_不区分大小写;
objAttrs.SecurityDescriptor=NULL;
objAttrs.SecurityQualityOfService=NULL;
结果=NtCreateKey(&pKey,GENERIC_ALL,&objAttrs,0,NULL,0,NULL);
如果(结果)
{
printf(“NtCreateKey:%x\n”,结果);
返回NULL;
}
#如果0//请启用此部分以删除密钥
//您将无法使用regedit!
结果=NtDeleteKey(pKey);
如果(结果)
{
printf(“NtDeleteKey:%x\n”,结果);
返回NULL;
}
#恩迪夫
}
至少在Windows7中,这仍然有效。(您需要一份ntdll.lib的副本,可从DDK/WDK获得,以便生成此代码。)


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

未找到对象名称,这当然是一个非常常见的问题。你到底为什么要这样做,它没有给RegOpenKeyEx()添加任何内容,只是移植了痛苦和自我造成的混乱。据介绍,
NtOpenKey
不包括在用户模式应用程序应该使用的本机API调用列表中。因此,说“不要使用它”,是有帮助的。据我所知,它只能通过
ZwOpenKey
例程从驱动程序中使用。@Specializet:Windows中没有隐藏的注册表项,但恶意软件可以(或至少可以)创建它们,如OP链接到的文章所述。(有可能Windows从那时起已经被更新,以防止创建此类密钥,但我还没有看到任何关于此类更改的报告。)此外,大多数NtXXX函数实际上可以从Win32代码访问;它们必须是,因为Win32 API使用它们。它们不受支持,可能会在不通知的情况下更改,但您可以使用它们。@Specializet:如果您有一些实际证据,例如描述注册表基本格式的文档,请出示它。内核注册表函数使用计数字符串的事实表明,该设计实际上可能允许包含嵌入式nul的键名,如果是这样,Win32 API使用nul终止字符串的事实显然会使它无法访问这些键。@Specializet:好的,我现在可以确认(从Windows 7开始)您确实可以创建一个注册表项,其名称包含嵌入的null。如果有人感兴趣,可在上获取代码。(不,这并不是因为“regedit使用UCHAR”;如果您使用非空Unicode字符创建一个键名,regedit可以很好地处理它。这个问题只发生在嵌入的空字符中,并且是所有使用Win32 API的代码中固有的。)另外,您可以通过支持的方式完成大量工作。创建一个驱动程序。从驱动程序来看,支持此API。将您的通信从用户空间中继到您的驱动程序,并让它完成此工作。
#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
}