第3讲:导入表的定位和读取操作
// ImportFun.cpp : 完整代码如下
//
#include "stdafx.h" #include <stdio.h> #include <windows.h> //用来实现RVA到磁盘文件偏移的转换 DWORD RVAToOffset(LPVOID lpBase,DWORD VirtualAddress) { IMAGE_DOS_HEADER *dosHeader; IMAGE_NT_HEADERS *ntHeader; IMAGE_SECTION_HEADER *SectionHeader; int NumOfSections;//Section 的数量 //定位到PE head dosHeader=(IMAGE_DOS_HEADER*)lpBase; ntHeader=(IMAGE_NT_HEADERS*)((BYTE*)lpBase+dosHeader->e_lfanew); NumOfSections=ntHeader->FileHeader.NumberOfSections; for (int i=0;i<NumOfSections;i++) { SectionHeader=(IMAGE_SECTION_HEADER*)((BYTE*)lpBase+dosHeader->e_lfanew+sizeof(IMAGE_NT_HEADERS))+i; if(VirtualAddress>SectionHeader->VirtualAddress&&VirtualAddress<SectionHeader->VirtualAddress+SectionHeader->SizeOfRawData) { DWORD AposRAV=VirtualAddress-SectionHeader->VirtualAddress; DWORD Offset=SectionHeader->PointerToRawData+AposRAV; return Offset; } } return 0; } int main(int argc, char* argv[]) { //打开文件 HANDLE hFile=CreateFile("c:\\calc.exe",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile==INVALID_HANDLE_VALUE) { printf("CreateFile Failed\n"); return 0; } //创建内存映射文件的内核对象 HANDLE hMap=CreateFileMapping(hFile,NULL,PAGE_READONLY,NULL,NULL,NULL); if(hMap==INVALID_HANDLE_VALUE) { printf("CreateFileMapping Failed\n"); return 0; } //把文件映射入内存 LPVOID lpBase=MapViewOfFile(hMap,FILE_MAP_READ,0,0,0);//返回内存文件映射句柄,lpBase if(lpBase==NULL) { printf("MapViewOfFile Failed\n"); return 0; } IMAGE_DOS_HEADER *dosHeader; IMAGE_NT_HEADERS *ntHeader; IMAGE_IMPORT_BY_NAME *ImportName; //lpBase由MapViewOfFile函数返回 dosHeader=(IMAGE_DOS_HEADER*)lpBase; //检测是否是有效的PE文件 if (dosHeader->e_magic!=IMAGE_DOS_SIGNATURE) { printf("This is not a windows file\n"); return 0; } //定位到PE header ntHeader=(IMAGE_NT_HEADERS*)((BYTE*)lpBase+dosHeader->e_lfanew);//e_lfanew成员定位到PE header //判断是否是一个有效的win32文件 if(ntHeader->Signature!=IMAGE_NT_SIGNATURE) { printf("This is not a win32 file\n"); return 0; } //定位到导入表 IMAGE_IMPORT_DESCRIPTOR *ImportDec=(IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)lpBase+RVAToOffset(lpBase,ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); while(ImportDec->FirstThunk) { //得到DLL文件名 char *pDllName=(char*)((BYTE*)lpBase+RVAToOffset(lpBase,ImportDec->Name)); printf("\nDLL文件名:%s\n",pDllName); //通过OriginalFirstThunk定位到PIMAGE_THUNK_DATA结构数组 PIMAGE_THUNK_DATA pThunk=(PIMAGE_THUNK_DATA)((BYTE*)lpBase+RVAToOffset(lpBase,ImportDec->OriginalFirstThunk)); while(pThunk->u1.Function) { //判断函数是用函数名导入的还是序号导入的 if(pThunk->u1.Ordinal& IMAGE_ORDINAL_FLAG32)//高位为1 { //输出序号 printf("从此DLL模块导出的函数的序号:%x\n",pThunk->u1.Ordinal&0xFFFF); } else//高位为0 { //得到IMAGE_IMPORT_BY_NAME结构中的函数名 ImportName=(IMAGE_IMPORT_BY_NAME*)((BYTE*)lpBase+RVAToOffset(lpBase,(DWORD)pThunk->u1.AddressOfData)); printf("从此DLL模块导出的函数的函数名:%s\n",ImportName->Name); } pThunk++; } ImportDec++; } UnmapViewOfFile(lpBase); CloseHandle(hMap); CloseHandle(hFile); return 0; }