一、概述

在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'\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);
else
RtlInitUnicodeString(&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获取函数地址就可以了。

  看书、学习、写代码

自己调用NTDLL函数的更多相关文章

  1. Native Application 开发详解(直接在程序中调用 ntdll.dll 中的 Native API,有内存小、速度快、安全、API丰富等8大优点)

    文章目录:                   1. 引子: 2. Native Application Demo 展示: 3. Native Application 简介: 4. Native Ap ...

  2. C++如何在r3静态调用NT函数

    原文最早发表于百度空间2010-02-22. 1.把ntapi.h.ntdll.lib放在一个目录,然后设置工具——选项——项目和解决方案——VC++目录——包含文件,把刚刚的目录设置在改包 含文件中 ...

  3. 调用Nt函数内核模式切换问题

    很久不写博客了,笔记大多记在电脑上在,以后整理好了再搬运上来吧. 今天记一下“进程内存管理器”这个小程序上遇到的一个问题——内核模式调用Nt*函数. 使用的是内核中的NtQueryVirtualMem ...

  4. ng-repeat循环出来的部分调用同一个函数并且实现每个模块之间不能相互干扰

    使用场景:用ng-repeat几个部分,每个部分调用同一个函数,但是每个模块之间的功能不能相互干扰 问题:在用repeat实现.content块repeat的时候打算这样做:新建一个空的数组(nmbe ...

  5. 深入理解javascript系列(4):立即调用的函数表达式

    本文来自汤姆大叔 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法 ...

  6. EC笔记,第二部分:9.不在构造、析构函数中调用虚函数

    9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...

  7. EC笔记,第二部分:5.了解C++默默编写并调用哪些函数

    5.了解C++默默编写并调用哪些函数 1.C++空类 C++会为一个空类建立以下函数 (1).默认构造函数 (2).默认拷贝构造函数 (3).析构函数 (4).赋值运算符(如果成员包含引用类型或con ...

  8. C++构造函数中不能调用虚函数

    在构造函数中调用虚函数,并不会产生多态的效果,就跟普通函数一样. c++ primer 第四版中497页15.4.5构造函数和析构中的虚函数讲到,如果在构造函数或析构函数中调用虚函数,则运行的是为构造 ...

  9. ZeroMQ接口函数之 :zmq_errno – 返回errno的值给调用此函数的线程

    ZeroMQ 官方地址 :http://api.zeromq.org/4-0:zmq_errno zmq_errno(3)         ØMQ Manual - ØMQ/3.2.5 Name zm ...

随机推荐

  1. 应用c#读取带cookie的http数据

    @(编程) private static string Login() { string url = string.Format("{0}/login-submit.html?identit ...

  2. Linux-Ubuntu 启用root账户

    Ubuntu Linux有一个与众不同的特点,那就是初次使用时,你无法作为root来登录系统,为什么会这样?这就要从系统的安装说起.对于其他Linux系统来 说,一般在安装过程就设定root密码,这样 ...

  3. linux常用基本命令

    Linux中许多常用命令是必须掌握的,这里将我学linux入门时学的一些常用的基本命令分享给大家一下,希望可以帮助你们.   系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器 ...

  4. 深入DNS

    什么是DNS? 我说前面说过http如何发送请求.这里的第一步就是将域名变为ip地址 如何将域名变为ip地址我们就得用到域名解析(DNS). 如何进行域名解析的? 第一步:在浏览器的url里输入域名, ...

  5. CodeForces 710A King Moves (水题)

    题意:给定一个坐标,问你皇后有几个方向可以走. 析:直接格举那八个方向即可. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000 ...

  6. jpa动态创建EntityManagerFactory 态设置数据库连接 EntityManager;

    //jpa动态创建EntityManagerFactory 态设置数据库连接EntityManager;createEntityManagerFactory(String persistenceUni ...

  7. GET与POST提交

    get是从服务器上获取数据,post是向服务器传送数据. get 是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,[在URL中可以看到].post是通过HTT ...

  8. jquery checkbox选中状态

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. 关于使用Transaction对于非数据库事务的操作

    在操作数据库的过程中,为了数据的一致性,我们可以使用Transaction,要么成功的时候全部提交,要么有任何一个操作失败立即全部回滚.不仅仅是在数据库方面,有时候操作其他的内容,比如说对于系统文件的 ...

  10. git filename to long问题解决

    在.git/config 下面编辑 [core] longpaths = true