一、概述
在DLL初始化的时候有时不能调用其它系统DLL的函数,以免导致问题,但有时候又必须要调用怎么办?一种办法就是自己直接调用NTDLL接口,这样肯定没有问题。
下面我写个自己调用Registry的封装类,用来代替原本系统注册表API。
二、申明NTDLL导出函数
在自己工程中需要调用NTDLL导出函数,可以通GetProcessAddr来获取函数地址再调用,也可以通过导入库的方式(这种需要ntdll.lib文件,在DDK中有),我这里采用第二种方式。
函数和类型声明:
NTDllDecl.h
#pragma once #include <windows.h> #include <winternl.h> namespace NT { extern "C" { // macro definition #ifndef NTSTATUS #define NTSTATUS LONG #endif #ifndef NTAPI #define NTAPI __stdcall #endif #ifndef NTSYSAPI #define NTSYSAPI __declspec(dllimport) #endif #ifndef STATUS_BUFFER_OVERFLOW #define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) #endif typedef enum _KEY_INFORMATION_CLASS { KeyBasicInformation, KeyNodeInformation, KeyFullInformation, KeyNameInformation, KeyCachedInformation, KeyFlagsInformation, KeyVirtualizationInformation, KeyHandleTagsInformation, MaxKeyInfoClass // MaxKeyInfoClass should always be the last enum } KEY_INFORMATION_CLASS; 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_BASIC_INFORMATION { LARGE_INTEGER LastWriteTime; ULONG TitleIndex; ULONG NameLength; WCHAR Name[1]; // Variable length string } KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; typedef struct _KEY_NODE_INFORMATION { LARGE_INTEGER LastWriteTime; ULONG TitleIndex; ULONG ClassOffset; ULONG ClassLength; ULONG NameLength; WCHAR Name[1]; // Variable length string // Class[1]; // Variable length string not declared } KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION; typedef struct _KEY_FULL_INFORMATION { LARGE_INTEGER LastWriteTime; ULONG TitleIndex; ULONG ClassOffset; ULONG ClassLength; ULONG SubKeys; ULONG MaxNameLen; ULONG MaxClassLen; ULONG Values; ULONG MaxValueNameLen; ULONG MaxValueDataLen; WCHAR Class[1]; // Variable length } KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; typedef struct _KEY_VALUE_BASIC_INFORMATION { ULONG TitleIndex; ULONG Type; ULONG NameLength; WCHAR Name[1]; // Variable size } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; typedef struct _KEY_VALUE_PARTIAL_INFORMATION { ULONG TitleIndex; ULONG Type; ULONG DataLength; UCHAR Data[1]; // Variable size } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; // Registry NTSYSAPI NTSTATUS NTAPI ZwCreateKey( OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex, IN PUNICODE_STRING Class, IN ULONG CreateOptions, OUT PULONG Disposition ); NTSYSAPI NTSTATUS NTAPI ZwOpenKey( OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes ); NTSYSAPI NTSTATUS NTAPI ZwQueryKey( IN HANDLE KeyHandle, IN KEY_INFORMATION_CLASS KeyInformationClass, OUT PVOID KeyInformation, IN ULONG KeyInformationLength, OUT PULONG ResultLength ); NTSYSAPI NTSTATUS NTAPI ZwSetValueKey( IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN ULONG TitleIndex, IN ULONG Type, IN PVOID Data, IN ULONG DataSize ); NTSYSAPI NTSTATUS NTAPI ZwQueryValueKey( IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, OUT PVOID KeyValueInformation, IN ULONG KeyValueInformationLength, OUT PULONG ResultLength ); NTSYSAPI NTSTATUS NTAPI ZwEnumerateKey( IN HANDLE KeyHandle, IN ULONG Index, IN KEY_INFORMATION_CLASS KeyInformationClass, OUT PVOID KeyInformation, IN ULONG KeyInformationLength, OUT PULONG ResultLength ); NTSYSAPI NTSTATUS NTAPI ZwClose( IN HANDLE Handle ); NTSYSAPI NTSTATUS NTAPI RtlFormatCurrentUserKeyPath( OUT PUNICODE_STRING RegistryPath ); } };
三、封装自己注册表函数
自己定义一个类用来封装注册表函数,我这里只封装了几个需要用的注册表函数(参考ReatOS和Windows代码),其余的可以后续再添加。
注册封装类声明:
NTRegistry.h
//******************************************************************** // 文件名: NTRegistry.h // 文件描述: Ntdll导出注册表函数定义头文件 // 作者: // 版本: 1.0 // // 修改历史: // 备注: //********************************************************************* #pragma once #ifndef STATIC #define STATIC static #endif #ifndef NTSTATUS #define NTSTATUS LONG #endif class NTRegistry { public: STATIC LONG RegCreateKey( HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition); STATIC LONG RegOpenKey( HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); STATIC LONG RegQueryInfoKey( HKEY hKey, LPWSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ); STATIC LONG RegSetValue( HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE* lpData, DWORD cbData); STATIC LONG RegQueryValue( HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ); STATIC LONG RegEnumKey( HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcbName, LPDWORD lpReserved, LPWSTR lpClass, LPDWORD lpcbClass, PFILETIME lpftLastWriteTime); STATIC LONG RegCloseKey(HKEY hKey); private: STATIC NTSTATUS OpenCurrentUser( IN ACCESS_MASK DesiredAccess, OUT PHANDLE KeyHandle); STATIC NTSTATUS OpenLocalMachineKey( OUT PHANDLE KeyHandle); STATIC NTSTATUS OpenCurrentConfigKey (PHANDLE KeyHandle); STATIC NTSTATUS OpenUsersKey(PHANDLE KeyHandle); STATIC NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle); STATIC NTSTATUS MapDefaultKey( OUT PHANDLE RealKey, IN HKEY Key); };
注册封装类定义:
NTRegistry.cpp
#include "StdAfx.h" #include "NTRegistry.h" #include "NTDllDecl.h" #define ARGUMENT_PRESENT( arg ) ((( PVOID ) arg ) != (( PVOID ) NULL )) #define DEFAULT_KEY_NAME_SIZE 128 #define DEFAULT_CLASS_SIZE 128 #define DEFAULT_VALUE_SIZE 128 #define REG_MAX_NAME_SIZE 256 #define REG_MAX_DATA_SIZE 2048 #ifndef STATUS_SUCCESS #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #endif #define RTL_CONSTANT_STRING(__SOURCE_STRING__) { sizeof(__SOURCE_STRING__) - sizeof((__SOURCE_STRING__)[0]), sizeof(__SOURCE_STRING__), (__SOURCE_STRING__) } #define IsPredefKey(HKey) (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000) #define ClosePredefKey(Handle) if ((ULONG_PTR)Handle & 0x1) { NT::ZwClose(Handle); } NTSTATUS NTRegistry::OpenCurrentUser( IN ACCESS_MASK DesiredAccess, OUT PHANDLE KeyHandle) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyPath; NTSTATUS Status; /* Get the user key */ Status = NT::RtlFormatCurrentUserKeyPath(&KeyPath); if (NT_SUCCESS(Status)) { /* Initialize the attributes and open it */ InitializeObjectAttributes(&ObjectAttributes, &KeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NT::ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); /* Free the path and return success if it worked */ RtlFreeUnicodeString(&KeyPath); } return Status; } NTSTATUS NTRegistry::OpenLocalMachineKey( OUT PHANDLE KeyHandle) { OBJECT_ATTRIBUTES Attributes; UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\Registry\Machine"); NTSTATUS Status; InitializeObjectAttributes( &Attributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NT::ZwOpenKey(KeyHandle, MAXIMUM_ALLOWED, &Attributes); return Status; } NTSTATUS NTRegistry::OpenClassesRootKey(PHANDLE KeyHandle) { OBJECT_ATTRIBUTES Attributes; UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\Registry\Machine\Software\CLASSES"); InitializeObjectAttributes( &Attributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); return NT::ZwOpenKey(KeyHandle, MAXIMUM_ALLOWED, &Attributes); } NTSTATUS NTRegistry::OpenUsersKey(PHANDLE KeyHandle) { OBJECT_ATTRIBUTES Attributes; UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\Registry\User"); InitializeObjectAttributes(&Attributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); return NT::ZwOpenKey(KeyHandle, MAXIMUM_ALLOWED, &Attributes); } NTSTATUS NTRegistry::OpenCurrentConfigKey (PHANDLE KeyHandle) { OBJECT_ATTRIBUTES Attributes; UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\Registry\Machine\System\CurrentControlSet\Hardware Profiles\Current"); InitializeObjectAttributes(&Attributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); return NT::ZwOpenKey(KeyHandle, MAXIMUM_ALLOWED, &Attributes); } NTSTATUS NTRegistry::MapDefaultKey( OUT PHANDLE RealKey, IN HKEY Key) { NTSTATUS Status; if (!IsPredefKey(Key)) { *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1); return STATUS_SUCCESS; } switch ((LONG)Key) { case HKEY_CURRENT_USER: { Status = OpenCurrentUser(MAXIMUM_ALLOWED, RealKey); } break; case HKEY_LOCAL_MACHINE: { Status = OpenLocalMachineKey(RealKey); } break; case HKEY_CLASSES_ROOT: { Status = OpenClassesRootKey(RealKey); } break; case HKEY_USERS: { Status = OpenUsersKey(RealKey); } break; case HKEY_CURRENT_CONFIG: { Status = OpenCurrentConfigKey(RealKey); } break; default: Status = STATUS_INVALID_PARAMETER; break; } return Status; } LONG NTRegistry::RegCreateKey( HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition) { UNICODE_STRING SubKeyString; UNICODE_STRING ClassString; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE ParentKey = NULL; NTSTATUS Status; if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES)) { return ERROR_INVALID_USER_BUFFER; } /* get the real parent key */ Status = MapDefaultKey(&ParentKey, hKey); if (!NT_SUCCESS(Status)) { return RtlNtStatusToDosError(Status); } if (!phkResult) { return ERROR_INVALID_PARAMETER; } RtlInitUnicodeString(&ClassString, lpClass); RtlInitUnicodeString(&SubKeyString, lpSubKey); InitializeObjectAttributes( &ObjectAttributes, &SubKeyString, OBJ_CASE_INSENSITIVE, (HANDLE)ParentKey, lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL); Status = NT::ZwCreateKey( (PHANDLE)phkResult, samDesired, &ObjectAttributes, 0, (lpClass == NULL) ? NULL : &ClassString, /* optional*/ dwOptions, lpdwDisposition ); ClosePredefKey(ParentKey); return RtlNtStatusToDosError( Status ); } LONG NTRegistry::RegOpenKey( HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING SubKeyString; HANDLE KeyHandle; NTSTATUS Status; if (!phkResult) { return ERROR_INVALID_PARAMETER; } Status = MapDefaultKey(&KeyHandle, hKey); if (!NT_SUCCESS(Status)) { return RtlNtStatusToDosError(Status); } if (lpSubKey != NULL) RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey); else RtlInitUnicodeString(&SubKeyString, (LPWSTR)L""); InitializeObjectAttributes( &ObjectAttributes, &SubKeyString, OBJ_CASE_INSENSITIVE, KeyHandle, NULL ); Status = NT::ZwOpenKey( (PHANDLE)phkResult, samDesired, &ObjectAttributes ); ClosePredefKey(KeyHandle); return RtlNtStatusToDosError( Status ); } LONG NTRegistry::RegQueryInfoKey( HKEY hKey, LPWSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ) { NT::KEY_FULL_INFORMATION FullInfoBuffer; NT::PKEY_FULL_INFORMATION FullInfo; ULONG FullInfoSize; ULONG ClassLength = 0; HANDLE KeyHandle; NTSTATUS Status; ULONG Length; LONG ErrorCode = ERROR_SUCCESS; if ((lpClass) && (!lpcbClass)) { return ERROR_INVALID_PARAMETER; } Status = MapDefaultKey(&KeyHandle, hKey); if (!NT_SUCCESS(Status)) { return RtlNtStatusToDosError(Status); } if (lpClass != NULL) { if (*lpcbClass > 0) { ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); } else { ClassLength = 0; } FullInfoSize = sizeof(NT::KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3); FullInfo = (NT::PKEY_FULL_INFORMATION)HeapAlloc(GetProcessHeap(), 0, FullInfoSize); if (FullInfo == NULL) { ErrorCode = ERROR_OUTOFMEMORY; goto Cleanup; } FullInfo->ClassLength = ClassLength; } else { FullInfoSize = sizeof(NT::KEY_FULL_INFORMATION); FullInfo = &FullInfoBuffer; FullInfo->ClassLength = 0; } FullInfo->ClassOffset = FIELD_OFFSET(NT::KEY_FULL_INFORMATION, Class); Status = NT::ZwQueryKey(KeyHandle, NT::KeyFullInformation, FullInfo, FullInfoSize, &Length); if (!NT_SUCCESS(Status)) { if (lpClass != NULL) { HeapFree(GetProcessHeap(), 0, FullInfo); } ErrorCode = RtlNtStatusToDosError(Status); goto Cleanup; } if (lpcSubKeys != NULL) { *lpcSubKeys = FullInfo->SubKeys; } if (lpcbMaxSubKeyLen != NULL) { *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1; } if (lpcbMaxClassLen != NULL) { *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1; } if (lpcValues != NULL) { *lpcValues = FullInfo->Values; } if (lpcbMaxValueNameLen != NULL) { *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1; } if (lpcbMaxValueLen != NULL) { *lpcbMaxValueLen = FullInfo->MaxValueDataLen; } if (lpftLastWriteTime != NULL) { lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart; lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart; } if (lpClass != NULL) { if (FullInfo->ClassLength > ClassLength) { ErrorCode = ERROR_BUFFER_OVERFLOW; } else { RtlCopyMemory(lpClass, FullInfo->Class, FullInfo->ClassLength); *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR); lpClass[*lpcbClass] = 0; } HeapFree(GetProcessHeap(), 0, FullInfo); } Cleanup: ClosePredefKey(KeyHandle); return ErrorCode; } LONG NTRegistry::RegSetValue( HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE* lpData, DWORD cbData) { UNICODE_STRING ValueName; PUNICODE_STRING pValueName; HANDLE KeyHandle; NTSTATUS Status; Status = MapDefaultKey(&KeyHandle, hKey); if (!NT_SUCCESS(Status)) { return RtlNtStatusToDosError(Status); } RtlInitUnicodeString(&ValueName, lpValueName); pValueName = &ValueName; if ((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ) || (dwType == REG_MULTI_SZ) && (cbData != 0)) { PWSTR pwsData = (PWSTR)lpData; if((pwsData[cbData / sizeof(WCHAR) - 1] != L'