Can the smallest program that crashes be smaller than the smallest program that doesn’t? Depends on a platform and a compiler/linker set. I’ve chosen x64 and MASM64 for my experiments. The smallest working program I came up first was this:
; ml64 /Zi TheSmallestProgram64.asm /link
; /entry:main /SUBSYSTEM:CONSOLE
_text SEGMENT
main PROC
ret
main ENDP
_text ENDS
END
It compiles and links to an executable with only one byte instruction in its main function:
0:000> u main
TheSmallestProgram64!main:
00000000`00401010 c3 ret
00000000`00401011 cc int 3
00000000`00401012 cc int 3
00000000`00401013 cc int 3
00000000`00401014 cc int 3
00000000`00401015 cc int 3
00000000`00401016 cc int 3
00000000`00401017 cc int 3
Then I thought about removing ret instruction and supposed that if we compile and link and try to execute the program with 0 bytes we get straight to int 3 instruction and in my case (I have NTSD set as a default postmortem debugger) a dump will be saved. So I did that but I found that unfortunately compiler inserts ret instruction if the procedure body is empty. So I cheated them by putting nop instruction (which is also one byte) and got my dump!
; ml64 /Zi TheSmallestProgramWithBug64.asm /link
; /entry:main /SUBSYSTEM:CONSOLE
_text SEGMENT
main PROC
nop
main ENDP
_text ENDS
END
Loading Dump File [new_2006-10-25_12-40-06-500_076C.dmp]
…
0:000> kL
TheSmallestProgramWithBug64!main+0×1
kernel32!BaseProcessStart+0×29
0:000> u main
TheSmallestProgramWithBug64!main:
00000000`00401010 90 nop
00000000`00401011 cc int 3
00000000`00401012 cc int 3
00000000`00401013 cc int 3
00000000`00401014 cc int 3
00000000`00401015 cc int 3
00000000`00401016 cc int 3
00000000`00401017 cc int 3
So one answer to my question: The smallest working program and the smallest crashing program have the same size unless we use some binary editors
Then I tried MS Visual C++ (this time 32-bit project) and came up with the following C or C++ program without any prolog and epilog code:
__declspec(naked) void Main ()
{
}
I changed entry point from standard main function to my own capitalized Main function and compiler/link options:
Compiler:
/Od /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE"
/D "_UNICODE" /D "UNICODE" /D "_AFXDLL"
/FD /MD /GS- /Fo"Release\"
/Fd"Releasevc80.pdb" /W3 /nologo /c
/Wp64 /Zi /TP /errorReport:prompt
Linker:
/OUT:"SmallestProgram.exe" /INCREMENTAL:NO
/NOLOGO /MANIFEST:NO /NODEFAULTLIB /DEBUG
/PDB:"SmallestProgram.pdb" /SUBSYSTEM:CONSOLE
/OPT:REF /OPT:ICF /LTCG /ENTRY:"Main"
/ERRORREPORT:PROMPT
The program crashes immediately because the body is empty:
Loading Dump File [new_2006-10-25_15-18-03-109_13B0.dmp]
0:000> u Main
SmallestProgram!Main:
00401000 cc int 3
00401001 0000 add byte ptr [eax],al
00401003 0000 add byte ptr [eax],al
00401005 0000 add byte ptr [eax],al
00401007 0000 add byte ptr [eax],al
00401009 0000 add byte ptr [eax],al
0040100b 0000 add byte ptr [eax],al
0040100d 0000 add byte ptr [eax],al
0:000> kL
ChildEBP RetAddr
002cfff0 00000000 SmallestProgram!Main
0:000> dds esp
002cffc4 7d4e992a kernel32!BaseProcessStart+0x28
002cffc8 00000000
002cffcc 00000000
002cffd0 7efdf000
002cffd4 80000003
002cffd8 002cffc8
002cffdc 002cfbbc
002cffe0 ffffffff
002cffe4 7d4d8998 kernel32!_except_handler3
002cffe8 7d4e9938 kernel32!`string'+0x28
002cffec 00000000
002cfff0 00000000
002cfff4 00000000
002cfff8 00401000 SmallestProgram!Main
002cfffc 00000000
So another answer to my question: The smallest crashing program can be less than the smallest working program and is actually 0 bytes
- Dmitry Vostokov -