千家信息网

win32下PE文件分析之DOS头

发表于:2024-11-27 作者:千家信息网编辑
千家信息网最后更新 2024年11月27日,(一).win32下的PE文件:PE是Portable Execute的缩写,是可移植可执行的意思,只要文件的数据结构遵循PE结构,就属于PE文件,windows中常见的PE文件有*.sys驱动类文件
千家信息网最后更新 2024年11月27日win32下PE文件分析之DOS头

(一).win32下的PE文件:

PE是Portable Execute的缩写,是可移植可执行的意思,只要文件的数据结构遵循PE结构,就属于PE文件,windows中常见的PE文件有

*.sys驱动类文件

*.dll动态链接库文件

*.exe可执行文件

*.ocx对象类别扩充组建

*.obj目标文件等.

同样,linux中使用的是ELF格式,和windows的PE格式有一定的差别,如:

可重定位文件*.o

可执行文件如/bin/ls等

共享目标文件*.so

核心转储文件core

都遵循ELF数据结构. unix从system v4开始也使用ELF了,而他们的始祖都是unix system v3的中COFF.如下图:

(二).win32中的PE文件二进制数据结构:

二进制数据结构如下图,看起来就比较复杂,但是当你亲自动手解析一波,那可能会改变你的世界观,前提是初学者.为了全部显示出来,看不太清,放附件里了.

(三).win32中PE的逻辑图:

一个标准的PE文件由DOS头,stub,NT头(包含PE标识,标准PE头和可选PE头三个成员),节表,节的内容以及一些为了内存对齐而填充的0.

以上就是一个PE文件的大体逻辑图,它里面的内容虽然是二进制,但绝不是随意填充的数据,而是严格遵循一定格式生成的,比如C语言写的一段代码,通过预处理, 汇编, 编译, 链接后生成的一个exe文件(PE文件中的一种),生成过程是由编译器来完成的.

(四).DOS头中的数据结构:

Visual C++ 6.0中winnt头文件中的定义:

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;

(五).C语言实现对win32中notepad.exe的DOS头的简单解析:

该代码中只是输出了DOS头中两个较为有用的数据,第一个和最后一个(e_magic和e_lfanew),代码如下:

Dos_Header_Analyze.cpp:


// Dos_Header_Analyze.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include "dos.h"           //包含进自己写的dos.h文件#define filepath "notepad.exe"        //指定好notepad.exe的位置,写绝对路径,或放于源代码目录中int main(int argc, char* argv[]){        void* pbuff = NULL;                              //方便后面当参数使用        pbuff = ReadFileToBuff(filepath);        Output_Dos(pbuff);                              //解析DOS头        free(pbuff);                                    //释放空间        return 0;}

dos.h:

void* ReadFileToBuff(char* file)       //将文件读取到内存{        FILE* fp = fopen(file, "rb");       //以二进制只读形式打开文件        void* buff = NULL;               //用来指向申请的内存缓冲区        unsigned long sz = 0;               //用来存放文件的大小        if(!fp)        {                printf("Failed to open file \"%s\"\n", file);                exit(-1);        }        fseek(fp, 0, SEEK_END);             //让文件指针fp指向文件的末位位置,用于计算文件的大小        sz = ftell(fp);                     //获取当前文件指针相对于起始位置的偏移        fseek(fp, 0, SEEK_SET);             //让文件指针fp指向文件的起始位置        printf("File \"%s\" size: %ld KB\n", file, sz / 1024);  //输出文件大小(单位KB)        buff = malloc(sz);          //申请一块与文件大小相等的内存,用作文件缓冲区        if(!buff)        {                printf("Alloc memery failed!\n");                exit(-2)        }        memset(buff, 0, sz);           //置零缓冲区                //将文件中的数据写入文件缓冲区,每次读取128字节,读取sz/128次,正好读取sz字节        if(!fread(buff, 128, sz/128, fp))         {                printf("Read file \"%s\" error!\n", file);                exit(-3);        }        fclose(fp);                     //关闭刚刚打开的文件        return buff;                       //返回文件缓冲的内存地址                                           }//输出DOS头的重要信息void Output_Dos(void* buffer){        void* buf = buffer;        //定义一个指向文件缓冲的DOS头的指针        IMAGE_DOS_HEADER* pdos = (IMAGE_DOS_HEADER*)buf;        printf("DOS Header:\n");                //MZ标记,用于判断该文件是否为可执行文件(其值与MZ的ascii相对应)        printf("Magic Number:      %#X\n", pdos->e_magic);                //PE标识相对于文件其实位置的偏移 (单位字节)          printf("PE   Offset:     %#X\n", pdos->e_lfanew);                }

stdafx.h:

#if !defined(AFX_STDAFX_H__BBCA9272_49A3_4E1E_9262_9F0211C5BA05__INCLUDED_)#define AFX_STDAFX_H__BBCA9272_49A3_4E1E_9262_9F0211C5BA05__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#define WIN32_LEAN_AND_MEAN                // Exclude rarely-used stuff from Windows headers//主要是把相应的头文件包含进去#include #include #include #include 

执行结果如下图:


如果有空会继续更新.


附件:http://down.51cto.com/data/2366651
0