[编程代码] 《PE文件解析-DOS头解析》学习

7349 3
小菜鸟一枚 2021-6-24 20:16:10 | 显示全部楼层 |阅读模式
本帖最后由 小菜鸟一枚 于 2021-6-24 20:20 编辑

0x1什么是PE文件?
  1.PE文件是在windows平台可执行的文件。
包括:.exe(可执行程序),dll(动态链接库).sys(驱动程序)
要想学好逆向PE必须要掌握。
  2.DOS头
DOS头
e_magic//DOS头签名,可执行文件的标志。
e_lfanew//PE头的偏移位置
PE头
区段1
区段2
区段3
0x2打开一个exe文件
  1.打开vs 2015编译器,写一个helloworld程序:
复制代码 隐藏代码
#include <Windows.h>
int WINAPI WinMain(
        HINSTANCE hInstance, // handle to current instance
        HINSTANCE hPrevInstance, // handle to previous instance
        LPSTR lpCmdLine, // command line
        int nCmdShow // show state
)
{
        DWORD  a;
        MessageBox(NULL, TEXT("Helloworld!"), TEXT("小菜鸟提醒您:"), MB_OK);
        return 0;
}

&#8195;&#8195;2.生成exe文件,这里使用winHex工具打开exe文件。
&#8195;&#8195;3.DOS头开头word,2字节,e_magic就是前四位0x5A4D(从高到低位读),对应ASCII码MZ,再看e_lfanew,看看前面的图,数一下30个word,占了60位偏移,看看typedef unsigned long       DWORD;,所以e_lfanew就是0x00000108,相对PE头偏移量就是0x108。
&#8195;&#8195;4.0x108就是PE头,PE头第一个字节就是WORD Magic,根据偏移量得到0x4550,对应的ASCII码正是PE。
0x3解析DOS头
&#8195;&#8195;1.要想解析DOS,首先得读文件,这里使用CreateFile,读完之后得解析,在编译器中查到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;
&#8195;&#8195;2.这里可以定义一个IMAGE_DOS_HEADER,也可以使用*PIMAGE_DOS_HEADER类型解析DOS头,这里我使用后者,读取了DOS结构能干嘛呢?
1)判断e_magic是不是0x5A4D开头
2)获取PE结构的偏移地址
&#8195;&#8195;3.实现代码如下:
复制代码 隐藏代码
#include<Windows.h>
#include<iostream>

using namespace std;

int main()
{
        /*
                HANDLE CreateFile(LPCTSTR lpFileName, //普通文件名或者设备文件名
                DWORD dwDesiredAccess, //访问模式(写/读)
                DWORD dwShareMode, //共享模式
                LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针
                DWORD dwCreationDisposition, //如何创建
                DWORD dwFlagsAndAttributes, //文件属性
                HANDLE hTemplateFile //用于复制文件句柄
                );
        */

        HANDLE hfile = CreateFile(TEXT("Win32Project0623.exe"),
                GENERIC_READ,
                FILE_SHARE_READ,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                0);

        if (!hfile)
        {

                cout << "打开Win32Project0623.exe文件失败!" << endl;
                return -1;
        }

        /*
                BOOL ReadFile(
                HANDLE hFile,                                    //文件的句柄
                LPVOID lpBuffer,                                //用于保存读入数据的一个缓冲区
                DWORD nNumberOfBytesToRead,    //要读入的字节数
                LPDWORD lpNumberOfBytesRead,    //指向实际读取字节数的指针
                LPOVERLAPPED lpOverlapped
                //如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。
                //该结构定义了一次异步读取操作。否则,应将这个参数设为NULL
);
        */
        DWORD fileSize = GetFileSize(hfile, NULL);//获取文件大小
        char *lpBuffer = new char[fileSize];
        DWORD lpNumberOfBytesRead = 0;//实际读了多大,这是一个输出变量,需要将地址传递进去,带回结果
        BOOL blReadFile = ReadFile(hfile, lpBuffer, fileSize, &lpNumberOfBytesRead, NULL);

        PIMAGE_DOS_HEADER pIMAGE_DOS_HEADER = 0;
        if (blReadFile)
        {
                pIMAGE_DOS_HEADER = (PIMAGE_DOS_HEADER) lpBuffer;
                if (pIMAGE_DOS_HEADER->e_magic != 0x5A4D)
                {
                        cout <<"这不是一个有效的PE文件" << endl;
                }
        }

        cout << "pIMAGE_DOS_HEADER->e_lfanew:0x"<<hex<< pIMAGE_DOS_HEADER->e_lfanew << endl;
        delete[] lpBuffer;

        system("pause");

        return 0;
        
}
&#8195;&#8195;4.打个断点,看看是不是解析出来了:
&#8195;&#8195;5.是不是和我们前面在十六进制编辑器里面分析的一样,开头是0X5A4D,结果指向PE头的偏移量是0x108。
0x4总结
&#8195;&#8195;1.第一次接触PE结构,一点一点慢慢来,做好笔记。
&#8195;&#8195;2.程序的DOS头开始是MZ,PE头的开始是PE。
0x5参考资料:
&#8195;&#8195;1.CreateFile函数
&#8195;&#8195;2.ReadFile函数
&#8195;&#8195;3.GetFileSize函数
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行