自己调用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)
#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函数的更多相关文章
- Native Application 开发详解(直接在程序中调用 ntdll.dll 中的 Native API,有内存小、速度快、安全、API丰富等8大优点)
文章目录: 1. 引子: 2. Native Application Demo 展示: 3. Native Application 简介: 4. Native Ap ...
- C++如何在r3静态调用NT函数
原文最早发表于百度空间2010-02-22. 1.把ntapi.h.ntdll.lib放在一个目录,然后设置工具——选项——项目和解决方案——VC++目录——包含文件,把刚刚的目录设置在改包 含文件中 ...
- 调用Nt函数内核模式切换问题
很久不写博客了,笔记大多记在电脑上在,以后整理好了再搬运上来吧. 今天记一下“进程内存管理器”这个小程序上遇到的一个问题——内核模式调用Nt*函数. 使用的是内核中的NtQueryVirtualMem ...
- ng-repeat循环出来的部分调用同一个函数并且实现每个模块之间不能相互干扰
使用场景:用ng-repeat几个部分,每个部分调用同一个函数,但是每个模块之间的功能不能相互干扰 问题:在用repeat实现.content块repeat的时候打算这样做:新建一个空的数组(nmbe ...
- 深入理解javascript系列(4):立即调用的函数表达式
本文来自汤姆大叔 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法 ...
- EC笔记,第二部分:9.不在构造、析构函数中调用虚函数
9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...
- EC笔记,第二部分:5.了解C++默默编写并调用哪些函数
5.了解C++默默编写并调用哪些函数 1.C++空类 C++会为一个空类建立以下函数 (1).默认构造函数 (2).默认拷贝构造函数 (3).析构函数 (4).赋值运算符(如果成员包含引用类型或con ...
- C++构造函数中不能调用虚函数
在构造函数中调用虚函数,并不会产生多态的效果,就跟普通函数一样. c++ primer 第四版中497页15.4.5构造函数和析构中的虚函数讲到,如果在构造函数或析构函数中调用虚函数,则运行的是为构造 ...
- ZeroMQ接口函数之 :zmq_errno – 返回errno的值给调用此函数的线程
ZeroMQ 官方地址 :http://api.zeromq.org/4-0:zmq_errno zmq_errno(3) ØMQ Manual - ØMQ/3.2.5 Name zm ...
随机推荐
- Codeforces 597C. Subsequences (树状数组+dp)
题目链接:http://codeforces.com/contest/597/problem/C 给你n和数(1~n各不同),问你长为k+1的上升自序列有多少. dp[i][j] 表示末尾数字为i 长 ...
- openmp 并行求完数
// GetWanShu.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "omp.h" #inclu ...
- Oracle中的NVL,NVL2,NULLIF以及COALESCE函数使用
首先注意空(null)值,空值加任何值都是空值,空值乘任何值也都是空值,依此类推. 1.NVL函数 NVL函数的格式如下:NVL(expr1,expr2) 含义是:如果oracle第一个参数为空那么显 ...
- as3.0:文字 效果
//文字描边效果var tf1 = _root.createTextField("tf1", _root.getNextHighestDepth(), 10, 10, 0, 0); ...
- 一条结合where、group、orderby的linq语法
DataTable dt = (from x in dsResult.Tables[0].AsEnumerable() where DataTrans.CBoolean(x["IsCheck ...
- webstorm 主题设置 皮肤设置
推荐个编辑器主题下载的一个网站. Color Themes 网址:http://color-themes.com [点这里直接跳转] 但是,只支持几个编辑器. 各种颜色搭配的主题,随你选择!我个 ...
- 用jQuery解决弹出层的问题
在BS 项目中 经常需要用到这种弹出层.做这种弹出层一般都会遇到下面几个问题:0,弹出层必须定义在input的下边显示.1,点击input弹出div层.2,点击div层外面任何地方,关闭div层.3, ...
- Netty高并发原理
Netty是一个高性能 事件驱动的异步的非堵塞的IO(NIO)框架,用于建立TCP等底层的连接,基于Netty可以建立高性能的Http服务器.支持HTTP. WebSocket .Protob ...
- 【转】【公司调查】车来了APP
http://blog.sina.com.cn/s/blog_83b10acc0102vk7k.html [APP简介] "车来了"是武汉元光科技有限公司开发的一款查询公交车实 ...
- Mac OS增删环境变量
一.首先查看shell版本 使用命令echo $SHELL 如果输出的是:csh或者是tcsh,就是C Shell.如果输出的是:bash,sh,zsh,就是Bourne Shell的一个变种. Ma ...