环境 & 工具

 

macOS Sierra 10.12.4
Xcode 8.3.1
Jailbreak iPad 8.4
No Jailbreak iPhone 10.1.1

影响因素

 

  • _CodeSignature
  • 二进制文件
  • embedded.mobileprovision
  • entitlements

手动

Developer 环境

 

  AppStore 上下载的应用是加壳的,是不能直接用于重签名的。为什么呢? 现在的我不清楚,如果我去实现的话,可以在 codesign 在签名时可以判断代码段是否已经加密了,如果加密过证明已经处理了,就不去签名。二进制的签名依然是苹果服务器上的私钥的签名,在安装过程中,去验证二进制的签名时,无法匹配,因此安装失败。
 
  重签名需要已经脱壳的应用,可以手动/商店下载一个已经脱壳的应用。

以酷狗音乐为例

  1. 解压 .iPa
  2. cdkugou.app
  3. 删除应用中的 _CodeSignature 目录
  4. 从自己的其他应用的 .app 文件中,拷贝一份 embedded.mobileprovisionkugou.app 目录下
  5. 用脱壳后的二进制文件替换掉原来的。
  6. 找到重签名的 sign 值(钥匙串)与 entitlement 文件
  7. codesign 完成签名操作

entitlement 文件的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>XXXX.包名</string>
<key>com.apple.developer.team-identifier</key>
<string>XXXX</string>
<key>get-task-allow</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>XXXX.包名</string>
</array>
</dict>
</plist>
1
2
3
➜ blog-52 /usr/bin/codesign --force --sign 签名值 --entitlements Runtrace.app.xcent --timestamp=none kugou.app
kugou.app: replacing existing signature
➜ blog-52

 
  签名完 .app 需要打包成 .ipa 文件,可以将 .app 拖入到 .iTunes 来生成 .ipa
  
  

 

在越狱设备上报

 

在非越狱设备上报

  
  修改 info.plist 的包名,重新制作 .ipa ,再次尝试
  
  在越狱与非越狱设备上都能正常安装,打开不闪退,表明已经过了 Apple 的签名检查了。

AdHoc 环境

 
 
  操作与 Developer 环境类似,但 embedded.mobileprovision 需要换成 AdHoc 的描述文件,同时 entitlement 文件需要处理,再 Xcode 直接 Archive 工程,照着日志中的路径查找,得到的 entitlement 还是开发环境的,在当前环境下是无效的。

下面是一个 entitlement 的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>XXXX.包名</string>
<key>aps-environment</key>
<string>production</string>
<key>com.apple.developer.team-identifier</key>
<string>XXXX</string>
<key>get-task-allow</key>
<false/>
<key>keychain-access-groups</key>
<array>
<string>XXXX.包名</string>
</array>
</dict>
</plist>

 

  与上面不同之处在于 get-task-allowfalse ,同时增加了 aps-environment 这个节点。如何找到的?主要还是通过对比工具比较出用 ios-app-signer 工具签名与 codesign 签名后,两个 .app 包的 4 个影响因素的差异,最后发现两者的决定性差异在二进制文件中。

 

小插曲

 
  在越狱设备上,用开发的 sign 签名也能成功安装,但在非越狱上无法安装,目标主要还是在非越狱设备上,越狱应该是会影响应用签名认证的这个过程。

工具

 
  关于重签名的工具还是挺多的,就说我使用过的。在非越狱设备上要过签名的认证,本质上来说应该都是依赖于 codesign 这个原生的工具的。   

ios-app-signer

Swift 开发,主界面如下

 

选签名证书 + 描述文件就可以了,操作也非常简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//MARK: Codesigning
func codeSign(file: String, certificate: String, entitlements: String?,before:((file: String, certificate: String, entitlements: String?)->Void)?, after: ((file: String, certificate: String, entitlements: String?, codesignTask: AppSignerTaskOutput)->Void)?)->AppSignerTaskOutput{
let useEntitlements: Bool = ({
if entitlements == nil {
return false
} else {
if fileManager.fileExistsAtPath(entitlements!) {
return true
} else {
return false
}
}
})()
if let beforeFunc = before {
beforeFunc(file: file, certificate: certificate, entitlements: entitlements)
}
var arguments = ["-vvv","-fs",certificate,"--no-strict"]
if useEntitlements {
arguments.append("--entitlements=\(entitlements!)")
}
arguments.append(file)
let codesignTask = NSTask().execute(codesignPath, workingDirectory: nil, arguments: arguments)
if let afterFunc = after {
afterFunc(file: file, certificate: certificate, entitlements: entitlements, codesignTask: codesignTask)
}
return codesignTask
}

  其中 codesignPath 就是 let codesignPath = “/usr/bin/codesign” 。大致也是利用 codesign 进行签名。

fastlane sigh resign

  来自 帖子

  fastlane 是一个很棒的工具集,能辅助去解决 iOSMacAndroid 一些繁琐的任务,比如生成截图处理配置文件以及发布应用程序等。

  命令行的操作也非常简单,只是一般在重签名时要传一个 .ipa 地址,这需要处理一下,不像直接用 codesign 或者 ios-app-signer 可以传 .app 文件,中间可能需要用 iTunes 处理下。

操作流程是:

  1. .ipa 地址
  2. 选择 sign
1
2
3
4
5
6
7
8
9
10
[WARNING] You are calling sigh directly. Usage of the tool name without the `fastlane` prefix is deprecated in fastlane 2.0
Please update your scripts to use `fastlane sigh resign` instead.
Path to ipa file: /Users/Jason/Music/iTunes/iTunes\ Media/Mobile\ Applications/kugou.ipa
[00:05:56]: Available identities:
iPhone Developer: xxxx xxxxx (576J77ZA38)
DE64343206CB84E95C5CF22F1C5D346664171B5A
iPhone Developer: xxx@126.com (VRZB43ZE67)
...
Signing Identity:

里面在对动态库签名时,有如下的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
for framework in "$FRAMEWORKS_DIR"/*
do
if [[ "$framework" == *.framework || "$framework" == *.dylib ]]
then
log "Resigning '$framework'"
# Must not qote KEYCHAIN_FLAG because it needs to be unwrapped and passed to codesign with spaces
# shellcheck disable=SC2086
/usr/bin/codesign ${VERBOSE} ${KEYCHAIN_FLAG} -f -s "$CERTIFICATE" "$framework"
checkStatus
else
log "Ignoring non-framework: $framework"
fi
done

总结

 
  本文主要以 codesign 指令的方式实现了重签名中比较简单的一种情况,同时介绍了几个比较有效的重签名的工具。

参考

  1. ios打包ipa的四种实用方法(.app转.ipa)
  2. iOS证书及ipa包重签名探究
  3. 最简单的重签名应用的方法
  4. iOS: Already installed app is not launching and crashing everytime in launching