内核分析PE获取DLL导出函数地址
来源:互联网 发布:数据迁移工程师 编辑:程序博客网 时间:2024/06/02 05:12
环境:VS2012+WIN8 64
类型:C++编写的WDM驱动程序
测试:VM WIN7
用途:主要用于驱动程序中得到WIN32 API地址,也可得到自定义的DLL中的函数导出地址,记录内核文件相关操作以便以后查看。
说明:此段代码来源于网络,经修改调试而成。
头文件 HelloWDM.h
#if __cplusplusextern "C"{#endif#include <wdm.h>#include <windef.h>#ifdef __cplusplus}#endif//winnt.h中的定义 由于是WDM不能引用该文件 所以只有复制过来#define SEC_IMAGE 0x1000000 //PE相关结构typedef struct _SECTION_IMAGE_INFORMATION{ PVOID TransferAddress; ULONG ZeroBits; ULONG MaximumStackSize; ULONG CommittedStackSize; ULONG SubSystemType; union { struct { WORD SubSystemMinorVersion; WORD SubSystemMajorVersion; }; ULONG SubSystemVersion; }; ULONG GpValue; WORD ImageCharacteristics; WORD DllCharacteristics; WORD Machine; UCHAR ImageContainsCode; UCHAR ImageFlags; ULONG ComPlusNativeReady: 1; ULONG ComPlusILOnly: 1; ULONG ImageDynamicallyRelocated: 1; ULONG Reserved: 5; ULONG LoaderFlags; ULONG ImageFileSize; ULONG CheckSum;} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size;} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[16];} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;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;
HelloWDM.cpp文件
#include "HelloWDM.h"//得到DLL中的指定函数地址 相当于应用层的GetProcAddress函数DWORD GetDllFunctionAddress(PTSTR lpFunctionName, PTSTR pDllName){ HANDLE hThread, hSection, hFile, hMod; SIZE_T size=0; NTSTATUS status; PVOID BaseAddress = NULL; //转换DLL名称 UNICODE_STRING strDllName; RtlInitUnicodeString(&strDllName, pDllName); OBJECT_ATTRIBUTES objectAttributes={0}; IO_STATUS_BLOCK iosb={0}; //初始化 objectAttributes InitializeObjectAttributes(&objectAttributes, &strDllName, OBJ_KERNEL_HANDLE, NULL, NULL); //打开文件 status=ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &objectAttributes, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); if(!NT_SUCCESS(status)) { return status; } objectAttributes.ObjectName = 0; //创建内存块 status=ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &objectAttributes, 0, PAGE_READONLY, SEC_IMAGE, hFile); //PAGE_READONLY页面保护属性,必须结合SEC_IMAGE属性 if(!NT_SUCCESS(status)) { return status; } //内存映射文件 status=ZwMapViewOfSection(hSection, ZwCurrentProcess(), &BaseAddress, 0, 1024, 0, &size, ViewUnmap, MEM_LARGE_PAGES, //针对DLL文件较小是可以用MEM_TOP_DOWN 文件较大比如USER32.DLL时需要用MEM_LARGE_PAGES PAGE_READWRITE); if(!NT_SUCCESS(status)) { return status; } //关闭文件句柄 ZwClose(hFile); //读取PE头信息 IMAGE_DOS_HEADER* dosheader; IMAGE_OPTIONAL_HEADER* opthdr; IMAGE_EXPORT_DIRECTORY* pExportTable; PDWORD arrayOfFunctionAddresses, arrayOfFunctionNames; PWORD arrayOfFunctionOrdinals; DWORD functionOrdinal, functionAddress=0; PSTR functionName; ANSI_STRING anFunName; UNICODE_STRING unFunctionName, unFunctionNameSearch; //模块句柄 hMod = BaseAddress; //得到DOS头 dosheader = (PIMAGE_DOS_HEADER)hMod; //得到PE选项头 opthdr =(PIMAGE_OPTIONAL_HEADER) ((PBYTE)hMod+dosheader->e_lfanew+24); //得到导出表 pExportTable =(PIMAGE_EXPORT_DIRECTORY)((PBYTE) hMod + opthdr->DataDirectory[0].VirtualAddress); //得到函数地址列表 arrayOfFunctionAddresses = (PDWORD)( (PBYTE)hMod + pExportTable->AddressOfFunctions); //得到函数名称列表 arrayOfFunctionNames = (PDWORD)( (PBYTE)hMod + pExportTable->AddressOfNames); //得到函数序号 arrayOfFunctionOrdinals = (PWORD)( (PBYTE)hMod + pExportTable->AddressOfNameOrdinals); //导出表基地址 DWORD Base = pExportTable->Base; //转换函数名 RtlInitUnicodeString(&unFunctionNameSearch, lpFunctionName); //循环导出表 for(DWORD x = 0; x < pExportTable->NumberOfNames; x++) //导出函数有名称 编号之分,导出函数总数=名称导出+编号导出,这里是循环导出名称的函数 { //得到函数名 functionName = (PSTR)( (PBYTE)hMod + arrayOfFunctionNames[x]); //转化为ANSI_STRING RtlInitAnsiString(&anFunName, functionName); //转化为UNICODE_STRING RtlAnsiStringToUnicodeString(&unFunctionName, &anFunName, TRUE); //打印调试信息 KdPrint(("%d/%d,FunName:%wZ\n", x+1, pExportTable->NumberOfNames, &unFunctionName)); //比较函数名称 if (RtlCompareUnicodeString(&unFunctionName, &unFunctionNameSearch, TRUE) == 0) { //得到该函数地址 functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; functionAddress = (DWORD)( (PBYTE)hMod + arrayOfFunctionAddresses[functionOrdinal]); break; } } ZwClose(hSection); return functionAddress;}
以上代码虽可以运行但没有考虑到 ZwMapViewOfSection的资源释放问题 修改如下:
//HelloWDM.h#if __cplusplusextern "C"{#endif#include <wdm.h>#include <windef.h>#ifdef __cplusplus}#endif//定义设备扩展typedef struct _DEVICE_EXTERSION{ PDEVICE_OBJECT fdo; PDEVICE_OBJECT NextStatckDevice; UNICODE_STRING ustrDeviceName; //设备名 UNICODE_STRING ustrSymLinkName; //符号链接名 PVOID tmpPoint; //记录临时指针}DEVICE_EXTENSION, *PDEVICE_EXTENSION;//全局变量 PDEVICE_EXTENSION gDevExt=NULL;//winnt.h中的定义 由于是WDM不能引用该文件 所以只有复制过来#define SEC_IMAGE 0x1000000 //PE相关结构typedef struct _SECTION_IMAGE_INFORMATION{ PVOID TransferAddress; ULONG ZeroBits; ULONG MaximumStackSize; ULONG CommittedStackSize; ULONG SubSystemType; union { struct { WORD SubSystemMinorVersion; WORD SubSystemMajorVersion; }; ULONG SubSystemVersion; }; ULONG GpValue; WORD ImageCharacteristics; WORD DllCharacteristics; WORD Machine; UCHAR ImageContainsCode; UCHAR ImageFlags; ULONG ComPlusNativeReady: 1; ULONG ComPlusILOnly: 1; ULONG ImageDynamicallyRelocated: 1; ULONG Reserved: 5; ULONG LoaderFlags; ULONG ImageFileSize; ULONG CheckSum;} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size;} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[16];} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;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;
//HelloWDM.cpp//得到DLL中的指定函数地址 相当于应用层的GetProcAddress函数DWORD GetDllFunctionAddress(PTSTR lpFunctionName, PTSTR pDllName){HANDLE hSection=NULL, hFile=NULL;SIZE_T size=0;NTSTATUS status;PVOID BaseAddress = NULL;//转换DLL名称UNICODE_STRING strDllName;RtlInitUnicodeString(&strDllName, pDllName);OBJECT_ATTRIBUTES objectAttributes={0};IO_STATUS_BLOCK iosb={0};//初始化 objectAttributesInitializeObjectAttributes(&objectAttributes, &strDllName, OBJ_KERNEL_HANDLE, NULL, NULL);__try{//打开文件status=ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &objectAttributes, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);if(!NT_SUCCESS(status)){__leave;}objectAttributes.ObjectName = 0;//创建内存块status=ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &objectAttributes, 0, PAGE_READONLY, SEC_IMAGE, hFile); //PAGE_READONLY页面保护属性,必须结合SEC_IMAGE属性if(!NT_SUCCESS(status)){__leave;}//内存映射文件status=ZwMapViewOfSection(hSection, ZwCurrentProcess(), &BaseAddress, 0, 1024, 0, &size, ViewUnmap, MEM_LARGE_PAGES,//针对DLL文件较小是可以用MEM_TOP_DOWN 文件较大比如USER32.DLL时需要用MEM_LARGE_PAGESPAGE_READWRITE);}__finally{if(hFile != NULL){//关闭文件句柄ZwClose(hFile);}if(!NT_SUCCESS(status) && hSection != NULL){//关闭内存块ZwClose(hSection);}}//如果失败 直接返回if(!NT_SUCCESS(status)){return 0;}//读取PE头信息IMAGE_DOS_HEADER* dosheader;IMAGE_OPTIONAL_HEADER* opthdr;IMAGE_EXPORT_DIRECTORY* pExportTable;PDWORD arrayOfFunctionAddresses, arrayOfFunctionNames;PWORD arrayOfFunctionOrdinals;DWORD functionOrdinal, functionAddress=0;PSTR functionName;ANSI_STRING anFunName;UNICODE_STRING unFunctionName, unFunctionNameSearch;//模块句柄HANDLE hMod = BaseAddress;//得到DOS头dosheader = (PIMAGE_DOS_HEADER)hMod;//得到PE选项头opthdr =(PIMAGE_OPTIONAL_HEADER) ((PBYTE)hMod+dosheader->e_lfanew+24);//得到导出表pExportTable =(PIMAGE_EXPORT_DIRECTORY)((PBYTE) hMod + opthdr->DataDirectory[0].VirtualAddress);//得到函数地址列表arrayOfFunctionAddresses = (PDWORD)( (PBYTE)hMod + pExportTable->AddressOfFunctions);//得到函数名称列表arrayOfFunctionNames = (PDWORD)( (PBYTE)hMod + pExportTable->AddressOfNames);//得到函数序号arrayOfFunctionOrdinals = (PWORD)( (PBYTE)hMod + pExportTable->AddressOfNameOrdinals);//导出表基地址DWORD Base = pExportTable->Base;//转换函数名RtlInitUnicodeString(&unFunctionNameSearch, lpFunctionName);//循环导出表for(DWORD x = 0; x < pExportTable->NumberOfNames; x++)//导出函数有名称 编号之分,导出函数总数=名称导出+编号导出,这里是循环导出名称的函数{//得到函数名 functionName = (PSTR)( (PBYTE)hMod + arrayOfFunctionNames[x]);//转化为ANSI_STRINGRtlInitAnsiString(&anFunName, functionName);//转化为UNICODE_STRINGRtlAnsiStringToUnicodeString(&unFunctionName, &anFunName, TRUE);//打印调试信息KdPrint(("%d/%d,FunName:%wZ\n", x+1, pExportTable->NumberOfNames, &unFunctionName));//比较函数名称if (RtlCompareUnicodeString(&unFunctionName, &unFunctionNameSearch, TRUE) == 0){//得到该函数地址functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1;functionAddress = (DWORD)( (PBYTE)hMod + arrayOfFunctionAddresses[functionOrdinal]);break;}}//这里释放资源返回的地址将无效 所以先存放起来//ZwUnmapViewOfSection (NtCurrentProcess(), BaseAddress);gDevExt->tmpPoint=BaseAddress;ZwClose(hSection);return functionAddress;}
调用代码如下:
ULONG ulOriginalProcAddr=GetDllFunctionAddress(TEXT("NtOpenProcess"), TEXT("\\SystemRoot\\system32\\ntdll.dll"));//释放GetDllFunctionAddress的内存块if(gDevExt->tmpPoint!=0){ ZwUnmapViewOfSection (NtCurrentProcess(), gDevExt->tmpPoint); gDevExt->tmpPoint=0;}
- 内核分析PE获取DLL导出函数地址
- 内核分析PE获取DLL导出函数地址
- 内核分析PE获取DLL导出函数地址
- 获取内核未导出函数地址
- 获取未导出的内核函数地址
- 获取PE文件的导出函数列表
- 获取PE文件的导出函数
- PE格式文件导出函数
- PE结构---获取导入表中函数的实际地址
- C#获取dll中函数地址
- dll函数偏移地址获取方式方法
- GetProcAddressEx跨进程获取导出函数地址
- GetProcAddressEx跨进程获取导出函数地址
- Windows PE导出表编程2(重组导出表函数地址)
- 获取内核函数地址的几种方
- 获取内核函数的原始地址
- 获取内核函数的原始地址
- 获取内核函数的原始地址
- [Cocoa]把程序窗口放在屏幕中央
- STL初涉~
- ajax的原理
- HDU 4544 湫湫系列故事——消灭兔子
- android的多屏支持
- 内核分析PE获取DLL导出函数地址
- Python中的排序
- Android LCD调试实例流程
- POJ 2752 Seek the Name, Seek the Fame
- VIM命令
- Android TextView文字超出一屏不能显示其它的文字 解决方案
- The server does not support version 3.0 of the J2EE Web module specification
- hdu2572
- HttpStatus