打印 PE導入導出表
阿新 • • 發佈:2018-04-17
PE
#include<Windows.h> #include<iostream> #include<stdio.h> #include<stdlib.h> #include<commdlg.h> 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 << "----------------------第"<<i<<"個-----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++; } } 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(); }
打印 PE導入導出表