一、概述
在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)