PE操作—结构重叠

  结构重叠是指在不影响 PE 文件正常加载的前提下,将某些数据结构进行重叠。结构重叠可以缩小 PE 文件。比如新增一个节的时可能节表后没有足够的空间容纳新的节表,那么我们就可以考虑使用结构重叠来获得大量空间。现在我们以重叠 IMAGE_DOS_HEADER 和 IMAGE_NT_HEADERS 结构为例。IMAGE_DOS_HEADER.e_lfanew 成员指向 IMAGE_NT_HEADERS 结构的位置,如果我们将 IMAGE_NT_HEADERS 结构提前到 IMAGE_DOS_HEADER 结构中,那么 e_lfanew 就会覆盖在 IMAGE_NT_HEADERS 中,就需要使用 IMAGE_NT_HEADERS 结构中某个 字段来 代替 e_lfanew。IMAGE_DOS_HEADER.BaseOfData 这个字段 windows 加载器并不使用,我们可以把这个字段重叠到 IMAGE_DOS_HEADER.e_lfanew  中。介绍完基本原理,我们再来看一下实际操作。

 

    以下是 PE 文件的 IMAGE_DOS_HEADER 和 IMAGE_NT_HEADERS 重叠后的字节码

 

  先模拟 windows 读取 IMAGE_DOS_HEADER 和 IMAGE_NT_HEADERS 查看下每个字段都是些什么值

  

IMAGE_DOS_HEADER (DOS文件头)结构如下:

    e_magic:      0x5A4D] 
    e_cblp:       0x0090
    e_cp:       0x0003
    e_crlc:      0x0000
    e_cparhdr:     0x0004
    e_minalloc:       0x0000
    e_maxalloc:       0x4550
    e_ss:             0x0000
    e_sp:             0x014C
    e_csum:           0x0003
    e_ip:             0x5287
    e_cs:             0x4802
    e_lfarlc:         0x0000
    e_ovno:           0x0000
    e_res[4]:         0x0000000000E0010F
    e_oemid:          0x010B
    e_oeminfo:        0x0A07
    e_res2[10]:       780000008800000000000000739D000010000000
    e_lfanew:         0x0000000C

  e_lfanew 指向 0x0000000C,我们从 0x0000000C 处读取 IMAGE_NT_HEADERS 结构

    Signature:                 0x00004550

    Machine: 0x014C
    NumberOfSections: 0x0003
    TimeDateStamp: 0x48025287
    PointerOfSymbolTable: 0x00000000
    NumberOfSymbols: 0x00000000
    SizeOfOptionHeader: 0x00E0 
    Characteristics: 0x010F

    

    Magic: 0x010B
    MajorLinkerVersion: 0x07
    MinorLinkerVersion: 0x0A
    SizeOfCode: 0x00007800
    SizeOfInitializedData: 0x00008800
    SizeOfUninitializedData: 0x00000000
    AddressOfEntryPoint(RVA): 0x0000739D
    BaseOfCode: 0x00001000
    BaseOfData: 0x0000000C
    ImageBase: 0x01000000
    SectionAlignment: 0x00001000
    FileAlignment: 0x00000200

    ....

 

  IMAGE_DOS_HEADER.BaseOfData 和 IMAGE_DOS_HEADER.e_lfanew 进行了重叠

 

伪代码

 1 bool overlap_dos_file_header(void* image)
 2 {
 3     auto dos_nt = (PIMAGE_DOS_HEADER)image;
 4     auto nt_ptr = get_pe_nt32(image);
 5 
 6     //----------------------------> 重叠公用字段
 7     nt_ptr->OptionalHeader.BaseOfData = 0xC;
 8 
 9     //----------------------------> move
10     auto nt_section_size = file_headers_size(image);
11     memmove((byte*)dos_nt + 0xC, nt_ptr, nt_section_size);
12 
13     return true;
14 }

 

  

 

posted @ 2022-02-28 13:32  farmer3301  阅读(189)  评论(0)    收藏  举报