逆向Appstore应用(二)

准备工作

代码签名 (code signing) 对一个App来讲至关重要,是iOS系统安全的重要组成部分,决定了App的哪些功能是被授权或者禁止的。尽管各种证书、配置文件等让初学这头痛不已,但确实给用户带来了极大的安全保障。

文件及环境:

  • 一个苹果的认证部门 Apple Worldwide Developer Relations CA颁发的Certificate
  • 基于该Certificate生成的mobileprovision文件
  • 系统环境 OSX 10.11.5

证书及文件

Certificate

Certificate是如何生成的呢?

首先需要开发者生成一个CertificateSigningRequest.certSigningRequest文件,具体步骤为钥匙串访问⟶证书助理⟶从证书颁发机构请求证书,按照提示填写相关信息,保存到磁盘即可。

等到CertificateSigningRequest.certSigningRequest后,通过 openssl asn1parse -i -in CertificateSigningRequest.certSigningRequest查看如下:

这个文件包含:
1,申请者信息
2,申请者公钥,此信息是申请者使用的私钥对应的公钥
3,摘要算法(SHA)和公钥加密算法(RSA)

此文件包含了我的信息,使用了sha1摘要算法和RSA公钥加密算法。苹果的Meber Center在拿到certSigningRequest文件后,将信息记录下来,并签发出相关的证书(Certificate),car证书包含哪些信息呢?又是如何使用certSigningRequest文件中的公钥呢?我们用openssl来看一下证书的内容:

openssl x509 -inform der -in ios_distribution.cer -noout -text

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            05:33:03:2c:57:2a:ad:6c
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority
        Validity
            Not Before: Jul 10 07:45:50 2014 GMT
            Not After : Jul  9 07:45:50 2017 GMT
        Subject:......
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
    Signature Algorithm: sha1WithRSAEncryption
        a8:b8:b5:ea:74:e9:06:d0:52:90:21:10:10:f1:f6:ce:1f:e7:
        73:08:4f:ca:02:f8:73:66:06:36:48:5b:46:7d:ac:be:bd:c4:
        ......
        d5:46:0a:7b         

Data域即为证书的实际内容,与Data域平级的Signature Algorithm实际就是苹果的CA(Certificate Authority)的公钥,Data域包含我的苹果账号信息,其中最为重要的是我的公钥(Subject Public Key Info),这个公钥与我本机的私钥是对应的。当我们双击安装完证书后,KeyChain会自动将这对密钥关联起来,所以在KeyChain中可以看到类似的效果:

后续在程序上真机的过程中,会使用这个私钥,对代码进行签名,而公钥会附带在mobileprovision文件中,打包进app。那么mobileprovision又从哪里来?有什么作用呢?

mobileprovision

首先来看一张图:

在Apple Developer Center通过之前生成的Certificate来生成mobileprovision配置文件,它将授权和沙盒联系了起来,可以用于让应用在你的开发设备上可以被运行和调试,也可以用于内部测试 (ad-hoc) 或者企业级应用的发布。配置文件并不是一个 plist 文件,它是一个根据密码讯息语法 (Cryptographic Message Syntax) 加密的文件(下文中会简称 CMS)。security 也可以解码这个 CMS 格式,那么我们就用 security 来看看一个 mobileprovision 文件内部是什么样子:

$ security cms -D -i example.mobileprovision

你会得到一个 XML 格式的 plist 文件内容输出,DeveloperCertificates 这项,这一项是一个列表,包含了可以为使用这个配置文件的应用签名的所有证书。如果你用了一个不在这个列表中的证书进行签名,无论这个证书是否有效,这个应用都无法运行。ProvisionedDevices,在这一项里包含了所有可以用于测试的设备列表。因为配置文件需要被苹果签名,所以每次你添加了新的设备进去就要重新下载新的配置文件。具体如下:

<?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>DeveloperCertificates</key>
        <array>
            <data>MIIF0DCCBLi......Oo7Clog==</data>
        </array>
  <key>ProvisionsAllDevices</key>
  <true/>
  <key>TeamIdentifier</key>
        <array>
            <string>C789GLWV85</string>
        </array>
  <key>Version</key>
        <integer>1</integer>
</dict>
</plist>

证书(及其对应的私钥)和配置文件(mobileprovision)是签名和打包的两个必要文件,如果要重新签名一个App,就需要在这两个上面动手脚了。

首先来了解一个已经签名了的App包含的内容,$ codesign -vv -d Example.app 会列出一些有关 Example.app 的签名信息:

Executable=/Users/pandora/Desktop/shell/gcdsample/Payload/GCDSample.app/GCDSample
Identifier=com.baidu.GCDSample
Format=app bundle with Mach-O universal (armv7 arm64)
CodeDirectory v=20200 size=851 flags=0x0(none) hashes=19+5 location=embedded
Signature size=4700
Authority=iPhone Developer: 张三 (AFCH46B9XZ)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=Jul 18, 2016, 17:23:01
Info.plist entries=26
TeamIdentifier=RYRPKMVKDL
Sealed Resources version=2 rules=12 files=7
Internal requirements count=1 size=180

Authority=iPhone Developer: 张三 (AFCH46B9XZ)就是我的证书,iPhone Developer是开发使用,如果是发布证书的话则显示为 iPhone Distribution,Identifier是我在 Xcode 中设置的 bundle identifier。TeamIdentifier用于标识我的工作组(系统会用这个来判断应用是否是由同一个开发者发布),可以通过私钥共享的方式进行团队开发,首先,将存储在keychain中的证书所对应的私钥导出为p12文件,其他团队成员将此文件导入自己电脑,然后从member center下载对应的mobileprovision文件,就可以进行真机开发以及打包发布了。

值得一提的是在新发布的Xcode8中新增了支持自动管理证书和自定义管理证书,自动管理证书将会根据你所选择的开发者账号自动为你处理配置文件和签名证书的设置,并且只在必要时进行提醒。这为开发者节省了不少时间和经历。

上面提到证书(及其对应的私钥)和配置文件(mobileprovision)是签名和打包的两个必要文件,那么,mobileprovision在哪里呢?

App在签名的过程中会在程序包中新建一个叫做_CodeSignatue/CodeResources 的文件,这个文件中存储了被签名的程序包中所有文件的签名。可以查看plist 格式文件,它不光包含了文件和签名的列表,还包含了一系列规则,这些规则决定了哪些资源文件应当被设置签名。在 CodeResources文件中会有4个不同区域,其中的rules和files是为老版本准备的,而 files2和rules2是为新的第二版的代码签名准备的。最主要的区别是在新版本中你无法再将某些资源文件排除在代码签名之外,在过去(OS X 10.9.5 之前)你是可以的,只要在被设置签名的程序包中添加一个名为 ResourceRules.plist的文件,这个文件会规定哪些资源文件在检查代码签名是否完好时应该被忽略。但是在新版本的代码签名中,这种做法不再有效。在新版本的代码签名规定中,所有的代码文件和资源文件都必须设置签名,不再可以有例外,一个程序包中的可执行程序包,例如扩展 (extension),是一个独立的需要设置签名的个体,在检查签名是否完整时应当被单独对待。

所以,比如微信这种多target的App,在做重签名的时候,不仅是主工程,还包括watch app及其他extension,都需要重新签名才可以。

以开源中国为例,先从Appstore下载ipa文件,首先执行$ unzip oschina.ipa,解压ipa包,进入Payload文件夹内,找到iosapp.app包,$ codesign -vv -d oschina.app 会列出一些有关 Example.app 的签名信息,通过security命令产看keychain中已经安装的证书文件$ security find-identity -p codesigning,显示结果如下:

Policy: Code Signing
  Matching identities
  1) C552814957BC5691121564774AC86E036B9E2AEE "iPhone Developer: abc (WGDSKET7K5)" (CSSMERR_TP_CERT_EXPIRED)
  2) 630648B3BF32E6D349EDE08C4517CAFA9B12FD6B "iPhone Developer: def (UX59QF88DD)" (CSSMERR_TP_CERT_EXPIRED)
  
  Valid identities only
  1) 32F000F9C845C6626E8E18919E58C386065C5D16 "iPhone Distribution: abc Co.,Ltd."
  2) 38A279804C22853C3F2575FD06BF26E225C08569 "iPhone Distribution: def Co., Ltd."

Matching identities下显示所有已经安装的证书,Valid identities only代表当前可用的证书。

真正的开始

由于Appstore的的应用都是经过DRM加密的,如果想重签名App,需要将从Appstore下载的ipa文件解密,否则就算签名成功,安装成功,app还是会闪退。通过逆向Appstore应用(一)中的方法,可以拿到解密后开源中国iosapp.decrypted文件,替换Payload目录下ios.app内的名为iosapp的二进制文件,此时就可以得到解密后的iosapp.app文件了。在Payload目录下执行:

$ codesign -s "iPhone Distribution: abc" iosapp.app

提示:iosapp.app: is already signed,说明此app文件已经被签名过了,需要加上-f参数:

$ codesign -f -s "iPhone Distribution: abc" iosapp.app

显示:iosapp.app: replacing existing signature,签名成功,执行codesign -vv -d查看签名信息如下:

➜  Payload codesign -vv -d iosapp.app
Executable=/Users/pandora/Desktop/shell/oschina/Payload/iosapp.app/iosapp
Identifier=net.oschina.iosapp
Format=app bundle with Mach-O universal (armv7 arm64)
CodeDirectory v=20200 size=64082 flags=0x0(none) hashes=1997+3 location=embedded
Signature size=4758
Authority=iPhone Distribution: abc.
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=Sep 6, 2016, 18:08:09
Info.plist entries=36
TeamIdentifier=C789GLWV85
Sealed Resources version=2 rules=12 files=473
Internal requirements count=1 size=212

然后,压缩已经签名的Payload文件夹为zip格式,然后修改zip为ipa格式即可得到解密后的ipa文件了。使用同步推安装提示ApplicationVerificationFail,提示认证失败,这是因为配置文件(.mobileprovision)认证失败,决定了某一个应用是否能够在某一个特定的设备上运行,接下来需要给替换开源中国的mobileprovision文件。找到证书"iPhone Distribution: abc"对应的配置文件A.mobileprovision,修改名称为:embedded.mobileprovision,copy至iosapp.app包内,重新压缩转换为ipa文件,安装时依然提示:ApplicationVerificationFail。

这是因为缺少了entitlements文件,它决定了哪些系统资源在什么情况下允许被一个应用使用。简单的说它就是一个沙盒的配置列表,上面列出了哪些行为被允许,哪些会被拒绝,Xcode 会将这个文件作为 --entitlements 参数的内容传给codesign。在 Xcode 的 Capabilities 选项卡下选择一些选项之后, Xcode 会自动生成一个 entitlements文件,然后在需要的时候往里面添加条目。比如将应用添加进了一个 App Group (比如说为了与extensions 共享数据,com.apple.security.application-groups), 或者开启了推送功能 (aps-environment),如果有将它连接到调试器的需求,这就需要将 get-task-allow 设为true等等。

可以通过如下命令查看entitlements文件:

codesign -d --entitlements - /Users/pandora/Desktop/shell/oschina/开源中国\ 3.7.1/Payload/iosapp.app

得到的信息如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!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>WSUBE85MHP.net.oschina.iosapp</string>
            </array>

            <key>com.apple.developer.team-identifier</key>
            <string>WSUBE85MHP</string>

            <key>application-identifier</key>
            <string>WSUBE85MHP.net.oschina.iosapp</string>

        </dict>
</plist>

所以,重新签名一个app时,除了替换Certificate证书与mobileprovision配置文件外,还需要生成对应的entitlements.plist文件,分别执行以下两个命令:

$ security cms -D -i "extracted/Payload/$APPLICATION/embedded.mobileprovision" > t_entitlements_full.plist
$ /usr/libexec/PlistBuddy -x -c 'Print:Entitlements' t_entitlements_full.plist > t_entitlements.plist

t_entitlements.plist内容如下:

<?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>C789GLWV85.com.baidu.abc</string>
    <key>aps-environment</key>
    <string>production</string>
    <key>com.apple.developer.associated-domains</key>
    <string>*</string>
    <key>com.apple.developer.team-identifier</key>
    <string>C789GLWV85</string>
    <key>com.apple.security.application-groups</key>
    <array>
        <string>group.com.baidu.abc</string>
    </array>
    <key>get-task-allow</key>
    <false/>
    <key>keychain-access-groups</key>
    <array>
        <string>C789GLWV85.*</string>
    </array>
</dict>
</plist>

得到t_entitlements.plist后,把它作为参数传递给codesign,重新签名app文件:

codesign -f -s "iPhone Distribution: abc" /Users/pandora/Desktop/shell/oschina/Payload/iosapp.app/ --entitlements t_entitlements.plist

最后,压缩Payload文件夹,转化为ipa格式的文件,终于安装成功!本次重签名未更改bundleID,安装的时候会覆盖之前从Appstore下载的应用。如果希望两个或多个App共存的话,需要先替换App包中Info.plist的Bundle identifier的值:

/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.baidu.abc" ./Payload/iosapp.app/Info.plist

然后再重新执行:

codesign -f -s "iPhone Distribution: abc" /Users/pandora/Desktop/shell/oschina/Payload/iosapp.app/ --entitlements t_entitlements.plist

就得到了更改bundle id后的App包,将其压缩转换为ipa文件,使用同步堆安装至手机,就可以实现多个相同的App共存了。总结,共需6步:

#1,解密二进制文件
#2,替换embedded.mobileprovision
#3,修改Bundle ID
$ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.baidu.bac" ./Payload/iosapp.app/Info.plist
#4,生成mobileprovision证书对应的entitlements文件
$ security cms -D -i "./Payload/iosapp.app/embedded.mobileprovision" > t_entitlements_full.plist
$ /usr/libexec/PlistBuddy -x -c 'Print:Entitlements' t_entitlements_full.plist > t_entitlements.plist
#5,将Certificate和entitlements作为参数,传递给codesign签名
$ codesign -f -s "iPhone Distribution: abc" /Users/pandora/Desktop/shell/demo/oschina/Payload/iosapp.app/ --entitlements t_entitlements.plist
# 成功提示:replacing existing signature
#6,压缩签名后的Payload文件夹,转换zip为ipa格式,安装即可。

参考:

ObjC中国

iOS重签名探索

Resigning 3rd party apps

漫谈iOS程序的证书和签名机制

iOS 冰与火之歌番外篇 - App Hook 答疑以及 iOS 9 砸壳

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

推荐阅读更多精彩内容

  • 笔者接触打包已经一段时间了,但一直对签名都是似懂非懂,最近从加密数论知识起回看这部分知识,感觉还是有很多不懂的地方...
    luonaerduo阅读 1,154评论 0 3
  • 学习路线 学前须知 如何防止被窃听? 如何加解密 密码的类型 根据秘钥的使用方法,可以将密码分为了两类 对称密码 ...
    Rathen阅读 1,386评论 1 4
  • 1. 应用签名 应用签名原理回顾 上一篇博客“IOS 逆向开发(三)应用签名”中详细讲解了IOS 应用签名,证书的...
    孔雨露阅读 2,426评论 0 4
  • 引言 关于开发证书配置(Certificates & Identifiers & Provisioning Pro...
    Damen_9527阅读 9,356评论 0 4
  • 窗外是云 团团簇簇的云多像是一处村庄 去找吧 弯弯的土路,深深的机井 还有那片种了豌豆的打麦场 每一处场景都在这云...
    双枪老太阅读 154评论 0 2