zoukankan      html  css  js  c++  java
  • 滴水逆向-手动解析PE头&PE头字段说明及课后练习

    1.PE文件的两种状态
    PE文件与内存镜像,她们以节的形式进行分割,由于历史原因,很早之前的编译器将文件在磁盘和执行之后在内存
    中的状态以""的形式分离,在内存空间的时候分隔的是1000H,在硬盘的时候是200H(十六进制)
    
    一、PE为什么要分节?
    
    (1)节省硬盘空间.(这个不是决定的,由编译器决定)
    (2)一个应用程序多开
    (3)理解FileBuffer和ImageBuffer
    
    二、PE文件分了很多个节,那每个节在文件中从哪里开始?有多大?在内存中从哪里开始,有多大?由谁决定?
    一个可执行文件所有的密码都在这个结构中.
    
    分析PE文件
    
    DOS头
    
    typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
        WORD   e_magic;                     // Magic number --> DOS头的标识,为4Dh和5Ah。分别为字母MZ
        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
        DWORD  e_lfanew;                    // File address of new exe header
    }IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
    
    NT头
    
    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    }IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
    
    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;
    
    typedef struct _IMAGE_OPTIONAL_HEADER {
        WORD    Magic;
        BYTE    MajorLinkerVersion;
        BYTE    MinorLinkerVersion;
        DWORD   SizeOfCode;
        DWORD   SizeOfInitializedData;
        DWORD   SizeOfUninitializedData;
        DWORD   AddressOfEntryPoint;
        DWORD   BaseOfCode;
        DWORD   BaseOfData;
        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;
    
    课后练习
    
    (1)找出所有DOS头数据,并统计DOS头大小.
    
    typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
        WORD   e_magic;                     // Magic number --> DOS头的标识,为4Dh和5Ah。分别为字母MZ(ASCII表)
        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
        DWORD  e_lfanew;                    // 32位可执行文件扩展域,用来指向DOS头之后的NT头相对文件起始地址的偏移,就是指向IMAGE_NT_HEADERS的所在
    }IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
    
    测试练习可执行文件ipmsg.exe文件的DOS头部
    
    typedef struct _IMAGE_DOS_HEADER {
        WORD   e_magic;                     // 5A4D
        WORD   e_cblp;                      // 0090
        WORD   e_cp;                        // 0003
        WORD   e_crlc;                      // 0000
        WORD   e_cparhdr;                   // 0004
        WORD   e_minalloc;                  // 0000
        WORD   e_maxalloc;                  // FFFF
        WORD   e_ss;                        // 0000
        WORD   e_sp;                        // 00B8
        WORD   e_csum;                      // 0000
        WORD   e_ip;                        // 0000
        WORD   e_cs;                        // 0000
        WORD   e_lfarlc;                    // 0040
        WORD   e_ovno;                      // 0000
        WORD   e_res[4];                    // 0000000000000000
        WORD   e_oemid;                     // 0000
        WORD   e_oeminfo;                   // 0000
        WORD   e_res2[10];                  // 0000000000000000000000000000000000000000
        DWORD  e_lfanew;                    // 000000F8
    }IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
    
    统计出来的DOS头大小为:16x2=32 2x4+2x10=8+20=28 4 --> 32+28+4=32+32=64byte
    总大小:64字节
    
    (2)找出所有标准PE头数据,并统计标准PE头大小.
    
    上面说的标准PE头就是在NT头里面的Signature和FileHeader,再理解下就是PE文件头
    
    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    }IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
    
    DWORD Signature; 4个字节 0x00004550
    
    typedef struct _IMAGE_FILE_HEADER {
        WORD    Machine;                         //0x014C
        WORD    NumberOfSections;                //0x0004
        DWORD   TimeDateStamp;            //0x4DD1F580
        DWORD   PointerToSymbolTable;     //0x00000000
        DWORD   NumberOfSymbols;                    //0x00000000
        WORD    SizeOfOptionalHeader;     //0x00E0
        WORD    Characteristics;                    //0x010F
    }IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
    
    统计出来的PE头大小为:4 2x4=8 3x4=12 4+8+12=24 --> 24byte
    总大小:24字节
    
    (3)找出所有可选PE头数据,并统计可选PE头大小.
    
    上面说的可选PE头就是在NT头里面的OptionalHeader,再理解下就是PE可选头
    
    typedef struct _IMAGE_OPTIONAL_HEADER {
        WORD    Magic;                         //0x010B
        BYTE    MajorLinkerVersion;            //0x06
        BYTE    MinorLinkerVersion;            //0x00
        DWORD   SizeOfCode;                    //0x00045000
        DWORD   SizeOfInitializedData;         //0x00028000
        DWORD   SizeOfUninitializedData;       //0x00000000
        DWORD   AddressOfEntryPoint;           //0x000441EC
        DWORD   BaseOfCode;                    //0x00001000
        DWORD   BaseOfData;                    //0x00046000
        DWORD   ImageBase;                     //0x00400000
        DWORD   SectionAlignment;              //0x00001000
        DWORD   FileAlignment;                 //0x00001000
        WORD    MajorOperatingSystemVersion;   //0x0004
        WORD    MinorOperatingSystemVersion;   //0x0000
        WORD    MajorImageVersion;             //0x0000
        WORD    MinorImageVersion;             //0x0000
        WORD    MajorSubsystemVersion;         //0x0004
        WORD    MinorSubsystemVersion;         //0x0000
        DWORD   Win32VersionValue;             //0x00000000
        DWORD   SizeOfImage;                   //0x0006E000
        DWORD   SizeOfHeaders;                 //0x00001000
        DWORD   CheckSum;                      //0x00000000
        WORD    Subsystem;                     //0x0002
        WORD    DllCharacteristics;            //0x0000
        DWORD   SizeOfStackReserve;            //0x00100000
        DWORD   SizeOfStackCommit;             //0x00001000
        DWORD   SizeOfHeapReserve;             //0x00100000
        DWORD   SizeOfHeapCommit;              //0x00001000
        DWORD   LoaderFlags;                   //0x00000000
        DWORD   NumberOfRvaAndSizes;           //0x00000010
        IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
    }IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
    
    统计出来的PE头大小为:1x2=2 2x9=18 19x4=76  2+18+76=96 --> 96byte
    总大小:96字节
    
    
    2021/08/27 01:51:03 PM
    
    1.DOS头
    
    0x1    WORD   e_magic                *                "MZ标记" 用于判断是否为可执行文件.
    0x2    DWORD  e_lfanew;              *                PE头相对于文件的偏移,用于定位PE文件
    
    PE标记(或者叫PE签名)
    
    DWORD  Signature
    
    2.标准PE头(也叫标准PE文件头):
    
    0x1    WORD    Machine;              *                程序运行的CPU型号:0x0 任何处理器/0x14C 386及后续处理器
    0x2    WORD    NumberOfSections;     *                文件中存在的节的总数,如果要新增节或者合并节 就要修改这个值.
    0x3    DWORD   TimeDateStamp;        *                时间戳:文件的创建时间(和操作系统的创建时间无关),编译器填写的.
          DWORD   PointerToSymbolTable;
          DWORD   NumberOfSymbols;
    0x6    WORD    SizeOfOptionalHeader; *                可选PE头的大小,32位PE文件默认E0h 64位PE文件默认为F0h  大小可以自定义.
    0x7    WORD    Characteristics;      *                每个位有不同的含义,可执行文件值为10F 即0 1 2 3 8位置1
    
        3、可选PE头:
    
    0x1    WORD    Magic;        *                        说明文件类型:10B 32位下的PE文件     20B 64位下的PE文件
          BYTE    MajorLinkerVersion;
          BYTE    MinorLinkerVersion;
    0x4    DWORD   SizeOfCode;*                          所有代码节的和,必须是FileAlignment的整数倍 编译器填的  没用
    0x5    DWORD   SizeOfInitializedData;*                已初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的  没用
    0x6    DWORD   SizeOfUninitializedData;*            未初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的  没用
    0x7    DWORD   AddressOfEntryPoint;*                  程序入口
    0x8    DWORD   BaseOfCode;*                          代码开始的基址,编译器填的   没用
    0x9    DWORD   BaseOfData;*                          数据开始的基址,编译器填的   没用
    0xA    DWORD   ImageBase;*                            内存镜像基址
    0xB    DWORD   SectionAlignment;*                    内存对齐
    0xC    DWORD   FileAlignment;*                        文件对齐
            WORD    MajorOperatingSystemVersion;
            WORD    MinorOperatingSystemVersion;
            WORD    MajorImageVersion;
            WORD    MinorImageVersion;
            WORD    MajorSubsystemVersion;
            WORD    MinorSubsystemVersion;
            DWORD   Win32VersionValue;
    0x14    DWORD   SizeOfImage;*                                内存中整个PE文件的映射的尺寸,可以比实际的值大,但必须是SectionAlignment的整数倍
    0x15    DWORD   SizeOfHeaders;*                            所有头+节表按照文件对齐后的大小,否则加载会出错
    0x16    DWORD   CheckSum;*                                    校验和,一些系统文件有要求.用来判断文件是否被修改.
                WORD    Subsystem;
                WORD    DllCharacteristics;
    0x19    DWORD   SizeOfStackReserve;*                初始化时保留的堆栈大小
    0x1A    DWORD   SizeOfStackCommit;*                    初始化时实际提交的大小
    0x1B    DWORD   SizeOfHeapReserve;*                    初始化时保留的堆大小
    0x1C    DWORD   SizeOfHeapCommit;*                    初始化时实践提交的大小
                DWORD   LoaderFlags;
    0x1E    DWORD   NumberOfRvaAndSizes;*                目录项数目
    
    
    课堂海哥给的范例代码
    
    前面是否有宏定义
    
    LPVOID ReadPEFile(LPSTR lpszFile)
        {
            FILE *pFile = NULL;
            DWORD fileSize = 0;
            LPVOID pFileBuffer = NULL;
    
            //打开文件
            pFile = fopen(lpszFile, "rb");
            //判断文件是否打开
            if(!pFile)
            {
                printf(" 无法打开 EXE 文件! ");
                return NULL;
            }
            //读取文件大小
            fseek(pFile, 0, SEEK_END);
            fileSize = ftell(pFile);
            fseek(pFile, 0, SEEK_SET);
            //分配缓冲区
            pFileBuffer = malloc(fileSize);
    
            if(!pFileBuffer)
            {
                printf(" 分配空间失败! ");
                fclose(pFile);
                return NULL;
            }
            //将文件数据读取到缓冲区
            size_t n = fread(pFileBuffer, fileSize, 1, pFile);
            if(!n)
            {
                printf(" 读取数据失败! ");
                free(pFileBuffer);
                fclose(pFile);
                return NULL;
            }
            //关闭文件
            fclose(pFile);
            return pFileBuffer;
    }
    
    VOID PrintNTHeaders()
        {                                                            void*
            LPVOID pFileBuffer = NULL;                                                                            目测是一个结构体
            PIMAGE_DOS_HEADER pDosHeader = NULL;                                                        目测是一个结构体
            PIMAGE_NT_HEADERS pNTHeader = NULL;                                                            目测是一个结构体
            PIMAGE_FILE_HEADER pPEHeader = NULL;                                                        目测是一个结构体
            PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;                                    目测是一个结构体
            PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    
            进行赋值
            pFileBuffer = ReadPEFile(FILEPATH);
            if(!pFileBuffer)                                            观察后是否有结构体的赋值方式
            {
                printf("文件读取失败
    ");
                return ;
            }
    
            //判断是否是有效的MZ标志
            if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
            {
                printf("不是有效的MZ标志
    ");
                free(pFileBuffer);
                return ;
            }
            pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
            //打印DOC头
            printf("********************DOC头********************
    ");
            printf("MZ标志:%x
    ",pDosHeader->e_magic);
            printf("PE偏移:%x
    ",pDosHeader->e_lfanew);
            //判断是否是有效的PE标志
            if(*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
            {
                printf("不是有效的PE标志
    ");
                free(pFileBuffer);
                return ;
            }
            pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
            //打印NT头
            printf("********************NT头********************
    ");
    
            printf("NT:%x
    ",pNTHeader->Signature);
    
            pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
            printf("********************PE头********************
    ");
            printf("PE:%x
    ",pPEHeader->Machine);
            printf("节的数量:%x
    ",pPEHeader->NumberOfSections);
            printf("SizeOfOptionalHeader:%x
    ",pPEHeader->SizeOfOptionalHeader);
            //可选PE头
            pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
            printf("********************OPTIOIN_PE头********************
    ");
            printf("OPTION_PE:%x
    ",pOptionHeader->Magic);
            //释放内存
            free(pFileBuffer);
    }
    
    
    课后练习
    
    练习:
    
    1.编写程序读取一个.exe文件,输出所有的PE头信息.
    
    先测试读取notepad.exe
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int* OpenFile()
    {
        FILE* PointToFile = NULL;
        int FileSize = 0;
        int* StrBuffer = NULL;
        int Num = 0;
    
        //打开文件
        if ((PointToFile = fopen("C:\WINDOWS\system32\notepad.exe","rb")) == NULL) {
            printf("打开文件失败!
    ");
            exit(1);
        }
    
        //获取文件大小
        fseek(PointToFile,0,2);
        FileSize = ftell(PointToFile);
    
        //重定位指针
        fseek(PointToFile,0,0);
    
        //buffer指向申请的堆
        StrBuffer = (int*)(malloc(FileSize));
        if (!StrBuffer)
        {
            printf("堆空间分配失败!
    ");
            free(StrBuffer);
            return 0;
        }
    
        //读取文件内容
        Num = fread(StrBuffer,FileSize,1,PointToFile);
        if (!Num)
        {
            printf("读取文件内容失败!
    ");
            free(StrBuffer);
            return 0;
        }
    
        //关闭文件
        fclose(PointToFile);
    
        //将缓冲区内的文件内容的地址返回到调用函数的地方
        return StrBuffer;
    }
    
    int* FileSizes = OpenFile();
    
    int PrintfNtHeaders()
    {
        //文件指针
        unsigned int* PointBuffer = (unsigned int*)FileSizes;
        unsigned short* pBuffer = (unsigned short*)PointBuffer;
        unsigned char* pcBuffer = (unsigned char*)PointBuffer;
    
        //判断MZ和PE的标志
        unsigned short Cmp1 = 0x5A4D;
        unsigned int Cmp2 = 0x00004550;
    
        //判断文件是否读取成功
        if(!PointBuffer)
        {
            printf("文件读取失败!
    ");
            free(PointBuffer);
            return 0;
        }
    
        //判断是否为MZ标志
        if (*pBuffer != Cmp1)
        {
            printf("不是有效MZ标志!
    ");
            printf("%X
    ",*pBuffer);
            free(PointBuffer);
            return 0;
        }
        printf("*********打印DOS头*********
    ");
        printf("e_magic:			%X
    ",*(pBuffer));
        printf("e_ifanew:			%08X
    
    
    ",*(PointBuffer+15));
    
        //判断是否为PE标志
        if (*(PointBuffer+56) != Cmp2)
        {
            printf("不是有效的PE标志!
    ");
            printf("%X
    ",*(PointBuffer+56));
            free(PointBuffer);
            return 0;
        }
    
        printf("*********打印标准PE文件头*********
    ");
    
        printf("PE标志:				%X
    ",*(PointBuffer+56));
    
        printf("Machine:			%04X
    ",*(pBuffer+114));
        printf("NumberOfSection:		%04X
    ",*(pBuffer+115));
        printf("TimeDateStamp:			%08X
    ",*(PointBuffer+58));
        printf("PointerToSymbolTable:		%08X
    ",*(PointBuffer+59));
        printf("NumberOfSymbols:		%08X
    ",*(PointBuffer+60));
        printf("SizeOfOptionalHeader:		%04X
    ",*(pBuffer+122));
        printf("Chrarcteristics:		%04X
    
    
    ",*(pBuffer+123));
    
        printf("*********打印标准可选PE头*********
    ");
    
        printf("Magic:				%04X
    ", *(pBuffer+124));
        printf("MajorLinkerVersion:		%02X
    ", *(pcBuffer+250));
        printf("MinorLinkerVersion:		%02X
    ", *(pcBuffer+251));
        printf("SizeOfCode:			%08X
    ", *(PointBuffer+63));
        printf("SizeOfInitializedData:		%08X
    ", *(PointBuffer+64));
        printf("SizeOfUninitializedData:	%08X
    ", *(PointBuffer+65));
        printf("AddressOfEntryPoint:		%08X
    ", *(PointBuffer+66));
        printf("BaseOfCode:			%08X
    ", *(PointBuffer+67));
        printf("BaseOfData:			%08X
    ", *(PointBuffer+68));
        printf("ImageBase:			%08X
    ", *(PointBuffer+69));
        printf("SectionAlignment:		%08X
    ", *(PointBuffer+70));
        printf("FileAlignment:			%08X
    ", *(PointBuffer+71));
        printf("MajorOperatingSystemVersion:	%04X
    ", *(pBuffer+144));
        printf("MinorOperatingSystemVersion:	%04X
    ", *(pBuffer+145));
        printf("MajorImageVersion:		%04X
    ", *(pBuffer+146));
        printf("MinorImageVersion:		%04X
    ", *(pBuffer+147));
        printf("MajorSubsystemVersion:		%04X
    ", *(pBuffer+148));
        printf("MinorSubsystemVersion:		%04X
    ", *(pBuffer+149));
        printf("Win32VersionValue:		%08X
    ", *(PointBuffer+75));
        printf("SizeOfImage:			%08X
    ", *(PointBuffer+76));
        printf("SizeOfHeaders:			%08X
    ", *(PointBuffer+77));
        printf("CheckSum:			%08X
    ", *(PointBuffer+78));
        printf("Subsystem:			%04X
    ", *(pBuffer+158));
        printf("DllCharacteristics:		%04X
    ", *(pBuffer+159));
        printf("SizeOfStackReserve:		%08X
    ", *(PointBuffer+80));
        printf("SizeOfStackCommit:		%08X
    ", *(PointBuffer+81));
        printf("SizeOfHeapReserve:		%08X
    ", *(PointBuffer+82));
        printf("SizeOfHeapCommit:		%08X
    ", *(PointBuffer+83));
        printf("LoaderFlags:			%08X
    ", *(PointBuffer+84));
        printf("NumberOfRvaAndSizes:		%08X
    ", *(PointBuffer+85));
    
        free(PointBuffer);
        return 0;
    }
    
    int main()
    {
        PrintfNtHeaders();
         OpenFile();
         return 0;
    }
    
    打印结果:
    
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
    Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
    
    pelx.cpp
    Microsoft (R) Incremental Linker Version 6.00.8168
    Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
    
       Creating library pelx.lib and object pelx.exp
    *********打印DOS头*********
    e_magic:                        5A4D
    e_ifanew:                       000000E0
    
    
    *********打印标准PE文件头*********
    PE标志:                         4550
    Machine:                        014C
    NumberOfSection:                0003
    TimeDateStamp:                  41107CC3
    PointerToSymbolTable:           00000000
    NumberOfSymbols:                00000000
    SizeOfOptionalHeader:           00E0
    Chrarcteristics:                010F
    
    
    *********打印标准可选PE头*********
    Magic:                          010B
    MajorLinkerVersion:             07
    MinorLinkerVersion:             0A
    SizeOfCode:                     00007800
    SizeOfInitializedData:          00008800
    SizeOfUninitializedData:        00000000
    AddressOfEntryPoint:            0000739D
    BaseOfCode:                     00001000
    BaseOfData:                     00009000
    ImageBase:                      01000000
    SectionAlignment:               00001000
    FileAlignment:                  00000200
    MajorOperatingSystemVersion:    0005
    MinorOperatingSystemVersion:    0001
    MajorImageVersion:              0005
    MinorImageVersion:              0001
    MajorSubsystemVersion:          0004
    MinorSubsystemVersion:          0000
    Win32VersionValue:              00000000
    SizeOfImage:                    00013000
    SizeOfHeaders:                  00000400
    CheckSum:                       00017959
    Subsystem:                      0002
    DllCharacteristics:             8000
    SizeOfStackReserve:             00040000
    SizeOfStackCommit:              00011000
    SizeOfHeapReserve:              00100000
    SizeOfHeapCommit:               00001000
    LoaderFlags:                    00000000
    NumberOfRvaAndSizes:            00000010
    请按任意键继续. . .
    
    上述代码有个极大的缺点,就是只能加载打印特定固定的notepad.exe文件,而且在
    不同的操作系统下面会有异常,可移植性差
    
    互联网上有一份代码可以完美打印任何文件的PE相关的信息,我做了一些优化,参考地址:https://www.it610.com/article/1304362536954531840.htm
    具体代码如下:
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <windows.h>
    #include <malloc.h>
    
    #define F_PATH "C:\cntflx\ipmsg.exe"
    
    FILE* open_file(char* file_path,char* open_mode);
    int compute_file_size(FILE* file_address);
    char* allocate_buffer(int file_size);
    char* readfile2memory(char* file_buffer,int file_size,FILE* file_address);
    void analysis_PE_head(char* File_buffer);
    
    VOID PrintNTHeaders()
    {
        // 初始化
        //char file_path[] = "C:\Windows\System32\notepad.exe";
        char file_path[] = F_PATH;
        char open_mode[] = "rb";
        // 打开文件,返回文件指针
        FILE* file_address = open_file(file_path,open_mode);
        // 计算文件长度
        int file_size = compute_file_size(file_address);
        // 分配内存
        char* File_buffer = allocate_buffer(file_size);
        // 写入内存,返回内存地址
        File_buffer = readfile2memory(File_buffer,file_size,file_address);
        // 打印PE头部信息
        analysis_PE_head(File_buffer);
        // 释放内存、关闭文件流
        free(File_buffer);
        fclose(file_address);
    }
    
    FILE* open_file(char* file_path,char* open_mode)
    {
        FILE* file_address = fopen(file_path,open_mode);  // fopen() 参数是字符串也就是常量指针类型
        if(!file_address)
        {
            printf("打开文件失败!
    ");
            return 0;
        }
        return file_address;
    }
    
    int compute_file_size(FILE* file_address)
    {
        int size = 0;
        fseek(file_address,0,SEEK_END);
        size = ftell(file_address);
        fseek(file_address,0,SEEK_SET);
        return size;
    }
    
    char* allocate_buffer(int file_size)
    {
        char* file_buffer = (char*)malloc(file_size);
        if(!file_buffer)
        {
            printf("申请内存失败!
    ");
            return 0;
        }
        memset(file_buffer,0,file_size);
        return file_buffer;
    }
    
    char* readfile2memory(char* file_buffer,int file_size,FILE* file_address)
    {
        if(!(fread(file_buffer,file_size,1,file_address)))
        {
            printf("从文件向内存中读取数据失败!
    ");
            return 0;
        }
        return file_buffer; // 如果写入内存成功,则返回内地址
    }
    
    void analysis_PE_head(char* File_buffer)
    {
        // 实例化PE文件头几个结构体
        PIMAGE_DOS_HEADER pDosHeader = NULL;
        PIMAGE_NT_HEADERS pNTHeader = NULL;
        PIMAGE_FILE_HEADER pPEHeader = NULL;
        PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
        PIMAGE_SECTION_HEADER pSectionHeader = NULL;
        // 强制类型转换
        pDosHeader = (PIMAGE_DOS_HEADER)File_buffer;
        // 判断是不是有效的MZ标志
        if(*((PWORD)pDosHeader) != IMAGE_DOS_SIGNATURE)
        {
            printf("不是有效的MZ标志!
    ");
            free(File_buffer);
            return;
        }
        // 强制类型转换 PIMAGE_DOS_HEADER结构体
        pDosHeader = (PIMAGE_DOS_HEADER)File_buffer;
        // 打印DOS头
        printf("=============================DOS头信息如下=============================
    ");
        printf("MZ标志:			%04X
    ",pDosHeader->e_magic);
        printf("PE偏移:			%08X
    ",pDosHeader->e_lfanew);
    
        // 判断是不是有效的PE标志
        if(*((PDWORD)((DWORD)File_buffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
        {
            printf("不是有效的PE标志!
    ");
            free(File_buffer);
            return;
        }
        // 强制类型转换 PIMAGE_NT_HEADERS结构体
        pNTHeader = PIMAGE_NT_HEADERS((DWORD)File_buffer+pDosHeader->e_lfanew);
        // 打印NT头
        printf("=============================NT头信息如下===============================
    ");
        printf("NT:				%04X
    ",pNTHeader->Signature);
        // 强制类型转换 PIMAGE_FILE_HEADER结构体
        pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
        // 打印标准PE文件头
        printf("=============================标准PE头信息如下============================
    ");
        printf("PE_machine:			%04X
    ",pPEHeader->Machine);
        printf("NumberOfSections:		%04X
    ",pPEHeader->NumberOfSections);
        printf("SizeOfOptionalHeader:		%04X
    ",pPEHeader->SizeOfOptionalHeader);
        // 强制类型转换
        pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);//
        // 打印可选PE头
        printf("==============================可选PE头信息如下==============================
    ");
        printf("Magic:				%04X
    ",pOptionHeader->Magic);
        printf("AddressOfEntryPoint:		%08X
    ",pOptionHeader->AddressOfEntryPoint);
        printf("ImageBase:			%08X
    ",pOptionHeader->ImageBase);
        printf("SizeOfImage:			%08X
    ",pOptionHeader->SizeOfImage);
        printf("SizeOfHeaders:			%08X
    ",pOptionHeader->SizeOfHeaders);
        printf("SectionAlignment:		%08X
    ",pOptionHeader->SectionAlignment);
        printf("FileAlignment:			%08X
    ",pOptionHeader->FileAlignment);
        // 强制类型转换
        pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
        printf("==============================节表信息如下===============================
    ");
        //printf("name:%s
    ",pSectionHeader->Misc);
        DWORD dwNumberOfSection = pPEHeader->NumberOfSections;
        /*
        printf("%x
    ",pPEHeader->NumberOfSections);
        printf("IMAGE_SIZEOF_SHORT_NAME:%x
    ",IMAGE_SIZEOF_SHORT_NAME);
        printf("option_add:%x
    ",pOptionHeader);
        printf("psection_add:%x
    ",pSectionHeader);
        printf("==============================================================
    ");*/
        for(DWORD i = 0;i<dwNumberOfSection;i++,pSectionHeader++)
        {
            printf("========================第%d个节信息:===============================
    ",i+1);
            printf("section_name:");
            for(DWORD j = 0;j<IMAGE_SIZEOF_SHORT_NAME;j++)
            {
                printf("%c",pSectionHeader->Name[j]);
            }
            printf("
    ");
            printf("Misc:				%08X
    ",pSectionHeader->Misc);
            printf("VirtualAddress:			%08X
    ",pSectionHeader->VirtualAddress);
            printf("SizeOfRawData:			%08X
    ",pSectionHeader->SizeOfRawData);
            printf("PointerToRawData:		%08X
    ",pSectionHeader->PointerToRawData);
            printf("Characteristics:		%08X
    ",pSectionHeader->Characteristics);
        }
    }
    
    int main(int argc, char* argv[])
    {
        PrintNTHeaders();
        //getchar();
        return 0;
    }
    
    打印结果如下:
    
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
    Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
    
    pelx.cpp
    Microsoft (R) Incremental Linker Version 6.00.8168
    Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
    
       Creating library pelx.lib and object pelx.exp
    =============================DOS头信息如下=============================
    MZ标志:                        5A4D
    PE偏移:                        000000F8
    =============================NT头信息如下===============================
    NT:                             4550
    =============================标准PE头信息如下============================
    PE_machine:                     014C
    NumberOfSections:               0004
    SizeOfOptionalHeader:          00E0
    ==============================可选PE头信息如下==============================
    Magic:                         010B
    AddressOfEntryPoint:            000441EC
    ImageBase:                      00400000
    SizeOfImage:                    0006E000
    SizeOfHeaders:                  00001000
    SectionAlignment:               00001000
    FileAlignment:                  00001000
    ==============================节表信息如下===============================
    ========================第1个节信息:===============================
    section_name:.text
    Misc:                           000440A2
    VirtualAddress:                 00001000
    SizeOfRawData:                  00045000
    PointerToRawData:               00001000
    Characteristics:                60000020
    ========================第2个节信息:===============================
    section_name:.rdata
    Misc:                           0000D74D
    VirtualAddress:                 00046000
    SizeOfRawData:                  0000E000
    PointerToRawData:               00046000
    Characteristics:                40000040
    ========================第3个节信息:===============================
    section_name:.data
    Misc:                           0000F5F8
    VirtualAddress:                 00054000
    SizeOfRawData:                  00007000
    PointerToRawData:               00054000
    Characteristics:                C0000040
    ========================第4个节信息:===============================
    section_name:.rsrc
    Misc:                           00009968
    VirtualAddress:                 00064000
    SizeOfRawData:                  0000A000
    PointerToRawData:               0005B000
    Characteristics:                40000040
    
    2.使用第三方的PE工具,对比如下信息,看是否一致:
    
    使用了第三方工具,确定了信息是一致的!

    优化的完美代码打印结果:

    迷茫的人生,需要不断努力,才能看清远方模糊的志向!
  • 相关阅读:
    oracle 数据库安全审计
    oracle 共享服务器监控
    oralce MTS
    配置一个Oracle共享服务器进程环境需要哪两项参数
    python3 小技巧(2)
    python3 操作注册表
    PYC文件简介
    常见HTTP状态(304,200等)
    用Python模拟浏览器操作
    python3下的IE自动化模块PAMIE
  • 原文地址:https://www.cnblogs.com/autopwn/p/15200145.html
Copyright © 2011-2022 走看看