逆向(七)重签名

阅读本文前,请确保具有加密和签名的基础,可以查阅iOS安全(二)加密与签名

一、iOS签名机制

iOS签名机制的作用,就是保证安装到用户手机上的App都是经过Apple官方审核、认证、允许部分权限的。

不管是真机调试,还是发布APP,开发者都需要经过一系列复杂的步骤

☞ 生成CertificateSigningRequest.certSigningRequest文件

☞ 生成并获取ios_development.cerios_distribution.cer证书文件

☞ 添加App ID、注册device

☞ 生成并获取*.mobileprovision文件

每一步的作用是什么?

.certSigningRequest.cer.mobileprovision

文件究竟里面包含了什么?有何用处?

##1. Apple 的签名流程

下面针对三种情况下的Apple 签名流程做了一个梗概:

  • 用户从App Store下载的App,是如何进行安全验证的?

  • 开发者Xcode直接安装App,是如何进行安全验证的?

  • 发布App,不管是发布到App Store还是第三方渠道,是如何进行安全验证的?

1.1 App Store 安装

如果APP是从AppStore下载安装的,你会发现里面是没有mobileprovision文件的

它的验证流程会简单很多,大概如下所示

屏幕快照 2018-11-02 14.55.25

1.2 Xcode安装

屏幕快照 2018-11-02 14.55.18

1.3 完整

屏幕快照 2018-11-02 14.55.10

2. iOS签名机制步骤

2.1. 生成Mac设备的公私钥

keychain 里的 “从证书颁发机构请求证书”,这里就本地生成了一对公私钥,保存的 CertificateSigningRequest 就是公钥,私钥保存在本地电脑里。

屏幕快照 2018-11-02 15.54.26

2.2 生成证书

屏幕快照 2018-11-02 15.57.04

2.3 获得证书

ios_development.cer、ios_distribution.cer文件

利用Apple后台的私钥,对Mac设备的公钥进行签名后的证书文件

屏幕快照 2018-11-02 16.00.48

2.4 生成mobileprovision

屏幕快照 2018-11-02 17.08.55

2.5 安全检测

apple_detect

p12

本地私钥,可以导入到其他电脑,用于团队开发。

二、重签名

如果需要将破坏了签名的安装包,安装到非越狱的手机上,需要对安装包进行重签名的操作。

​ 签名.app包,假如没有.app包,只有ipa包,那么直接解压ipa,就可以获得.app包。

进行重签名的包,必须是未加壳的。

再一次强调,必须未加壳。

所以,加壳应用,先进行脱壳

重签名打包后,安装到设备的过程中,可能需要经常查看设备的日志信息:

  • 程序运行过程中:Windows -> Device and Simulators -> View Device
  • 程序安装过程中:Windows -> Device and Simulators -> Open Consel

1、重签.app包

首先,我们讨论最简单的情况,.app包内不包含其他动态库或者App Extension等。

只有应用主程序的Mach-O文件的情况。

1.1 准备

首先必须准备将embedded.mobileprovision文件,必须是付费证书产生的 ,appid,device一定要匹配,并将embedded.mobileprovision放入.app内部

  • 可以通过Xcode自动生成,然后在编译后的APP包中找到;
  • 可以去开发者账户中心生成下载;

1.2 查看本机证书

重签名要用到证书,所以通过下面命令查看:

1
2
3
$ security find-identity -v -p codesigning
1) F11EAA6593D8BBE******3AA95C19BE66CB8250 "iPhone Distribution: **** Weng (69*****F36)"
2) BC4FF0F29BD938EC****3AA5271F71D64894B60 "iPhone Developer: **** Weng (7R*****BXZ)"

1.3 生成权限文件

embedded.mobileprovision文件中提取出entitlements.plist权限文件。

1
2
3
$ security cms -D -i embedded.mobileprovision > temp.plist

$ /usr/libexec/PlistBuddy -x -c 'Print :Entitlements' temp.plist > entitlements.plist

1.4 签名

1)app包签名

对.app包进行签名

1
$ codesign -fs 证书ID或名称 --entitlements entitlements.plist xxx.app

实例:

1
2
$ codesign -fs BC4FF0F29******A5271F71D64894B60 --entitlements entitlements.plist CodesignApp.app
CodesignApp.app: replacing existing signature

2)打包ipa

新建Payload文件夹,将.app安装包放入,压缩成zip包,并将后缀名改名为.ipa即可。

1.5 GUI工具一步达成

只需要将embedded.mobileprovision拷贝到.app包内。然后,采用iOS App Signer来一步达成。

屏幕快照 2018-11-02 22.18.33

  • 只要在Input File中输入.app文件路径,只针对.app包签名,.app内部动态库需要单独签名。
  • iReSign 与该功能类似,但是操作比上面多。
  • 签名完成之后会导出ipa

2. 含动态库的.app包

包含动态库也分两种情况:

  • 从App Store下载的包中包含动态库、App Extension等;
  • Tweak项目中,需要加载我们自己开发的插件;

2.1 App Store下载.app包重签名

  1. 移除.app包内部_CodeSignature文件夹。
  2. .app包内的所有动态库(.framework、.dylib)、App Extension(PlugIns 文件夹,拓展名为appex)、Watch App(Watch文件夹)都需要进行重新签名

查看可用证书:

1
$ security find-identify -v -p codesigning

签名:

1
2
$ cd .app内部目录
$ codesign -fs 证书ID或名称 xxx.dylib
  1. embedded.mobileprovision拷贝到.app包内

  2. iOS App Signer对整个.app包进行重签名,得到ipa包。

2.2 tweak项目

我们在theos编译后生成的是动态库,现在需要打包到Mach-O文件,并通过签名安装到非越狱手机上。

通过Theos开发动态库插件(dylib)

  • 默认都依赖于/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate
  • 如果要将动态库插件打包到ipa中,也需要将CydiaSubstrate打包到ipa中,并且修改下CydiaSubstrate的加载地址。

下面均以test开头为例:

1)准备

  • test.app
    • 假设test.app内Mach-O为testmach
    • 通过MJAppTool找到路径,拷贝到电脑
    • 假如app未脱壳,先脱壳获取ipa,将ipa拷贝到电脑,得到.app,然后进行一下操作
  • tweak_test.dylib
    • theos开发得到的动态库插件
    • /Library/MobileSubstrate/DynamicLibraries
  • CydiaSubstrate
    • /Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate

2)流程

☞ 移除.app包内部_CodeSignature文件夹。

embedded.mobileprovision拷贝到.app包内。

☞ 将②③放入①中:直接拷贝,注意注意!!!确保①②③处于同级目录!!!

☞ 将②插入①中:利用insert_dylib

☞ 更改②中加载③的地址:利用install_name_tool

☞ 且②③需要单独签名:利用codesign

注意注意:看①中.app内是否有其他动态库,假如有,还是要!!!单独签名!!!

☞ 再给①签名:利用iOS App Signer,得到ipa包

3)insert_dylib

insert_dylib作用就是将tweak_test.dylib动态库插入到.app内testmach主程序的可执行文件中。

a. 下载源码

https://github.com/Tyilo/insert_dylib

b. 编译

源码下载后,打开工程,Edit Scheme中以Release编译,然后在Product中,找到命令行程序。

屏幕快照 2018-11-02 22.53.41

将其,移动到/usr/local/bin即可。

c. 使用
1
2
3
$ insert_dylib  动态库加载路径  Mach-O文件
//or,假如新旧名称一样,就会覆盖
$ insert_dylib 动态库加载路径 原来Mach-O文件 新Mach-O文件
  • --weak:以weak方式加载动态库,即使动态库找不到也不会保存。

  • --all-yes:后面所有的选择都为yes

  • insert_dylib的本质是往Mach-O文件的Load Commands中添加了一个LC_LOAD_DYLIB或

LC_LOAD_WEAK_DYLIB

d.实例

假如Mach-O文件Testtweak_test.dylib处在同一目录下。

这里用到一个环境变量:

@executable_path 代表Mach-O可执行文件目录下寻找动态库

1
2
3
$ cd test.app内部目录
//覆盖原来mach-o
$ insert_dylib @executable_path/tweak_test.dylib testmach testmach --weak --all-yes

4)更改动态库加载地址

可以使用install_name_tool修改Mach-O文件中动态库的加载地址,用法如下:

1
$ install_name_tool  -change 旧地址  新地址  Mach-O文件

此处我们需要修改tweak_test.dylib中加载CydiaSubstrate的地址:

屏幕快照 2018-11-03 14.44.37

由于tweak_test.dylibCydiaSubstrate处于同级目录,这里用到另一个环境变量:

@loader_path 代表动态库所在目录

1
$ install_name_tool  -change  /Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate  @loader_path/CydiaSubstrate tweak_test.dylib

修改之后:

屏幕快照 2018-11-03 14.46.34

这样一来,dylib就会从本地目录加载CydiaSubstrate

5)签名动态库

.app`包内的所有动态库(.framework、.dylib)、App Extension(PlugIns 文件夹,拓展名为appex)、Watch App(Watch文件夹)都需要进行重新签名。

1
2
$ cd .app内部目录
$ codesign -fs 证书ID或名称 xxx.dylib

6)其他

  • 查看Mach-O动态库依赖信息

    看看我们Mach-O是否已经加载了tweak生成的动态库,或者查看动态库加载的动态库:

    1
    - $ otool -L Mach-O文件(可以是动态库,动态库本身就是Mach-O文件)
  • sigh

    fastlane工具之一,用于获取provisioning文件

    1
    $ sudo gem install sigh
  • 假如app只支持iPhone,不支持iPad,可以直接通过修改Info.plist文件中的相关配置即可,删除Support Device;

参考

工具

  1. AppBox
  2. code signing A new approach to code signing
  3. insert_dylib
  4. iOS App Signer

链接

  1. Apple Code Signing Guide
  2. Inside Code Signing 中文
  3. iOS Code Signing: Under The Hood
  4. iOS App 签名的原理
  5. 漫谈iOS程序的证书和签名机制