自己调用NTDLL函数
一、概述
在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) #endiftypedef 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 #endifclass 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);elseRtlInitUnicodeString(&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'\0') &&(pwsData[cbData / sizeof(WCHAR)] == L'\0')){/* Increment length if last character is not zero and next is zero */cbData += sizeof(WCHAR);}}Status = NT::ZwSetValueKey(hKey,&ValueName,0,dwType,(PVOID)lpData,cbData);ClosePredefKey(KeyHandle);return RtlNtStatusToDosError( Status ); }LONG NTRegistry::RegQueryValue(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData) {NTSTATUS Status;UNICODE_STRING ValueName;ULONG BufferLength;NT::KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;PVOID KeyValueInformation;ULONG ResultLength;HANDLE KeyHandle;BYTE PrivateKeyValueInformation[ sizeof( NT::KEY_VALUE_PARTIAL_INFORMATION ) +DEFAULT_VALUE_SIZE ];//// Validate dependency between lpData and lpcbData parameters.// if( ARGUMENT_PRESENT( lpReserved ) ||(ARGUMENT_PRESENT( lpData ) && ( ! ARGUMENT_PRESENT( lpcbData )))) {return ERROR_INVALID_PARAMETER;}Status = MapDefaultKey(&KeyHandle,hKey);if (!NT_SUCCESS(Status)){return RtlNtStatusToDosError(Status);}//// Convert the value name to a counted Unicode string.// RtlInitUnicodeString( &ValueName, lpValueName );//// First we assume that the information we want will fit on// PrivateKeyValueInformattion// KeyValueInformationClass = ( ARGUMENT_PRESENT( lpcbData ))?NT::KeyValuePartialInformation :NT::KeyValueBasicInformation;KeyValueInformation = PrivateKeyValueInformation;BufferLength = sizeof( PrivateKeyValueInformation ); Status = NT::ZwQueryValueKey(KeyHandle,&ValueName,KeyValueInformationClass,KeyValueInformation,BufferLength,&ResultLength);if( ( Status == STATUS_BUFFER_OVERFLOW ) &&( !ARGUMENT_PRESENT( lpData ) ) ) {Status = STATUS_SUCCESS;}if( Status == STATUS_BUFFER_OVERFLOW ) {//// The buffer defined in the stack wasn't big enough to hold// the Value information.// If the caller's buffer is big enough to hold the value data// then allocate a new buffer, and call the NT API again.// if( ( ( KeyValueInformationClass == NT::KeyValuePartialInformation ) &&( ARGUMENT_PRESENT( lpData ) ) &&( *lpcbData >= (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength)) ) {BufferLength = ResultLength;KeyValueInformation = HeapAlloc( GetProcessHeap( ), 0, BufferLength);//// If the memory allocation fails, return a Registry error.// if( ! KeyValueInformation ) {return ERROR_OUTOFMEMORY;}//// Query for the necessary information about the supplied value.// Status = NT::ZwQueryValueKey( KeyHandle,&ValueName,KeyValueInformationClass,KeyValueInformation,BufferLength,&ResultLength);}}if( NT_SUCCESS( Status ) &&ARGUMENT_PRESENT( lpData ) ) {//// If requested, copy the value data// if( *lpcbData >= (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength ) {RtlMoveMemory( lpData, (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->Data,(( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength);} else {Status = STATUS_BUFFER_OVERFLOW;}}//// Certain information is returned on success or in the case of// NtQueryValueKey returning STATUS_BUFFER_OVERFLOW. This information// is always available because we always pass the minimum size required for// the NtQueryValueKey API.// if( NT_SUCCESS( Status ) ||( Status == STATUS_BUFFER_OVERFLOW ) ) {if( KeyValueInformationClass == NT::KeyValueBasicInformation ) {//// If requested, return the value type.// if( ARGUMENT_PRESENT( lpType )) {*lpType = (( NT::PKEY_VALUE_BASIC_INFORMATION )KeyValueInformation )->Type;}} else {//// If requested, return the value type.// if( ARGUMENT_PRESENT( lpType )) {*lpType = (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->Type;}//// Return the value data size// *lpcbData = (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength;}}//// Transmit all of the data back to the client.// if( ARGUMENT_PRESENT( lpcbData ) ) {if( NT_SUCCESS( Status ) &&ARGUMENT_PRESENT( lpData ) ) {*lpcbData = (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength;} else {//// The API failed, so make sure that no data is transmitted back// to the client. This ensures that the client stub will not// attempt to unmarshall data that doesn't exist.// *lpcbData = 0;}}//// If memory was allocated, then free it// if( KeyValueInformation != PrivateKeyValueInformation ) {HeapFree( GetProcessHeap( ), 0, KeyValueInformation );}return RtlNtStatusToDosError( Status ); }LONG NTRegistry::RegEnumKey(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcClass,PFILETIME lpftLastWriteTime) {NTSTATUS Status;NT::KEY_INFORMATION_CLASS KeyInformationClass;UNICODE_STRING NameString;UNICODE_STRING ClassString;PVOID KeyInformation;ULONG BufferLength;ULONG ResultLength;HANDLE KeyHandle;BYTE PrivateKeyInformation[ sizeof( NT::KEY_NODE_INFORMATION ) +DEFAULT_KEY_NAME_SIZE +DEFAULT_CLASS_SIZE ];if( !ARGUMENT_PRESENT( lpName ) ||(ARGUMENT_PRESENT( lpClass ) && ( ! ARGUMENT_PRESENT( lpcClass )))) {return ERROR_INVALID_PARAMETER;}//// Use the supplied name string buffer as the buffer in a counted// Unicode string.// NameString.Length = 0;if ((*lpcName << 1) > 0xFFFE) {NameString.MaximumLength = ( USHORT ) 0xFFFE;} else {NameString.MaximumLength = ( USHORT )( *lpcName << 1 );} NameString.Buffer = lpName;//// If supplied use the supplied name string buffer as the buffer in a// counted Unicode string.// if (ARGUMENT_PRESENT( lpClass ))RtlInitUnicodeString(&ClassString, (LPWSTR)lpClass);elseRtlInitUnicodeString(&ClassString, (LPWSTR)L""); //// First we assume that the information we want will fit on// PrivateKeyValueInformattion// KeyInformationClass = (ARGUMENT_PRESENT( lpClass )) ? NT::KeyNodeInformation : NT::KeyBasicInformation;KeyInformation = PrivateKeyInformation;BufferLength = sizeof( PrivateKeyInformation );Status = MapDefaultKey(&KeyHandle,hKey);if (!NT_SUCCESS(Status)){return RtlNtStatusToDosError(Status);}Status = NT::ZwEnumerateKey(KeyHandle, dwIndex,KeyInformationClass,KeyInformation,BufferLength,&ResultLength);if( Status == STATUS_BUFFER_OVERFLOW ) {//// The buffer defined in the stack wasn't big enough to hold// the Key information.// If the caller's buffer are big enough to hold the key name// and key class, then allocate a new buffer, and call the// NT API again.// if( ( ( KeyInformationClass == NT::KeyBasicInformation ) &&( (ULONG)(NameString.MaximumLength) >= (( NT::PKEY_BASIC_INFORMATION )KeyInformation )->NameLength + sizeof(UNICODE_NULL)) ) ||( ( KeyInformationClass == NT::KeyNodeInformation ) &&( (ULONG)(NameString.MaximumLength) >= (( NT::PKEY_NODE_INFORMATION )KeyInformation )->NameLength + sizeof(UNICODE_NULL)) &&( ARGUMENT_PRESENT( lpClass )) && ( (ULONG)(ClassString.MaximumLength) >= (( NT::PKEY_NODE_INFORMATION )KeyInformation )->ClassLength + sizeof(UNICODE_NULL))) ) {BufferLength = ResultLength;KeyInformation = HeapAlloc( GetProcessHeap( ), 0, BufferLength);//// If the memory allocation fails, return a Registry error.// if( ! KeyInformation ) {return ERROR_OUTOFMEMORY;}//// Query for the necessary information about the supplied key.// This may or may not include the class depending on lpClass->Buffer// as determined above.// {Status = NT::ZwEnumerateKey(KeyHandle, dwIndex,KeyInformationClass,KeyInformation,BufferLength,&ResultLength);}}}if( NT_SUCCESS( Status ) ) {if( KeyInformationClass == NT::KeyBasicInformation ) {//// Return the name length and the name of the key.// Note that the NUL byte is included so that RPC copies the// correct number of bytes. It is decremented on the client// side.// if( (ULONG)(NameString.MaximumLength) >=(( NT::PKEY_BASIC_INFORMATION )KeyInformation )->NameLength + sizeof( UNICODE_NULL ) ) {NameString.Length = ( USHORT )(( NT::PKEY_BASIC_INFORMATION )KeyInformation )->NameLength;RtlMoveMemory( NameString.Buffer, (( NT::PKEY_BASIC_INFORMATION )KeyInformation )->Name, NameString.Length);//// NUL terminate the value name.// NameString.Buffer[ NameString.Length >> 1 ] = UNICODE_NULL;if( ARGUMENT_PRESENT( lpcName )) {*lpcName = NameString.Length >> 1;}} else {Status = STATUS_BUFFER_OVERFLOW;}//// If requested, return the last write time.// if( ARGUMENT_PRESENT( lpftLastWriteTime )) {*lpftLastWriteTime = *( PFILETIME )&(( NT::PKEY_BASIC_INFORMATION ) KeyInformation )->LastWriteTime;}} else {//// Return the name length and the name of the key.// Note that the NUL byte is included so that RPC copies the// correct number of bytes. It is decremented on the client// side.// if( ( (ULONG)(NameString.MaximumLength) >=(( NT::PKEY_NODE_INFORMATION )KeyInformation )->NameLength + sizeof( UNICODE_NULL ) ) &&( (ULONG)(ClassString.MaximumLength) >=(( NT::PKEY_NODE_INFORMATION )KeyInformation )->ClassLength + sizeof( UNICODE_NULL) )) {//// Copy the key name// NameString.Length = ( USHORT )(( NT::PKEY_NODE_INFORMATION )KeyInformation )->NameLength;RtlMoveMemory( NameString.Buffer,(( NT::PKEY_NODE_INFORMATION )KeyInformation )->Name,NameString.Length);//// NUL terminate the key name.// NameString.Buffer[ NameString.Length >> 1 ] = UNICODE_NULL; if( ARGUMENT_PRESENT( lpcName )) {*lpcName = NameString.Length >> 1;}//// Copy the key class// ClassString.Length = (USHORT)((( NT::PKEY_NODE_INFORMATION ) KeyInformation )->ClassLength );RtlMoveMemory(ClassString.Buffer,( PBYTE ) KeyInformation+ (( NT::PKEY_NODE_INFORMATION ) KeyInformation )->ClassOffset,ClassString.Length);//// NUL terminate the class.// ClassString.Buffer[ ClassString.Length >> 1 ] = UNICODE_NULL;if( ARGUMENT_PRESENT( lpcClass )) {*lpcClass = ClassString.Length >> 1;}} else {Status = STATUS_BUFFER_OVERFLOW;}//// If requested, return the last write time.// if( ARGUMENT_PRESENT( lpftLastWriteTime )) {*lpftLastWriteTime= *( PFILETIME )&(( NT::PKEY_NODE_INFORMATION ) KeyInformation )->LastWriteTime;}}}if( KeyInformation != PrivateKeyInformation ) {//// Free the buffer allocated.// HeapFree( GetProcessHeap( ), 0, KeyInformation );}return RtlNtStatusToDosError( Status ); }LONG NTRegistry::RegCloseKey(HKEY hKey) {NTSTATUS Status;/* don't close null handle or a pseudo handle */if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000)){return ERROR_INVALID_HANDLE;}Status = NT::ZwClose( hKey );return RtlNtStatusToDosError( Status ); }
四、项目设置
为了使用NTDLL导出函数,我们这里还需要用到ntdll.lib,需要在工程属性中添加导入ntdll.lib,只需要把ntdll.lib从DDK中拷贝出来放到你自己第三方库位置。
五、测试程序
测试了个获取Adobe安装目录的程序
NtFunctionTest.cpp
#include "stdafx.h" #include <gtest/gtest.h> #include <string> #include <NT/NtRegistry.h>TEST(GsKernelTest, tRegistryKey) {HKEY hKey = NULL;LONG RetVal = NTRegistry::RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Adobe\\Acrobat Reader", REG_OPTION_NON_VOLATILE,KEY_READ, &hKey);ASSERT_TRUE(RetVal==ERROR_SUCCESS);if ( ERROR_SUCCESS != RetVal ){return;}DWORD cSubKeys = 0;RetVal = NTRegistry::RegQueryInfoKey(hKey, NULL, NULL, NULL, &cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL );ASSERT_TRUE(RetVal==ERROR_SUCCESS);if ( ERROR_SUCCESS != RetVal ){NTRegistry::RegCloseKey(hKey);return;}TCHAR szKeyName[MAX_PATH];for ( DWORD i=0; i < cSubKeys; ++i ){DWORD dwKeyNameLength = sizeof(szKeyName)/sizeof(szKeyName[0]);RetVal = NTRegistry::RegEnumKey( hKey, i, szKeyName, &dwKeyNameLength, NULL, NULL, NULL,NULL);if ( ERROR_SUCCESS != RetVal ){continue;}double fVersion = _tstof(szKeyName);DWORD dwVesion = (DWORD)(fVersion*10);if ( dwVesion > 120 || dwVesion < 60 ){continue;} /// 拷贝文件 TCHAR szAdobePath[MAX_PATH];_tcscat_s(szKeyName,_countof(szKeyName), TEXT("\\InstallPath"));HKEY hChildKey = NULL;RetVal = NTRegistry::RegOpenKey(hKey, szKeyName, 0, KEY_READ, &hChildKey);if ( ERROR_SUCCESS != RetVal ){continue;}DWORD cKey = sizeof(szAdobePath);RetVal = NTRegistry::RegQueryValue(hChildKey, NULL, 0, NULL, (LPBYTE)szAdobePath, &cKey );if ( ERROR_SUCCESS == RetVal ){wcout << L"InstallPath: " << szAdobePath << endl; }NTRegistry::RegCloseKey(hChildKey);}NTRegistry::RegCloseKey(hKey); }
我的测试代码都是放到测试工程中的,采用的是gTest框架。
不采用导入ntdll.lib库方式的我后面再补充,只要通过GetProcessAddr获取函数地址就可以了。
看书、学习、写代码
转载于:https://www.cnblogs.com/Quincy/p/4838600.html
自己调用NTDLL函数相关推荐
- c语言中ntdll.dll,在Win32环境中从ntdll.dll调用Nt函数,C
我想从ntdll.dll调用一些Nt函数,我就是这样做的. 对于调用:NtTestAlert(),您需要典型的ntcall内核例程,可通过int 2Eh访问. (从这里我得到Nt功能http://un ...
- (49)逆向分析KiSystemService/KiFastCallEntry调用内核函数部分(SST,SSDT,SSPT)
一.回顾 前两篇博客,我逆向分析了 KiSystemService 和 KiFastCallEntry 填充_KTRAP_FRAME 结构体的代码,二者大同小异,主要的区别是 sysenter 只改了 ...
- 如何在sqlite3连接中创建并调用自定义函数
#!/user/bin/env python # @Time :2018/6/8 14:44 # @Author :PGIDYSQ #@File :CreateFunTest.py '''如何在sql ...
- Go 学习笔记(16)— 函数(02)[函数签名、有名函数、匿名函数、调用匿名函数、匿名函数赋值给变量、匿名函数做回调函数]
1. 函数签名 函数类型也叫做函数签名,可以使用 fmt.Printf("%T") 格式化参数打印函数类型. package mainimport "fmt"f ...
- Iar环境c语言调用汇编函数,如何在IAR EWARM中通过内联汇编程序在另一个模块中调用C函数?...
我在硬故障处理程序中有一些程序集.程序集基本上是为了传递当前堆栈指针作为参数(在R0中).它看起来像这样...如何在IAR EWARM中通过内联汇编程序在另一个模块中调用C函数? __asm(&quo ...
- mybatis可以用oracle,使用MyBatis调用oracle函数(基于注释)
我需要使用注解在MyBatis中调用Oracle函数.使用MyBatis调用oracle函数(基于注释) 我的映射: @Select("{ CALL #{outParam, jdbcType ...
- C语言中连续调用rand函数,返回值不变
C语言中连续调用rand函数,返回值不变 最近用C语言随机函数编程发现了一个奇怪的现象: 简易版代码: #include<stdio.h> #include<stdlib.h> ...
- 读书笔记 effective c++ Item 5 了解c++默认生成并调用的函数
1 编译器会默认生成哪些函数 什么时候空类不再是一个空类?答案是用c++处理的空类.如果你自己不声明,编译器会为你声明它们自己版本的拷贝构造函数,拷贝赋值运算符和析构函数,如果你一个构造函数都没有声 ...
- C#编码实践:使用委托和特性调用指定函数
2019独角兽企业重金招聘Python工程师标准>>> 建立一个C#控制台应用程序AttributeTest. 建立一个类Operations,代码如下: namespace Att ...
- 了解C++默默编写并调用哪些函数
在C++中,如果你写下 1 classEmpty{-}; 就相当于写下 1 classEmpty{ 2 public: 3 Empty();//default构造函数 4 Empty(constEmp ...
最新文章
- C++判断一个数字是否是某个数字的阶乘(附完整源码)
- 2020年中国智能客服行业研究报告
- 在C#中将集合用作键
- js 自动分配金额_(2.4w字,建议收藏)??原生JS灵魂之问(下), 冲刺??进阶最后一公里(附个人成长经验分享)
- 一个dsp最小系统至少要有_苏州设公厕指示牌,每500米至少要有一个
- Nginx监控数据采集与分析
- Cool Edit Pro 中把歌曲的原唱声消除掉制作伴奏带
- drools-基本使用
- English--不定式
- Springboot图片上传 百度ocr文字识别提取
- c语言课程实验总结报告,c语言实验总结报告.doc
- CodeForces 760B. Frodo and pillows(二分)
- 软件测试类型——集成测试
- 苹果手表支持心电图功能,可能还是逃不过噱头的命运
- Unity2d 坦克大战 (一)坦克移动、转向、皮肤切换
- 苹果为App订阅付费添加二次确认 避免意外支付情况
- 玫瑰c语言程序教程,c语言如何实现玫瑰花
- csgo服务器性能要求,CSGO服务器怎么选择合适的配置?CSGO服务器如何选择系统?...
- 心情日记——20071109(发泄一下)
- 网络直播不应只是秀场,新的场景机会在哪?
热门文章
- 使用group by rollup和group by cube后的辅助函数
- python 2 版本中的input() 和 raw_input() 函数的比较
- openstack nova调用libvirt,跟踪libvirt源码实例详解(cpu_mode及live_migrate 错误解决)...
- Linux 组与用户
- 呼吸灯 裸机 S3C2416
- linux安装 wegt_linux 下安装wget
- Redis内存相关知识
- nginx访问502,日志报错:connect() to 127.0.0.1:180 failed (13: Permission denied)解决
- Prototype两个常用监听器
- 【渝粤教育】国家开放大学2018年春季 4990T电子商务概论(农) 参考试题