前言
使用otool 之前有必要对Mach-O 了解一下。可以使用Mach-O文件的可视化工具MachOExplorer进行查看。
- iPhone app 存放的路径
#app 下载的app路径 iPhone:~ root# ls -l /var/mobile/Containers/Bundle/Application total 0 drwxr-xr-x 3 mobile mobile 170 Dec 17 11:43 15912B70-1938-479E-A21E-624525AEC733/ #Apple原生的应用路径 lrwxr-xr-x 1 root admin 32 Apr 23 2017 /Applications -> /var/stash/_.TvfJPY/Applications/ iPhone:~ root# cd /var/stash/_.TvfJPY/Applications/ iPhone:/var/stash/_.TvfJPY/Applications root# ls -l total 0 drwxrwxr-x 3 root admin 272 Sep 27 2014 AACredentialRecoveryDialog.app/ drwxrwxr-x 3 root admin 306 Sep 13 2014 AccountAuthenticationDialog.app/ drwxrwxr-x 42 root admin 1700 Oct 14 2014 AdSheet.app/
- Universal Binary 通用二进制文件,也称胖二进制文件 Fat headers
iPhone:/var/stash/_.TvfJPY/Applications/iRE.app root# otool -f iRE2 Fat headers fat_magic 0xcafebabe nfat_arch 2 architecture 0 cputype 12 cpusubtype 9 capabilities 0x0 offset 16384 size 67248 align 2^14 (16384) architecture 1 cputype 12 cpusubtype 11 capabilities 0x0 offset 98304 size 67264 align 2^14 (16384)
- Fat Header的数据结构在<mach-o/fat.h>头文件上有定义:
#define FAT_MAGIC 0xcafebabe #define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */ struct fat_header { uint32_t magic; /* FAT_MAGIC */ uint32_t nfat_arch; /* number of structs that follow */ }; //说明对应Mach-O文件大小、支持的CPU架构、偏移地址 struct fat_arch { cpu_type_t cputype; /* cpu specifier (int) */ cpu_subtype_t cpusubtype; /* machine specifier (int) */ uint32_t offset; /* file offset to this object file */ uint32_t size; /* size of this object file */ uint32_t align; /* alignment as a power of 2 */ };
从上面的例子,可以看出胖文件的fat_magic是0xcafebabe;顺便说一下64位的Mach-O文件的魔数值为#define MH_MAGIC_64 0xfeedfacf
- file 就是根据Magic 来判断的
devzkndeMacBook-Pro:knMoknKKKKKKokkn.decryptedV5.4.0 devzkn$ file knMoknKKKKKKokkn.decrypted.dec* knMoknKKKKKKokkn.decrypted.decrypted: Mach-O universal binary with 2 architectures: [arm_v7:Mach-O executable arm_v7] [arm64] knMoknKKKKKKokkn.decrypted.decrypted (for architecture armv7): Mach-O executable arm_v7 knMoknKKKKKKokkn.decrypted.decrypted (for architecture arm64): Mach-O 64-bit executable arm64
Mach-O
是Mach object文件格式的缩写,是一种可执行文件、目标代码、共享程序库、动态加载代码和核心DUMP;是a.out格式的一种替代;Mach-O提供更多的可扩展性和更快的符号表信息存取。
- #include <mach-o/loader.h>
-l print the load commands
这些加载命令在Mach-O文件加载解析时,被内核加载器或者动态链接器调用,指导如何设置加载对应的二进制数据段;
- Load Commend的数据结构如下:
struct load_command { uint32_t cmd; /* type of load command */ uint32_t cmdsize; /* total size of command in bytes */ };
- otool -l MKNooJn.dec*
devzkndeMacBook-Pro:knMoknKKKKKKokkn.decrypted.4.0 devzkn$ knMoknKKKKKKokkn.decrypted.decrypted (architecture armv7): Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags 0xfeedface 12 9 0x00 2 75 7500 0x00218085 Load command 0 cmd LC_SEGMENT cmdsize 56 segname __PAGEZERO vmaddr 0x00000000 vmsize 0x00004000 fileoff 0 filesize 0 maxprot 0x00000000 initprot 0x00000000 nsects 0 flags 0x0
OS X/iOS发展到今天,已经有40多条加载命令,其中部分是由内核加载器直接使用,而其他则是由动态链接器处理。其中几个主要的Load Commend为LC_SEGMENT, LC_LOAD_DYLINKER, LC_UNIXTHREAD, LC_MAIN;LC_SEGMENT 的数据结构的更多信息请查看这里
- LC_LOAD_DYLIB 、LC_LOAD_WEAK_DYLIB
#define LC_LOAD_DYLIB 0xc /* load a dynamically linked shared library */
/*
* load a dynamically linked shared library that is allowed to be missing
* (all symbols are weak imported).
*/
#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
-h print the mach header
- otool -h MKNooJn.dec*
Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags 0xfeedface 12 9 0x00 2 75 7500 0x00218085 Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags 0xfeedfacf 16777228 0 0x00 2 75 8344 0x00218085
-t print the text section (disassemble with -v)
devzkndeMacBook-Pro:knMokssnossV5.4.0 devzkn$ otool -tv knMokssnoss.decrypted
knMokssnoss.decrypted (architecture armv7):
(__TEXT,__text) section
000097b0 f0 b5 03 af svcge #0x3b5f0
llvm-objdump: warning: invalid instruction encoding
- __TEXT __cstring
devzkndeMacBook-Pro:~ devzkn$ otool -sv __TEXT __cstring /bin/ls /bin/ls: Contents of (__TEXT,__cstring) section
otool -o
一个可执行文件包含多个段, 在每一个段内有一些片段。它们包含了可执行文件的不同的部分, 包含了部分的源码及DATA.
- otool -o MKNooJn.dec*
devzkndeMacBook-Pro:knMoknKKKKKKokkn.decrypted.4.0 devzkn$ otool -o MKNooJn.dec* |grep password name 0x82b11e passwordTextFieldFrame name 0x82b135 passwordPlaceholder name 0x82b11e passwordTextFieldFrame name 0x82b135 passwordPlaceholder name 0x82b11e passwordTextFieldFrame name 0x82b135 passwordPlaceholder
- LC_SEGMENT(__TEXT) Number of Sections + LC_SEGMENT(__DATA) Number of Sections = Sections Number of sections
- otool -s
devzkndeMacBook-Pro:knMoknKKKKKKokkn.decrypted.4.0 devzkn$ otool -s __TEXT __const MKNooJn.dec* knMoknKKKKKKokkn.decrypted.decrypted (architecture armv7): Contents of (__TEXT,__const) section 00951340 6f6f4d34 3141306e 61724734 6c416564
- Raw segment data
一般Mach-O文件有多个段(Segement),段每个段有不同的功能; 1). __PAGEZERO: 空指针陷阱段,映射到虚拟内存空间的第一页,用于捕捉对NULL指针的引用;<br> 2). __TEXT: 包含了执行代码以及其他只读数据。该段数据的保护级别为:VM_PROT_READ(读)、VM_PROT_EXECUTE(执行),防止在内存中被修改;<br> 3). __DATA: 包含了程序数据,该段可写;<br> 4). __OBJC: Objective-C运行时支持库;<br> 5). __LINKEDIT: 链接器使用的符号以及其他表<br> 一般的段又会按不同的功能划分为几个区(section)。
- section的命名规则
命名规则标识段-区的表示方法为(__SEGMENT.__section)SEGMENT所有字母大写,加两个下横线作为前缀;section为小写,同样加两个下横线作为前缀。
Sequence of Steps in Executing an Image
- flow_of_process_execution Flow of the various process execution functions in OS X 引用自《Mac OS X and iOS Internals》P519
devzkndeMacBook-Pro:kern devzkn$ open /Users/devzkn/Downloads/kevinsoftware/ios-Reverse_Engineering/xnu-2782.1.97/bsd/kern/kern_exec.c
- parse_machfile()
(1):解析线程状态,UUID和代码签名。相关命令为LC_UNIXTHREAD、LC_MAIN、LC_UUID、LC_CODE_SIGNATURE (2):解析代码段Segment。相关命令为LC_SEGMENT、LC_SEGMENT_64; (3):解析动态链接库、加密信息。相关命令为:LC_ENCRYPTION_INFO、LC_ENCRYPTION_INFO_64、LC_LOAD_DYLINKER
- load 函数是如何被调用的 dyld 是Apple 的动态链接器;在 xnu 内核为程序启动做好准备后,就会将 PC 控制权交给 dyld 负责剩下的工作 (dyld 是运行在 用户态的, 这里由 内核态 切到了用户态).
参考
- Mach-O 文件格式探索
- macOS软件安全
- iOS 程序 main 函数之前发生了什么
- friday-qa-2012-11-09-dyld-dynamic-linking-on-os-x.html
- dyld
- Security_Overview
- ManPages/man1/dyld.
- newosxbook
- App防止dylib注入
- 由App的启动说起
- XNU版本为v2782.1.97
- iOS系统分析(二)Mach-O二进制文件解析
- 阅读内核准备知识
- Mach-O 的动态链接(Lazy Bind 机制)
附
- app 的启动过程
1、内核(OS Kernel)创建一个进程,分配虚拟的进程空间等等,加载动态链接器。 2、通过动态链接器加载主二进制程序引用的库、绑定符号。 3、启动程序
- mach-o_execution:
- Darwin体系
Darwin是一种类似unix的操作系统,他的核心是XNU。 XNU是一种混合式内核。结合了mach与BSD两种内核。 Mach 是微内核实现。 BSD 实现在Mach的上层,这一层提供的API 支持了POSIX标准模型。在XNU中主要实现了一些高级的API与模块。
iOS安全机制
- 代码签名:
- 强制访问控制(Mandatory Access Control):系统检测安全属性以便确定一个用户是否有权访问该文件
- sandbox: 沙盒在启动的时候可以设置运行的程序是否可以访问网络、文件、目录
在操作过程或者文章有问题的话欢迎在 原文 里提问或指正。