减少 PE 标头

逆向工程 拆卸 部件
2021-07-05 10:18:37

我正在尝试创建一个编译器,我将开始执行代码生成的部分。为了更简单地生成可执行文件,我希望 PE 标头保持尽可能小。

为了更好地理解我将做什么,我正在使用 OllyDbg 编译和分析程序。

我使用 FASM 制作了一个程序,并使用了我在 Internet 上找到的一些宏来减小导入的大小。一切都在一个部分。

生成的可执行文件有 1024 个字节。然后我使用了一个 PEiD 插件,将文件减少到 722 字节。

我对此还不是很了解,但是查看互联网上的一些文章似乎在我的文件标题中有一些不必要的东西。所以我想在不影响程序的情况下帮助减少标题的大小。如果可能的话,我也想帮助减少进口的大小!

这是源代码:

format PE console
entry start

include 'win32a.inc'

macro import_part1 library, [api]
{ 
  common
    library#_str: db `library 
  forward 
    if rva $ mod 2 = 0
     ; db 0
    end if
    ; When align is right, one byte from previous import name 
    ; is used as byte for next import's hint. 
    api#_str = $-1 
    db 0, `api 
  common
    db 0
} 

import_part2_first = 0

macro import_part2 library, [api]
{ 
  common
    if import_part2_first = 0
      align 4
      import_part2_first = 1
    else
      dd 0
    end if
    library#_import: 
  forward 
    api dd rva api#_str 
} 

macro import_part3 [library]
{ 
  common
    data import
  forward 
    dd 0, 0, 0, rva library#_str, rva library#_import 
  common
    rd 5
    end data 
} 

import_list equ
import_libraries equ

macro import library,[api]
{ 
  common
    import_list equ import_list import_#library 
    import_#library equ library,api 
    import_libraries equ import_libraries,library 
} 

macro importend 
{ 
  match a, import_list 
  \{ 
    irps b, a \\{ match c, b \\\{ import_part1 c \\\} \\} 
    irps b, a \\{ match c, b \\\{ import_part2 c \\\} \\} 
  \} 
  match =,a,import_libraries \{ import_part3 a \} 
}


start:

         push var
         call [printf]


         push 0
         call [ExitProcess]

         var db 'Test', 0

import kernel32.dll, ExitProcess, AttachConsole
import msvcrt.dll, printf, scanf
importend

我使用 RebuildPE 插件来减少 de exe 的大小。这是编译后的代码:

CPU Disasm
Address   Hex dump                                       Command                           Comments
00401000   .  68 13104000                                PUSH 00401013                     ; /format = "Test"
00401005   .  FF15 80104000                              CALL DWORD PTR DS:[<&msvcrt.print ; \MSVCRT.printf
0040100B   .  6A 00                                      PUSH 0                            ; /ExitCode = 0
0040100D   .  FF15 74104000                              CALL DWORD PTR DS:[<&kernel32.Exi ; \KERNEL32.ExitProcess
00401013   .  54                                         PUSH ESP
00401014   .  65:73 74                                   JAE SHORT 0040108B                ; Superfluous segment override prefix
00401017   .  006B 65                                    ADD BYTE PTR DS:[EBX+65], CH
0040101A   .  72 6E 65 6C 33 32 2E 64 6C 6C 00           ASCII "rnel32.dll",0              ; ASCII "rnel32.dll"
00401025   .  45 78 69 74 50 72 6F 63 65 73 73 00        ASCII "ExitProcess",0             ; ASCII "ExitProcess"
00401031   .  41 74 74 61 63 68 43 6F 6E 73 6F 6C 65 00  ASCII "AttachConsole",0           ; ASCII "AttachConsole"
0040103F   .  6D 73 76 63 72 74 2E 64 6C 6C 00           ASCII "msvcrt.dll",0              ; ASCII "msvcrt.dll"
0040104A   .  70 72 69 6E 74 66 00                       ASCII "printf",0                  ; ASCII "printf"
00401051   .  73 63 61 6E 66 00                          ASCII "scanf",0                   ; ASCII "scanf"
00401057   .  70 75 74 73 00                             ASCII "puts",0                    ; ASCII "puts"
0040105C   .  75 73 65 72 33 32 2E 64 6C 6C 00           ASCII "user32.dll",0              ; ASCII "user32.dll"
00401067   .  4D 65 73 73 61 67 65 42 6F 78 41 00        ASCII "MessageBoxA",0             ; ASCII "MessageBoxA"
00401073      90                                         NOP
00401074   .  647FA577                                   DD 77A57F64
00401078   .  1878A577                                   DD 77A57818
0040107C   .  00000000                                   DD 00000000
00401080   .  C4D2B777                                   DD 77B7D2C4
00401084   .  BF16C077                                   DD 77C016BF
00401088   .  9C3BC077                                   DD 77C03B9C
0040108C   .  00000000                                   DD 00000000
00401090   .  9E278B77                                   DD 778B279E
00401094   .  00000000                                   DD 00000000                       ; Struct 'IMAGE_IMPORT_DESCRIPTOR'
00401098   .  00000000                                   DD 00000000
0040109C   .  00000000                                   DD 00000000
004010A0   .  18100000                                   DD 00001018
004010A4   .  74100000                                   DD 00001074
004010A8   .  00000000                                   DD 00000000                       ; Struct 'IMAGE_IMPORT_DESCRIPTOR'
004010AC   .  00000000                                   DD 00000000
004010B0   .  00000000                                   DD 00000000
004010B4   .  3F100000                                   DD 0000103F
004010B8   .  80100000                                   DD 00001080
004010BC   .  00000000                                   DD 00000000                       ; Struct 'IMAGE_IMPORT_DESCRIPTOR'
004010C0   .  00000000                                   DD 00000000
004010C4   .  00000000                                   DD 00000000
004010C8   .  5C100000                                   DD 0000105C
004010CC   .  90100000                                   DD 00001090
004010D0   .  00000000                                   DD 00000000                       ; Struct 'IMAGE_IMPORT_DESCRIPTOR'
004010D4   .  00000000                                   DD 00000000
004010D8   .  00000000                                   DD 00000000
004010DC   .  00000000                                   DD 00000000
004010E0   .  00000000                                   DD 00000000

和标题:

CPU Disasm
Address   Hex dump                                       Command                           Comments
00400000  /.  4D 5A                                      ASCII "MZ"                        ; DOS_Signature[2] = "MZ"
00400002  |.  8000                                       DW 80                             ; DOS_PartPag = 128.
00400004  |.  0100                                       DW 1                              ; DOS_PageCnt = 1
00400006  |.  0000                                       DW 0                              ; DOS_ReloCnt = 0
00400008  |.  0400                                       DW 4                              ; DOS_HdrSize = 4
0040000A  |.  1000                                       DW 10                             ; DOS_MinMem = 16.
0040000C   .  50 45 00 00                                ASCII "PE",0,0                    ; IMAGE_NT_SIGNATURE[4] = "PE"
00400010  /.  4C01                                       DW 14C                            ; Machine = IMAGE_FILE_MACHINE_I386
00400012  |.  0100                                       DW 1                              ; DOS_ChkSum = 1
00400014  |.  76264555                                   DD 55452676                       ; DOS_ExeIP = 55452676
00400018  |.  00000000                                   DD 00000000                       ; DOS_RelocOffset = 0
0040001C  |.  00000000                                   DD 00000000                       ; DOS_Reserved1[4] = 00000000
00400020  |.  E000                                       DW 0E0                            ; SizeOfOptionalHeader = 224.
00400022  \.  0F01                                       DW 10F                            ; Characteristics = EXECUTABLE_IMAGE|32BIT_MACHINE|RELOCS_STRIPPED|LINE_NUMS_STRIPPED|LOCAL_SYMS_STRIPPED
00400024  /.  0B01                                       DW 10B                            ; DOS_OEM_ID = 10B
00400026  |.  0147                                       DW 4701                           ; DOS_OEM_Info = 4701
00400028  |.  00020000                                   DD 00000200                       ; SizeOfCode = 512.
0040002C  |.  00020000                                   DD 00000200                       ; SizeOfInitializedData = 512.
00400030  |.  00000000                                   DD 00000000                       ; SizeOfUninitializedData = 0
00400034  |.  00100000                                   DD 00001000                       ; AddressOfEntryPoint = 1000
00400038  |.  00100000                                   DD 00001000                       ; BaseOfCode = 1000
0040003C  |.  0C000000                                   DD 0000000C                       ; DOS_PEOffset = 0C
00400040  |.  00004000                                   DD 00400000                       ; ImageBase = 400000
00400044  |.  00100000                                   DD 00001000                       ; SectionAlignment = 1000
00400048  |.  00020000                                   DD 00000200                       ; FileAlignment = 200
0040004C  |.  0100                                       DW 1                              ; MajorOSVersion = 1
0040004E  |.  0000                                       DW 0                              ; MinorOSVersion = 0
00400050  |.  0000                                       DW 0                              ; MajorImageVersion = 0
00400052  |.  0000                                       DW 0                              ; MinorImageVersion = 0
00400054  |.  0300                                       DW 3                              ; MajorSubsystemVersion = 3
00400056  |.  0A00                                       DW 0A                             ; MinorSubsystemVersion = 10.
00400058  |.  00000000                                   DD 00000000                       ; Win32VersionValue = 0
0040005C  |.  E4100000                                   DD 000010E4                       ; SizeOfImage = 4324.
00400060  |.  00020000                                   DD 00000200                       ; SizeOfHeaders = 512.
00400064  |.  53C80000                                   DD 0000C853                       ; CheckSum = 0C853
00400068  |.  0300                                       DW 3                              ; Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
0040006A  |.  0000                                       DW 0                              ; DLLCharacteristics = 0
0040006C  |.  00100000                                   DD 00001000                       ; SizeOfStackReserve = 4096.
00400070  |.  00100000                                   DD 00001000                       ; SizeOfStackCommit = 4096.
00400074  |.  00000100                                   DD 00010000                       ; SizeOfHeapReserve = 65536.
00400078  |.  00000000                                   DD 00000000                       ; SizeOfHeapCommit = 0
0040007C  |.  00000000                                   DD 00000000                       ; LoaderFlags = 0
00400080  \.  10000000                                   DD 00000010                       ; NumberOfRvaAndSizes = 16.
00400084  /.  00000000                                   DD 00000000                       ; Export Table address = 0
00400088  |.  00000000                                   DD 00000000                       ; Export Table size = 0
0040008C  |.  94100000                                   DD 00001094                       ; Import Table address = 1094
00400090  |.  50000000                                   DD 00000050                       ; Import Table size = 80.
00400094  |.  00000000                                   DD 00000000                       ; Resource Table address = 0
00400098  |.  00000000                                   DD 00000000                       ; Resource Table size = 0
0040009C  |.  00000000                                   DD 00000000                       ; Exception Table address = 0
004000A0  |.  00000000                                   DD 00000000                       ; Exception Table size = 0
004000A4  |.  00000000                                   DD 00000000                       ; Certificate File pointer = 0
004000A8  |.  00000000                                   DD 00000000                       ; Certificate Table size = 0
004000AC  |.  00000000                                   DD 00000000                       ; Relocation Table address = 0
004000B0  |.  00000000                                   DD 00000000                       ; Relocation Table size = 0
004000B4  |.  00000000                                   DD 00000000                       ; Debug Data address = 0
004000B8  |.  00000000                                   DD 00000000                       ; Debug Data size = 0
004000BC  |.  00000000                                   DD 00000000                       ; Architecture Data address = 0
004000C0  |.  00000000                                   DD 00000000                       ; Architecture Data size = 0
004000C4  |.  00000000                                   DD 00000000                       ; Global Ptr address = 0
004000C8  |.  00000000                                   DD 00000000                       ; Reserved = 00000000
004000CC  |.  00000000                                   DD 00000000                       ; TLS Table address = 0
004000D0  |.  00000000                                   DD 00000000                       ; TLS Table size = 0
004000D4  |.  00000000                                   DD 00000000                       ; Load Config Table address = 0
004000D8  |.  00000000                                   DD 00000000                       ; Load Config Table size = 0
004000DC  |.  00000000                                   DD 00000000                       ; Bound Import Table address = 0
004000E0  |.  00000000                                   DD 00000000                       ; Bound Import Table size = 0
004000E4  |.  00000000                                   DD 00000000                       ; Import Address Table address = 0
004000E8  |.  00000000                                   DD 00000000                       ; Import Address Table size = 0
004000EC  |.  00000000                                   DD 00000000                       ; Delay Import Descriptor address = 0
004000F0  |.  00000000                                   DD 00000000                       ; Delay Import Descriptor size = 0
004000F4  |.  00000000                                   DD 00000000                       ; COM+/CLI Header address = 0
004000F8  |.  00000000                                   DD 00000000                       ; COM+/CLI Header size = 0
004000FC  |.  00000000                                   DD 00000000                       ; Reserved = 00000000
00400100  \.  00000000                                   DD 00000000                       ; Reserved = 00000000
00400104  /.  2E 66 6C 61 74 00 00 00                    ASCII ".flat",0,0,0               ; Name[8] = ".flat"
0040010C  |.  E4000000                                   DD 000000E4                       ; VirtualSize = 228.
00400110  |.  00100000                                   DD 00001000                       ; VirtualAddress = 1000
00400114  |.  D2000000                                   DD 000000D2                       ; SizeOfRawData = 210.
00400118  |.  00020000                                   DD 00000200                       ; PointerToRawData = 200
0040011C  |.  00000000                                   DD 00000000                       ; PointerToRelocations = 0
00400120  |.  00000000                                   DD 00000000                       ; PointerToLineNumbers = 0
00400124  |.  0000                                       DW 0                              ; NumberOfRelocations = 0
00400126  |.  0000                                       DW 0                              ; NumberOfLineNumbers = 0
00400128  \.  600000E0                                   DD E0000060                       ; Characteristics = CODE|INITIALIZED_DATA|EXECUTE|READ|WRITE

所以我的问题是:我可以从标题中删除什么并改进导入以使其更小?

2个回答

您需要PE详细了解格式。有很多标题条目可以删除以使其PE尽可能小。但是,通常不建议这样做,因为这是一项未记录的功能,可能会破坏各种 Windows 版本的兼容性。此外,您的文件更有可能触发防病毒产品的警报。

是一篇关于创建最小可能的伟大文章PE大部分信息是通过对文件格式进行模糊测试获得的,因此之前的警告适用。

好吧,如果您的目的是生成小的二进制文件,则标题绝对不是您应该使用的内容,因为大多数标题条目,无论二进制格式是什么 ( PE, ELF, Mach-O, ...),都是为了处理某些奇怪的情况而设计的你可能从未想过。而且,就大小优化而言,您真的不能走得太远,最多可以节省几百个字节。

另一方面,如果您希望编译器生成小的二进制文件,您应该优化生成的代码(-Os优化标志在GCC 中这样做)。你会发现有用的信息这个环节,也是这一个(在积极的优化部分)。另一个有趣的事情是检查GCCLLVM的大小优化通过。源代码可在编译器各自的网站上免费获得。

通常,代码大小优化对于嵌入式系统至关重要,因为它们最有可能占用很小的内存。这是一篇非常有趣的科学文章,它通过使用DAG(有向无环图)覆盖算法巧妙地选择指令来解决嵌入式系统的代码大小优化问题由于您正在编写编译器,这听起来比切断二进制格式头中的条目更好。您可以在编译器的后端合理地实现上述出版物中提供的算法。如需更长更完整的参考资料,请查看Neil 的这份文档。E. Johnson 来自剑桥大学这是一座金矿。

附录 :

一个纯粹的逆向工程技巧是通过使用代码优化标志(-O2用于GCC编译一个简单的程序,然后使用大小优化标志(-Os用于GCC),然后比较两个二进制文件来执行差异分析使用这种技术,您很可能能够发现标头中的差异(如果有的话)以及不同的代码大小优化。