/
header_tiny.asm
162 lines (140 loc) · 5.56 KB
/
header_tiny.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
;-----------------------
; header_tiny.asm
; Hand-written PE32 format headers and hash-based function import;
; Program code is packed into sections of headers which are found to be unused
; according to various published materials.
; Heavily borrowing techniques from Crinkler,
; https://github.com/runestubbe/Crinkler
;
; SizeOfOptionalHeader has two possibilities:
; 0x0158 pop eax / add... Requires minimum file size 0x0158+0x1C = 372
; Importer frees its own usage of the stack.
; 0x0140 inc eax / add... Requires minimum file size 0x0140+0x1C = 348
; Given N imports and M exports per imported library,
; the importer pushes O(N*M) items to the stack which are never popped.
; This is not anticipated to cause overflow for the tiny number of imports
; in any 348-371 bytes small executable.
; (20KB stack consumed for the 15 imports of HelloWindows)
;
; Sizes: header+importer+LoadLibraryA hash
; 2023-01-27 160 Theron Tarigo
; First publication
; 2023-01-29 157 (from suggestion by qkumba)
; (-3) add edi,4*n -> times n scasd
; 2023-01-30 154 Theron Tarigo
; (-3) Test for zero hash as import table end condition
; 157
; (+3) Scan library name string lengths, no more fixed sizes
;
;-----------------------
bits 32
%macro ASSERTEQ 2
%%A equ %1
%%B equ %2
times %%A-%%B db 0
times %%B-%%A db 0
%endmacro
IMGBASE equ 0x400000
%define RVA(x) ((x)-IMGBASE)
section bin progbits start=0 vstart=IMGBASE
; Overlapped data/executable notation:
; Values ignored by PE loader: written instructions, bytes in comments
; Values significant to loader: written bytes, disassembly in comments
exefile:
doshdr:
dw "MZ"
dw "TT"
pehdr:
dw "PE",0 ; Signature = "PE",0,0
dw 0x014C ; Machine = i386
dw 0 ; NumberOfSections = 0
execpart0:
mov edx,[ebx+4*edx] ; 8B1496 [0:2] TimeDateStamp
pop ebx ; 5B [ 3] TimeDateStamp
mov eax,[eax+0x20] ; 8B4020 [0:2] PointerToSymbolTable
add eax,ebx ; 01D8 [3/0] ///
mov esi,[eax+4*ecx] ; 033488 [1:3] NumberOfSymbols
ASSERTEQ $-pehdr,0x14
dw 0x0158 ; pop eax / add... SizeOfOptionalHeader
dw 0xD8DE ; esi,ebx / fmul... Characteristics
ASSERTEQ $-exefile,0x1C
opthdr:
dw 0x010B ; dword[ebx] / add... Magic = PE32
db 0xDA ; edx,ebx MajorLinkerVersion
execpart1:
xor eax,eax ; 31C0 [0/0] MinorLinkerVersion ///
hashloop:
imul eax,5651 ; 69C013160000 [1:3/0:2] SizeOfCode ///
lodsb ; AC [ 3] SizeOfInitializedData
test al,al ; 84C0 [0:1] SizeOfUninitializedData
jmp short execpartB ; EBxx [2:3] ...
ASSERTEQ $-opthdr,0x10
dd RVA(execpart2) ; AddressOfEntryPoint
execpart2:
mov eax,[ebx+0xC] ; 8B430C [0:1] BaseOfCode
mov eax,[eax+0xC] ; 8B400C [2:3] ...
jmp short execpart3 ; EBxx BaseOfData
ASSERTEQ $-opthdr,0x1C
dd IMGBASE ; ImageBase
ASSERTEQ $-exefile,0x3C ; (overlapped fields)
ASSERTEQ 0x4,pehdr-exefile ; { PE hdr offset
dd 0x4 ; SectionAlignment }
dd 0x4 ; FileAlignment
execpart3:
mov ebp,regrelref ; BDxxxx4000 [0:1/0:1/0] {Major/Minor}
IMPTBLOFFSET equ importtable-regrelref ; OperatingSystemVersion //
lea edi,[ebp+IMPTBLOFFSET] ; 8D7Dxx [1/0:1] {Major/Minor}ImageVersion
ASSERTEQ $-opthdr,0x30
dw 0x4 ; add al,0x0 MajorSubsystemVersion
execpart4:
mov eax,[eax] ; 8B00 MinorSubsystemVersion
mov eax,[eax] ; 8B00 [0:1] Win32VersionValue
mov ebx,[eax+0x18] ; 8B5818 [2:3/0] /// SizeOfImage
importloop:
xor ecx,ecx ; 31C9 [1:2] ...(SizeOfImage)
searchloop:
db 0x25 ; and eax, [ 3] ...(SizeOfImage)
ASSERTEQ $-opthdr,0x3C
dd 0x0000002C ; 0x2C SizeOfHeaders
execpart5:
mov edx,[ebx+0x3C] ; 8B533C [0:2] Checksum
db 0x64 ; fs: [ 3] ...
ASSERTEQ $-opthdr,0x44
dw 0x0002 ; add al,[:::eax] Subsystem = gui
dw 0x8906 ; push es / mov.. DllCharacteristics
dd 0x134403D8 ;.. eax,ebx / add eax,[ebx+edx+... SizeOfStackReserve
dd 0x03DA8978 ;.. 0x78] / mov edx,ebx / add... SizeOfStackCommit
dd 0x0F532450 ;.. edx,[eax+0x24] / push ebx / movzx... SizeOfHeapReserve
dd 0x034A14B7 ;.. edx,word[edx+2*ecx] / add.. SizeOfHeapCommit
dw 0x1C58 ;.. ebx,[eax+0x1C] [0:1] LoaderFlags
jmp short execpart0 ; EBxx [2:3] ..
ASSERTEQ $-opthdr,0x5C
dd 0 ; NumberOfRvaAndSizes
regrelref equ relrefstart+0x80
%define REFREL_REG(R,N) dword[byte R+((N)-regrelref)]
%define REFREL(N) REFREL_REG(ebp,N)
%macro CALLIMPORT 1
call REFREL(pfn %+ %1)
%endmacro
execpartB:
jnz hashloop
inc ecx
cmp eax,[edi]
jne searchloop
mov [edi],edx
scasd
push edi
CALLIMPORT LoadLibraryA
test eax,eax
jz nonextlib
mov ebx,eax
; module will be page aligned, thus al=0
mov cl,0xFF
repne scasb
dec edi
nonextlib:
; eax=0 unless a module was just loaded
or eax,[edi]
jnz importloop
; END OF HASH LOADER
; eax = 0