实践篇:iOS 应用重签名 (下)

导语

 

  本文主要描述了在包含多 target 与 注入 dylib 的场景下该如何进行重签名的操作。

环境 & 工具

 

macOS Sierra 10.12.4
Xcode 8.3.1
Jailbreak iPad 8.4
No Jailbreak iPhone 10.1.1
yololib
theos
mobiledevice
Wechat 6.5.7

target

 

  在 Apple 官方的Code Signing Guide 中提到参与签名的有二进制文件,库文件,资源文件。微信的 .ipa 包中包含了 PlugIns 目录,里面包含了插件的二进制文件,Watch 目录,其中包含了应用在 Watch OS 平台下的二进制文件。

  该如何签名呢? 创建一个工程,添加了 ShareExtension + Watch OStarget,然后 Archive 看看 Xcode 是如何执行签名流程的。

 

  从上面的截图可知 Xcode 签名的所需要的内容,还是和上篇中说的一致,但是多 target 环境下需要对二进制由内到外进行签名操作,同时每个 target 都需要有各自的描述文件。

  用 otool -l path/to/unix_exec_file | grep -B 2 crypt 来确定是否被加壳了。经过测试发现 Plugins 目录下的二进制是加密的,而 Watch 目录下的二进制并没有被加密

  
  因为加壳的代码要脱壳才能进行重签名,一般会用类似 dumpdecrypted 的工具在运行时通过 dump 的方式来获得脱壳后的文件,因此在这里可以将 PluginsWatch 目录删除,这样处理后,应用就从多 target 就转换为单 target 了。

以微信 6.5.7 版本为例,准备好 AdHoc 类型的描述文件之后,进行如下操作:

  1. 删除应用中的 _CodeSignature 目录
  2. 用脱壳后的二进制文件替换掉原应用的二进制文件
  3. copy 描述文件到应用目录中
  4. 修改 info.plist 中的包名替换为重签名的描述文件对应的包名
  5. 对整个应用的二进制进行签名( codesign ...
  6. 拖拽到 iTunes 生成 .ipa 文件

安装 .ipa 结果成功。

注入 dylib

 

  用 Xcode 中的 OpenDev 模板(需要单独下载),生成要注入到微信中的 dylib,在生成的工程中添加类似下面的方法。

1
2
3
4
5
6
7
8
9

@implementation Dylib

__attribute__((constructor))
static void entry() {
NSLog(@"hello, world!");
}

@end

  ⌘ B 编译生成动态库,用 yololib 将动态库注入到微信的二进制。同时将该动态库拷贝到微信应用的目录中

1
./yololib 目标可执行文件 需注入的dylib

  同样进行重签名操作,拖到 iTunes 中生成 .ipa 文件。用 mobiledevice 工具进行安装操作。

1
$ mobiledevice install_app /path/to/.ipa

❎ 安装失败

错误一: dylib 未重签名

 

  查看设备日志,发现如下输出,可以看出是动态库没有进行签名操作

1
2
<Notice>: SystemUI unknown identifier: 'com.coder.demo'
Apr 17 10:53:17 xiaoguai amfid[12845] <Notice>: /private/var/containers/Bundle/Application/89E48C85-CC8E-4A9E-B6C0-9E1329DDF2AD/WeChat.app/Dylib.dylib not valid: 0xe800801c: No code signature found.

解决方法

1
# codesign --force --sign xxxxxx -a arm64 Dylib.dylib

因为我脱壳的是 arm64 的二进制,所以可以通过 -a 指定对动态库的具体架构进行签名操作。

错误二: dylib 路径错误

 

  因为 yololib 注入后动态库的执行路径由 @executable_path 指明,所以要确认在执行时能找到对应的动态库二进制。下面就是一个错误的路径

Snip20170417_19

  如果动态库执行路径错误时,可以安装,但是运行就会闪退

解决方法

 

  cdWeChat.app 目录下,确保 yololib 注入后,动态库的执行路径为 @executable_path /Dylib.dylib

结果

  查看设备日志,可以看到动态库已成功注入

总结

 

要注意的是,由于中国的开发者利用免费的证书大量对应用进行重签名,所以目前苹果加上了许多限制,免费开发者的provisioning证书有效时间从之前的30天改为7天,过期后需要重新签名。另外就是一个星期内最多只能申请到10个证书。

 

  本文通过 Xcode 的一次多 target 的工程签名流程入手,了解多 target 的签名顺序。因为重签名需要进行脱壳的操作,因此对多 target 的应用,在不影响的情况下,可删除其他 target 文件,将其转换为单 target。注入的 dylib 需要独立签名,同时使用 yololib 时需要注意执行路径的问题。
  
最后把整体流程再整理下:

  1. 删除应用中的 _CodeSignature 目录
  2. 用脱壳后的二进制文件替换掉原应用的二进制文件
  3. copy 描述文件到应用目录中
  4. 修改 info.plist 中的包名替换为重签名的描述文件对应的包名
  5. 使用 XcodeOpenDev 模板生成 dylib 文件
  6. 对动态库进行签名
  7. 使用 yololib 将动态库注入到二进制文件中
  8. 对整个应用的二进制进行签名( codesign ...
  9. 拖拽到 iTunes 生成 .ipa 文件
  10. 使用 mobiledevice 安装 ipa 文件

参考

  1. 一步一步实现iOS微信自动抢红包(非越狱)
  2. linux连接iOS设备并且安装ipa应用
  3. libimobiledevice
  4. iOSAppHook