Skip to content

Commit 759229e

Browse files
committed
Add hh1 testbin
1 parent 5054271 commit 759229e

File tree

2 files changed

+298
-1
lines changed

2 files changed

+298
-1
lines changed

testbins/Makefile-win64

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# nmake -f Makefile-win64 from within "x64 Native Tools Command Prompt"
22

3-
TARGETS_ALL = helloworld_x64-windows.exe exitcode_x64-windows.exe helloworld_loop_x64-windows.exe helloworld_thread_x64-windows.exe helloworld_func_x64-windows.exe helloworld_pie_x64-windows.exe helloworld_loop_pie_x64-windows.exe helloworld_thread_pie_x64-windows.exe helloworld_func_pie_x64-windows.exe asmtest_x64-windows.exe do_exception_pie_x64-windows.exe hello_x64-windows.exe indirect_calls_x64-windows.exe missing_switch_case_x64-windows.exe cat_x64-windows.exe
3+
TARGETS_ALL = helloworld_x64-windows.exe exitcode_x64-windows.exe helloworld_loop_x64-windows.exe helloworld_thread_x64-windows.exe helloworld_func_x64-windows.exe helloworld_pie_x64-windows.exe helloworld_loop_pie_x64-windows.exe helloworld_thread_pie_x64-windows.exe helloworld_func_pie_x64-windows.exe asmtest_x64-windows.exe hh1.exe do_exception_pie_x64-windows.exe hello_x64-windows.exe indirect_calls_x64-windows.exe missing_switch_case_x64-windows.exe cat_x64-windows.exe
44

55
all: $(TARGETS_ALL)
66

@@ -46,6 +46,9 @@ asmtest_x64-windows.exe: asmtest_x64-windows.obj
4646
asmtest_x64-windows.obj: asmtest_x64.asm
4747
nasm -f win64 -DOS_IS_WINDOWS asmtest_x64.asm -o asmtest_x64-windows.obj
4848

49+
hh1.exe: hh1.asm
50+
nasm -f bin -DOS_IS_WINDOWS hh1.asm -o hh1.exe
51+
4952
hello_x64-windows.exe: hello_x64-windows.obj
5053
link hello_x64-windows.obj /ENTRY:WinMain /SUBSYSTEM:CONSOLE /LARGEADDRESSAWARE:NO /DYNAMICBASE:NO /OUT:hello_x64-windows.exe kernel32.lib
5154

testbins/hh1.asm

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
;
2+
; hh1.nasm: 664-byte, tiny hello-world Win32 PE .exe
3+
; by [email protected] at Sat Jan 13 11:53:58 CET 2018
4+
;
5+
; How to compile hh1.exe:
6+
;
7+
; $ nasm -f bin -o hh1.exe hh1.nasm
8+
; $ chmod 755 hh1.exe # For QEMU Samba server.
9+
; $ ndisasm -b 32 -e 0x200 -o 0x403000 hh1.exe
10+
;
11+
; hh1.asm was inspired by the 268-byte .exe on
12+
; https://www.codejuggle.dj/creating-the-smallest-possible-windows-executable-using-assembly-language/
13+
; . The fundamental difference is that hh1.exe works on Windows XP ... Windows
14+
; 10, while the program above doesn't work on Windows XP.
15+
;
16+
; The generated hh1.exe works on:
17+
;
18+
; * Wine 1.6.2 on Linux.
19+
; * Windows XP SP3, 32-bit: Microsoft Windows XP [Version 5.1.2600]
20+
; * Windows 10 64-bit: Microsoft Windows [Version 10.0.16299.192]
21+
;
22+
; Output .exe file size in bytes (approximately):
23+
;
24+
; len(text_bytes) + len(data_bytes) + len(rodata_bytes) +
25+
; + 384
26+
; + sum(len(name) for name in imported_names) + 2 * len(imported_names) - 1
27+
; + 8 * len(imported_names) + 6
28+
; + sum(len(name) for name in library_names) + len(library_names)
29+
; + 20 * len(library_names)
30+
;
31+
; Assumptions:
32+
;
33+
; * len(imported_names) >= 1: ['ExitProcess']
34+
; * len(library_names) >= 1: ['kernel32']
35+
;
36+
bits 32
37+
imagebase equ 0x400000 ; Default base since Windows 95.
38+
textbase equ imagebase + 0x3000
39+
file_alignment equ 0x200
40+
bits 32
41+
org 0 ; Can be anything, this file doesn't depend on it.
42+
43+
_filestart:
44+
;_text:
45+
46+
IMAGE_DOS_HEADER: ; Truncated, breaks file(1) etc.
47+
db 'MZ'
48+
times 10 db 'x'
49+
50+
IMAGE_NT_HEADERS:
51+
Signature: dw 'PE', 0
52+
53+
IMAGE_FILE_HEADER:
54+
Machine: dw 0x14c ; IMAGE_FILE_MACHINE_I386
55+
NumberOfSections: dw (_headers_end - _sechead) / 40 ; Windows XP needs >= 3.
56+
TimeDateStamp: dd 0x00000000
57+
PointerToSymbolTable: dd 0x00000000
58+
NumberOfSymbols: dd 0x00000000
59+
SizeOfOptionalHeader: dw _datadir_end - _opthd ; Windows XP needs >= 0x78.
60+
Characteristics: dw 0x030f
61+
_opthd:
62+
IMAGE_OPTIONAL_HEADER32:
63+
Magic: dw 0x10b ; IMAGE_NT_OPTIONAL_HDR32_MAGIC
64+
MajorLinkerVersion: db 0
65+
MinorLinkerVersion: db 0
66+
SizeOfCode: dd 0x00000000
67+
SizeOfInitializedData: dd 0x00000000
68+
SizeOfUninitializedData: dd 0x00000000
69+
AddressOfEntryPoint: dd (textbase - imagebase) + (_entry - _text)
70+
BaseOfCode: dd 0x00000000
71+
BaseOfData: dd (IMAGE_NT_HEADERS - _filestart) ; Overlaps with: IMAGE_DOS_HEADER.e_lfanew.
72+
ImageBase: dd imagebase
73+
SectionAlignment: dd 0x1000 ; Minimum value for Windows XP.
74+
%if file_alignment == 0 || file_alignment & (file_alignment - 1)
75+
%fatal Invalid file_alignment, must be a power of 2.
76+
%endif
77+
%if file_alignment < 0x200
78+
%fatal Windows XP needs file_alignment >= 0x200
79+
%endif
80+
FileAlignment: dd file_alignment ; Minimum value for Windows XP.
81+
MajorOperatingSystemVersion: dw 4
82+
MinorOperatingSystemVersion: dw 0
83+
MajorImageVersion: dw 1
84+
MinorImageVersion: dw 0
85+
MajorSubsystemVersion: dw 4
86+
MinorSubsystemVersion: dw 0
87+
Win32VersionValue: dd 0
88+
SizeOfImage: dd (textbase - imagebase) + (_eof + bss_size - _text) ; Wine rounds it up to a multiple of 0x1000, and loads and maps that much.
89+
SizeOfHeaders: dd _headers_end - _filestart ; Windows XP needs > 0.
90+
CheckSum: dd 0
91+
Subsystem: dw 3 ; IMAGE_SUBSYSTEM_WINDOWS_CUI; gcc -mconsole
92+
DllCharacteristics: dw 0
93+
SizeOfStackReserve: dd 0x00100000
94+
SizeOfStackCommit: dd 0x00001000
95+
SizeOfHeapReserve: dd 0
96+
SizeOfHeapCommit: dd 0
97+
LoaderFlags: dd 0
98+
; If we hardcode 2 here, on Windows XP we can put arbitrary bytes to
99+
; IMAGE_DIRECTORY_ENTRY_RESOURCE.VirtualAddress and .Size. If we put
100+
; 3 here (autogenerated), then the values must be 0.
101+
;NumberOfRvaAndSizes: dd (_datadir_end - _datadir) / 8 ; Number of IMAGE_DATA_DIRECTORY entries below.
102+
NumberOfRvaAndSizes: dd 2
103+
104+
_datadir:
105+
DataDirectory:
106+
IMAGE_DIRECTORY_ENTRY_EXPORT:
107+
.VirtualAddress: dd 0x00000000
108+
.Size: dd 0x00000000
109+
IMAGE_DIRECTORY_ENTRY_IMPORT:
110+
.VirtualAddress: dd (textbase - imagebase) + (_idescs - _text)
111+
.Size: dd _idata_data_end - _idata
112+
IMAGE_DIRECTORY_ENTRY_RESOURCE:
113+
.VirtualAddress_AndSize: db 'tiny.exe'
114+
%if 0
115+
; Changing all 0x78787878 to 0 below may fix startup errors.
116+
IMAGE_DIRECTORY_ENTRY_EXCEPTION:
117+
.VirtualAddress: dd 0x78787878
118+
.Size: dd 0x78787878
119+
IMAGE_DIRECTORY_ENTRY_SECURITY:
120+
.VirtualAddress: dd 0x78787878
121+
.Size: dd 0x78787878
122+
IMAGE_DIRECTORY_ENTRY_BASERELOC:
123+
.VirtualAddress: dd 0x78787878
124+
.Size: dd 0x78787878
125+
IMAGE_DIRECTORY_ENTRY_DEBUG:
126+
.VirtualAddress: dd 0x78787878
127+
.Size: dd 0x00000000
128+
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE:
129+
.VirtualAddress: dd 0x00000000
130+
.Size: dd 0x00000000
131+
IMAGE_DIRECTORY_ENTRY_GLOBALPTR:
132+
.VirtualAddress: dd 0x00000000
133+
.Size: dd 0x78787878
134+
IMAGE_DIRECTORY_ENTRY_TLS:
135+
.VirtualAddress: dd 0x78787878
136+
.Size: dd 0x78787878
137+
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG:
138+
.VirtualAddress: dd 0x78787878
139+
.Size: dd 0x78787878
140+
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT:
141+
.VirtualAddress: dd 0x78787878
142+
.Size: dd 0x78787878
143+
IMAGE_DIRECTORY_ENTRY_IAT:
144+
.VirtualAddress: dd 0x78787878
145+
.Size: dd 0x78787878
146+
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:
147+
.VirtualAddress: dd 0x78787878
148+
.Size: dd 0x78787878
149+
Missing:
150+
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:
151+
.VirtualAddress: dd 0x78787878
152+
.Size: dd 0x78787878
153+
IMAGE_DIRECTORY_ENTRY_RESERVED:
154+
.VirtualAddress: dd 0x78787878
155+
.Size: dd 0x78787878
156+
%endif
157+
_datadir_end:
158+
159+
_sechead:
160+
161+
IMAGE_SECTION_HEADER__0:
162+
.Name: db '.dummy1', 0
163+
.VirtualSize: dd 0x000000001 ; Must be positive for Windows XP.
164+
.VirtualAddress: dd 0x1000 ; Must be positive and divisible by 0x1000 for Windows XP.
165+
.SizeOfRawData: dd 0x00000000
166+
.PointerToRawData: dd 0x00000000
167+
.PointerToRelocations: dd 0
168+
.PointerToLineNumbers: dd 0
169+
.NumberOfRelocations: dw 0
170+
.NumberOfLineNumbers: dw 0
171+
.Characteristics: dd 0xc0300040
172+
173+
IMAGE_SECTION_HEADER__1:
174+
.Name: db '.dummy2', 0
175+
.VirtualSize: dd 0x00000001 ; Must be positive for Windows XP.
176+
.VirtualAddress: dd 0x2000 ; Must be positive, divisible by 0x1000, and larger then the prev .VirtualAddress for Windows XP.
177+
.SizeOfRawData: dd 0x00000000
178+
.PointerToRawData: dd 0x00000000
179+
.PointerToRelocations: dd 0
180+
.PointerToLineNumbers: dd 0
181+
.NumberOfRelocations: dw 0
182+
.NumberOfLineNumbers: dw 0
183+
.Characteristics: dd 0xc0300040
184+
185+
IMAGE_SECTION_HEADER__2:
186+
.Name: db '.text', 0, 0, 0
187+
.VirtualSize: dd (_eof - _text) + bss_size
188+
%if (textbase - imagebase) & 0xfff
189+
%fatal _text doesn't start at page boundary, needed by Windows XP.
190+
%endif
191+
%if (textbase - imagebase) <= 0x2000
192+
%fatal _text doesn't start later than the previous sections, needed by Windows XP.
193+
%endif
194+
.VirtualAddress: dd textbase - imagebase
195+
.SizeOfRawData: dd _eof - _text
196+
.PointerToRawData: dd _text - _filestart
197+
.PointerToRelocations: dd 0
198+
.PointerToLineNumbers: dd 0
199+
.NumberOfRelocations: dw 0
200+
.NumberOfLineNumbers: dw 0
201+
.Characteristics: dd 0xe0300020
202+
203+
_headers_end:
204+
; We can check it only this late, when _headers_end is defined.
205+
%if (_headers_end - _sechead) % 40 != 0
206+
%fatal Multiples of IMAGE_SECTION_HEADER needed.
207+
%endif
208+
%if (_headers_end - _sechead) / 40 < 3
209+
%fatal Windows XP needs at least 3 sections.
210+
%endif
211+
212+
times 0x200 - ($-$$) db 'x'
213+
214+
;times 0x100 db 'y' ; Doesn't work, _text is not aligned properly.
215+
;times 0x200 db 'y' ; Works, making the .exe larger.
216+
217+
_text:
218+
219+
_entry:
220+
; Arguments pushed in reverse order, popped by the callee.
221+
; WINBASEAPI HANDLE WINAPI GetStdHandle (DWORD nStdHandle);
222+
; HANDLE hfile = GetStdHandle(STD_OUTPUT_HANDLE);
223+
push byte -11 ; STD_OUTPUT_HANDLE
224+
call [textbase + (__imp__GetStdHandle@4 - _text)]
225+
; Arguments pushed in reverse order, popped by the callee.
226+
; WINBASEAPI WINBOOL WINAPI WriteFile (HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
227+
; DWORD bw;
228+
push eax ; Value does't matter.
229+
mov ecx, esp
230+
push byte 0 ; lpOverlapped
231+
push ecx ; lpNumberOfBytesWritten = &dw
232+
push byte (_msg_end - _msg) ; nNumberOfBytesToWrite
233+
push textbase + (_msg - _text) ; lpBuffer
234+
push eax ; hFile = hfile
235+
call [textbase + (__imp__WriteFile@20 - _text)]
236+
;pop eax ; This would pop dw. Needed for cleanup.
237+
; Arguments pushed in reverse order, popped by the callee.
238+
; WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitProcess(UINT uExitCode);
239+
push byte 0 ; uExitCode
240+
call [textbase + (__imp__ExitProcess@4 - _text)]
241+
242+
_data:
243+
_msg:
244+
db 'Hello, World!', 13, 10
245+
_msg_end:
246+
247+
; This can be before of after _entry, it doesn't matter.
248+
_idata: ; Relocations, IMAGE_DIRECTORY_ENTRY_IMPORT data.
249+
_hintnames:
250+
dd (textbase - imagebase) + (IMAGE_IMPORT_BY_NAME_ExitProcess - _text)
251+
dd (textbase - imagebase) + (IMAGE_IMPORT_BY_NAME_GetStdHandle - _text)
252+
dd (textbase - imagebase) + (IMAGE_IMPORT_BY_NAME_WriteFile - _text)
253+
dd 0 ; Marks end-of-list.
254+
_iat: ; Modified by the PE loader before jumping to _entry.
255+
__imp__ExitProcess@4: dd (textbase - imagebase) + (IMAGE_IMPORT_BY_NAME_ExitProcess - _text)
256+
__imp__GetStdHandle@4: dd (textbase - imagebase) + (IMAGE_IMPORT_BY_NAME_GetStdHandle - _text)
257+
__imp__WriteFile@20: dd (textbase - imagebase) + (IMAGE_IMPORT_BY_NAME_WriteFile - _text)
258+
dd 0 ; Marks end-of-list.
259+
IMAGE_IMPORT_BY_NAME_ExitProcess:
260+
.Hint: dw 0
261+
.Name: db 'ExitProcess' ; Terminated by the subsequent .Hint.
262+
IMAGE_IMPORT_BY_NAME_GetStdHandle:
263+
.Hint: dw 0
264+
.Name: db 'GetStdHandle' ; Terminated by the subsequent .Hint.
265+
IMAGE_IMPORT_BY_NAME_WriteFile:
266+
.Hint: dw 0
267+
.Name: db 'WriteFile' ; Terminated below.
268+
db 0 ; Terminates last .Name.
269+
270+
_KERNEL32_str: db 'kernel32', 0 ; 'KERNEL32' and 'KERNEL32.dll' also work.
271+
_idescs:
272+
IMAGE_IMPORT_DESCRIPTOR__0:
273+
.OriginalFirstThunk: dd (textbase - imagebase) + (_hintnames - _text)
274+
.TimeDateStamp: dd 0
275+
.ForwarderChain: dd 0
276+
.Name: dd (textbase - imagebase) + (_KERNEL32_str - _text)
277+
.FirstThunk: dd (textbase - imagebase) + (_iat - _text)
278+
279+
_idata_data_end:
280+
_eof:
281+
;bss_size equ 0
282+
;IMAGE_IMPORT_DESCRIPTOR__1: ; Empty, marks end-of-list.
283+
;.OriginalFirstThunk: dd 0
284+
;.TimeDateStamp: dd 0
285+
;.ForwarderChain: dd 0
286+
;.Name: dd 0
287+
;.FirstThunk: dd 0
288+
;_idata_end:
289+
bss_size equ 20 ; _idata_end - _eof
290+
291+
%if (_text - _filestart) & (file_alignment - 1)
292+
%fatal _text is not aligned to file_alignment, needed by Windows XP.
293+
%endif
294+

0 commit comments

Comments
 (0)