【滴水三期】32/64位——PE文件头字段打印与解析

一、【作业描述】

1、编写程序读取一个exe文件,输出所有的PE头信息;

2、使用第三方的PE工具,对比如下信息,看是否一致;

二、【PE头字段解析】

注:海哥发的PE结构 PDF也不是特别全的,可以去<winNT.h>头文件自己查看相关结构,这样能更清晰一些。

PE头字段解析说明:标黄色的为海哥画的重要要背的,个人认为了解即可弄清偏移量是咋回事就好。其中的重点,后期主要操作的资源都在这个存放各种表的结构里面: _IMAGE_DATA_DIRECTORY DataDirectory[16];

 

struct _IMAGE_FILE_HEADER {描述一个可执行文件的基本属性和结构
0x00 WORD Machine;目标机器类型
0x02 WORD NumberOfSections;PE文件中包含的节的数量
0x04 DWORD TimeDateStamp;文件的编译时间戳
0x08 DWORD PointerToSymbolTable;符号表信息不包含在最终的可执行文件中。如果是.OBJ文件,则指向符号表的RVA(相对虚拟信息);如果是可执行文件则值为0。
0x0c DWORD NumberOfSymbols;如果是.obj文件,表示符号表中的符号数量
0x10 WORD SizeOfOptionalHeader;可选头结构体的大小(字节)
0x12 WORD Characteristics;是否只读
};
struct _IMAGE_OPTIONAL_HEADER {提供可执行文件的详细信息:文件布局、内存需求、入口点、数据目录等信息。
0x00 WORD Magic;区分32位还是64位文件
0x02 BYTE MajorLinkerVersion;链接器主要版本
0x03 BYTE MinorLinkerVersion;链接器次要版本
0x04 DWORD SizeOfCode;代码节的总大小,无影响
0x08 DWORD SizeOfInitializedData;已初始化数据节的总大小,无影响
0x0c DWORD SizeOfUninitializedData;未初始化数据节的总大小,无影响
0x10 DWORD AddressOfEntryPoint;程序入口点、相对于映像基地址的RVA
0x14 DWORD BaseOfCode;代码节相对于映像基地址的RVA 无影响
64位没有此项;0x18 DWORD BaseOfData;数据节相对于映像基地址的RVA 无影响
64位——ULONGLONG类型0x1c DWORD ImageBase;映像在内存中的首选基地址
0x20 DWORD SectionAlignment;内存中节的对齐大小
0x24 DWORD FileAlignment;文件中节的对齐大小
0x28 WORD MajorOperatingSystemVersion;目标操作系统的版本
0x2a WORD MinorOperatingSystemVersion;目标操作系统的版本
0x2c WORD MajorImageVersion;映像的版本
0x2e WORD MinorImageVersion;映像的版本
0x30 WORD MajorSubsystemVersion;目标子系统的版本
0x32 WORD MinorSubsystemVersion;目标子系统的版本
0x34 DWORD Win32VersionValue;通常保留为0
0x38 DWORD SizeOfImage;映像在内存中占用的大小,必须是SectionAlignment整数倍。
0x3c DWORD SizeOfHeaders;文件头部+节表按照FileAlignment对齐后的总大小
0x40 DWORD CheckSum;文件的校验和 ,一些系统文件、驱动程序有要求,用来判断文件是否被修改,或NTdll,系统会检查。可逆
0x44 WORD Subsystem;映像的子系统类型(如控制台程序还是GUI程序)
0x46 WORD DllCharacteristics;DLL的特性。如是否支持搞地质映射或是否使用NX兼容性
64位——ULONGLONG类型0x48 DWORD SizeOfStackReserve;栈的预留大小
64位——ULONGLONG类型0x4c DWORD SizeOfStackCommit;栈的提交大小
64位——ULONGLONG类型0x50 DWORD SizeOfHeapReserve;堆的预留大小
64位——ULONGLONG类型0x54 DWORD SizeOfHeapCommit;堆的提交大小
0x58 DWORD LoaderFlags;保留使用,目前总是0
0x5c DWORD NumberOfRvaAndSizes;后面的数据目录数组中的条目数量
0x60 _IMAGE_DATA_DIRECTORY DataDirectory[16];用于存储导入表、导出表、资源、异常处理等的RVA和大小

三、代码如下:

#include <windows.h>
#include <winNT.h>
#include <stdio.h>

//这里我之前犯了一个错误,windows.h 包含winNT.h 头,所以windows.h必须要在winNT.h头前面,否则会引起冲突。单独使用windows.h头有些无法输出出来
// 
//#include <stdio.h>
//#include <windows.h>
//#include <time.h>
//#include <winNT.h>
//#include <pshpack1.h>
//#include <wintrust.h>
//读取一个exe文件,输出所有PE头信息。
/*
* 1、以二进制模式打开文件
* 2、存储到一个buffer中
* 3、判断前两个字符是否为5A 4D
* 4、如果是,则是PE文件,否则输出不是标准可执行文件
* 5、顺着往下走
*/


int main(){
    
    FILE* pfile = NULL;
    //测试64位、32位程序 ;1:64  、2:32  
    //fopen_s(&pfile, "C:\/Users\/Administrator\/source\/repos\/文件内存读写\/x64\/Debug\\notepad_fileRW.exe", "rb");
    fopen_s(&pfile, "C:\/Windows\/syswow64\/odbcad32.exe", "rb");
        if (!pfile) {
            printf("Failed to open file.\n");
            return 1;
        }

        fseek(pfile,0,SEEK_END);
        size_t file_size=ftell(pfile);
        rewind(pfile);

        char* file_buffer;
        file_buffer=(char*)calloc(file_size,1);
        PIMAGE_DOS_HEADER dos_header;


        int check_fread=fread_s(file_buffer, file_size, 1, file_size,pfile);
        if (check_fread!= file_size)
        {
            printf("file read erro");  
            fclose(pfile);
            free(file_buffer);
        }
        dos_header = (PIMAGE_DOS_HEADER)file_buffer;
        fclose(pfile);

        if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
            printf("Not a valid PE file.\n");
            free(file_buffer);
            return 1;
        }
        //在打印16进制数字时,%x 默认输出小写字母,%X默认输出大写字母。
        //dos_header
        printf("e_magic: 【%04X】\n", dos_header->e_magic);
        printf("e_lfanew: 【%04X】\n", dos_header->e_lfanew);

        //NT_header
        PIMAGE_NT_HEADERS nt_header;
        file_buffer =file_buffer + dos_header->e_lfanew;
        nt_header = (PIMAGE_NT_HEADERS)file_buffer;
        printf("Signature:【%04X】\n",nt_header->Signature);

        //file_header
        PIMAGE_FILE_HEADER file_header;
        file_header = (PIMAGE_FILE_HEADER)(file_buffer + sizeof(nt_header->Signature));
        printf("Machine:【%04X】\n", file_header->Machine);
        printf("NumberOfSections:【%04X】\n", file_header->NumberOfSections);
        printf("TimeDateStamp:【%08X】\n", file_header->TimeDateStamp);
        printf("PointerToSymbolTable:【%08X】\n", file_header->PointerToSymbolTable);
        printf("NumberOfSymbols:【%08X】\n", file_header->NumberOfSymbols);
        printf("SizeOfOptionalHeader:【%04X】\n", file_header->SizeOfOptionalHeader);
        //还可以继续分解Characteristics
        printf("Characteristics:【%04X】\n", file_header->Characteristics);
 
        //optional_header
        PIMAGE_OPTIONAL_HEADER optional_header;
        PIMAGE_OPTIONAL_HEADER64 optional_header_64;
        //file_header++ ;这里的file_header 是IMAGE_FILE_HEADER型的,占14H个字节,后面的运算也是按照这个类型算的,所以只需向后加1即可。卡了30分钟才解决。
        optional_header = (PIMAGE_OPTIONAL_HEADER)(++file_header);// sizeof(IMAGE_FILE_HEADER);
       

        printf("Magic:【%02X】\n", optional_header->Magic);
        int magic=sizeof(optional_header->Magic);
        printf("SizeOfCode:【%04X】\n", optional_header->SizeOfCode);
        printf(":SizeOfInitializedData【%04X】\n", optional_header->SizeOfInitializedData);
        printf("SizeOfUninitializedData:【%04X】\n", optional_header->SizeOfUninitializedData);
        printf("AddressOfEntryPoint:【%04X】\n", optional_header->AddressOfEntryPoint);
        printf("BaseOfCode:【%04X】\n", optional_header->BaseOfCode);
       
        
        //64位PE的imageBase是 Ulonglong型的,这里需要处理一下;%I64X是打印输出ulonglong型的16位数据的格式化符
        if (optional_header->Magic ==0x20B)
        {
            optional_header_64 = (PIMAGE_OPTIONAL_HEADER64)(file_header);
            printf("=============================64位PE文件=========================================\n");
            printf("ImageBase:【%0I64X】\n", optional_header_64->ImageBase);
            printf("SectionAlignment:【%08X】\n", optional_header_64->SectionAlignment);
            printf("FileAlignment:【%08X】\n", optional_header_64->FileAlignment);
            printf("SizeOfImage:【%08X】\n", optional_header_64->SizeOfImage);
            printf("SizeOfHeaders:【%08X】\n", optional_header_64->SizeOfHeaders);
            printf("CheckSum:【%08X】\n", optional_header_64->CheckSum);
            printf("SizeOfStackReserve:【%0I64X】\n", optional_header_64->SizeOfStackReserve);
            printf("SizeOfStackCommit:【%0I64X】\n", optional_header_64->SizeOfStackCommit);
            printf("SizeOfHeapReserve:【%0I64X】\n", optional_header_64->SizeOfHeapReserve);
            printf("SizeOfHeapCommit:【%0I64X】\n", optional_header_64->SizeOfHeapCommit);
            printf("NumberOfRvaAndSizes:【%08X】\n", optional_header_64->NumberOfRvaAndSizes);
            printf("=============================64位PE文件=========================================\n");

        }
        else
        {
            //32位PE
            printf("=============================32位PE文件=========================================\n");
            printf("BaseOfData:【%04X】\n", optional_header->BaseOfData);
            printf("ImageBase:【%04X】\n", optional_header->ImageBase);
            printf("SectionAlignment:【%04X】\n", optional_header->SectionAlignment);
            printf("FileAlignment:【%04X】\n", optional_header->FileAlignment);
            printf("SizeOfImage:【%04X】\n", optional_header->SizeOfImage);
            printf("SizeOfHeaders:【%04X】\n", optional_header->SizeOfHeaders);
            printf("CheckSum:【%04X】\n", optional_header->CheckSum);
            printf("SizeOfStackReserve:【%04X】\n", optional_header->SizeOfStackReserve);
            printf("SizeOfStackCommit:【%04X】\n", optional_header->SizeOfStackCommit);
            printf("SizeOfHeapReserve:【%04X】\n", optional_header->SizeOfHeapReserve);
            printf("SizeOfHeapCommit:【%04X】\n", optional_header->SizeOfHeapCommit);
            printf("NumberOfRvaAndSizes:【%04X】\n", optional_header->NumberOfRvaAndSizes);
            printf("=============================32位PE文件=========================================\n");
        }
       
     
  
        // 在释放free(file_buffer); 之前,应先将file_buffer = NULL; 否则会报“Expression:is_block_type_valid(header->_block_use)”错误
        file_buffer = NULL;
        free(file_buffer);
       
	return 0;
}

四、010editor  介绍

本人使用的是010 editor当做第三方PE工具的,因为确实可以这么做到,真的很强大,强烈推荐,不过官网下载是英文版的,其中熟悉软件用了不少时间。效果如下图:

本人在编辑的时候可能会受到自身逻辑限制,无法想到一些重要的情况,欢迎各位一起学习的小伙伴多多批评指正。

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值