#include <ntifs.h>
#include <windef.h>
/*
文件名:MiFindExportedRoutineByName.c
写作目的:
MmGetSystemRoutineAddress这个函数有如下的限制:
It can only be used for routines exported by the kernel or HAL, not for any driver-defined routine.
有时候获取别的内核模块的函数的地址是一个解决问题的办法,如:WINHV.sys。
有人为此还专门写了函数,当然是解析PE32/PE32+了。
其实系统已经提供了一些函数,只不过导出而没有公开而已。
看WRK知道:MmGetSystemRoutineAddress是通过MiFindExportedRoutineByName实现的。
可是:MiFindExportedRoutineByName没有导出,定位又没有好的稳定的办法。
所以自己实现,还好RtlImageDirectoryEntryToData(RtlImageNtHeader)已经导出。
本文的一些信息摘自:WRK。
不过这也是源码,加入驱动也是可以使用的。
made by correy
made at 2014.08.18
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
/*
这个应该兼容PE32+也就是64位的系统。
有待看PE32规范。
*/
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
}
PVOID RtlImageDirectoryEntryToData (IN PVOID Base, IN BOOLEAN MappedAsImage, IN USHORT DirectoryEntry, OUT PULONG Size);
/*++
Routine Description:
This function locates a Directory Entry within the image header and returns either the virtual address or seek address of the data the Directory describes.
Arguments:
Base - Supplies the base of the image or data file.
MappedAsImage - FALSE if the file is mapped as a data file.
- TRUE if the file is mapped as an image.
DirectoryEntry - Supplies the directory entry to locate.
Size - Return the size of the directory.
Return Value:
NULL - The file does not contain data for the specified directory entry.
NON-NULL - Returns the address of the raw data the directory describes.
--*/
//{
// PIMAGE_NT_HEADERS NtHeaders;
//
// if (LDR_IS_DATAFILE(Base)) {
// Base = LDR_DATAFILE_TO_VIEW(Base);
// MappedAsImage = FALSE;
// }
//
// NtHeaders = RtlImageNtHeader(Base);
//
// if (!NtHeaders)
// return NULL;
//
// if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
// return (RtlpImageDirectoryEntryToData32(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS32)NtHeaders));
// } else if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
// return (RtlpImageDirectoryEntryToData64(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS64)NtHeaders));
// } else {
// return (NULL);
// }
//}
PVOID MiFindExportedRoutineByName (IN PVOID DllBase, IN PANSI_STRING AnsiImageRoutineName)
/*++
Routine Description:
This function searches the argument module looking for the requested exported function name.
Arguments:
DllBase - Supplies the base address of the requested module.
AnsiImageRoutineName - Supplies the ANSI routine name being searched for.
Return Value:
The virtual address of the requested routine or NULL if not found.
--*/
{
USHORT OrdinalNumber;
PULONG NameTableBase;
PUSHORT NameOrdinalTableBase;
PULONG Addr;
LONG High;
LONG Low;
LONG Middle;
LONG Result;
ULONG ExportSize;
PVOID FunctionAddress;
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
PAGED_CODE();
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData (DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize);
if (ExportDirectory == NULL) {
return NULL;
}
NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);// Initialize the pointer to the array of RVA-based ansi export strings.
NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);// Initialize the pointer to the array of USHORT ordinal numbers.
Low = 0;
Middle = 0;
High = ExportDirectory->NumberOfNames - 1;
while (High >= Low) // Lookup the desired name in the name table using a binary search.
{
Middle = (Low + High) >> 1;// Compute the next probe index and compare the import name with the export name entry.
Result = strcmp (AnsiImageRoutineName->Buffer, (PCHAR)DllBase + NameTableBase[Middle]);
if (Result < 0) {
High = Middle - 1;
} else if (Result > 0) {
Low = Middle + 1;
} else {
break;
}
}
// If the high index is less than the low index, then a matching table entry was not found.
// Otherwise, get the ordinal number from the ordinal table.
if (High < Low) {
return NULL;
}
OrdinalNumber = NameOrdinalTableBase[Middle];
// If the OrdinalNumber is not within the Export Address Table,then this image does not implement the function.
// Return not found.
if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {
return NULL;
}
// Index into the array of RVA export addresses by ordinal number.
Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);
// Forwarders are not used by the kernel and HAL to each other.
ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) || (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize)));
return FunctionAddress;
}
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
KdBreakPoint();
DriverObject->DriverUnload = Unload;
//测试的代码就不写了。
return status;
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include <ntifs.h>
#include <windef.h>
#include <Aux_klib.h> //source里面要有TARGETLIBS=$(DDK_LIB_PATH)\Aux_klib.lib
/*
made by correy
made at 2014.08.19
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/
#define TAG 'tset' //test
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
}
PVOID RtlImageDirectoryEntryToData (IN PVOID Base, IN BOOLEAN MappedAsImage, IN USHORT DirectoryEntry, OUT PULONG Size);
/*++
Routine Description:
This function locates a Directory Entry within the image header and returns either the virtual address or seek address of the data the Directory describes.
Arguments:
Base - Supplies the base of the image or data file.
MappedAsImage - FALSE if the file is mapped as a data file.
- TRUE if the file is mapped as an image.
DirectoryEntry - Supplies the directory entry to locate.
Size - Return the size of the directory.
Return Value:
NULL - The file does not contain data for the specified directory entry.
NON-NULL - Returns the address of the raw data the directory describes.
--*/
//{
// PIMAGE_NT_HEADERS NtHeaders;
//
// if (LDR_IS_DATAFILE(Base)) {
// Base = LDR_DATAFILE_TO_VIEW(Base);
// MappedAsImage = FALSE;
// }
//
// NtHeaders = RtlImageNtHeader(Base);
//
// if (!NtHeaders)
// return NULL;
//
// if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
// return (RtlpImageDirectoryEntryToData32(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS32)NtHeaders));
// } else if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
// return (RtlpImageDirectoryEntryToData64(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS64)NtHeaders));
// } else {
// return (NULL);
// }
//}
PVOID MiFindExportedRoutineByName (IN PVOID DllBase, IN PANSI_STRING AnsiImageRoutineName)
/*++
Routine Description:
This function searches the argument module looking for the requested exported function name.
Arguments:
DllBase - Supplies the base address of the requested module.
AnsiImageRoutineName - Supplies the ANSI routine name being searched for.
Return Value:
The virtual address of the requested routine or NULL if not found.
--*/
{
USHORT OrdinalNumber;
PULONG NameTableBase;
PUSHORT NameOrdinalTableBase;
PULONG Addr;
LONG High;
LONG Low;
LONG Middle;
LONG Result;
ULONG ExportSize;
PVOID FunctionAddress = 0;
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
PAGED_CODE();
__try
{
FunctionAddress = *(PVOID *)DllBase;
FunctionAddress = 0;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return FunctionAddress;
}
//确保DllBase可以访问。否则蓝屏。
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData (DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize);
if (ExportDirectory == NULL) {
return NULL;
}
NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);// Initialize the pointer to the array of RVA-based ansi export strings.
NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);// Initialize the pointer to the array of USHORT ordinal numbers.
Low = 0;
Middle = 0;
High = ExportDirectory->NumberOfNames - 1;
while (High >= Low) // Lookup the desired name in the name table using a binary search.
{
Middle = (Low + High) >> 1;// Compute the next probe index and compare the import name with the export name entry.
Result = strcmp (AnsiImageRoutineName->Buffer, (PCHAR)DllBase + NameTableBase[Middle]);
if (Result < 0) {
High = Middle - 1;
} else if (Result > 0) {
Low = Middle + 1;
} else {
break;
}
}
// If the high index is less than the low index, then a matching table entry was not found.
// Otherwise, get the ordinal number from the ordinal table.
if (High < Low) {
return NULL;
}
OrdinalNumber = NameOrdinalTableBase[Middle];
// If the OrdinalNumber is not within the Export Address Table,then this image does not implement the function.
// Return not found.
if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {
return NULL;
}
// Index into the array of RVA export addresses by ordinal number.
Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);
// Forwarders are not used by the kernel and HAL to each other.
ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) || (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize)));
return FunctionAddress;
}
PVOID get_module_image_base(__in UCHAR * name)
{
NTSTATUS status = 0;
ULONG modulesSize;
AUX_MODULE_EXTENDED_INFO * modules;
ULONG numberOfModules;
ULONG i;
PIMAGE_EXPORT_DIRECTORY pied = 0;
PVOID ImageBase = 0;
status = AuxKlibInitialize();
if (!NT_SUCCESS( status ))
{
KdPrint(( "AuxKlibInitialize fail %d\n", status));
return ImageBase;
}
status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL);// Get the required array size.
if (!NT_SUCCESS(status) || modulesSize == 0) {
return ImageBase;
}
numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO);// Calculate the number of modules.
modules = (AUX_MODULE_EXTENDED_INFO*) ExAllocatePoolWithTag(PagedPool, modulesSize, TAG);// Allocate memory to receive data.
if (modules == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
return ImageBase;
}
RtlZeroMemory(modules, modulesSize);
status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), modules);// Obtain the module information.
if (!NT_SUCCESS(status)) {
ExFreePoolWithTag(modules,TAG);
return ImageBase;
}
for (i = 0;i<numberOfModules;i++)
{
UCHAR * pfilename = modules[i].FullPathName + modules[i].FileNameOffset;
if (_stricmp(pfilename, name) == 0)
{
ImageBase = modules[i].BasicInfo.ImageBase;
break;
}
}
ExFreePoolWithTag(modules,TAG);
return ImageBase;
}
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID ImageBase = 0;
PVOID FunctionAddress;
//ANSI_STRING EngCreateBitmap = RTL_CONSTANT_STRING("EngCreateBitmap");//NT开头的函数竟然一个也没有导出。
ANSI_STRING EngCreateBitmap = RTL_CONSTANT_STRING("ArcFilterDprIndicateReceive");
KdBreakPoint();
DriverObject->DriverUnload = Unload;
//ImageBase = get_module_image_base("WIN32k.sys");//注意这个的环境:有的线程不可以访问。不然地址不可访问。
ImageBase = get_module_image_base("ndis.sys");
if (ImageBase == 0)
{
return status;
}
FunctionAddress = MiFindExportedRoutineByName (ImageBase, &EngCreateBitmap);
if (FunctionAddress == 0)
{
return status;
}
/*
验证下:
1: kd> dd FunctionAddress L1
f88f6c78 ba5552cd
1: kd> u ba5552cd
NDIS!ArcFilterDprIndicateReceive:
ba5552cd 8bff mov edi,edi
ba5552cf 55 push ebp
ba5552d0 8bec mov ebp,esp
ba5552d2 83ec24 sub esp,24h
ba5552d5 a11c6353ba mov eax,dword ptr [NDIS!__security_cookie (ba53631c)]
ba5552da 53 push ebx
ba5552db 8b5d10 mov ebx,dword ptr [ebp+10h]
ba5552de 56 push esi
*/
return status;
}
2014年8月18日星期一
内核中的GetProcAddress
订阅:
博文评论 (Atom)
没有评论:
发表评论