我正在使用C++中的VS 2013创建用户模式CMD应用程序,我正在尝试使用其中的本机注册表编辑功能.我正试图用'NtOpenKey'打开某个键,但它总是以'STATUS_OBJECT_NAME_NOT_FOUND'失败,我确信'对象'在它的位置,所以原因必须在其他地方.我想使用本机注册表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;
}
//....
}
Run Code Online (Sandbox Code Playgroud)
和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
);
Run Code Online (Sandbox Code Playgroud)
注意:这是教育程序,所以请不要问我为什么不使用WIN32 API.
Har*_*ton 20
注意:不支持从用户模式使用内核API.我强烈建议不要这样做,除非有令人信服的理由说明为什么有必要.
这是问题所在:
UNICODE_STRING uStrTmp = { sizeof(strRegSteam), sizeof(strRegSteam), strRegSteam };
Run Code Online (Sandbox Code Playgroud)
如果字符串以null结尾,则Length不包括尾随空字符.
所以你应该这样说
UNICODE_STRING uStrTmp = { sizeof(strRegSteam) - sizeof(wchar_t),
sizeof(strRegSteam),
strRegSteam };
Run Code Online (Sandbox Code Playgroud)
如上所述,您的代码试图打开名为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
}
Run Code Online (Sandbox Code Playgroud)
至少从Windows 7开始,这仍然有效.(您需要一个ntdll.lib的副本,可以从DDK/WDK获得,以构建此代码.)
请不要没有在生产代码或其他人的机器做到这一点.