// 02 解析PE头.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "windows.h" bool IsPeFile(TCHAR* szPath) { BOOL bSuccess = TRUE; //1 将PE文件读取到内存 HANDLE hFile = CreateFile( szPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL ); DWORD dwSize = GetFileSize(hFile, NULL); DWORD dwRubbish = 0; unsigned char * pBuf = new unsigned char[dwSize]; ReadFile(hFile, pBuf, dwSize, &dwRubbish, NULL); //2 判断是否是PE文件 PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; if (pDos->e_magic != IMAGE_DOS_SIGNATURE) { bSuccess = FALSE; goto Error; } PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pBuf + pDos->e_lfanew); if (pNt->Signature != IMAGE_NT_SIGNATURE) { bSuccess = FALSE; goto Error; } Error: if (pBuf!=NULL) { delete []pBuf; } if (hFile!=INVALID_HANDLE_VALUE) { CloseHandle(hFile); } return bSuccess; } DWORD RvaToOffect(DWORD rva ,unsigned char* pFile) { //1 找到NT头 PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFile; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pFile + pDos->e_lfanew); //2 找到数据目录表 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt); //3 判断要转换的位置是不是PE头部 if (rva< pSection->VirtualAddress) { return rva; } //4 在数据目录表中遍历,进行计算 for (int i = 0; i < pNt->FileHeader.NumberOfSections; i++) { if ( (rva >= pSection->VirtualAddress)&& (rva <= pSection->VirtualAddress+pSection->Misc.VirtualSize) ) { return rva - pSection->VirtualAddress + pSection->PointerToRawData; } pSection++; } return -1; } int _tmain(int argc, _TCHAR* argv[]) { BOOL bSuccess = IsPeFile(L"D:\Test.exe"); if (bSuccess == TRUE) { //1 将PE文件读取到内存 HANDLE hFile = CreateFile( L"D:\Test.exe", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL ); DWORD dwSize = GetFileSize(hFile, NULL); DWORD dwRubbish = 0; unsigned char * pBuf = new unsigned char[dwSize]; ReadFile(hFile, pBuf, dwSize, &dwRubbish, NULL); //2 找到NT头 PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pBuf + pDos->e_lfanew); //2.1 找到文件头 PIMAGE_FILE_HEADER pFileHeader = &pNt->FileHeader; printf("运行平台:%x ", pFileHeader->Machine); printf("区段数量:%x ", pFileHeader->NumberOfSections); //2.2找到扩展头、 PIMAGE_OPTIONAL_HEADER pOptionHeader = &pNt->OptionalHeader; printf("入口点:%x ", pOptionHeader->AddressOfEntryPoint); printf("加载基址:%x ", pOptionHeader->ImageBase); printf("文件对齐:%x ", pOptionHeader->FileAlignment); printf("内存对齐:%x ", pOptionHeader->SectionAlignment); //....... //2.3找到数据目录表 PIMAGE_DATA_DIRECTORY pDataDir = pOptionHeader->DataDirectory; printf("导出表的地址是:%x ",pDataDir[0].VirtualAddress);//导出表的RVA printf("导出表的大小是:%x ",pDataDir[0].Size); //导出表这个数据的大小 printf("导入表的地址是:%x ", pDataDir[1].VirtualAddress);//导入表的RVA printf("导入表的大小是:%x ", pDataDir[1].Size); //导入表这个数据的大小 pDataDir[2];//资源 pDataDir[3];//异常 pDataDir[4];//安全结构 pDataDir[5];//重定位 pDataDir[6];//调试信息 //....... //2.4找到区段表 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt); for (int i = 0; i < pFileHeader->NumberOfSections;i++) { printf("区段名:%s ,起始RVA:%x,在映像中的大小:%x,起始Offect%x,在文件中的大小%x ", pSection->Name, pSection->VirtualAddress, pSection->Misc.VirtualSize, pSection->PointerToRawData, pSection->SizeOfRawData); pSection++; } DWORD Offect = RvaToOffect(0x2010, pBuf); printf("%x", Offect); } return 0; }