I suppose I’m just not good with this kind of things, e.g. maintaining a blog.
Anyways, this post is about something easy and fun. I was asked about a tiny hello-world mach-o and since it was actually at least a year from last time I’ve been playing with a mach-o file it felt like a very good excuse for playing with them once again.
First thing I did was to go over to www.osxbook.com. I was pretty sure Amit Singh would have wrote a tiny mach-o already, and that was the case.
Downloaded tiny.asm and started from this phrase “There are plenty of zeros lurking in there.”.
- LC_SEGMENT segnames must be padded to 16 bytes, we can actually use that space for storing few opcodes (there must be at least a null termination after segname)
- we can use registers from LC_UNIXTHREAD for storing initial values we might need in order to avoid using bigger opcodes
That’s all, and it gives us a 180 bytes valid/working hello-world mach-o, which is, pretty small.
I think it’s still possible to have even a smaller one, but it would probably be >=10.8 only.
You can grab sources here.
Or have a quick look here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | ; ; yasm -f bin rev_mach-o.asm ; it's tiny.asm from http://osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/ ; with very few modifications in order to have both a valid and working hello-world mach-o ; ; http://twitter.com/__rev ; BITS 32 org 0x1000 db 0xce, 0xfa, 0xed, 0xfe ; magic dd 7 ; cputype (CPU_TYPE_X86) dd 3 ; cpusubtype (CPU_SUBTYPE_I386_ALL) dd 2 ; filetype (MH_EXECUTE) dd 2 ; ncmds dd _ep2 - _text ; cmdsize dd 0 ; flags _text: dd 1 ; cmd (LC_SEGMENT) dd 56 ; cmdsize | sizeof(segment_command) makes it valid db "T" ; segname db 0 ; segname padding _ep: ; SYS_write push msg_size ; this is part of segname padding push msg push ecx push ebx int 0x80 ; - SYS_exit push ebx jmp _ep2 dd 0x1000 ; vmaddr dd 0x1000 ; vmsize dd 0 ; fileoff dd filesize ; filesize dd 7 ; maxprot dd 5 ; initprot dd 0 ; nsects dd 0 ; flags dd 5 ; cmd (LC_UNIXTHREAD) dd 80 ; cmdsize dd 1 ; flavor (i386_THREAD_STATE) dd 16 ; count (i386_THREAD_STATE_COUNT) dd 4, 0, 1, 0, 0, 0, 0, 0 ; state dd 0, 0, _ep, 0, 0, 0, 0, 0 ; state _ep2: mov eax, ecx int 0x80 filesize equ $ - $$ msg db 'Hello world', 0ah msg_size equ $ - msg |
Thanks:
- Amit Singh for his tiny.asm
- Orlando for suggesting me that “__TEXT” segname is not really needed/enforced
References:
- http://osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/
- http://www.feiri.de/macho/
- http://corkami.googlecode.com/svn-history/trunk/asm/macho/helloworld.asm
- http://seriot.ch/hello_macho.php