Tiny mach-0 are fun
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; yasm -f bin rev_mach-o.asm
3; it's tiny.asm from http://osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/
4; with very few modifications in order to have both a valid and working hello-world mach-o
5;
6; https://twitter.com/__rev
7;
8
9BITS 32
10 org 0x1000
11
12 db 0xce, 0xfa, 0xed, 0xfe ; magic
13 dd 7 ; cputype (CPU_TYPE_X86)
14 dd 3 ; cpusubtype (CPU_SUBTYPE_I386_ALL)
15 dd 2 ; filetype (MH_EXECUTE)
16 dd 2 ; ncmds
17 dd _ep2 - _text ; cmdsize
18 dd 0 ; flags
19_text:
20 dd 1 ; cmd (LC_SEGMENT)
21 dd 56 ; cmdsize | sizeof(segment_command) makes it valid
22 db "T" ; segname
23 db 0 ; segname padding
24_ep:
25 ; SYS_write
26 push msg_size ; this is part of segname padding
27 push msg
28 push ecx
29 push ebx
30 int 0x80
31
32 ; - SYS_exit
33 push ebx
34 jmp _ep2
35
36 dd 0x1000 ; vmaddr
37 dd 0x1000 ; vmsize
38 dd 0 ; fileoff
39 dd filesize ; filesize
40 dd 7 ; maxprot
41 dd 5 ; initprot
42 dd 0 ; nsects
43 dd 0 ; flags
44
45 dd 5 ; cmd (LC_UNIXTHREAD)
46 dd 80 ; cmdsize
47 dd 1 ; flavor (i386_THREAD_STATE)
48 dd 16 ; count (i386_THREAD_STATE_COUNT)
49 dd 4, 0, 1, 0, 0, 0, 0, 0 ; state
50 dd 0, 0, _ep, 0, 0, 0, 0, 0 ; state
51_ep2:
52 mov eax, ecx
53 int 0x80
54
55filesize equ $ - $$
56
57msg db 'Hello world', 0ah
58 msg_size equ $ - msg
Thanks:
- Amit Singh for his tiny.asm
- Orlando for suggesting that __TEXT segname is not really needed/enforced
References: