环境:VS2012+WIN8 64

类型:C++编写的WDM驱动程序

测试:VM WIN7

用途:主要用于驱动程序中得到WIN32 API地址,也可得到自定义的DLL中的函数导出地址,记录内核文件相关操作以便以后查看。

说明:此段代码来源于网络,经修改调试而成。

头文件 HelloWDM.h

#if __cplusplus
extern "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 headerWORD   e_magic;                     // Magic numberWORD   e_cblp;                      // Bytes on last page of fileWORD   e_cp;                        // Pages in fileWORD   e_crlc;                      // RelocationsWORD   e_cparhdr;                   // Size of header in paragraphsWORD   e_minalloc;                  // Minimum extra paragraphs neededWORD   e_maxalloc;                  // Maximum extra paragraphs neededWORD   e_ss;                        // Initial (relative) SS valueWORD   e_sp;                        // Initial SP valueWORD   e_csum;                      // ChecksumWORD   e_ip;                        // Initial IP valueWORD   e_cs;                        // Initial (relative) CS valueWORD   e_lfarlc;                    // File address of relocation tableWORD   e_ovno;                      // Overlay numberWORD   e_res[4];                    // Reserved wordsWORD   e_oemid;                     // OEM identifier (for e_oeminfo)WORD   e_oeminfo;                   // OEM information; e_oemid specificWORD   e_res2[10];                  // Reserved wordsLONG   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 imageDWORD   AddressOfNames;         // RVA from base of imageDWORD   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};//初始化 objectAttributesInitializeObjectAttributes(&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_PAGESPAGE_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_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;}}ZwClose(hSection);return functionAddress;
}

以上代码虽可以运行但没有考虑到 ZwMapViewOfSection的资源释放问题 修改如下:

//HelloWDM.h#if __cplusplus
extern "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 headerWORD   e_magic;                     // Magic numberWORD   e_cblp;                      // Bytes on last page of fileWORD   e_cp;                        // Pages in fileWORD   e_crlc;                      // RelocationsWORD   e_cparhdr;                   // Size of header in paragraphsWORD   e_minalloc;                  // Minimum extra paragraphs neededWORD   e_maxalloc;                  // Maximum extra paragraphs neededWORD   e_ss;                        // Initial (relative) SS valueWORD   e_sp;                        // Initial SP valueWORD   e_csum;                      // ChecksumWORD   e_ip;                        // Initial IP valueWORD   e_cs;                        // Initial (relative) CS valueWORD   e_lfarlc;                    // File address of relocation tableWORD   e_ovno;                      // Overlay numberWORD   e_res[4];                    // Reserved wordsWORD   e_oemid;                     // OEM identifier (for e_oeminfo)WORD   e_oeminfo;                   // OEM information; e_oemid specificWORD   e_res2[10];                  // Reserved wordsLONG   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 imageDWORD   AddressOfNames;         // RVA from base of imageDWORD   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导出函数地址相关推荐

  1. C# 遍历DLL导出函数

    C#如何去遍历一个由C++或E语言编写的本地DLL导出函数呢 不过在这里我建议对PE一无所知的人 你或许应先补补这方面的知识,我不知道为什么PE方面的 应用在C#中怎么这么少,我查阅过相关 C#的知识 ...

  2. windows 查看DLL导出函数的方法

    windows 查看DLL导出函数的方法 点我查看原文 在window下查看动态库的导出函数可以用vs自带的Dependenc工具: 对于VC6.0,VC所带的Depends软件,在VC6安装目录下的 ...

  3. VC++  DLL 导出函数

    VC++ DLL  导出函数 经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关 ...

  4. dll 导出函数 下划线_内核中的代码完整性:深入分析ci.dll

    前言 在某些场景中,如果我们希望在允许某个进程进行特定动作前,以一种可靠的方式确认该进程是否可信,那么验证该进程的Authenticode签名是一个不错的方式.用户模式下的DLL wintrust提供 ...

  5. MFC DLL 导出函数的定义方式

    一直在鼓捣DLL,每天的工作都是调试一个一个的DLL,往DLL里面添加自己的代码,但是对于DLL一直不太了解啊!今天一查资料,才发现自己对于DLL编写的一些基本知识也不了解.要学习,这篇文章先总结DL ...

  6. DLL导出函数名称改编的解决方法

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  7. windows查看dll导出函数名

    1.找到vcvarsall.bat(我路径在D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC),dos窗口中运行这个bat. 2.运行dum ...

  8. 获取上层调用函数地址的代码

    _asm { add ebp,4 mov eax,[ebp] sub ebp,4 mov callerAdress,eax } #define CALLER_ADDRESS_STDCALL(x) / ...

  9. 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取注入的 libbridge.so 动态库中的 load 函数地址 并 通过 远程调用 执行该函数 )

    文章目录 一.dlsym 函数简介 二.获取 目标进程 linker 中的 dlsym 函数地址 三.远程调用 目标进程 linker 中的 dlsym 函数 获取 注入的 libbridge.so ...

最新文章

  1. 文本分类step by step(二)
  2. Spring.NET 1.3.1 新特性探索系列1——ASP.NET MVC的依赖注入
  3. python 只取数值_Python:你会生成列表吗?-- 列表生成式
  4. 并查集(Union-Find-Set)简洁而高效地处理连通分量的查询与合并
  5. C语言查找单链列表的第k个元素的算法(附完整源码)
  6. Consul在.Net Core中初体验
  7. linux中shell数组的使用和建立
  8. kvm虚拟化学习笔记(二)之linux kvm虚拟机安装
  9. python语言是 创造的_1.python简介
  10. matlab输入一个正的实数x,VB程序题:用InputBox 输入一个正实数,用Pring方法在一行上显示出它的平方和平方根、立方和立方根,每个数保留三位小数,其间有间隔。...
  11. SHA算法 (sha0 sha1源码魔改)
  12. linux CPU压力测试stress
  13. 开源一套DUI控件源码
  14. 用数据分析看共享单车
  15. windows 编译libtorrent
  16. java技术英文名词读音_Java开发,Java development,音标,读音,翻译,英文例句,英语词典...
  17. PyQt6 使用 QAxWidget 打开 IE/Word
  18. 苏教版四年级下册计算机说课稿,苏教版四年级下册认识多位数说课稿
  19. Win Server 2008 R2
  20. SQL列转行及行转列

热门文章

  1. 腾讯云+未来高峰对话:智能+时代的创新与探索
  2. eclipse添加maven环境
  3. tomcat 之APR优化
  4. Android性能优化篇 [ 谷歌官方 ]
  5. SQL Server复制需要有实际的服务器名称才能连接到服务器
  6. 张孝祥Java培训视频及孙鑫java视频网址
  7. 微软聘请游说公司为收购雅虎作势
  8. 关键词与关键词之间的相关度计算
  9. Spring boot + Redis
  10. 这年头居然连MSDN Library都靠不住呀