自己调用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 ...
随机推荐
- 【原创】用Pwnage + Redsnow 制作完美越狱固件
原帖我发表在威锋论坛 现在貌似IOS 7.X系 大行其道,就算不是IOS7.X ,很多人也装着IOS 6.X系. 进入正文前首先介绍一下自己目前的"环境" 设备:iphone4 G ...
- 实时监控mysql数据库变化
对于二次开发来说,很大一部分就找找文件和找数据库的变化情况 对于数据库变化.还没有发现比较好用的监控数据库变化监控软件. 今天,我就给大家介绍一个如何使用mysql自带的功能监控数据库变化 1.打开数 ...
- makefile中一些符号的含义
关于gnu make的详细介绍参看http://www.gnu.org/software/make/manual/make.html 规则 让我们先来粗略地看一看Makefile的规则. targ ...
- Codeforces 444 C. DZY Loves Colors (线段树+剪枝)
题目链接:http://codeforces.com/contest/444/problem/C 给定一个长度为n的序列,初始时ai=i,vali=0(1≤i≤n).有两种操作: 将区间[L,R]的值 ...
- DNS原理及其解析过程(转)
转自(http://369369.blog.51cto.com/319630/812889) 网络通讯大部分是基于TCP/IP的,而TCP/IP是基于IP地址的,所以计算机在网络上进行通讯时只能识别如 ...
- android 工具类之图片加工
/** * 图片加工厂 * * @author way * */ public class ImageUtil { /** * 通过路径获取输入流 * * @param path * 路径 * @re ...
- [p2p]UDP用打洞技术穿透NAT的原理与实现
首先先介绍一些基本概念: NAT(Network Address Translators),网络地址转换:网络地址转换是在IP地址日益缺乏的情况下产生的, ...
- gulp安装和使用简介
一. gulp和grunt对比 grunt目前的工作流程:读文件.修改文件.写文件——读文件.修改文件.写文件——... gulp目前的工作流程:读取文件——修改文件——修改文件...——写文件 二. ...
- SAE J1850 VPW PWM, SAE J2411 SWC, ISO 11898 CAN, SAE J1708, Chrysler CCD 接口芯片电路
SAE J1850 VPW 接口芯片电路 SAE J1850 PWM 接口芯片电路 SAE J2411 SWC 接口芯片电路 ISO 11898 CAN 接口芯片电路 CANH 和CANL 上的电容 ...
- 手游产品经理初探(六)粗糙的logo会给产品致命一击
假设你的游戏产品从logo的设计開始就不注重细节的话,那么你的产品将不会走多远! 我们把图片放大看: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl1 ...