Mach-O入門 実践編
準備
というわけで、Mach-Oファイルの構造がわかったところで、実際のファイルで確かめてみることにする。
C言語で簡単な実行ファイルを作成して、otoolで構造を表示させてみよう。プログラムはこんな感じ。test.cというファイル名で保存する。
#include <stdio.h> int main(void) { printf("Hello World\n"); return 0; }
> gcc test.c -o test
準備完了。試しに実行してみる。
> ./test Hello World
うん、いいみたいだね。
共有ライブラリ
x86のLinuxだとlibcがダイナミックリンクされるプログラムだから、Mach-Oでも同じはず。otoolの-Lオプションを使って、依存する共有ライブラリを調べてみよう。
> otool -L test test: /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 88.3.4)
libSystem.Bに依存してるらしい。
Mach-Oヘッダ
otoolでMach-Oヘッダを表示してみる。
> otool -h -v test test: Mach header magic cputype cpusubtype filetype ncmds sizeofcmds flags MH_MAGIC I386 ALL EXECUTE 11 1104 NOUNDEFS DYLDLINK TWOLEVEL SUBSECTIONS_VIA_SYMBOLS
i386向けの実行ファイルで、ロードコマンドを11個含んでいることがわかる。
ロードコマンド
otoolでロードコマンドを表示してみる。-vオプションで、多少見やすくすることが可能。11個のロードコマンドがすべて表示されるので注意。
> otool -l -v test test: Load command 0 cmd LC_SEGMENT cmdsize 56 segname __PAGEZERO vmaddr 0x00000000 vmsize 0x00001000 fileoff 0 filesize 0 maxprot --- initprot --- nsects 0 flags NORELOC Load command 1 cmd LC_SEGMENT cmdsize 260 segname __TEXT vmaddr 0x00001000 vmsize 0x00001000 fileoff 0 filesize 4096 maxprot rwx initprot r-x nsects 3 flags (none) Section sectname __text segname __TEXT addr 0x00001e60 size 0x00000143 offset 3680 align 2^2 (4) reloff 0 nreloc 0 type S_REGULAR attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS reserved1 0 reserved2 0 Section sectname __cstring segname __TEXT addr 0x00001fa4 size 0x00000058 offset 4004 align 2^2 (4) reloff 0 nreloc 0 type S_CSTRING_LITERALS attributes (none) reserved1 0 reserved2 0 Section sectname __textcoal_nt segname __TEXT addr 0x00001ffc size 0x00000004 offset 4092 align 2^0 (1) reloff 0 nreloc 0 type S_COALESCED attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS reserved1 0 reserved2 0 Load command 2 cmd LC_SEGMENT cmdsize 260 segname __DATA vmaddr 0x00002000 vmsize 0x00001000 fileoff 4096 filesize 4096 maxprot rw- initprot rw- nsects 3 flags (none) Section sectname __data segname __DATA addr 0x00002000 size 0x00000010 offset 4096 align 2^2 (4) reloff 0 nreloc 0 type S_REGULAR attributes (none) reserved1 0 reserved2 0 Section sectname __dyld segname __DATA addr 0x00002010 size 0x00000008 offset 4112 align 2^2 (4) reloff 0 nreloc 0 type S_REGULAR attributes (none) reserved1 0 reserved2 0 Section sectname __common segname __DATA addr 0x00002020 size 0x00000034 offset 0 align 2^4 (16) reloff 0 nreloc 0 type S_ZEROFILL attributes (none) reserved1 0 reserved2 0 Load command 3 cmd LC_SEGMENT cmdsize 192 segname __IMPORT vmaddr 0x00003000 vmsize 0x00001000 fileoff 8192 filesize 4096 maxprot rwx initprot rwx nsects 2 flags (none) Section sectname __pointers segname __IMPORT addr 0x00003000 size 0x0000000c offset 8192 align 2^0 (1) reloff 0 nreloc 0 type S_NON_LAZY_SYMBOL_POINTERS attributes (none) reserved1 0 (index into indirect symbol table) reserved2 0 Section sectname __jump_table segname __IMPORT addr 0x0000300c size 0x00000014 offset 8204 align 2^0 (1) reloff 0 nreloc 0 type S_SYMBOL_STUBS attributes PURE_INSTRUCTIONS SELF_MODIFYING_CODE SOME_INSTRUCTIONS reserved1 3 (index into indirect symbol table) reserved2 5 (size of stubs) Load command 4 cmd LC_SEGMENT cmdsize 56 segname __LINKEDIT vmaddr 0x00004000 vmsize 0x00001000 fileoff 12288 filesize 1052 maxprot rw- initprot r-- nsects 0 flags NORELOC Load command 5 cmd LC_LOAD_DYLINKER cmdsize 28 name /usr/lib/dyld (offset 12) Load command 6 cmd LC_LOAD_DYLIB cmdsize 52 name /usr/lib/libSystem.B.dylib (offset 24) time stamp 1167494134 Sun Dec 31 00:55:34 2006 current version 88.3.4 compatibility version 1.0.0 Load command 7 cmd LC_SYMTAB cmdsize 24 symoff 12288 nsyms 31 stroff 12716 strsize 624 Load command 8 cmd LC_DYSYMTAB cmdsize 80 ilocalsym 0 nlocalsym 4 iextdefsym 4 nextdefsym 20 iundefsym 24 nundefsym 7 tocoff 0 ntoc 0 modtaboff 0 nmodtab 0 extrefsymoff 0 nextrefsyms 0 indirectsymoff 12688 nindirectsyms 7 extreloff 0 nextrel 0 locreloff 0 nlocrel 0 Load command 9 cmd LC_TWOLEVEL_HINTS cmdsize 16 offset 12660 nhints 7 Load command 10 cmd LC_UNIXTHREAD cmdsize 80 flavor i386_THREAD_STATE count i386_THREAD_STATE_COUNT eax 0x00000000 ebx 0x00000000 ecx 0x00000000 edx 0x00000000 edi 0x00000000 esi 0x00000000 ebp 0x00000000 esp 0x00000000 ss 0x0000001f eflags 0x00000000 eip 0x00001e60 cs 0x00000017 ds 0x0000001f es 0x0000001f fs 0x00000000 gs 0x00000000
__TEXTセグメント
otoolの-tオプションで、__TEXTセグメントの__textセクションを表示してみる。-Vオプションで逆アセンブルすることが可能。
> otool -t -v -V test test: (__TEXT,__text) section start: 00001e60 pushl $0x00 00001e62 movl %esp,%ebp 00001e64 andl $0xf0,%esp 00001e67 subl $0x10,%esp 00001e6a movl 0x04(%ebp),%ebx 00001e6d movl %ebx,0x00(%esp,1) 00001e71 leal 0x08(%ebp),%ecx 00001e74 movl %ecx,0x04(%esp,1) 00001e78 addl $0x01,%ebx 00001e7b shll $0x02,%ebx 00001e7e addl %ecx,%ebx 00001e80 movl %ebx,0x08(%esp,1) 00001e84 calll __start 00001e89 hlt __start: 00001e8a pushl %ebp 00001e8b movl %esp,%ebp 00001e8d pushl %edi 00001e8e pushl %esi 00001e8f pushl %ebx 00001e90 subl $0x2c,%esp 00001e93 movl 0x0c(%ebp),%edi 00001e96 movl 0x10(%ebp),%ebx 00001e99 movl 0x08(%ebp),%eax 00001e9c movl %eax,_NXArgc 00001ea1 movl %edi,_NXArgv 00001ea7 movl %ebx,_environ 00001ead movl (%edi),%ecx 00001eaf testl %ecx,%ecx 00001eb1 jne 0x00001eba 00001eb3 movl $0x00001fa4,%ecx 00001eb8 jmp 0x00001ed3 00001eba movl %ecx,%edx 00001ebc jmp 0x00001ecc 00001ebe cmpb $0x2f,%al 00001ec0 je 0x00001ec7 00001ec2 addl $0x01,%edx 00001ec5 jmp 0x00001ecc 00001ec7 addl $0x01,%edx 00001eca movl %edx,%ecx 00001ecc movzbl (%edx),%eax 00001ecf testb %al,%al 00001ed1 jne 0x00001ebe 00001ed3 movl %ecx,___progname 00001ed9 movl %ebx,%eax 00001edb jmp 0x00001ee0 00001edd addl $0x04,%eax 00001ee0 movl (%eax),%edx 00001ee2 testl %edx,%edx 00001ee4 jne 0x00001edd 00001ee6 leal 0x04(%eax),%esi 00001ee9 movl 0x00003000,%eax 00001eee movl (%eax),%eax 00001ef0 testl %eax,%eax 00001ef2 je 0x00001ef6 00001ef4 call *%eax 00001ef6 movl 0x00003008,%eax 00001efb movl (%eax),%eax 00001efd testl %eax,%eax 00001eff je 0x00001f03 00001f01 call *%eax 00001f03 calll 0x00003011 ; symbol stub for: ___keymgr_dwarf2_register_sections 00001f08 leal 0xe0(%ebp),%eax 00001f0b movl %eax,0x04(%esp,1) 00001f0f movl $0x00001fa8,(%esp,1) 00001f16 calll __dyld_func_lookup 00001f1b call *0xe0(%ebp) 00001f1e leal 0xe4(%ebp),%eax 00001f21 movl %eax,0x04(%esp,1) 00001f25 movl $0x00001fd8,(%esp,1) 00001f2c calll __dyld_func_lookup 00001f31 movl 0xe4(%ebp),%eax 00001f34 testl %eax,%eax 00001f36 je 0x00001f40 00001f38 movl %eax,(%esp,1) 00001f3b calll 0x00003016 ; symbol stub for: _atexit 00001f40 movl 0x00003004,%eax 00001f45 movl $0x00000000,(%eax) 00001f4b movl %esi,0x0c(%esp,1) 00001f4f movl %ebx,0x08(%esp,1) 00001f53 movl %edi,0x04(%esp,1) 00001f57 movl 0x08(%ebp),%eax 00001f5a movl %eax,(%esp,1) 00001f5d calll _main 00001f62 movl %eax,(%esp,1) 00001f65 calll 0x0000300c ; symbol stub for: _exit 00001f6a nop 00001f6b nop dyld_stub_binding_helper: 00001f6c pushl $__mh_execute_header 00001f71 jmp *0x00002010 00001f77 nop __dyld_func_lookup: 00001f78 jmp *0x00002014 _main: 00001f7e pushl %ebp 00001f7f movl %esp,%ebp 00001f81 pushl %ebx 00001f82 subl $0x14,%esp 00001f85 calll ___i686.get_pc_thunk.bx 00001f8a leal 0x00000066(%ebx),%eax 00001f90 movl %eax,(%esp,1) 00001f93 calll 0x0000301b ; symbol stub for: _puts 00001f98 movl $0x00000000,%eax 00001f9d addl $0x14,%esp 00001fa0 popl %ebx 00001fa1 popl %ebp 00001fa2 ret
ロードコマンドによると、__TEXTセグメントにはまだ__cstringと__textcoal_ntのセクションがあるから、それも表示してみる。otoolの-sオプションを使って、セグメントとセクションを指定すれば、任意のセクションを表示できる。-vオプションで多少見やすくなる。
__cstringには文字列が、__textcoal_ntセクションにはgccが用意した__i686.get_pc_thunk.bx関数が格納されている。
> otool -s __TEXT __cstring -v test test: Contents of (__TEXT,__cstring) section 00001fa4 00001fa5 00001fa6 00001fa7 00001fa8 __dyld_make_delayed_module_initializer_calls 00001fd5 00001fd6 00001fd7 00001fd8 __dyld_mod_term_funcs 00001fee 00001fef 00001ff0 Hello World
> otool -s __TEXT __textcoal_nt -v test test: Contents of (__TEXT,__textcoal_nt) section ___i686.get_pc_thunk.bx: 00001ffc movl (%esp,1),%ebx 00001fff ret