一、概述

在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函数相关推荐

  1. c语言中ntdll.dll,在Win32环境中从ntdll.dll调用Nt函数,C

    我想从ntdll.dll调用一些Nt函数,我就是这样做的. 对于调用:NtTestAlert(),您需要典型的ntcall内核例程,可通过int 2Eh访问. (从这里我得到Nt功能http://un ...

  2. (49)逆向分析KiSystemService/KiFastCallEntry调用内核函数部分(SST,SSDT,SSPT)

    一.回顾 前两篇博客,我逆向分析了 KiSystemService 和 KiFastCallEntry 填充_KTRAP_FRAME 结构体的代码,二者大同小异,主要的区别是 sysenter 只改了 ...

  3. 如何在sqlite3连接中创建并调用自定义函数

    #!/user/bin/env python # @Time :2018/6/8 14:44 # @Author :PGIDYSQ #@File :CreateFunTest.py '''如何在sql ...

  4. Go 学习笔记(16)— 函数(02)[函数签名、有名函数、匿名函数、调用匿名函数、匿名函数赋值给变量、匿名函数做回调函数]

    1. 函数签名 函数类型也叫做函数签名,可以使用 fmt.Printf("%T") 格式化参数打印函数类型. package mainimport "fmt"f ...

  5. Iar环境c语言调用汇编函数,如何在IAR EWARM中通过内联汇编程序在另一个模块中调用C函数?...

    我在硬故障处理程序中有一些程序集.程序集基本上是为了传递当前堆栈指针作为参数(在R0中).它看起来像这样...如何在IAR EWARM中通过内联汇编程序在另一个模块中调用C函数? __asm(&quo ...

  6. mybatis可以用oracle,使用MyBatis调用oracle函数(基于注释)

    我需要使用注解在MyBatis中调用Oracle函数.使用MyBatis调用oracle函数(基于注释) 我的映射: @Select("{ CALL #{outParam, jdbcType ...

  7. C语言中连续调用rand函数,返回值不变

    C语言中连续调用rand函数,返回值不变 最近用C语言随机函数编程发现了一个奇怪的现象: 简易版代码: #include<stdio.h> #include<stdlib.h> ...

  8. 读书笔记 effective c++ Item 5 了解c++默认生成并调用的函数

    1 编译器会默认生成哪些函数  什么时候空类不再是一个空类?答案是用c++处理的空类.如果你自己不声明,编译器会为你声明它们自己版本的拷贝构造函数,拷贝赋值运算符和析构函数,如果你一个构造函数都没有声 ...

  9. C#编码实践:使用委托和特性调用指定函数

    2019独角兽企业重金招聘Python工程师标准>>> 建立一个C#控制台应用程序AttributeTest. 建立一个类Operations,代码如下: namespace Att ...

  10. 了解C++默默编写并调用哪些函数

    在C++中,如果你写下 1 classEmpty{-}; 就相当于写下 1 classEmpty{ 2 public: 3 Empty();//default构造函数 4 Empty(constEmp ...

最新文章

  1. C++判断一个数字是否是某个数字的阶乘(附完整源码)
  2. 2020年中国智能客服行业研究报告
  3. 在C#中将集合用作键
  4. js 自动分配金额_(2.4w字,建议收藏)??原生JS灵魂之问(下), 冲刺??进阶最后一公里(附个人成长经验分享)
  5. 一个dsp最小系统至少要有_苏州设公厕指示牌,每500米至少要有一个
  6. Nginx监控数据采集与分析
  7. Cool Edit Pro 中把歌曲的原唱声消除掉制作伴奏带
  8. drools-基本使用
  9. English--不定式
  10. Springboot图片上传 百度ocr文字识别提取
  11. c语言课程实验总结报告,c语言实验总结报告.doc
  12. CodeForces 760B. Frodo and pillows(二分)
  13. 软件测试类型——集成测试
  14. 苹果手表支持心电图功能,可能还是逃不过噱头的命运
  15. Unity2d 坦克大战 (一)坦克移动、转向、皮肤切换
  16. 苹果为App订阅付费添加二次确认 避免意外支付情况
  17. 玫瑰c语言程序教程,c语言如何实现玫瑰花
  18. csgo服务器性能要求,CSGO服务器怎么选择合适的配置?CSGO服务器如何选择系统?...
  19. 心情日记——20071109(发泄一下)
  20. 网络直播不应只是秀场,新的场景机会在哪?

热门文章

  1. 使用group by rollup和group by cube后的辅助函数
  2. python 2 版本中的input() 和 raw_input() 函数的比较
  3. openstack nova调用libvirt,跟踪libvirt源码实例详解(cpu_mode及live_migrate 错误解决)...
  4. Linux 组与用户
  5. 呼吸灯 裸机 S3C2416
  6. linux安装 wegt_linux 下安装wget
  7. Redis内存相关知识
  8. nginx访问502,日志报错:connect() to 127.0.0.1:180 failed (13: Permission denied)解决
  9. Prototype两个常用监听器
  10. 【渝粤教育】国家开放大学2018年春季 4990T电子商务概论(农) 参考试题