iOS逆向 ipa包重签名

[TOC]

先来学习下三个重要概念:
public/private keys, entitlements, and provisioning profiles.

entitlements是嵌入在App里的XML字符串,表示App可以做什么不可以做什么

App里的provisioning profile文件包含entitlements、可以安装到的真机列表、用来验证签名的public key

Public/private keys

Requesting a Certificate From A Certificate Authority
You created a public/private key, sent up the public key to Apple servers (by the .csr file).

You can view the names, or identities, of your public/private key pairs used for signing your applications with the following Terminal command:

security find-identity -p codesigning -v

This command queries the macOS system keychain, looking for valid identities that contain a private key (-v) and whose type can codesign (-p codesigning).

This ouput will display identities that are valid, which can produce a code signed application. If you look for identities that contain the phrase “iPhone Developer], it’s likely that this identity can be used to sign an iOS application on your device.

➜  bin security find-identity -p codesigning -v
  1) D1F90756076CA6CD2495ED5798E146E2426300C0 "iPhone Distribution: Kun Li (2QNTW3GT23)"
  2) 6B9065E80E180DD48807C09F92E4D505812E029C "iPhone Developer: zhoujie_903@163.com (TCDLVFEQHJ)"
     2 valid identities found

Never, ever, delete a private key!

you can export the public certificates using the following command:

security find-certificate -c "iPhone Developer: Derek Selander (8AW8QLCX5U)" -p

This will output the public, x509 certificate of iPhone Developer: Derek Selander (8AW8QLCX5U) to stdout and format it in PEM format.

Use the Terminal command to cat this newly created file:

cat /tmp/public_cert.cer
-----BEGIN CERTIFICATE----MIIFnDCCBISgAwIBAgIIFMKm2AG4HekwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3 
...

This is how you can tell this certificate is in PEM.

From here, you can use the openssl Terminal command to query the public, x509 certificate:

openssl x509 -in /tmp/public_cert.cer -inform PEM -text -noout
  • The x509 option says that the openssl command should be able to work with a x509 certificate.
  • You provide the -in to the path of public_cert.cer with the decoding format of PEM (-inform PEM).
  • You specify you don’t want to output a certificate with the -noout param.
  • But instead, you do want the certificate in a (somewhat) readable “text” format with the -text option.

There’s two ways to display a certificate: DER and PEM.
PEM can be read by the Terminal (since it’s in base64 encoding)
while DER, in highly professional coding terms, will produce gobbledygook and make the Terminal beep a lot.

Entitlements

Embedded in (almost) every compiled application is a set of entitlements: again, this is an XML string embedded in the application saying what an app can and can’t do.

For example, App Groups, iCloud Services, Push Notifications, Associated Domains all will modify the entitlments to your app. These capabilities shown in Xcode are but a small piece of the entitlements on Apple platforms as the majority of them are private to Apple and enforced through code signing.

重点:
Probably the most important entitlement, at least in this book, is the get-task-allow entitlement, found on all your software compiled with a developer certificate. This allows the program in question to be attached to a debugger.

You can view the entitlements of an application through the codesign Terminal command.
Find the entitlements of the macOS Finder application:

codesign -d --entitlements :- /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder
  • The -d option says to display the option immediately following in the command, which is the --entitlements.
  • The - says to print to stdout
  • The : says to omit the blob header and length.

Provisioning profiles

A provisioning profile includes the public x509 certificate, the list of approved devices, as well as the entitlements all embedded into one file.

provisioning profiles默认位置:

~/Library/MobileDevice/Provisioning Profiles/

你和Xcode创建的provisioning profiles以UUID作为文件名,比如fe0c62fd-0f18-4974-821b-84b3337b0c12.mobileprovision

你可以通过security命令查看.mobileprovision文件的内容:

PP_FILE=$(ls ~/Library/MobileDevice/Provisioning\ Profiles/ *mobileprovision | head -1) 
security cms -D -i "$PP_FILE"

the security command which decodes (-D) the cryptographic message syntax (cms) format of the provisioning profile, specifying the input path via the -i option.

  • AppIDName This is the name of the Application ID that is tied to this provisioning profile
  • TeamIdentifier the unique team ID Apple has given me for my team identity
  • Entitlements contains the Entitlements of what the app can and can’t do with this signature.
  • ProvisionedDevices contains an array of approved devices this provisioning profile can install on, given by a device’s UDID.
  • DeveloperCertificates is an array that contains base64-encoded x509 certificates.
  • IsXcodeManaged is a Boolean value that indicates if Xcode manages this provisioning profile.
  • Name which is the name of the provisioning profile that Apple displays to identify the provisioning profiles on https:// developer.apple.com/account/ios/profile/limited.

探索WordPress app

apple商店上下载的ipa是经过加壳的,不能用于重签名。
这里以开源App:Wordpress v10.9 来重签名:
下载地址:https://github.com/wordpress-mobile/WordPress-iOS/releases/tag/10.9

也可以从像PP助手上下载越狱过的App来重签名

The provisioning profile

APP_FILE="/full/path/to/WordPress.app"
security cms -D -i "$APP_FILE/embedded.mobileprovision"

在这个provisioning profile,包含了如下信息:

  • Apple给Automattic, Inc.公司的team identifier为 3TMU3BH3NK.
  • Wordpress app使用了iCloud服务, 因为在entitlements dictionary可以看到com.apple.developer.icloud*等keys. It also looks to make use of certain extension like "App Groups".
  • get-task-allow 是 false, 调试器不能attach, 不能调试

DeveloperCertificates键的值为x509 证书base64编码后的值

CERT_DATA=MIIFozCCBIu...

解码后保存到/tmp/wordpress_cert.cer:

echo "$CERT_DATA" | base64 -D > /tmp/wordpress_cert.cer

通过openssl命令查看证书内容:

openssl x509 -in /tmp/wordpress_cert.cer -inform DER -text -noout

输出如下:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 786948871528664923 (0xaebcdd447dc4f5b)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority
        Validity
            Not Before: Jan 17 13:26:41 2018 GMT
            Not After : Jan 17 13:26:41 2019 GMT
        Subject: UID=PZYM8XX95Q, CN=iPhone Distribution: Automattic, Inc. (PZYM8XX95Q), OU=PZYM8XX95Q, O=Automattic, Inc., C=US

可以看出在“Automattic, Inc”工作的某人用“iPhone Distribution: Automattic, Inc. (PZYM8XX95Q)”签名了这个App

Embedded executables

除主应用外,还包含extensions(share extension, today widgets, 和其它等),./Plugins文件夹里的每个extension都有自己的application identifier和embedded.mobileprovision、签名

_CodeSignature文件夹

在真机的app中有一个_CodeSignature文件夹,里面只包含一个叫CodeResources文件。
它是一个XML plist文件,内容为***.app内的每个非可执行文件的checksum值

可以通过openssl命令自己来计算文件的checksum值:

openssl sha1 -binary "$APP_FILE/AboutViewController.nib" | base64

Apple已开始为Xcode 10创建的ios app从SHA-1 checksums过渡到SHA-256 checksums

重点:
CodeResources文件自身的checksum被嵌入到可执行文件中。这意味着在xxx.app中修改任一文件,甚至增加一个文件夹,不重新签名的话,app都会安装失败。

重签名app

需要做如下的步骤:

  1. 复制有效的provisioning profile文件到xxx.app为embedded.mobileprovision文件
  2. 修改Info.plist的CFBundleIdentifier键的值为provisioning profile文件中包含的application identifier的值.
  3. 以合适的entitlements和provisioning profile中包含的开发者身份来重签名App(合适的entitlements从provisioning profile文件里提取)

你能从
~/Library/MobileDevice/Provisioning Profiles/

https://developer.apple.com/
上得到provisioning profile文件

(Optional)生成有效的provisioning profile文件

替换provisioning profile文件

复制mobileprovision文件为app内的embedded.mobileprovision

PP_PATH=~/Downloads/ProvisProfile_92618.mobileprovision
cp "$PP_PATH" "$APP_FILE/embedded.mobileprovision"

删除Plugins、Watch等文件夹

app里如果有Plugins文件夹时,里面的每个扩展都有自己唯一的application identifier、唯一的provisioning profile。你能用其他唯一的provisioning profile重签名每个扩展,但作为demo,这样做太复杂了,我们选择删除整个Plugins文件夹。

删除这些文件夹后,重签名后的app就没有相应的功能了,但作为演示可以接受。

修改Info.plist文件

可以从provisioning profile提取到application identifier:

security cms -D -i "$PP_PATH" | grep application-identifier -A1

上面的命令得到如下输出:

<key>application-identifier</key> 
<string>H4U46V6494.com.selander.code-signing</string>

通过替换Info.plist中CFBundleIdentifier键的值来修改app的application identifier:

plutil -replace CFBundleIdentifier -string H4U46V6494.com.selander.codesigning "$APP_FILE/Info.plist"

修改WordPress app显示的名字:

plutil -replace CFBundleDisplayName -string "Woot" "$APP_FILE/Info.plist"

提取entitlements

因为entitlements在provisioning profile不是XML,而是字典,为了简单起见:从可执行文件中提取原来entitlements并保存到entitlements.xml文件,再从provisioning profile中提取新的entitlements并替换掉entitlements.xml文件中原来的entitlements

  1. 从可执行文件中提取entitlements并保存到文件:
codesign -d --entitlements :/tmp/entitlements.xml "$APP_FILE/WordPress"
cat /tmp/entitlements.xml
  1. 从provisioning profile生成新的entitlements.xml的模板:
security cms -D -i "$PP_PATH" > /tmp/scratch

使用xpath命令只提取entitlement信息到剪切板:

xpath /tmp/scratch '//*[text() = "Entitlements"]/following-sibling::dict' | pbcopy

现在剪切板包含了有效的entitlements,打开/tmp/entitlements.xml文件,删除<dict>包含的内容,粘帖剪切板的内容

最终的/tmp/entitlements.xml文件内容包含像如下的entitlements信息:

<?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>keychain-access-groups</key>
    <array>
        <string>P9DNHPPVMB.*</string>   
    </array>
    <key>get-task-allow</key>
    <true/>
    <key>application-identifier</key>
    <string>P9DNHPPVMB.com.jason.DeleteMe</string>
    <key>com.apple.developer.team-identifier</key>
    <string>P9DNHPPVMB</string>
</dict>
</plist>

重点:/tmp/entitlements.xml这个文件的格式一定要正确,我在实践时因为xpath .... | pbcopy命令生成了错误的<true />多了一个空格,而生成了不正确的entitlements.xml文件,导致安装成功后但启动app就崩溃

最后签名WordPress app

You now have performed all the setup.
You have a valid signing identity;
you have a valid provisioning profile embedded in the WordPress application at embedded.mobileprovision;
you have removed the Plugins directory;
and you have the entitlements of the new provisioning profile found at /tmp/entitlements.xml.

使用codesign命令用你的身份来重签名App:

codesign -f -s "iPhone Developer: Derek Selander (8AW8QLCX5U)" "$APP_FILE"/Frameworks/*
codesign --entitlements /tmp/entitlements.xml -f -s "iPhone Developer: Derek Selander (8AW8QLCX5U)" "$APP_FILE"

主要脚本代码

命令 文件 功能 命令行
plutil Info.plist 替换CFBundleIdentifier plutil -replace CFBundleIdentifier -string "xxx" Info.plist
security embedded.mobileprovision 二进制解码为文本格式 security cms -D -i xxx.mobileprovision
codesign 可执行文件 提取entitlements codesign -d --entitlements :xxx.xml WeChat
codesign xxx.app 重签名 codesign --deep -f -s "iPhone Developer: xxx@yyy.com (TCDLVFEQHJ)" --entitlements zzz.xml xxx.app
# 定义要重签名的app文件路径、和有效的mobileprovision文件路径
APP_FILE=~/Desktop/WeChat/Payload/WeChat.app
PP_PATH=~/Desktop/ProvisProfile_92618.mobileprovision

# 从mobileprovision文件中提取得到application-identifier(app id或CFBundleIdentifier)
EXTRACTED_ENT="/tmp/extracted_ent"
security cms -D -i "$PP_PATH" > "$EXTRACTED_ENT"
APP_IDENTIFIER=$(/usr/bin/xpath "$EXTRACTED_ENT" '//*[text() = "application-identifier"]/following-sibling::string[1]/text()' 2>/dev/null |  cut -d. -f 2-80 ) 
echo "app id is : $APP_IDENTIFIER"

# 复制mobileprovision文件为app内的embedded.mobileprovision
cp "$PP_PATH" "$APP_FILE/embedded.mobileprovision"

# 删除PlugIns、Watch等文件夹
rm -rf "$APP_FILE/PlugIns"
rm -rf "$APP_FILE/Watch"

# 替换Info.plist内的CFBundleIdentifier、CFBundleDisplayName
plutil -replace CFBundleDisplayName -string "Woot" "$APP_FILE/Info.plist"
plutil -replace CFBundleIdentifier -string ${APP_IDENTIFIER} "$APP_FILE/Info.plist"

# 生成签名app用的entitlements.xml
codesign -d --entitlements :/tmp/entitlements.xml "$APP_FILE/WeChat"
security cms -D -i "$PP_PATH" > /tmp/scratch

# 这名命令有点缺陷:生成的<true />多了一个空格,正确的是<true/>
xpath /tmp/scratch '//*[text() = "Entitlements"]/following-sibling::dict' | pbcopy 
# [不要用剪切板,否则会把上面命令得到剪切板中的内容给覆盖了。把剪切板上的内容粘贴到/tmp/entitlements.xml中]
open /tmp/entitlements.xml  

# 重签名Frameworks、 和app
codesign --deep -f -s "iPhone Developer: zhoujie_903@163.com (TCDLVFEQHJ)" "$APP_FILE/Frameworks/"*
codesign --deep -f -s "iPhone Developer: zhoujie_903@163.com (TCDLVFEQHJ)" --entitlements /tmp/entitlements.xml "$APP_FILE"

# 安装到真机
mobdevim -i "$APP_FILE"

完整详细代码可以参考dsresign

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容