1. 程式人生 > >倆種方式實現 PEdump

倆種方式實現 PEdump

PE

方式一
思路把 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 語言裏不會報錯

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