pouët.net

Tiny PE header for Windows 8 and in general.

category: code [glöplog]
 
I've been looking at some documents about the Portable Executable format that floats around on the web these days. Not been able to read all of them, but seems like some of them are a bit outdated. It seems like the PE format have some minor changes on each upcoming Windows versions, can someone confirm this too?
Most stuff seems the same because of the structure of the PE, but I am starting to doubt that they are the same on Windows 8, which I will point at in the next paragraph. Or It could be that the data in certain parts of the structure have other values.

There's a site http://www.phreedom.org/research/tinype/ which explains PE by a guy named Alexander Sotirov. I downloaded the Tiny exe's there and the tinyest .exe I was able to run there was 296 bytes on Windows 8 by changing the combatibility of the exe to Windows XP, service pack 3. Why the .exes that are under 296 bytes wont work, I dont have any knowledge about.

I downloaded a MASM compiler that doesnt even work on Win8, and hasn't been able to yet set up a project for this to experiment. Hopefully will do that shortly.

I wonder if there is anyone who have done a tiny .exe for Windows 8 and what kind of bytes and words one should be looking at to make the 296 byte even smaller. Or are anyone able to run the .exes that are tinyer from the site above, than the 296 byte one?

Comments, hints and talk in general about PE headers are welcome.
added on the 2013-08-28 15:40:59 by rudi rudi
Don't know about 8, but with XP/7 it's easy to produce 124 byte header with 76 bytes of injected useful code
(or more if you reuse constants properly), four (or three) short jumps are needed though.
added on the 2013-08-28 16:02:07 by frag frag
frag: Yeah, I think one could fill most of the MZ header with code, and also the DOS Stub-textmessage. Well, there is a 97 byte .exe of that site above, and more .exes which I have not been able to try because Windows complains about the compatibility.
I forgot to say that the OS i am running on is 64-bits, so I cant test the files that complain about this. The compatibility option in both Win7 and Win8 just wont work properly on those files either (even if a 64-bits versions of Windows say it will run 32-bit programs).
added on the 2013-08-29 02:19:07 by rudi rudi
At least up to Win7 filling up all of the DOS part except the "MZ" signature works fine.
added on the 2013-08-30 01:14:42 by T$ T$
On Windows 8, the SizeOfHeaders field must not be larger than the entry point. On Windows XP, SizeOfHeaders must be at least 44, at least with the PE header at offset 4 (that is, pointing at the entry point, right after the SizeOf* fields).

To fix the 97-byte header to work on Windows 8 (while still working on Windows XP), at least two things need to be done:
1. Move the entry point beyond offset 44 (it is currently at offset 10). There is space at offset 68, MajorOperatingSystemVersion.
2. Set SizeOfHeaders to 44.

The 97-byte version can be simplified somewhat, as an executable actually doesn't need to have any sections. The number of sections can be set to 0, and the values for the section-specific fields (the ones on the right) can be omitted, freeing up some space for more code. The size stays the same, though, as the subsystem type is still required.

Getting rid of the section header also means that the SizeOfOptionalHeader doesn't have to be 4, as it is currently. I don't quite remember what the requirements are on this. In the Crinkler header, it's 8...
added on the 2013-09-03 16:00:27 by Blueberry Blueberry
haha he has a tiny pe

no seriously, interesting stuff. i never researched it further than crt replace + smaller alignment.
added on the 2013-09-03 18:46:37 by superplek superplek
I have an hunch that 97 byte only works for driver-subsystems, or atleast that the subsystem is not a CUI or GUI. Is this right?

Blueberry: I've tried some now, and dont get that 97 byte version to work. 268 bytes in Windows 8 is as far as I've got. Number of sections in FILE_HEADER is now null.

IMAGE_DATA_DIRECTORIES's 'Delay import descriptor address and size' is the last directory that needs to be there, unless its crashing.

i wonder if there is a way to run an exe without the image data directories.
added on the 2013-09-24 21:59:22 by rudi rudi
ok, just found out some stupid bug in my code. drop that shit I said above.
added on the 2013-09-26 02:23:50 by rudi rudi
FYI I maintain a page with PE informations + PoCs + sources with such details.
added on the 2013-11-05 15:43:15 by ange ange
ange, that looks great :)
added on the 2013-11-05 17:36:15 by raizor raizor
i first found ange's page, then this thread ;) however, i can highly recommend his page. if you are looking for all kinds of "tiny pe"s, you can directly go for the "nightly builds" dropbox and grab the "pe.rar"

=)
added on the 2013-11-07 00:24:24 by HellMood HellMood
This bitfield mask is valid for 32 bit PE's on Windows XP, Windows Vista, Windows 7 and Windows 8. Each character is a single bit with the most significant bit on the left and the least significant on the right. The risky ones can only be set on systems with memory to burn.

Code: ; 0 = Must be zero ; 1 = Must be one ; ? = Can be either zero or one ; X = Should be zero ( Risky ) ; ; 01001101 01011010 ???????? ???????? ; 01010000 01000101 00000000 00000000 ; 01001100 00000001 00000000 00000000 ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; 00001000 00000000 ??????1? ??0????? ; 00001011 00000001 ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; 00000000 00000000 00000000 00000000 ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; 00000000 00000000 01000000 00000000 ; 00000100 00000000 00000000 00000000 ; 00000100 00000000 00000000 00000000 ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; 00000100 00000000 ???????? ???????1 ; ???????? ???????? ???????? ???????? ; ?1?????? ???????? ???????? 0XXX???? ; 00101100 00000000 00000000 00000000 ; ???????? ???????? ???????? ???????? ; 00000011 00000000 0??????? ???0?0?? ; ???????? ???????? ???????? 0XXX???? ; ???????? ???????? ?1?????? 0XXX???? ; ???????? ???????? ???????? 0XXX???? ; ???????? ???????? ???????? 0XXX???? ; ???????? ???????? ???????? ???????? ; 00000000 00000000 00000000 00000000 ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; ???????? ???????? ???????? ???????? ; 00000000 00000000 00000000 00000000
The following blog entry https://drakopensulo.wordpress.com/2017/08/06/smallest-pe-executable-x64-with-every-byte-executed/ contains the asm source of a x64 PE executable of size 268 bytes with every byte executed. It is Win Vista/7/8/10 compatibile.
My experiments showed that Windows 10 (and likely 8 too)
- does not run executables with a section alignment less than 512, unless the file does not use sections at all
- ignores the import tables in sectionless executables
The latter part is what breaks some of the older "tiny PE" examples that can be found on the internet. The executables will load just fine, but they will crash as soon as a supposed-to-be-imported function is called, as it's jumping to the function's name instead of the entry point. So, for small executables that do non-trivial things, you pretty much have to use a custom importer. This is not much of an issue though, as you'll likely want to import by hash anyway.
added on the 2017-09-05 09:05:16 by KeyJ KeyJ
I did quite a lot of experiments and was unable to obtain a working x64 executable with NumberOfSections equal to 0. In the file from the link above that field is equal to 1. However, the section descriptor contains zeros only (it is ignored by th loader)
Blueberry: I think I know why SizeOfOptionalHeader is 8 in Crinkler. The reason is that there's a bug(?) in Win7: Even when there are no sections, the file offset field for the first section must have its MSB cleared. The easiest way to ensure this is to have it point to the image base address (which has a fixed value of 0x400000), and that's done by setting SizeOfOptionalHeader to 8.
added on the 2017-09-10 00:05:10 by KeyJ KeyJ
KeyJ: Very interesting. Makes sense. Thanks for the info. :)
added on the 2017-09-11 20:20:41 by Blueberry Blueberry
I think that even Windows 7 won't allow imports that aren't located inside a section, but for sure Windows 8 doesn't.
SizeOfOptionalHeader must be a multiple of 8 for 64-bit compatibility.
(see http://pferrie.host22.com/misc/tiny/pehdr.htm)
added on the 2017-11-24 22:36:57 by qkumba qkumba

login