本文共 26721 字,大约阅读时间需要 89 分钟。
这里三层结构一定要注意
nameOffset OffsetToDirctory 与 OffsetToData 联合体中的这三个偏移是相对资源表最开始的位置的偏移但在第三层中的 offsetToData是相对虚拟地址(RVA)要先转换成 FOA再加上文件起始地址就是在文件中的地址#include#include #include #include #include using namespace std;DWORD dwFileSize;BYTE* g_pFileImageBase = 0;PIMAGE_NT_HEADERS g_pNt = 0;DWORD RVAtoFOA(DWORD dwRVA);//显示pe头//参数为内存映射首地址void myPE() { OPENFILENAME stOF; HANDLE hFile, hMapFile; DWORD totalSize; //文件大小 LPVOID lpMemory; //内存映像文件在内存的起始位置 char szFileName[MAX_PATH] = { 0 }; //要打开的文件路径及名称名 char bufTemp1[10]; //每个字符的十六进制字节码 char bufTemp2[20]; //第一列 char lpServicesBuffer[100]; //一行的所有内容 char bufDisplay[50]; //第三列ASCII码字符 DWORD dwCount; //计数,逢16则重新计 DWORD dwCount1; //地址顺号 DWORD dwBlanks; //最后一行空格数 char szExtPe[] = TEXT("PE Files\0*.exe;*.dll;*.scr;*.fon;*.drv\0All Files(*.*)\0*.*\0\0"); RtlZeroMemory(&stOF, sizeof(stOF)); stOF.lStructSize = sizeof(stOF); //stOF.hwndOwner = (HWND)GetModuleHandle(NULL); stOF.lpstrFilter = szExtPe; stOF.lpstrFile = szFileName; stOF.nMaxFile = MAX_PATH; stOF.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&stOF)) //让用户选择打开的文件 { hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); //如果是无效的句柄 if (hFile == INVALID_HANDLE_VALUE) { printf("文件打开失败\n"); return; } //获取文件大小 dwFileSize = GetFileSize(hFile, NULL); g_pFileImageBase = new BYTE[dwFileSize]{}; DWORD dwRead; //将文件读取到内存中 bool bRet =ReadFile(hFile, g_pFileImageBase, dwFileSize, &dwRead, NULL); //如果读取失败就返回 if (!bRet) { delete[] g_pFileImageBase; } //关闭句柄 CloseHandle(hFile);/dos头/// //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;/dos头/// //使用PIMAGE_DOS_HEADER(占64字节)解释前64个字节 PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)g_pFileImageBase; //判断PE文件的标识是否正确,有一个不对,那么它就不是PE文件 if (pDos->e_magic != IMAGE_DOS_SIGNATURE)//0x5A4D('MZ') { return ; } cout << "---------------------------DOS头(_IMAGE_DOS_HEADER)------------------------------- "<< endl; cout << hex << "WORD e_magic: " << pDos->e_magic << endl; cout << hex << "WORD e_cblp: " << pDos->e_cblp << endl; cout << hex << "WORD e_cp: " << pDos->e_cp << endl; cout << hex << "WORD e_cblp: " << pDos->e_cblp << endl; cout << hex << "WORD e_cparhdr: " << pDos->e_cparhdr << endl; cout << hex << "WORD e_minalloc: " << pDos->e_minalloc << endl; cout << hex << "WORD e_ss: " << pDos->e_ss << endl; cout << hex << "WORD e_sp: " << pDos->e_sp << endl; cout << hex << "WORD e_csum: " << pDos->e_csum << endl; cout << hex << "WORD e_ip: " << pDos->e_ip << endl; cout << hex << "WORD e_cs: " << pDos->e_cs << endl; cout << hex << "WORD e_lfarlc: " << pDos->e_lfarlc << endl; cout << hex << "WORD e_ovno: " << pDos->e_ovno << endl; cout << hex << "WORD e_res[4]: " << *(pDos->e_res) << endl; cout << hex << "WORD e_oemid: " << pDos->e_oemid << endl; cout << hex << "WORD e_oeminfo: " << pDos->e_oeminfo << endl; cout << hex << "WORD e_res2[10]: " << *(pDos->e_res2) << endl; cout << hex << "WORD e_lfanew: " << pDos->e_lfanew << endl;/NT头/// /*typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;*/ g_pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + g_pFileImageBase); if (g_pNt->Signature != IMAGE_NT_SIGNATURE)//0x00004550('PE') { return ; } cout << "---------------------------NT头(PIMAGE_NT_HEADERS)------------------------------- " << endl; cout << hex << "DWORD Signature; " << g_pNt->Signature << endl; cout << hex << "IMAGE_FILE_HEADER FileHeader; " << &g_pNt->OptionalHeader << endl; cout << hex << "IMAGE_OPTIONAL_HEADER32 OptionalHeader; " << &g_pNt->OptionalHeader << endl;/FILE头/// /*typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;*/ PIMAGE_FILE_HEADER mytmf = &(g_pNt->FileHeader); cout << "---------------------------FILE头(IMAGE_FILE_HEADER )----------------------------- " << endl; cout << hex << "WORD Machine; " << mytmf->Machine << endl; cout << hex << "WORD NumberOfSections; " << mytmf->NumberOfSections << endl; cout << hex << "DWORD TimeDateStamp; " << mytmf->TimeDateStamp << endl; cout << hex << "DWORD PointerToSymbolTable; " << mytmf->PointerToSymbolTable << endl; cout << hex << "DWORD NumberOfSymbols; " << mytmf->NumberOfSymbols << endl; cout << hex << "WORD SizeOfOptionalHeader; " << mytmf->SizeOfOptionalHeader << endl; cout << hex << "WORD Characteristics; " << mytmf->Characteristics << endl; /Optional头/// // // Optional header format. // //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[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; PIMAGE_OPTIONAL_HEADER32 myoption = &(g_pNt->OptionalHeader); cout << "---------------------------OPTIONAL头(PIMAGE_OPTIONAL_HEADER32 )-------------------------------------------------- " << endl; cout << "---------------------------------------Standard fields.------------------------------------------------------------- " << endl; cout << hex << "WORD Magic; " << myoption->Magic << endl; cout << hex << "BYTE MajorLinkerVersion; " << myoption->MajorLinkerVersion << endl; cout << hex << "BYTE MinorLinkerVersion; " << myoption->MinorLinkerVersion << endl; cout << hex << "DWORD SizeOfCode; " << myoption->SizeOfCode << endl; cout << hex << "DWORD SizeOfInitializedData; " << myoption->SizeOfInitializedData << endl; cout << hex << "DWORD SizeOfUninitializedData; " << myoption->SizeOfUninitializedData << endl; cout << hex << "DWORD AddressOfEntryPoint; " << myoption->AddressOfEntryPoint << endl; cout << hex << "DWORD BaseOfCode; " << myoption->BaseOfCode << endl; cout << hex << "DWORD BaseOfData; " << myoption->BaseOfData << endl; cout << "----------------------------------------- NT additional fields.----------------------------------------------------- " << endl; cout << hex << "DWORD ImageBase; " << myoption->ImageBase << endl; cout << hex << "DWORD SectionAlignment; " << myoption->SectionAlignment << endl; cout << hex << "DWORD FileAlignment; " << myoption->FileAlignment << endl; cout << hex << "WORD MajorOperatingSystemVersion; " << myoption->MajorOperatingSystemVersion << endl; cout << hex << "WORD MinorOperatingSystemVersion; " << myoption->MinorOperatingSystemVersion << endl; cout << hex << "WORD MajorImageVersion; " << myoption->MajorImageVersion << endl; cout << hex << "DWORD SectionAlignment; " << myoption->SectionAlignment << endl; cout << hex << "WORD MinorImageVersion; " << myoption->MinorImageVersion << endl; cout << hex << "WORD MajorSubsystemVersion; " << myoption->MajorSubsystemVersion << endl; cout << hex << "WORD MinorSubsystemVersion; " << myoption->MinorSubsystemVersion << endl; cout << hex << "DWORD Win32VersionValue; " << myoption->Win32VersionValue << endl; cout << hex << "DWORD SizeOfImage; " << myoption->SizeOfImage << endl; cout << hex << "DWORD SizeOfHeaders; " << myoption->SizeOfHeaders << endl; cout << hex << "DWORD CheckSum; " << myoption->CheckSum << endl; cout << hex << "WORD Subsystem; " << myoption->Subsystem << endl; cout << hex << "WORD DllCharacteristics; " << myoption->DllCharacteristics << endl; cout << hex << "DWORD SizeOfStackReserve; " << myoption->SizeOfStackReserve << endl; cout << hex << "DWORD SizeOfStackCommit; " << myoption->SizeOfStackCommit << endl; cout << hex << "DWORD SizeOfHeapReserve; " << myoption->SizeOfHeapReserve << endl; cout << hex << "DWORD SizeOfHeapCommit; " << myoption->SizeOfHeapCommit << endl; cout << hex << "DWORD LoaderFlags; " << myoption->LoaderFlags << endl; cout << hex << "DWORD NumberOfRvaAndSizes; " << myoption->NumberOfRvaAndSizes << endl; cout << hex << "IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];" << &(myoption->DataDirectory) << endl; /所有区段表头 /*typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;*/ //所有区表头都在一起 //大文件头中找区段数 int nCountOfSection = g_pNt->FileHeader.NumberOfSections; //取第一个区表头 PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt); //循环 for (int i = 0; i < nCountOfSection; i++) { cout << "----------------------第"< <<"个-----PIMAGE_SECTION_HEADER头(PIMAGE_OPTIONAL_HEADER32 )----------------------------- " << endl; cout << "BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; " << pSec->Name << endl; cout << hex << "DWORD PhysicalAddress; " << pSec->Misc.PhysicalAddress << endl; cout << hex << "DWORD VirtualSize; " << pSec->Misc.VirtualSize << endl; cout << hex << "DWORD VirtualAddress; " << pSec->VirtualAddress << endl; cout << hex << "DWORD SizeOfRawData; " << pSec->SizeOfRawData << endl; cout << hex << "DWORD PointerToRawData; " << pSec->PointerToRawData << endl; cout << hex << "DWORD PointerToRelocations; " << pSec->PointerToRelocations << endl; cout << hex << "WORD PointerToLinenumbers; " << pSec->PointerToLinenumbers << endl; cout << hex << "WORD NumberOfRelocations; " << pSec->NumberOfRelocations << endl; cout << hex << "DWORD NumberOfLinenumbers; " << pSec->NumberOfLinenumbers << endl; cout << hex << "DWORD Characteristics; " << pSec->Characteristics << endl; cout << hex << "在文件中相对文件偏移; " << RVAtoFOA(pSec->VirtualAddress) << endl; //下一个区表头首地址 ++pSec; } /导出表/// //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; //找到导出表 也就是第一个表下标为0 DWORD dwExportRVA =g_pNt->OptionalHeader.DataDirectory[0].VirtualAddress; //获取在文件中的位置 PIMAGE_EXPORT_DIRECTORY pExport =(PIMAGE_EXPORT_DIRECTORY)(RVAtoFOA(dwExportRVA) + g_pFileImageBase); //模块名字 char* pName = (char*)(RVAtoFOA(pExport->Name) + g_pFileImageBase); printf("%s\n", pName); //地址表中的个数 DWORD dwCountOfFuntions = pExport->NumberOfFunctions; //名称表中的个数 DWORD dwCountOfNames = pExport->NumberOfNames; //地址表地址 PDWORD pAddrOfFuntion = (PDWORD)(RVAtoFOA(pExport->AddressOfFunctions) + g_pFileImageBase); //名称表地址 PDWORD pAddrOfName = (PDWORD)(RVAtoFOA(pExport->AddressOfNames) + g_pFileImageBase); //序号表地址 PWORD pAddrOfOrdial = (PWORD)(RVAtoFOA(pExport->AddressOfNameOrdinals) + g_pFileImageBase); //base值 DWORD dwBase = pExport->Base; //遍历地址表中的元素 cout << "-----------------------------------------导出表中的导出函数与导出序号-------------------------------------------------- " << endl; if (dwExportRVA == 0) { printf("没有导出表\n"); //return; } else { for (int i = 0; i < dwCountOfFuntions;i++) { //地址表中可能存在无用的值(就是为0的值) if (pAddrOfFuntion[i] == 0) { continue; } //根据序号表中是否有值(地址表的下标值), //来判断是否是名称导出 bool bRet = false; for (int j = 0; j < dwCountOfNames;j++) { //i为地址表下标j为序号表的下标(值为地址表下标) //判断是否在序号表中 if (i == pAddrOfOrdial[j]) { //因为序号表与名称表的位置一一对应 //取出名称表中的名称地址RVA DWORD dwNameRVA = pAddrOfName[j]; char* pFunName = (char*)(RVAtoFOA(dwNameRVA) + g_pFileImageBase); printf("%04d %s 0x%08x\n", i + dwBase, pFunName, pAddrOfFuntion[i]); bRet = true; break; } } if (!bRet) { //序号表中没有,说明是以序号导出的 printf("%04d %08X\n", i + dwBase, pAddrOfFuntion[i]); } } } /导出表/// //typedef struct _IMAGE_IMPORT_DESCRIPTOR { // union { // DWORD Characteristics; // 0 for terminating null import descriptor // DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) // } DUMMYUNIONNAME; // DWORD TimeDateStamp; // 0 if not bound, // // -1 if bound, and real date\time stamp // // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) // // O.W. date/time stamp of DLL bound to (Old BIND) // DWORD ForwarderChain; // -1 if no forwarders // DWORD Name; // DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) //} IMAGE_IMPORT_DESCRIPTOR; //typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; cout << "-----------------------------------------导入表中的导入函数与导入模块-------------------------------------------------- " << endl; //找到导入表 也就是第二个下标为1 DWORD dwImpotRVA = g_pNt->OptionalHeader.DataDirectory[1].VirtualAddress; //在文件中的位置 DWORD dwImportInFile = (DWORD)(RVAtoFOA(dwImpotRVA) + g_pFileImageBase); PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwImportInFile; //遍历每一个导入表 通过最后一个为0作为判断条件 if (dwImpotRVA == 0) { printf("没有导入表\n"); return; } else { while (pImport->Name) { //函数名称地址 PIMAGE_THUNK_DATA pFirsThunk = (PIMAGE_THUNK_DATA)(RVAtoFOA(pImport->FirstThunk) + g_pFileImageBase); //模块名 char* pName = (char*)(RVAtoFOA(pImport->Name) + g_pFileImageBase); printf("导入模块名字%s\n", pName); //也是通过最后一个为0作为判断条件 while (pFirsThunk->u1.AddressOfData) { //判断导入方式 if (IMAGE_SNAP_BY_ORDINAL32(pFirsThunk->u1.AddressOfData)) { //说明是序号导入(低16位是其序号) printf("\t\t%04X \n", pFirsThunk->u1.Ordinal & 0xFFFF); } else { //名称导入 PIMAGE_IMPORT_BY_NAME pImportName = (PIMAGE_IMPORT_BY_NAME)(RVAtoFOA(pFirsThunk->u1.AddressOfData) + g_pFileImageBase); printf("\t\t%04X %s \n", pImportName->Hint, pImportName->Name); } // pFirsThunk++; } pImport++; } } cout << "--------------------------------------------------资源表--------------------------------------------------------------- " << endl; //注意的是NameOffset偏移 OffsetToDirectory偏移 OffsetToData偏移都是资源表最开始的偏移 //找到资源表 DWORD dwResRVA = g_pNt->OptionalHeader.DataDirectory[2].VirtualAddress; DWORD dwResFOA = (DWORD)(RVAtoFOA(dwResRVA) + g_pFileImageBase); PIMAGE_RESOURCE_DIRECTORY pRes = (PIMAGE_RESOURCE_DIRECTORY)dwResFOA; //资源有三层 每一层都以一个PIMAGE_RESOURCE_DIRECTORY开头,之后跟数个 //PIMAGE_RESOURCE_DIRECTORY_ENTRY结构,可以说第一层由一个PIMAGE_RESOURCE_DIRECTORY //与一个PIMAGE_RESOURCE_DIRECTORY_ENTRY结构体组成 //第一层(种类) //种类个数 DWORD dwCountOfResType = pRes->NumberOfIdEntries + pRes->NumberOfNamedEntries; for (int i = 0; i < dwCountOfResType;i++) { //pRes代表PIMAGE_RESOURCE_DIRECTORY的首地址+1之后就是后面的PIMAGE_RESOURCE_DIRECTORY_ENTRY首地址 PIMAGE_RESOURCE_DIRECTORY_ENTRY pResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes + 1); //typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { //这个联合体说明资源叫什么 如果这种资源是已知的也就是微软定义的那么 //联合体最高位为0也就是NameIsString成员为0这个时候整个四字节(union)代表着已知资源的类型,也就是ID起 //作用 如果这种资源是未知是那么NameIsString的最高位为1 低31位指向一个name的结构体(PIMAGE_RESOURCE_DIR_STRING_U)偏移,也就是DWORD Name;起作用 // union { // struct { // DWORD NameOffset : 31; // DWORD NameIsString : 1; // } DUMMYSTRUCTNAME; // DWORD Name; // WORD Id; // } DUMMYUNIONNAME; //这个联合体说明资源在哪里 //当DataIsDirectory字段为1时(也就是这个四字节最高位为1)说明这个联合体表示的地方是一个目录,OffsetToDirectory(低31位)表示具体有 //多少个地方,这个些地方就是第二层 // union { // DWORD OffsetToData; // struct { // DWORD OffsetToDirectory : 31; // DWORD DataIsDirectory : 1; // } DUMMYSTRUCTNAME2; // } DUMMYUNIONNAME2; //} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY; //判断这种资源是字符串还是ID if (pResEntry->NameIsString) { //如果是字符串,NameOffset保存的就是这个字符串相对资源起始位置的偏移 //得到名字字符串的FOA DWORD dwName = (DWORD)(pResEntry->NameOffset+ (DWORD)pRes); //NameOffset所指向的结构体是IMAGE_RESOURCE_DIR_STRING_U类型 //这里保存了字符串的长度和起始位置 PIMAGE_RESOURCE_DIR_STRING_U pName = (PIMAGE_RESOURCE_DIR_STRING_U)dwName; //这里的字符串不是以0结尾的,所以需要拷贝出来加上‘\0’结尾后再打印 WCHAR *pResName = new WCHAR[pName->Length + 1]{}; memcpy(pResName, pName, (pName->Length) * sizeof(WCHAR)); //因为是WCHAR,所以用wprintf wprintf(L"%s\n", pResName); //释放内存 delete[] pResName; } else //id { char* arryResType[] = { "", "鼠标指针(Cursor)", "位图(Bitmap)", "图标(Icon)", "菜单(Menu)" , "对话框(Dialog)", "字符串列表(String Table)", "字体目录(Font Directory)", "字体(Font)", "快捷键(Accelerators)" , "非格式化资源(Unformatted)", "消息列表(Message Table)", "鼠标指针组(Croup Cursor)", "", "图标组(Group Icon)", "" , "版本信息(Version Information)" }; if (pResEntry->Id < 17) { printf("arryResType[pResEntry->Id] %s\n", arryResType[pResEntry->Id]); } else { printf("pResEntry->Id %04X\n", pResEntry->Id); } //判断是否有下一层(0个表示没有下一层) if (pResEntry->DataIsDirectory) { //到了第二层相对结构体同样和上一层一样但是OffsetToDirectory就指向对三层了 DWORD dwResSecond = (DWORD)pRes + pResEntry->OffsetToDirectory; PIMAGE_RESOURCE_DIRECTORY pResSecond = (PIMAGE_RESOURCE_DIRECTORY)dwResSecond; //第二层个数 DWORD dwCountOfSecond = pResSecond->NumberOfIdEntries + pResSecond->NumberOfNamedEntries; //遍历每一个资源 for (int iSecond = 0; iSecond < dwCountOfSecond;iSecond++) { PIMAGE_RESOURCE_DIRECTORY_ENTRY pResSecondEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResSecond + 1); //判断这种资源是字符串还是ID if (pResEntry->NameIsString) { //如果是字符串,NameOffset保存的就是这个字符串的RVA //得到名字字符串的FOA DWORD dwNameFOA = (DWORD)(RVAtoFOA(pResEntry->NameOffset) + g_pFileImageBase); //NameOffset所指向的结构体是IMAGE_RESOURCE_DIR_STRING_U类型 //这里保存了字符串的长度和起始位置 PIMAGE_RESOURCE_DIR_STRING_U pName = (PIMAGE_RESOURCE_DIR_STRING_U)dwNameFOA; //这里的字符串不是以0结尾的,所以需要拷贝出来加上‘\0’结尾后再打印 WCHAR *pResName = new WCHAR[pName->Length + 1]{}; memcpy(pResName, pName, (pName->Length) * sizeof(WCHAR)); wprintf(L"pResName %s\n", pResName); delete[] pResName; } else //id { printf("pResEntry->Id %04X\n", pResEntry->Id); } //判断有没有下一层 //第三层 同样套路从第一个结构体开始找 到了OffsetToDirectory就是第三层了 //这里要注意的是到了第三层这个IMAGE_RESOURCE_DIRECTORY_ENTRY结构体的第一个联合体就没用了 //同时第二个联合体的DataIsDirectory为0没有下一层了 //通过OffsetToData字段找到资源结构体的偏移(指向_IMAGE_RESOURCE_DATA_ENTRY结构体) if (pResSecondEntry->DataIsDirectory) { //第三层的起始位置 DWORD dwResThrid = (DWORD)pRes + pResSecondEntry->OffsetToDirectory; PIMAGE_RESOURCE_DIRECTORY pResThrid = (PIMAGE_RESOURCE_DIRECTORY)dwResThrid; PIMAGE_RESOURCE_DIRECTORY_ENTRY pResThridEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResThrid + 1); //第三层,已经是最后一层,使用PIMAGE_RESOURCE_DIRECTORY_ENTRY中的 //OffsetToData成员,得到PIMAGE_RESOURCE_DATA_ENTRY结构的位置 /*typedef struct _IMAGE_RESOURCE_DATA_ENTRY { DWORD OffsetToData; //资源偏移 DWORD Size; DWORD CodePage; DWORD Reserved; } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY; */ PIMAGE_RESOURCE_DATA_ENTRY pResData = (PIMAGE_RESOURCE_DATA_ENTRY)(pResThridEntry->OffsetToData + (DWORD)pRes); //资源的RVA和Size DWORD dwResDataRVA = pResData->OffsetToData; DWORD dwResDataSize = pResData->Size; //PIMAGE_RESOURCE_DATA_ENTRY中的OffsetToData是个RVA DWORD dwResDataFOA = (DWORD)(RVAtoFOA(dwResDataRVA) + g_pFileImageBase); //资源的二进制数据 //遍历打印资源的二进制数据 这里就只能是二进制了 PBYTE pData = (PBYTE)dwResDataFOA; for (int iData = 0; iData < dwResDataSize; iData++) { if (iData % 16 == 0 && iData != 0) { printf("\n"); } printf("%02X ", pData[iData]); } printf("\n"); } //下一个资源 pResSecondEntry++; } } } //下一种资源 pResEntry++; } cout << "----------------------------------------------------重定位表------------------------------------------------------------ " << endl; //因为代码用的是绝对地址因此要有定位表 //当重定位发生时,只需要现在pe文件的加载基址,用现在的加载基址减去默认加载基址得到一个数,再用这个数加上需要重定位的数据即可,所以重定位 //表中保存的只是需要重定位信息 typedef struct _OFFSET_TYPE { WORD offset : 12; //本页的偏移量 WORD type : 4; //重定位类型(3) }OFFSET_TYPE, *POFFSET_TYPE; //重定位表RVA DWORD dwRelocRVA = g_pNt->OptionalHeader.DataDirectory[5].VirtualAddress; //是否为空 if (!dwRelocRVA) { printf("没有重定位表\n"); return; } //重定位表在文件中的地址 PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)(RVAtoFOA(dwRelocRVA) + g_pFileImageBase); //循环重定位表 //如果SizeOfBlock为0,说明没有需要重定位的数据了 while (pReloc->SizeOfBlock) { //当前重定位页RVA printf("%08X\n\n", pReloc->VirtualAddress); //这一页一共有多少个重定位块(即多少个需要重定位的数据) DWORD dwCount = (pReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); //指向重定位块地址 POFFSET_TYPE pOffset = (POFFSET_TYPE)(pReloc + 1); //遍历每一个重定位块 for (int i = 0; i < dwCount;i++) { //在这一页中的位置地址RVA DWORD dwRelocDataRVA = pReloc->VirtualAddress + pOffset->offset; //转成FOA DWORD dwRelocDataFOA = (DWORD)(RVAtoFOA(dwRelocDataRVA) + g_pFileImageBase); //实际需要重定位的数据地址是个VA DWORD dwRealDataVA = *(DWORD*)dwRelocDataFOA; //转成RVA(这就是内存中的转换完成的相对地址了) DWORD dwRealDataRVA = dwRealDataVA - g_pNt->OptionalHeader.ImageBase; //再转FOA(RVA在文件中的地址) DWORD dwRealDataFOA = (DWORD)(RVAtoFOA(dwRealDataRVA) + g_pFileImageBase); //需要重定位的具体数据(字节数不确定) DWORD dwData = *(DWORD*)dwRealDataFOA; printf("需要重定位的第%d个数据 RVA:%08X VA:%08X DATA:%08X\n", i + 1, dwRelocDataRVA, dwRealDataVA, dwData); //下一个重定位数据位置 pOffset++; } //下一页 pReloc = (PIMAGE_BASE_RELOCATION)(pReloc->SizeOfBlock + (DWORD)pReloc); } return ; }}//void _openFile();DWORD RVAtoFOA(DWORD dwRVA){ //此RVA落在哪个区段中 //找到所在区段后, //减去所在区段的起始位置,加上在文件中的起始位置 //大文件头中找区段数 int nCountOfSection = g_pNt->FileHeader.NumberOfSections; //区段表头 PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt); //在扩展头中找到块对齐数 DWORD dwSecAligment = g_pNt->OptionalHeader.SectionAlignment; //循环 for (int i = 0; i < nCountOfSection; i++) { //求在内存中的真实大小 //Misc.VirtualSize % dwSecAligment如果是0代表刚好对齐否则就先对齐(非0就是真) //Misc.VirtualSize / dwSecAligment * dwSecAligment + dwSecAligment //最后加上余数的对齐 DWORD dwRealVirSize = pSec->Misc.VirtualSize % dwSecAligment ? pSec->Misc.VirtualSize / dwSecAligment * dwSecAligment + dwSecAligment : pSec->Misc.VirtualSize; //区段中的相对虚拟地址转文件偏移 思路是 用要转换的地址与各个区 //段起始地址做比较如果落在一个区段中(大于起始地址小于起始地址加区段最大偏移和), //就用要转换的相对虚拟地址减去区段的起始地址的相对虚拟地址, //得到了这个地址相对这个区段偏移,再用得到的这个偏移加上区段在文件中的偏移的起始位置 //(pointerToRawData字段)就是他在文件中的文件偏移 if (dwRVA >= pSec->VirtualAddress && dwRVA < pSec->VirtualAddress + dwRealVirSize) { //FOA = RVA - 内存中区段的起始位置 + 在文件中区段的起始位置 return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData; } //下一个区段地址 pSec++; }}int main() { myPE(); cin.get();}
转载于:https://blog.51cto.com/haidragon/2104874