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

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

背景知识

所有的可执行文件,库文件都需要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能显示更详细的签名信息

codesign -dvvvv debugserver
Executable=/private/tmp/x/debugserver
Identifier=debugserver
Format=Mach-O thin (armv7)
CodeDirectory v=20100 size=900 flags=0x0(none) hashes=37+5 location=embedded
CDHash=577b90c4091310762cbd2350e4e32ee919deccf2
Signature size=1599
Authority=iPhone Developer
Signed Time=Feb 9, 2012 11:29:10 PM
Info.plist=not bound
Sealed Resources=none
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 0x00043908
size 0x000002fc
offset 272648
align 2^2 (4)
reloff 0
nreloc 0
flags 0x00000000
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 0x00000000 r1 0x00000000 r2 0x00000000 r3 0x00000000
r4 0x00000000 r5 0x00000000 r6 0x00000000 r7 0x00000000
r8 0x00000000 r9 0x00000000 r10 0x00000000 r11 0x00000000
r12 0x00000000 sp 0x00000000 lr 0x00000000 pc 0x00002000
cpsr 0x00000000

可以看到 start 的地址是 0x2000

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 找到

/*
* The 32-bit mach header appears at the very beginning of the object file for
* 32-bit architectures.
*/
struct mach_header {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
};

可以用 otool -h 命令查看

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

/*
* The load commands directly follow the mach_header. The total size of all
* of the commands is given by the sizeofcmds field in the mach_header. All
* load commands must have as their first two fields cmd and cmdsize. The cmd
* field is filled in with a constant for that command type. Each command type
* has a structure specifically for it. The cmdsize field is the size in bytes
* of the particular load command structure plus anything that follows it that
* is a part of the load command (i.e. section structures, strings, etc.). To
* advance to the next load command the cmdsize can be added to the offset or
* pointer of the current load command. The cmdsize for 32-bit architectures
* MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple
* of 8 bytes (these are forever the maximum alignment of any load commands).
* The padded bytes must be zero. All tables in the object file must also
* follow these rules so the file can be memory mapped. Otherwise the pointers
* to these tables will not work well or at all on some machines. With all
* padding zeroed like objects will compare byte for byte.
*/
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
};

一个查看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字符串

/*
* The segment load command indicates that a part of this file is to be
* mapped into the task's address space. The size of this segment in memory,
* vmsize, maybe equal to or larger than the amount to map from this file,
* filesize. The file is mapped starting at fileoff to the beginning of
* the segment in memory, vmaddr. The rest of the memory of the segment,
* if any, is allocated zero fill on demand. The segment's maximum virtual
* memory protection and initial virtual memory protection are specified
* by the maxprot and initprot fields. If the segment has sections then the
* section structures directly follow the segment command and their size is
* reflected in cmdsize.
*/
struct segment_command { /* for 32-bit architectures */
uint32_t cmd; /* LC_SEGMENT */
uint32_t cmdsize; /* includes sizeof section structs */
char segname[16]; /* segment name */
uint32_t vmaddr; /* memory address of this segment */
uint32_t vmsize; /* memory size of this segment */
uint32_t fileoff; /* file offset of this segment */
uint32_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
};

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

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

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

/*
* A segment is made up of zero or more sections. Non-MH_OBJECT files have
* all of their segments with the proper sections in each, and padded to the
* specified segment alignment when produced by the link editor. The first
* segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header
* and load commands of the object file before its first section. The zero
* fill sections are always last in their segment (in all formats). This
* allows the zeroed segment padding to be mapped into memory where zero fill
* sections might be. The gigabyte zero fill sections, those with the section
* type S_GB_ZEROFILL, can only be in a segment with sections of this type.
* These segments are then placed after all other segments.
*
* The MH_OBJECT format has all of its sections in one segment for
* compactness. There is no padding to a specified segment boundary and the
* mach_header and load commands are not part of the segment.
*
* Sections with the same section name, sectname, going into the same segment,
* segname, are combined by the link editor. The resulting section is aligned
* to the maximum alignment of the combined sections and is the new section's
* alignment. The combined sections are aligned to their original alignment in
* the combined section. Any padded bytes to get the specified alignment are
* zeroed.
*
* The format of the relocation entries referenced by the reloff and nreloc
* fields of the section structure for mach object files is described in the
* header file .
*/
struct section { /* for 32-bit architectures */
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint32_t addr; /* memory address of this section */
uint32_t size; /* size in bytes of this section */
uint32_t offset; /* file offset of this section */
uint32_t align; /* section alignment (power of 2) */
uint32_t reloff; /* file offset of relocation entries */
uint32_t nreloc; /* number of relocation entries */
uint32_t flags; /* flags (section type and attributes)*/
uint32_t reserved1; /* reserved (for offset or index) */
uint32_t reserved2; /* reserved (for count or sizeof) */
};

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

/*
* The linkedit_data_command contains the offsets and sizes of a blob
* of data in the __LINKEDIT segment.
*/
struct linkedit_data_command {
uint32_t cmd; /* LC_CODE_SIGNATURE or LC_SEGMENT_SPLIT_INFO */
uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */
uint32_t dataoff; /* file offset of data in __LINKEDIT segment */
uint32_t datasize; /* file size of data in __LINKEDIT segment */
};

可以用 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

https://zhiwei.li/text/2012/02/15/iphone-mach-o文件格式与代码签名/

iPhone Mach-O文件格式与代码签名的更多相关文章

  1. iPhone OS 开发 - 了解并解决代码签名问题

    译者:Jestery 发表时间:2010-04-24浏览量:21082评论数:0挑错数:0 了解并解决代码签名问题 (为保持跟开发环境以及APPLE开发者社区网站结构对应,一些名词未作翻译) 绝大多数 ...

  2. iOS代码签名理解

    前言 做了几年iOS app coder了,对于证书的生成.使用流程烂熟于心,然而对于这套机制的原理却一直不甚理解.近来由于工作需要仔细研究了一下,特将自己的学习经验记录于此,以供大家学习指正. 问题 ...

  3. IOS证书/私钥/代码签名/描述文件

    1.   相关资源 (1)   钥匙串程序(常用工具->钥匙串),用于创建证书请求.安装证书.导出私钥等 (2)   IOS开发中心:https://developer.apple.com/de ...

  4. 密钥库文件格式[keystore]代码

    密钥库文件格式[keystore]代码 格式    :     JKS 扩展名  :      .jks/.ks 描述    :     [Java Keystore]密钥库的Java实现版本,pro ...

  5. SQL Server安全(6/11):执行上下文与代码签名(Execution Context and Code Signing)

    在保密你的服务器和数据,防备当前复杂的攻击,SQL Server有你需要的一切.但在你能有效使用这些安全功能前,你需要理解你面对的威胁和一些基本的安全概念.这篇文章提供了基础,因此你可以对SQL Se ...

  6. 第六篇 SQL Server安全执行上下文和代码签名

    本篇文章是SQL Server安全系列的第六篇,详细内容请参考原文. SQL Server决定主体是否有必要的执行代码权限的根本途径是其执行上下文规则.这一切都可能复杂一个主体有执行代码的权限,但是却 ...

  7. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  8. Electron 打包Mac安装包代码签名问题解决方案Could not get code signature for running application

    最近一直在做electron应用的打包,集成mac版本的自动更新时出现了问题. Error: Could not get code signature for running application ...

  9. 【译】第六篇 SQL Server安全执行上下文和代码签名

    本篇文章是SQL Server安全系列的第六篇,详细内容请参考原文. SQL Server决定主体是否有必要的执行代码权限的根本途径是其执行上下文规则.这一切都可能复杂一个主体有执行代码的权限,但是却 ...

随机推荐

  1. Llinux,NFS服务搭建(文件共享)

    NFS配置文件权限参数说明(/etc/exports) 1.rw :表示可读写权限. 2.ro :表示只读权限. 3.sync :请求或写入数据时,数据同步写入到NFS Server的硬盘后才返回.( ...

  2. Git 基础教程 之 删除文件

    ① 手动或命令 rm删除工作区的问价:       git checkout -- readme.txt 可恢复       checkout 实际上是用版本库里的替换工作区的版本 ② 删除了工作区文 ...

  3. Spring MVC学习总结(4)——SpringMVC权限管理

    1.DispatcherServlet SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet.     DispatcherServl ...

  4. 转载 - KMP算法

    出处:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html KMP算法 在介绍KMP算法之前,先介绍一下BF算法. 一. ...

  5. CLR与Netframework版本的关系

    CLR有3个版本,详细地址看微软官方文档

  6. 链表快排 & 基于链表的排序

    以前只知道链表做插入(朴素.非二分)排序挺方便的.现在知道了(单)链表进行快速排序也是很好的(只是跟一般的快排的方式不一样). 参考: http://blog.csdn.net/otuhacker/a ...

  7. 怎样从C++代码直接訪问android framework层的WifiService

    说究竟,Java层的service就是就C++层的binder的封装.所以从原理上来讲通过C++代码直接訪问android framework层的service是全然可能的,这篇文章以訪问WifiSe ...

  8. 让cocos2dx支持并通过arm64 编译

    为了要支持64位,请把这个文件直接替换到相应的lib文件夹下.本来是须要改neton_matrix_impl.c里的宏定义, 在 platform/ios/EAGLVIEW.mm中 在neon_mat ...

  9. JAVA基础实例(一)

    1写一个方法,用一个for循环打印九九乘法表 /** *一个for循环打印九九乘法表 */ public void nineNineMultiTable() { for (int i = 1,j = ...

  10. CSS学习(十六)-HSLA颜色模式

    一.理论: 1.HSLA颜色模式 a.HSLA在HSL基础上添加了不透明度,值越大透明度越低 b.HSLA颜色模式的浏览器兼容性和HSL一样,仅仅有较新版本号的主流浏览器才支持 2.RGBA和HSLA ...