一、IPA 的简单认识
首先,我们需要了解一个 ipa 包的结构。ipa 包实际上是一个压缩文件包,解压后会得到一个 Payload 文件夹,其中包含一个 .app 文件夹。进一步进入 .app 文件夹,我们可以看到以下内容:
image.png
这是一个简单的 app 文件夹,实际项目中这里面的文件会很多。总之,以上就是对一个 ipa 包结构的一个简要介绍。需要注意的是,这个结构是通过 Xcode 的 Archive 工具打包的,但不同的包结构可能会有所不同。例如,从 App Store 下载下来的包可能会有多一层包装,但大体结构仍然是相同的。
二、简单的打包
接下来,我们将创建一个新的项目 IPADev 并进行打包。这里我们使用的打包方法并不是使用 Xcode 的 Archive 工具,而是手动打包。以下是项目的配置过程:
0.png
配置完成后,直接按 command+b 键。在 Products 文件夹下,.app 文件变黑了。接着按 Show in Finder 将 .app 文件导入到 Finder 中:
image.png
按照上一节的介绍,我们是否可以通过这个 IPADev.app 手动构建一个 ipa 包呢?答案是可以的。只需将 IPADev.app 放入一个空的 Payload 文件夹中,然后压缩成 zip 文件,将 zip 改成 ipa 即可。最后的结果如下:
image.png
现在 Payload.ipa 就成为一个正规的 ipa 包了。当然,这个包与平时看到的文件名有些不同,手动将其改为 IPADev.app 即可。至于能否安装到真机上,尝试一下就知道答案了。需要注意的是,这个 ipa 包只能安装到一个已在 .app 文件中包含的 embedded.mobileprovision 配置文件中的已注册设备上,与一个 Ad Hoc 包的性质相同。此外,也可以在任意越狱手机上安装。
然而,如果我们手动删除 IPADev.app 中与签名相关的文件再进行压缩,那么这个 ipa 包只能在越狱真机上安装,而不能在非越狱真机上安装,否则会报错。在安装过程中,我们可以明显感觉到越狱真机上的安装速度较快。这说明了 ...
动态库注入,也称为占为己有并添加自定义代码(如动态库)的操作。有许多方法可以实现动态库注入,其中一种相对常规的方法是通过Theos技术生成dylib库。需要注意的是,通过Theos生成的dylib库只能在越狱手机上使用。如果要在非越狱设备上运行,需要进行动态库注入、重签名打包等操作。
以下是动态库注入的步骤:
3.1 资源准备:
- 需要重签名的.app文件;
- 要添加的dylib库;
- 签名配置文件(embedded.mobileprovision);
- 与dylib关联的动态库CydiaSubstrate;
- 动态库注入工具insert_dylib。
3.2 动态库注入:
将hgdev.dylib放入HGSecurityDev.app中,然后执行以下命令:
```bash
./insert_dylib @executable_path/hgdev.dylib HGSecurityDev.app/HGSecurityDev --weak --all-yes HGSecurityDev.app/HGSecurityDev
```
命令格式为:`./insert_dylib ++动态库文件++ ++Mach-O文件++ ++--weak --all-yes++ ++最终生成的 MachO 文件++`
通过otool查看动态库的关联情况:
```bash
otool -L HGSecurityDev.app/HGSecurityDev
```
如果成功注入,会显示关联的动态库信息。
需要注意的是,这个动态库(hgdev.dylib)是在越狱设备上生成的,会默认关联一个越狱设备上特有的动态库(CydiaSubstrate)。可以通过以下命令查看关联情况:
```bash
otool -L HGSecurityDev.app/hgdev.dylib
```
最后,如果希望在非越狱的真机上也能运行,需要手动添加并重新关联CydiaSubstrate。将CydiaSubstrate放入HGSecurityDev.app中,然后执行相应的命令。
以下是重构后的内容:
3. 动态库注入操作完成
在完成动态库注入操作后,接下来需要进行数字签名。
3.1 给相应的文件签名
一般情况下,只要对.app文件、动态库文件和关联的扩展项目进行了修改,这些文件都需要重新签名。
3.1.1 签名前的准备
在对.app文件进行签名之前,需要有一个签名配置文件(embedded.mobileprovision)。如果破解的是一个Ad Hoc包,那么在.app文件中会有一个;如果没有,可以自己准备一个。
先来看一下Xcode是如何签名的:
!image.png
接下来,我们使用的就是这个指令。上图中的.xcent文件,就是签名配置文件(embedded.mobileprovision)转化后的配置文件(后面介绍如何转)。
对于动态库的签名,只要有证书编号即可。查看证书编号的命令如下:
```markdown
security find-identity -v -p codesigning
```
3.2 给动态库签名
给动态库签名的指令很简单,格式为:`codesign -fs`证书编号`Mach-O文件`。分别给两个动态库签名,命令如下:
```markdown
codesign -fs 283729D4DDC7F173281DA85F105982C4B1E3C15E HGSecurityDev.app/CydiaSubstrate
codesign -fs 283729D4DDC7F173281DA85F105982C4B1E3C15E HGSecurityDev.app/hgdev.dylib
```
3.3 给.app文件签名
首先从embedded.mobileprovision文件中提取出entitlements.plist权限文件,命令如下:
```markdown
security cms -D -i embedded.mobileprovision > temp.plist
```
将以下内容重构为一个段落,并保持原有的格式和结构:
```
/usr/libexec/PlistBuddy -x -c 'Print :Entitlements' temp.plist > entitlements.plist
codesign -fs 283729D4DDC7F173281DA85F105982C4B1E3C15E --entitlements entitlements.plist HGSecurityDev.app
生成的 .app 文件如下:
image.png
上面的 CydiaSubtrate 与 hgdev.dylib 是新添加的动态库。至此,重签名的操作已经全部完成,下一步,直接变成 ipa 文件。
为什么需要重签名操作?因为注入动态库之后,对当前的 Mach-O 文件有所修改,破坏了之前的签名,想要保证在非越狱的设备上也能安装,那么就需要重新签名。
3.4 压缩成 ipa 文件:将 HGSecurityDev.app 放入一个空的 Payload 文件夹中,压缩改名为 HGSecurityDev.ipa 即可。生成的包可以直接安装到越狱设备中,也可以安装在非越狱的设备中(前提是要在签名文件中注册与 Ad Hoc 包的性质一样)。
四、注意事项:上面是以我自己创建的一个简单项目为例子,但是通常我们所要重签名的包都是来自 App Store。步骤都是一致的,但是有几点需要注意:必须是未加壳的 Mach-O 文件重签名打包后才能安装于非越狱的设备。重签名生成的 ipa 包一般是不能上线 App Store 的,只能自己使用或者企业账号下使用。这是一个简单的例子,在实际的项目中可能还会有其它的 framework,这样在 .app 文件夹中就会有所有的 framework,那么在重签名的时候需要先给这个 framework 中的 MachO 文件重签名。当我们进入某一个 framework 会发现都有一个 _CodeSignature 文件夹(下一小节会介绍),所以也需要将这些提前重签名。
五、关于签名文件:对于一个 ipa 文件来说,打开 .app 文件夹就会有一个这样的文件夹:image.png
```
在 Mach-O 文件中,每个可执行文件都会包含一个签名文件夹。这个文件夹中的签名信息是针对当前 Mach-O 文件所在目录中的所有文件进行签名的。例如在一个 framework 文件中,也会有一个类似的签名文件夹。然而,我们实际上更关心的是可执行文件的签名文件夹中的签名内容。
需要注意的是,苹果为其数字签名设置了唯一性。但是对于已经在 App Store 上架的应用,其安装到不同的设备上时的签名可能并非唯一。这是因为一旦应用上线,其签名就会固定不变;然而,当应用安装到不同的设备上时,签名可能会有所不同。例如,一个应用在arm-64设备上下载并安装后,其可执行文件将是针对arm-64架构的;而在其他设备上下载并安装时,可能会针对不同架构生成不同的可执行文件。这也是苹果在 App Store 上进行的一种优化。
此外,还有一种情况是用户可以通过其他渠道直接下载 ipa 文件(例如 itools),然后通过这种方式安装应用。这样下载并安装的应用包会是一个胖二进制文件。这种情况下,由于不同的设备可能会针对不同的架构生成不同的可执行文件,因此签名文件也会有所不同。
综上所述,由于不同设备上的可执行文件签名可能存在差异,因此通过检查签名文件来判断当前应用是否被多开变得相当复杂和困难。