#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)
没有评论:
发表评论