📜 ⬆️ ⬇️

"Digital Rain" for Windows in 314 bytes

In the comments to the recent topic, a discussion has arisen: to what size can you shrink the Windows EXE typing in the “Hello, World!” Console? Answer: 268 bytes, smaller Windows files simply refuse to load.

If “Hello, World!” Has already reached the limit of possible contractions, then I wondered to what extent a program can be compressed that does at least something more interesting.

First, I boast about the result: my program is only 46 bytes more than the theoretical minimum!
')


base64
  TVprZXJuZWwzMgAAUEUAAEwBAQC4AwABAPdlEIlFEMN4AA8BCwEFDL0UEEAAjXyNAFfraD
 gQAAAzyesoDAAAAAAAQAAAEAAAAAIAAAAAAAACAgoCBAAAAAAAAAAQAAAAAIAALFQ68AD
 AAAAEgEAAAAAAABABABAAAAAFAFAQADAAAAAAAAAAAAAAAoEQAAKAAAAAAAAAAAAAAAA / 9
 Wr4vvrEQAAMAAAABAAADkBAAABAAAAi / df6wMAAAAzybFQV4sHgPwZdygPttyNHJvB4waN
 HItQweAYwegei0RFOIhEMwKIpDPC / v /// 9WIJDNY / sSA / GR8Av / Vq + LFjUVcUFH / dWhWZZ
 tBMItAEP9wHP9VWOuiV3JpdGVDb25zb2xlT3V0cHV0QQBsEAAAAAAAAAAAAAACAAAAAbBA = 

(If there is a volunteer to kill these 314 bytes, I will add a link here.)




Previous enthusiasts have found that the smallest program for Win2000 and WinXP occupies 133 bytes ; The smallest 32-bit program for Windows x64 is 268 bytes . The last limitation is tightly wired into the Windows x64 bootloader: if from the beginning of the PE header to the end of the file is less than IMAGE_NT_HEADERS64 = 0x108 bytes, then Windows refuses to load the file. The PE header cannot start earlier than at offset 4, therefore the program content, which occupies ( in the minimum possible version ) even less than 268 bytes, has to be finished with zeros to the minimum acceptable size.

Existing examples of programs of 268 bytes do not contain any sections, and in fact, they are entirely placed inside the PE header, for which Windows allocates one page of memory (4KB) for loading. But for “Digital Rain” you need to keep a screen buffer (80 columns × 25 lines × 4 bytes per character = 8000 bytes), so you cannot do without a section in the program. This is not so wasteful: the section header is only 0x28 bytes, of which more than half are not used, so they can be occupied with code. In fact, “inside” of the section - after its header - in my program are part of the executable code, the name of the function being imported, and part of the import table (the last 0x16 of its bytes are zero, and are not stored in the file). The import table and the subsequent 8KB of memory during operation are used to store data (state array and screen buffer). All initialized data, part of the service information (import chain and library name), and part of the code are pushed through the headers. “Double up” the following: Headers PointerToRelocations, PointerToLinenumbers, NumberOfRelocations, NumberOfLinenumbers and Characteristics . For the Characteristics field (section flags) it was enough that the MSB was set ( IMAGE_SCN_MEM_WRITE ); Restrictions are also imposed on the values ​​of some other fields — for example, SizeOfStackCommit and SizeOfHeapReserve should be placed in memory. The value of the PointerToLinenumbers field is mistakenly taken by the system for the size of the debugging information table, and if there is a value larger than the program size in memory (0x4000), the program crashes upon loading.

In the previous "minimal" programs, the values FileAlignment = 4 and SectionAlignment = 4 were used. In a file without sections, Windows x64 allows this; but if at least one section is declared, then FileAlignment must be at least 0x200, and SectionAlignment must be 0x1000. Therefore, it is impossible to create a program of 268 bytes in size that would have a section: the overlap of e_lfanew = 4 and SectionAlignment unacceptable. Move the PE header by 4 bytes a little, because ImageBase must be a multiple of 0x1000. It turns out that the minimum possible size of a program with a section is 276 bytes, with overlapping e_lfanew = 0xC and BaseOfData . In other words, my program is 38 bytes more than the minimum possible, which would use> 4K of memory.

I tested the performance of my program on Win7 and Win2008. On WinXP, my program, unfortunately, does not work ( edit: it works, but after a time) - it refuses to load programs that have less than 0xD entries in the directory. If in the “Hello, World!” Program all the code is 0x10 bytes, and they don’t mind typing 0x50 zero bytes into the file for WinXP compatibility, I felt sorry for inflating the program a quarter of a size for this. I apologize to all lovers of vintage OS.

Source: https://habr.com/ru/post/276371/


All Articles