倆種方式實現 PEdump
阿新 • • 發佈:2018-04-16
PE方式一
思路把 pe 文件打開,然後通過ReadFile讀到一個緩沖區裏(內存上)
優點一直保存在那
缺點 得先讀完(這一般不算什麽讀的速度非常快)
c++版
思路把 pe 文件打開,然後通過ReadFile讀到一個緩沖區裏(內存上)
優點一直保存在那
缺點 得先讀完(這一般不算什麽讀的速度非常快)
方式二(這裏多了步打開文件管理器)
思路把pe 文件打開,然後通過MapViewOfFile映射到內存(返回首地址Return value
If the function succeeds, the return value is the starting address of the mapped view.)
優點動態加載
缺點 由於操作系統只能同時做一件事 因此如果你點擊了其它地方他就停止加載。再次點擊窗口又開始加載。
倆種方式都是首地址加加(第一種前輟加加報錯,後輟加加不報錯,然而MapViewOfFile的返回值做++不管你前後都會報錯 這種方式就可以lpMemory = (char*)lpMemory + 1; 我理解不了,如果說返回是常量不能修改為什麽這種方式就可以)註意在匯編與 c 語言裏不會報錯
// PE練習.cpp : 定義控制臺應用程序的入口點。 // #include<Windows.h> #include<iostream> using namespace std; void _openFile(); DWORD dwStop; DWORD dwFileSize; BYTE* g_pFileImageBase = 0; PIMAGE_NT_HEADERS g_pNt = 0; void ReadFileToMem(char* szFilePath) { //打開文件獲取文件句柄 HANDLE hFile = CreateFile((LPCTSTR)szFilePath, GENERIC_READ, FALSE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 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); } bool IsPEFile() { //使用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 false; } g_pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + g_pFileImageBase); if (g_pNt->Signature != IMAGE_NT_SIGNATURE)//0x00004550(‘PE‘) { return false; } return true; } void ShowNtImportance() { printf("入口點RVA:%08X", g_pNt->OptionalHeader.AddressOfEntryPoint); printf("文件默認加載:%08X", g_pNt->OptionalHeader.ImageBase); printf("文件區段個數:%d", g_pNt->FileHeader.NumberOfSections); //.... } void ShowDirTable() { //獲取目錄表個數 int nCountOfDirTable = g_pNt->OptionalHeader.NumberOfRvaAndSizes; printf("數據目錄表個數:%d", g_pNt->OptionalHeader.NumberOfRvaAndSizes); for (int i = 0; i < nCountOfDirTable;i++) { //如果VirtualAddress不為0,說明此表存在 if (g_pNt->OptionalHeader.DataDirectory[i].VirtualAddress) { //.... } } } void ShowSectionTable() { //獲取區段個數 int nCountOfSection = g_pNt->FileHeader.NumberOfSections; //得到首個區段的位置 PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt); //保存區段名字(區段名字可能不是以0為結尾的) char strName[9] = {}; for (int i = 0; i < nCountOfSection;i++) { memcpy(strName, pSec->Name, 8); printf("第%d個區段名:%s", i + 1, strName); printf("區段RVA:%08X", pSec->VirtualAddress); //.... //下一個區段地址 pSec++; } } 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++) { //求在內存中的真實大小 DWORD dwRealVirSize = pSec->Misc.VirtualSize % dwSecAligment ? pSec->Misc.VirtualSize / dwSecAligment * dwSecAligment + dwSecAligment : pSec->Misc.VirtualSize; if (dwRVA >= pSec->VirtualAddress && dwRVA < pSec->VirtualAddress + dwRealVirSize) { //FOA = RVA - 內存中區段的起始位置 + 在文件中區段的起始位置 return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData; } //下一個區段地址 pSec++; } } // DWORD FOAtoRVA(DWORD dwFOA) // { // // } int main() { //方式1-------------------------------------------------------------------------------- //ReadFileToMem("C:\\Users\\allenboy\\Desktop\\fun.exe"); //int i = 0; //int j = 0; //while (j<dwFileSize) //{ // printf("%x ", *(char *)g_pFileImageBase); // ++i; // if (i == 16) { // printf("\n"); // i = 0; // } // ++j; // (char *)g_pFileImageBase++; //} //方式2-------------------------------------------------------------------------------- _openFile(); cin.get(); return 0; } /* 打開PE文件並處理 */ void _openFile() { 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) { totalSize = GetFileSize(hFile, NULL);//獲取文件大小 if (totalSize) { hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);//內存映射文件 if (hMapFile) { lpMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);//獲得文件在內存的映象起始位置 if (lpMemory) { //開始處理文件 //緩沖區初始化 RtlZeroMemory(bufTemp1, 10); RtlZeroMemory(bufTemp2, 20); RtlZeroMemory(lpServicesBuffer, 100); RtlZeroMemory(bufDisplay, 50); dwCount = 1; //將第一列寫入lpServicesBuffer dwCount1 = 0; sprintf(bufTemp2, "%08x ", dwCount1); lstrcat(lpServicesBuffer, bufTemp2); //函數功能:該函數將一個字符串附加在另一個字符串後面。 dwBlanks = (16 - totalSize % 16) * 3;//求最後一行的空格數 while (TRUE) { if (totalSize == 0)//最後一行 { while (dwBlanks)//填充空格 { lstrcat(lpServicesBuffer, TEXT("#")); --dwBlanks; } lstrcat(lpServicesBuffer, TEXT(" "));//第二列與第三列中間的空格 lstrcat(lpServicesBuffer, bufDisplay);//第三列內容 lstrcat(lpServicesBuffer, TEXT("\n"));//回車換行符號 break; } //翻譯成可以顯示的ascii碼字,寫入第三列的值 if (*(char *)lpMemory > 0x20 && *(char *)lpMemory < 0x7e) { bufDisplay[dwCount - 1] = *(char *)lpMemory; } else { bufDisplay[dwCount - 1] = 0x2e;//如果不是ASCII碼值,則顯示“.” } sprintf(bufTemp1, "%02X ", *(TBYTE *)lpMemory);//字節的十六進制字符串到@bufTemp1中 lstrcat(lpServicesBuffer, bufTemp1);//將第二列寫入lpServicesBuffer if (dwCount == 16)//已到16個字節, { lstrcat(lpServicesBuffer, TEXT(" "));//第二列與第三列中間的空格 lstrcat(lpServicesBuffer, bufDisplay);//顯示第三列字符 lstrcat(lpServicesBuffer, TEXT("\n"));//回車換行 printf("%s",lpServicesBuffer); RtlZeroMemory(lpServicesBuffer, 100); if (dwStop == 1) { break; } sprintf(bufTemp2, "%08X ", (++dwCount1) * 16); // 顯示下一行的地址 lstrcat(lpServicesBuffer, bufTemp2); dwCount = 0; RtlZeroMemory(bufDisplay, 50); } --totalSize; ++dwCount; //((char *)lpMemory)++; lpMemory = (char*)lpMemory + 1; //break; } // _appendInfo(lpServicesBuffer); //添加最後一行 printf("%s", lpServicesBuffer); UnmapViewOfFile(lpMemory); } CloseHandle(hMapFile); } } CloseHandle(hFile); } } }
--------------------------------------c版只能運行第二種第一種用的 c++寫的在 c 裏註釋了
// PE練習.cpp : 定義控制臺應用程序的入口點。 // #include<Windows.h> #include<stdio.h> //#include<iostream> //using namespace std; void _openFile(); DWORD dwStop; BYTE* g_pFileImageBase = 0; PIMAGE_NT_HEADERS g_pNt = 0; void ReadFileToMem(char* szFilePath) { //打開文件獲取文件句柄 HANDLE hFile = CreateFile((LPCTSTR)szFilePath, GENERIC_READ, FALSE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("文件打開失敗\n"); return; } //獲取文件大小 DWORD 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); } BOOL IsPEFile() { //使用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 FALSE; } g_pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + g_pFileImageBase); if (g_pNt->Signature != IMAGE_NT_SIGNATURE)//0x00004550(‘PE‘) { return FALSE; } return TRUE; } void ShowNtImportance() { printf("入口點RVA:%08X", g_pNt->OptionalHeader.AddressOfEntryPoint); printf("文件默認加載:%08X", g_pNt->OptionalHeader.ImageBase); printf("文件區段個數:%d", g_pNt->FileHeader.NumberOfSections); //.... } void ShowDirTable() { //獲取目錄表個數 int nCountOfDirTable = g_pNt->OptionalHeader.NumberOfRvaAndSizes; printf("數據目錄表個數:%d", g_pNt->OptionalHeader.NumberOfRvaAndSizes); for (int i = 0; i < nCountOfDirTable;i++) { //如果VirtualAddress不為0,說明此表存在 if (g_pNt->OptionalHeader.DataDirectory[i].VirtualAddress) { //.... } } } void ShowSectionTable() { //獲取區段個數 int nCountOfSection = g_pNt->FileHeader.NumberOfSections; //得到首個區段的位置 PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(g_pNt); //保存區段名字(區段名字可能不是以0為結尾的) //char strName[9] = {}; char strName[9]; for (int i = 0; i < nCountOfSection;i++) { memcpy(strName, pSec->Name, 8); printf("第%d個區段名:%s", i + 1, strName); printf("區段RVA:%08X", pSec->VirtualAddress); //.... //下一個區段地址 pSec++; } } 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++) { //求在內存中的真實大小 DWORD dwRealVirSize = pSec->Misc.VirtualSize % dwSecAligment ? pSec->Misc.VirtualSize / dwSecAligment * dwSecAligment + dwSecAligment : pSec->Misc.VirtualSize; if (dwRVA >= pSec->VirtualAddress && dwRVA < pSec->VirtualAddress + dwRealVirSize) { //FOA = RVA - 內存中區段的起始位置 + 在文件中區段的起始位置 return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData; } //下一個區段地址 pSec++; } } // DWORD FOAtoRVA(DWORD dwFOA) // { // // } int main1() { /*ReadFileToMem("C:\\Users\\allenboy\\Desktop\\fun.exe"); int i = 0; while ((char *)g_pFileImageBase++) { printf("%x ", *(char *)g_pFileImageBase); ++i; if (i == 16) { printf("\n"); i = 0; } }*/ _openFile(); //cin.get(); getchar(); return 0; } /* 打開PE文件並處理 */ void _openFile() { 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) { totalSize = GetFileSize(hFile, NULL);//獲取文件大小 if (totalSize) { hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);//內存映射文件 if (hMapFile) { lpMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);//獲得文件在內存的映象起始位置 if (lpMemory) { //開始處理文件 //緩沖區初始化 RtlZeroMemory(bufTemp1, 10); RtlZeroMemory(bufTemp2, 20); RtlZeroMemory(lpServicesBuffer, 100); RtlZeroMemory(bufDisplay, 50); dwCount = 1; //將第一列寫入lpServicesBuffer dwCount1 = 0; sprintf(bufTemp2, "%08x ", dwCount1); lstrcat(lpServicesBuffer, bufTemp2); //函數功能:該函數將一個字符串附加在另一個字符串後面。 dwBlanks = (16 - totalSize % 16) * 3;//求最後一行的空格數 while (TRUE) { if (totalSize == 0)//最後一行 { while (dwBlanks)//填充空格 { lstrcat(lpServicesBuffer, TEXT("#")); --dwBlanks; } lstrcat(lpServicesBuffer, TEXT(" "));//第二列與第三列中間的空格 lstrcat(lpServicesBuffer, bufDisplay);//第三列內容 lstrcat(lpServicesBuffer, TEXT("\n"));//回車換行符號 break; } //翻譯成可以顯示的ascii碼字,寫入第三列的值 if (*(char *)lpMemory > 0x20 && *(char *)lpMemory < 0x7e) { bufDisplay[dwCount - 1] = *(char *)lpMemory; } else { bufDisplay[dwCount - 1] = 0x2e;//如果不是ASCII碼值,則顯示“.” } sprintf(bufTemp1, "%02X ", *(TBYTE *)lpMemory);//字節的十六進制字符串到@bufTemp1中 lstrcat(lpServicesBuffer, bufTemp1);//將第二列寫入lpServicesBuffer if (dwCount == 16)//已到16個字節, { lstrcat(lpServicesBuffer, TEXT(" "));//第二列與第三列中間的空格 lstrcat(lpServicesBuffer, bufDisplay);//顯示第三列字符 lstrcat(lpServicesBuffer, TEXT("\n"));//回車換行 //_appendInfo(lpServicesBuffer);//寫入內容 //一行的所有內容) printf("%s", lpServicesBuffer); RtlZeroMemory(lpServicesBuffer, 100); if (dwStop == 1) { break; } sprintf(bufTemp2, "%08X ", (++dwCount1) * 16); // 顯示下一行的地址 lstrcat(lpServicesBuffer, bufTemp2); dwCount = 0; RtlZeroMemory(bufDisplay, 50); } --totalSize; ++dwCount; ++((char *)lpMemory); //break; } // _appendInfo(lpServicesBuffer); //添加最後一行 printf("%s", lpServicesBuffer); UnmapViewOfFile(lpMemory); } CloseHandle(hMapFile); } } CloseHandle(hFile); } } }
倆種方式實現 PEdump