iPhone Mach-O文件格式与代码签名

错误现象
1) 直接运行
/Applications/MobileFonex.app/MobileFonex
Killed: 9

2)gdb调试
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: 50 at address: 0×00043030

背景知识

所有的可执行文件,库文件都需要Apple签名才可以运行在iOS中
内核会在调用execve之前检测Mach-O文件中的LC_CODE_SIGNATURE段是否有效和可信任

iOS内核以及内核扩展 都以 加密的形式 存储在KernelCache文件中
可以在 the iphone wiki上查找解密的key

一般来说,越狱后,Codesigning是禁止的, 可执行的代码页 是可写的

iPhone 上的每个二进制文件都有数字签名
每个内存页都有sha1校验
签名由内核进行检查
访问 标记为可执行的页面时 执行检查
如果签名不合法,进程被内核杀掉


如何检查二进制文件的数字签名

otool -l debugserver | grep LC_CODE_SIGNATURE         cmd LC_CODE_SIGNATURE

或者
grep -b “Apple Code Signing Certification Authority” debugserver

用codesign能显示更详细的签名信息

  1. codesign -dvvvv debugserver

  2. Executable=/private/tmp/x/debugserver

  3. Identifier=debugserver

  4. Format=Mach-O thin (armv7)

  5. CodeDirectory v=20100 size=900 flags=0x0(none) hashes=37+5 location=embedded

  6. CDHash=577b90c4091310762cbd2350e4e32ee919deccf2

  7. Signature size=1599

  8. Authority=iPhone Developer

  9. Signed Time=Feb 9, 2012 11:29:10 PM

  10. Info.plist=not bound

  11. Sealed Resources=none

  12. Internal requirements count=1 size=112复制代码
复制代码


参考资料

https://developer.apple.com/library/mac/#technotes/tn2206/_index.html

Mach-O文件格式

Mach-O 文件分为三个区域: 头部、载入命令区Section和原始段数据.
头部和载入命令区描述文件功能、布局和其他特性;
原始段数据包含由载入命令引用的字节序列。

otools -l 可以查看
Section
sectname __const
segname __TEXT
addr 0×00043908
size 0x000002fc
offset 272648
align 2^2 (4)
reloff 0
nreloc 0
flags 0×00000000
reserved1 0
reserved2 0

Load command 7
cmd LC_UUID
cmdsize 24
uuid 5202B55F-F094-2350-9B4C-8E2C83358B11

Load command 8
cmd LC_UNIXTHREAD
cmdsize 84
flavor ARM_THREAD_STATE
count ARM_THREAD_STATE_COUNT
r0 0×00000000 r1 0×00000000 r2 0×00000000 r3 0×00000000
r4 0×00000000 r5 0×00000000 r6 0×00000000 r7 0×00000000
r8 0×00000000 r9 0×00000000 r10 0×00000000 r11 0×00000000
r12 0×00000000 sp 0×00000000 lr 0×00000000 pc 0×00002000
cpsr 0×00000000

可以看到 start 的地址是 0×2000

Load command 9
cmd LC_ENCRYPTION_INFO
cmdsize 20
cryptoff 4096
cryptsize 270336
cryptid 0

Load command 23
cmd LC_CODE_SIGNATURE
cmdsize 16
dataoff 590896
datasize 3040

注意到 LC_ENCRYPTION_INFO的cryptid是0,表示没有加密

http://opensource.apple.com/source/security_systemkeychain/security_systemkeychain-55105/src/cs_dump.cpp

// if the code is not signed, stop here
if (!api.get(kSecCodeInfoIdentifier))
MacOSError::throwMe(errSecCSUnsigned);

https://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html

目标格式
存储目标代码和相关的元数据的文件格式
在内存中建立进程镜像的蓝本
通常由编译器或者汇编器产生

布局
3个主要部分:header, load comands和sections
每个segemtn comand同多个section相关联

header结构可以在 /usr/include/mach-o/loader.h 找到

  1. /*

  2. * The 32-bit mach header appears at the very beginning of the object file for

  3. * 32-bit architectures.

  4. */

  5. struct mach_header {

  6.         uint32_t        magic;                /* mach magic number identifier */

  7.         cpu_type_t        cputype;        /* cpu specifier */

  8.         cpu_subtype_t        cpusubtype;        /* machine specifier */

  9.         uint32_t        filetype;        /* type of file */

  10.         uint32_t        ncmds;                /* number of load commands */

  11.         uint32_t        sizeofcmds;        /* the size of all the load commands */

  12.         uint32_t        flags;                /* flags */

  13. };复制代码
复制代码

可以用 otool -h 命令查看

load commmand直接跟在 header 部分的后面,结构定义如下

  1. /*

  2. * The load commands directly follow the mach_header.  The total size of all

  3. * of the commands is given by the sizeofcmds field in the mach_header.  All

  4. * load commands must have as their first two fields cmd and cmdsize.  The cmd

  5. * field is filled in with a constant for that command type.  Each command type

  6. * has a structure specifically for it.  The cmdsize field is the size in bytes

  7. * of the particular load command structure plus anything that follows it that

  8. * is a part of the load command (i.e. section structures, strings, etc.).  To

  9. * advance to the next load command the cmdsize can be added to the offset or

  10. * pointer of the current load command.  The cmdsize for 32-bit architectures

  11. * MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple

  12. * of 8 bytes (these are forever the maximum alignment of any load commands).

  13. * The padded bytes must be zero.  All tables in the object file must also

  14. * follow these rules so the file can be memory mapped.  Otherwise the pointers

  15. * to these tables will not work well or at all on some machines.  With all

  16. * padding zeroed like objects will compare byte for byte.

  17. */

  18. struct load_command {

  19.         uint32_t cmd;                /* type of load command */

  20.         uint32_t cmdsize;        /* total size of command in bytes */

  21. };复制代码
复制代码

一个查看Mach-O结构的工具  MachOView

http://sourceforge.net/projects/machoview/files/current/

第3部分是segments, 每个segment含有0个到多个sections
每个section都含有数据或代码
每个secgment都定义了一个虚拟内存的区域, 动态连接器 把这个区域映射到进程的地址空间。

在用户级的完全链接后的Mach-O 文件中,最后一个segement是__LINKEDIT段。
这个segment含有 link edit 信息的表,比如符号表,字符串表,等。

segment通过指定一个in-memory size就可以在运行时要求比实际磁盘中更多的大小
连接器生成的__PAGEZERO段, 有一个虚拟内存大小,而在磁盘上的空间是0. 因为__PAGEZERO不包含数据,所以不需要占用任何磁盘空间

静态链接器 会生成一个 __PAGEZERO段 作为可执行文件的第1个段。这个段位于虚拟内存的0地址, 并没有保护权限设置。这样就可保证程序访问NULL指针时,会立刻crash. 该段的大小是一个 当前的体系结构的完整的虚拟内存页面的大小(对于arm,intel 和powerpc都是4096个字节)

__TEXT段 含有可执行代码和只读的数据。 为了让内核将它 直接从可执行文件映射到共享内存, 静态连接器设置该段的虚拟内存权限为不允许写。当这个段被映射到内存后,可以被所有进程共享。(这主要用在frameworks, bundles和共享库等程序中,也可以为同一个可执行文件的多个进程拷贝使用)

__LINKEDIT段 含有为动态链接库使用的原始数据,比如符号,字符串,重定位表条目等等。

节/Section

一个段可能含有多个节。
__TEXT, __text 可执行机器码
__TEXT, __cstring 常量C字符串

  1. /*

  2. * The segment load command indicates that a part of this file is to be

  3. * mapped into the task's address space.  The size of this segment in memory,

  4. * vmsize, maybe equal to or larger than the amount to map from this file,

  5. * filesize.  The file is mapped starting at fileoff to the beginning of

  6. * the segment in memory, vmaddr.  The rest of the memory of the segment,

  7. * if any, is allocated zero fill on demand.  The segment's maximum virtual

  8. * memory protection and initial virtual memory protection are specified

  9. * by the maxprot and initprot fields.  If the segment has sections then the

  10. * section structures directly follow the segment command and their size is

  11. * reflected in cmdsize.

  12. */

  13. struct segment_command { /* for 32-bit architectures */

  14.         uint32_t        cmd;                /* LC_SEGMENT */

  15.         uint32_t        cmdsize;        /* includes sizeof section structs */

  16.         char                segname[16];        /* segment name */

  17.         uint32_t        vmaddr;                /* memory address of this segment */

  18.         uint32_t        vmsize;                /* memory size of this segment */

  19.         uint32_t        fileoff;        /* file offset of this segment */

  20.         uint32_t        filesize;        /* amount to map from the file */

  21.         vm_prot_t        maxprot;        /* maximum VM protection */

  22.         vm_prot_t        initprot;        /* initial VM protection */

  23.         uint32_t        nsects;                /* number of sections in segment */

  24.         uint32_t        flags;                /* flags */

  25. };复制代码
复制代码

要注意segement的cmdsize要包括它拥有的所有的section的结构的大小

fileoff 是从文件偏移的哪里开始映射到 vmaddr
filesize可以比 vmsize小

更在segment_command后面的就是 它所用于的 section数据结构的数组

  1. /*

  2. * A segment is made up of zero or more sections.  Non-MH_OBJECT files have

  3. * all of their segments with the proper sections in each, and padded to the

  4. * specified segment alignment when produced by the link editor.  The first

  5. * segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header

  6. * and load commands of the object file before its first section.  The zero

  7. * fill sections are always last in their segment (in all formats).  This

  8. * allows the zeroed segment padding to be mapped into memory where zero fill

  9. * sections might be. The gigabyte zero fill sections, those with the section

  10. * type S_GB_ZEROFILL, can only be in a segment with sections of this type.

  11. * These segments are then placed after all other segments.

  12. *

  13. * The MH_OBJECT format has all of its sections in one segment for

  14. * compactness.  There is no padding to a specified segment boundary and the

  15. * mach_header and load commands are not part of the segment.

  16. *

  17. * Sections with the same section name, sectname, going into the same segment,

  18. * segname, are combined by the link editor.  The resulting section is aligned

  19. * to the maximum alignment of the combined sections and is the new section's

  20. * alignment.  The combined sections are aligned to their original alignment in

  21. * the combined section.  Any padded bytes to get the specified alignment are

  22. * zeroed.

  23. *

  24. * The format of the relocation entries referenced by the reloff and nreloc

  25. * fields of the section structure for mach object files is described in the

  26. * header file .

  27. */

  28. struct section { /* for 32-bit architectures */

  29.         char                sectname[16];        /* name of this section */

  30.         char                segname[16];        /* segment this section goes in */

  31.         uint32_t        addr;                /* memory address of this section */

  32.         uint32_t        size;                /* size in bytes of this section */

  33.         uint32_t        offset;                /* file offset of this section */

  34.         uint32_t        align;                /* section alignment (power of 2) */

  35.         uint32_t        reloff;                /* file offset of relocation entries */

  36.         uint32_t        nreloc;                /* number of relocation entries */

  37.         uint32_t        flags;                /* flags (section type and attributes)*/

  38.         uint32_t        reserved1;        /* reserved (for offset or index) */

  39.         uint32_t        reserved2;        /* reserved (for count or sizeof) */

  40. };复制代码
复制代码

其中, addr 指定这个section在虚拟内存中的地址
offset 制定这个section在可执行文件中 的偏移
reloff 第1个重定位条目在文件中的偏移

  1. /*

  2. * The linkedit_data_command contains the offsets and sizes of a blob

  3. * of data in the __LINKEDIT segment.

  4. */

  5. struct linkedit_data_command {

  6.     uint32_t        cmd;                /* LC_CODE_SIGNATURE or LC_SEGMENT_SPLIT_INFO */

  7.     uint32_t        cmdsize;        /* sizeof(struct linkedit_data_command) */

  8.     uint32_t        dataoff;        /* file offset of data in __LINKEDIT segment */

  9.     uint32_t        datasize;        /* file size of data in __LINKEDIT segment  */

  10. };复制代码
复制代码

可以用 pagestuff mybinary -a 来查看

File Page 144 contains data of code signature
File Page 145 contains data of code signature

签名动作会修改可执行文件
对一个程序进行签名,会修改它的主执行文件。
1)如果你的程序有一个自验证模式,检查到文件被改变,那么你的代码会拒绝运行
2)如果在签名前附加了数据到 可执行文件上,那么签名的过程中,这些附加数据可能会被删除,或者放到其他位置
如果签名后,再次修改可执行文件,或者bundle它们, 代码签名验证引擎 会觉察到这些改变,并做适当的动作。

https://bitbucket.org/ronaldoussoren/macholib

macholib can be used to analyze and edit Mach-O headers, the executable
format used by Mac OS X.

签名后的变化
header部分 load cmd的数目加1, load cmd的size 加 16

__LINKEDIT的load command有变化, vm size 和 file size都增加了

然后在 load command 数组的最后添加了一个
cmd LC_CODE_SIGNATURE
cmdsize 16
dataoff 4176
datasize 5184

链接地址;http://www.1000phone.net/thread-7879-1-6.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值