版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/whatday/article/details/9879335
环境: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;
}