News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Looking for the smallest possible .EXE

Started by aw27, October 06, 2017, 05:20:57 AM

Previous topic - Next topic

aw27

 :biggrin:

I have been able to see 32-bit .exes with around 100 bytes, however they don't launch on a 64-bit operating system.

This is as small as I could go for a 32-bit .exe on 64-bit OS - 515 bytes (I could reduce it to 513 bytes leaving only the ret).

It was based on a sample in the Jwasm\Uasm Samples directory:



;--- assemble: UASM -bin -Fo tiny.exe tiny.ASM

    .386
    option casemap:none

    include winnt.inc   ;Use the simplified winnt.inc from Sample folder of UASM.

IMAGEBASE equ 400000h

PEHDR segment dword FLAT
    ORG IMAGEBASE
start_header label near

;--- simplified DOS "MZ" header
IMAGE_DOS_HEADER <"ZM", 0, 0, 0,0,0,0,0,0,0,0,0,0,0,<0>,0,0,<0>,IMAGEREL PEHdr>

;--- define the Win32 "PE" header
PEHdr label byte
    db "PE",0,0
    IMAGE_FILE_HEADER <IMAGE_FILE_MACHINE_I386, num_sections, 0, 0, 0, sizeof IMAGE_OPTIONAL_HEADER32,\
        IMAGE_FILE_RELOCS_STRIPPED or IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE or IMAGE_FILE_LOCAL_SYMS_STRIPPED>

    IMAGE_OPTIONAL_HEADER32 { 10Bh, ;magic
        6,0,                        ;linker major, minor
        0,0,0,              ;sizeof code, initialized data, uninitialized data
        IMAGEREL main,    ;entry point
        0, 0,  ;baseof code, data
        400000h,    ;imagebase
        1000h,200h,   ;section alignment, file alignment
        5,0,          ;OS major, minor
        0,0,          ;Image major, minor
        5,0,          ;Subsys major, minor
        0,            ;win32 version
        2000h,        ;sizeof image
        1000h,        ;sizeof header
        0,            ;checksum
        IMAGE_SUBSYSTEM_WINDOWS_CUI,
        0,            ;dll characteristics
        100000h,1000h,;stack res,com
        100000h,1000h,;heap res, com
        0,            ;loader flags
        16,           ;number of directories
  16 dup (<0,0>)}
;--- define the section table

sectiontable label byte
    IMAGE_SECTION_HEADER <".text", <sizeof_text>, IMAGEREL start_text, sizeof_text,\
        200h, 0, 0, 0, 0, 060000020h >
num_sections equ ( $ -  sectiontable ) / sizeof IMAGE_SECTION_HEADER

    ORG IMAGEBASE+200h   ;forces physical size of header to 200h and sets VA to 400200h

PEHDR ends


_TEXT segment dword public FLAT 'CODE'
ORG 0E00h   ; change pc to RVA 1000h, section alignment and file alignment are different
start_text label near

;--- entry
main proc c
xor eax, eax
ret
main endp

sizeof_text equ $ - start_text

_TEXT ends

    END


Note: Most of the PE fields are not used at all by the launcher, so you may be surprised to find them zeroed here.

aw27

I attach a 32-bit .exe with 358 bytes, but it will only run on a 32-bit Operating System.
This is probably as short as we can go without using the ultra "dirty" tricks elaborated here:
http://www.phreedom.org/research/tinype/

In the attachment I include a batch file to confirm that the .Exe actually works (it should echo the returned value which in this case is 33).



hutch--


aw27

Quote from: jj2007 on October 06, 2017, 06:39:05 PM
Eight bytes should be enough to print "hello world" ;)
Yes, I miss as well those days where .com were not top level domains.  :(

Quote
You guys must be bored.  :P
sights.  :(


Siekmanski

Cool topic.

aw27, thanks for the link to phreedom.org.
One thing on my To-Do list is to create an executable file Compressor/Packer/Cruncher.
You triggered me to finally start studying this topic.
Creative coders use backward thinking techniques as a strategy.

aw27

Since I was at it I decided to use some of the "dirty" tricks from phreedom.org and I reduced the file size to 130 bytes! It was tested in Windows XP 32-bits and worked.
Basically the dirty tricks consist in moving structures to the middle of unused (by the loader) structure parts.
I did not try the last part, where phreedom.org states that we could save a further 26 bytes by using the zeros of the page after the end of the file because according to him it was not working for Windows 2000, so I did not expect miracles for XP.
Also I did not move the executable code to the middle of a structure because the benefit would not be important, only 3 bytes less.

Quote
One thing on my To-Do list is to create an executable file Compressor/Packer/Cruncher.
Excellent idea, Siekmanski!  :t

aw27

Now working on 64-bit.  :bgrin:
Smallest file without stripping anything will be 520 bytes.


;--- assemble: UASM64 -bin -Fo tiny64.exe tiny64.ASM

.x64
option casemap:none

include winnt64.inc   ; Modification for 64-bit of winnt.inc from Sample folder of UASM.

IMAGEBASE equ 140000000h

PEHDR segment dword FLAT

;--- define the DOS "MZ" header

    ORG IMAGEBASE

    IMAGE_DOS_HEADER <"ZM", 80h, 1, 0,4,0,-1,0,200h,0,0,0,0,0,<0>,0,0,<0>,IMAGEREL PEHdr>

;--- define the "PE" header

PEHdr label byte
    db "PE",0,0
    IMAGE_FILE_HEADER <IMAGE_FILE_MACHINE_AMD64, num_sections, 0, 0, 0, sizeof IMAGE_OPTIONAL_HEADER64,\
        IMAGE_FILE_RELOCS_STRIPPED or IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_LARGE_ADDRESS_AWARE or IMAGE_FILE_LOCAL_SYMS_STRIPPED>

    IMAGE_OPTIONAL_HEADER64 { 20Bh, ;magic for PE+ 64-bit
        0Eh,0Ah,                          ;linker major, minor
        1000h,1000h,0,                 ;sizeof code, initialized data, uninitialized data
        IMAGEREL main,    ;entry point
        IMAGEREL start_text,  ;baseof code
        IMAGEBASE,    ;imagebase
        1000h,200h,    ;section alignment, file alignment
        6,0,          ;OS major, minor
        0,0,          ;Image major, minor
        6,0,          ;Subsys major, minor
        0,                    ;win32 version
        2000h,        ;sizeof image
        1000h,        ;sizeof header
        0,            ;checksum
        IMAGE_SUBSYSTEM_WINDOWS_CUI,
        0,            ;dll characteristics
        100000h,1000h, ;stack res,com
        100000h,1000h, ;heap res, com
        0,            ;loader flags
        16,            ;number of directories
        16 dup (<0,0>)}

;--- define the section table

sectiontable label byte
    IMAGE_SECTION_HEADER <".text", <sizeof_text>, IMAGEREL start_text, sizeof_text,\
        200h, 0, 0, 0, 0, 060000020h >
num_sections equ ( $ -  sectiontable ) / sizeof IMAGE_SECTION_HEADER

    ORG IMAGEBASE+200h   ;forces physical size of header to 200h and sets VA to IMAGEBASE + 200h

PEHDR ends

_TEXT segment dword public FLAT 'CODE'
ORG 0E00h   ; change pc to RVA 1000h section alignment and file alignment are different
start_text label near

main proc
mov rax,33
ret
main endp

sizeof_text equ $ - start_text

_TEXT ends




aw27

This is the final and tiniest x64 file I was able to obtain that runs without crashing and without under the table tricks. Size=376 bytes.
And this ends my quest for the smallest .exes  possible :dazzled:


Siekmanski

Hi all,

The aw27 32 bit examples did not run on my 64 bit Windows 8.1 machine.
I'm new to this topic, but did a lot of reading and testing the last few days.
The smallest 32 bit example that runs now on my Windows 8.1 is 268 bytes.
The code size is only 128 bytes. ( padded with zeros to 268 bytes )

You can run the RUN.bat to execute the small exe to get the result, it should be: 55
If it runs on Windows XP <-> Windows 10, I could use this as a template for an executable packer/cruncher.

Would you guys be so nice and test if it runs on other Windows versions?  :t

Included the source ( fully commented ) for the PE32 writer, which creates the executable file.

Marinus
Creative coders use backward thinking techniques as a strategy.

hutch--

Result on Win 10 64.

Executing Small_PE32.exe

Result is: 55

Press any key to continue . . .

jj2007

Same on Win7-64, but it fails with a c5 exception in my XP VM.

felipe

All good here in windows 8.1 64 bits
:icon14:

aw27

The first of my samples, with 515 bytes was tested and run on Windows 10 64-bit.
The others failed on 64-bit OS, as I mentioned.

I will check the  Siekmanski work.