I'm trying to create a compiler and I will start doing the part of the code generation. To become more simple to generate the executable, I want the PE headers remain as small as possible.
For me understand better what I will do I am compiling and analyzing programs with OllyDbg.
I made a program using FASM and used some macros that I found on the Internet to reduce the size of imports. Everything is in one section as well.
The executable was generated with 1024 bytes. Then I used a PEiD plugin which reduced the file to 722 bytes.
I do not understand much about it yet, but looking at some articles on the internet seems to have some unnecessary things in headers of my file. So I want to help to reduce the size of headers without compromising the program. If possible I want help to reduce the size of imports too!
Here is the source code:
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
I used RebuildPE plugin to reduce de exe size. Here is the compiled code:
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
And the headers:
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
So my question: what can I remove from headers and improve on imports to make them smaller?