环境: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 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 __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 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}; //初始化 objectAttributes InitializeObjectAttributes(&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_PAGES PAGE_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_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; } } //这里释放资源返回的地址将无效 所以先存放起来 //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; }