(转)细说iOS代码签名(四)

转自 http://xelz.info/blog/2019/01/11/ios-code-signature-4/,版权归原作者所有

导航

0x06 签名的校验

签名的校验并非一次性完成,在安装、启动、和运行时有着不同的校验规则。

安装

App安装时的校验由位于iOS设备上的/usr/lib/libmis.dylib (dyld_shared_cache)提供。

App的安装是由/usr/libexec/installd完成的,installd会通过libmis.dylib校验ProvisioningProfile、Entitlements及签名的合法性,并递归地校验签名时每一个步骤生成的哈希值:CDHash, Code Directory, _CodeSignature/CodeResources。

$ otool -L installd | grep mis
    /usr/lib/libmis.dylib (compatibility version 1.0.0, current version 1.0.0)   
$ nm installd | grep ValidateSignature
                 U _MISValidateSignatureAndCopyInfo
                 U _kMISValidationOptionValidateSignatureOnly    

启动

进程启动时,loader会先将可执行文件加载到虚拟内存,在加载的过程中mach_loader会自动解析MachO文件中的LC_CODE_SIGNATURE并进行校验,可以参考mach_loader的代码 bsd/kern/mach_loader.c

load_code_signature在解析完签名的数据后会调用mac_vnode_check_singature函数进行验证,而这个函数会被名为AFMI(AppleMobileFileIntegrity)的内核扩展(kext)通过Hook的方式接管,而AFMI只是一层壳,最终也是调用了libmis.dylib来实现签名的校验,这一校验过程基本与安装时一致,防止安装后的篡改。

需要注意的是,加载过程中为了提升加载效率,签名校验并不会去检查Code Directory与实际的代码是否匹配,仅仅只检查了CMS Signature及CDHash的合法性。

运行时

当一页代码被加载到虚拟内存后,会立即触发page fault,此时内核中的vm_fault函数会被调用,紧接着调用vm_fault_enter,在vm_fault_enter的实现中会判断代码页是否需要签名校验,并执行校验的操作,参考代码osfmk/vm/vm_fault.c

kern_return_t vm_fault_enter(...) {
// ...
    /* Validate code signature if necessary. */
    if (VM_FAULT_NEED_CS_VALIDATION(pmap, m, object)) {
        vm_object_lock_assert_exclusive(object);

        if (m->cs_validated) {
            vm_cs_revalidates++;
        }

        /* VM map is locked, so 1 ref will remain on VM object -
         * so no harm if vm_page_validate_cs drops the object lock */
        vm_page_validate_cs(m);
    }
// ...
}

对于宏VM_FAULT_NEED_CS_VALIDATION的解释是

/*
* CODE SIGNING:
* When soft faulting a page, we have to validate the page if:
* 1. the page is being mapped in user space
* 2. the page hasn't already been found to be "tainted"
* 3. the page belongs to a code-signed object
* 4. the page has not been validated yet or has been mapped
for write. */
#define VM_FAULT_NEED_CS_VALIDATION(pmap, page)
((pmap) != kernel_pmap /*1*/ && !(page)->cs_tainted /*2*/ && (page)->object->code_signed /*3*/ && (!(page)->cs_validated || (page)->wpmapped /*4*/))

vm_page_validate_cs会计算当前代码页的哈希值,并与签名中CodeDirectory记录的值进行比对,完成代码签名的验证。如果不符,且不满足系统预设的例外条件,则会向内核发出CS_KILL指令,将进程结束。

至此签名的校验流程就全部完成了。

0x07 越狱与重签名

越狱

越狱之后,签名校验机制会被破坏掉,否则用于实现越狱的代码自身就无法运行。比如在iOS6/7时代,典型的方式是替换 libmis.dylib中的_MISValidateSignature函数,使其永远返回验证成功,简单粗暴但很有效,因此越狱的设备可以不受签名限制运行任意程序。但是单纯解决掉这个函数只是解决了MachO文件的Load问题,运行时仍然会有沙盒和Code Directory的校验,想要对系统完全的控制权必须同时解决掉这两个问题。

由于沙盒机制的实现分散在系统的各个角落,没有简单的方式可以将沙盒一刀切地屏蔽掉,因此一般越狱并不会破坏掉沙盒。但因为越狱设备签名校验机制被绕过,不再会根据embedded.mobileprovision文件检查Entitlements的合法性,因此我们可以在沙盒范围内,声明任意的权限。Code Directory的校验在内核层,破解难度相对较大,并且完全没有必要进行破解,因为Code Directory只是单纯地校验未加密的哈希值而已,只需要按照代码签名的格式做好Code Directory即可。

越狱之父Saurik为此创造了ldid这个工具,用于给越狱设备上的程序制造"假"的签名。使用ldid进行签名只需要指定一个可选的Entitlements文件,签名之后,产生的LC_CODE_SIGNATURE中只会两个有效的Blob,分别是 Code Directory和 Entitlements,并没有最重要的CMS Signature部分,因为_MISCalidateSignature永远都会告诉系统签名是正确的。

$ cp TestCodeSign TestCodeSign.ldid
$ ldid -Sxxx.entitlements TestCodeSign.ldid
$ jtool --sig TestCodeSign.ldid -arch arm64
Blob at offset: 54016 (928 bytes) is an embedded signature
Code Directory (442 bytes)
    ...
 Empty requirement set (12 bytes)
Entitlements (424 bytes) (use --ent to view)

重签名

有的时候出于各种原因,我们需要对一个App进行重签名,然后在自己的设备上进行测试。回顾一下签名的必备条件:

  • 开发者证书,以及对应的密钥
  • Entitlements文件
  • embedded.mobileprovision

开发者证书和密钥我们已经有了,对于Entitlements和embedded.mobileprovision文件,为了确保重签后的App能够正常运行,必须使用和原App相同或者至少包含原App所需权限的Entitlements文件。这个并不难操作,只需要新建一个工程,开启相应的功能,让Xcode自动为我们生成即可。但是Entitlements文件中还有一些跟Team ID和App ID相关的配置,这两个是没有办法伪造的,因为我们不能使用已经被其他开发者注册过的ID。使用自己的ID一般也不会有什么问题,但在某些情况下可能导致最终的程序逻辑出现异常,这根具体的代码实现细节有关。

现在,只要确保有正确的Entitlements文件,Provisioning Profile与Entitlements文件匹配,且包含重签时使用的证书及目标设备的UUID,就可以进行重签名了,如果重签名后无法安装,请检查Provisioning Profile文件是否满足上述条件。

Entitlements文件中还标识了application-identifier,也就是Bundle ID,正常签名的App中,这个值和Info.plist中的CFBundleIdentifier的值是相同的,但实际在签名校验过程中,系统并不会检查二者是否一致。因此即使Entitlements中与Info.plist文件使用了不同的Bundle ID,理论上也不会影响重签名之后的运行。

需要注意,App中除了可执行程序文件外,还会可能会有Frameworks及Plugins,里面都会包含二进制的代码文件,他们的哈希值也会被存储在 _CodeSignature/CodeResources中。所有的二进制代码都必须进行签名,而签名后二进制文件的哈希值就会产生变化,因此需要先对这两个文件夹下的二进制文件进行签名,再对App进行签名。

重签名的基本流程,使用-f参数可以强制覆盖掉已有的签名

$ # 对Frameworks及Plugins中的每一个文件进行签名,此时不需要指定entitlements
$ codesign -f -s "证书名称或者SHA1值" Target.app/Frameworks/xxxxx.framework
$ codesign -f -s "证书名称或者SHA1值" Target.app/Frameworks/libxxxx.dylib
$ ...
$ # 将准备好的Provisioning Profile拷贝到App根目录
$ cp ~/Library/MobileDevice/Provisioning\ Profiles/xxxxx.mobileprovision Target.app/embedded.mobileprovision
$ # 对App进行签名
$ codesign -f -s "证书名称或者SHA1值" --entitlements resign.entitlements Target.app

0x08 References

reference link
Code Signing Guide https://developer.apple.com/...
ASN.1 JavaScript decoder http://lapo.it/asn1js/
Cryptographic Message Syntax (CMS) https://www.ietf.org/rfc/rfc3852.txt
iSign in python https://github.com/saucelabs/isign
CodeSigning (RSACon 2015) http://newosxbook.com/articles/CodeSigning.pdf
jtool http://www.newosxbook.com/tools/jtool.html
mistool http://newosxbook.com/tools/mistool.html
evasi0n7 jailbreak writeup https://geohot.com/e7writeup.html
iOS hacker's handbook https://books.google.com.hk/books?id=1kDcjKcz9GwC
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容

  • 转自 http://xelz.info/blog/2019/01/11/ios-code-signature-3/...
    minap阅读 3,319评论 1 4
  • 如果你看完书中的所有例子,你很可能已经做完你的实验和在已经越狱的iPhone上的研究。因为和许多人一样,几乎所有的...
    fishmai0阅读 15,970评论 2 42
  • 转自 http://xelz.info/blog/2019/01/11/ios-code-signature-2/...
    minap阅读 1,053评论 0 1
  • 转自 http://xelz.info/blog/2019/01/11/ios-code-signature-1/...
    minap阅读 1,552评论 0 1
  • 黑夜包裹着噼噼啪啪的炮声,带着旧日的记忆,一起走向新的一年。家乡的村庄正沉浸在节日的怒欢之中。 青春的那些年头,这...
    大泥沙阅读 416评论 0 1