(轉(zhuǎn))細(xì)說(shuō)iOS代碼簽名(三)

轉(zhuǎn)自 http://xelz.info/blog/2019/01/11/ios-code-signature-3/垃你,版權(quán)歸原作者所有

導(dǎo)航

0x05 CodeSign

萬(wàn)事具備凌摄,只欠東風(fēng)良姆,已經(jīng)具備了簽名所需的所有條件,接下來(lái)就可以開(kāi)始研究簽名的具體過(guò)程了垮媒。

在編譯iOS App時(shí)吮成,Xcode在編譯的打包的流程中會(huì)自動(dòng)進(jìn)行代碼簽名, 可以在編譯日志界面找到一個(gè)Sign的步驟竹捉,內(nèi)部是調(diào)用了codesign這個(gè)命令對(duì)app進(jìn)行簽名

codesign有幾個(gè)關(guān)鍵參數(shù)

  • --sign sign_identity 指定簽名所用的證書(shū),可以指定證書(shū)的名字,比如"iPhone Developer: xxx (xxx)"也可以直接寫(xiě)證書(shū)文件的sha1值豪直,xcode中就是直接指定sha1值的。通過(guò)觀察圖中的sha1值可以看出xcode自動(dòng)選擇了剛申請(qǐng)的最新證書(shū)珠移。
  • --entitlements entitlements_file 指定簽名所需要的entitlements文件弓乙,這里的entitlements文件跟前面看到的并不是同一個(gè)文件末融,而是基于原有entitlements文件,補(bǔ)充上缺省權(quán)限后生成的臨時(shí)文件
<?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>xxxxxxxxxx.test.CodeSign</string>
    <key>com.apple.developer.team-identifier</key>
    <string>xxxxxxxxxx</string>
    <key>get-task-allow</key>
    <true/>
    <key>inter-app-audio</key>
    <true/>
</dict>
</plist>

如果想對(duì)比簽名前后的區(qū)別暇韧,可以在Build Settings中找到Code Signing Identity勾习,選擇Other并將內(nèi)容清除(即設(shè)置為空),即可跳過(guò)代碼簽名懈玻。分別編譯一個(gè)不簽名的版本和簽名的版本巧婶,對(duì)比可以發(fā)現(xiàn)

  • 簽名過(guò)的app中多了一個(gè)_CodeSignature文件夾,里面只有一個(gè)文件CodeResources
  • 還多了一個(gè)embedded.mobileprovision 文件
  • 二進(jìn)制文件的內(nèi)容存在差異涂乌,并且簽名后體積變大了

其中embedded.mobileprovision就是前文提到的Provisioning Profile文件艺栈,它直接被拷貝到了app的根目錄并重命名,在此不再贅述湾盒,重點(diǎn)研究下另外兩個(gè)不同點(diǎn)湿右。

_CodeSignature/CodeResources

首先是_CodeSingature/CodeResources,這是一個(gè)plist文件罚勾,里面保存了app中每個(gè)文件(除了App的可執(zhí)行文件)的明文哈希值

<plist version="1.0">
<dict>
    <key>files</key>
    <dict>
        <key>Base.lproj/Main.storyboardc/Info.plist</key>
        <data>
            MDrKFvFWroTb0+KEbQShBcoBvo4=
        </data>
        ...
    </dict>
    <key>files2</key>
    <dict>
        <key>Base.lproj/Main.storyboardc/Info.plist</key>
        <dict>
            <key>hash</key>
            <data>
                MDrKFvFWroTb0+KEbQShBcoBvo4=
            </data>
            <key>hash2</key>
            <data>
                PpvapAjR62rl6Ym4E6hkTgpKmBICxTaQXeUqcpHmmqQ=
            </data>
        </dict>
        ...
    </dict>
    <key>rules</key>
    ...
    <key>rules2</key>
    ...
</dict>
</plist>

filesfiles2分別是舊版本和新版本的文件列表毅人,而rulesrules2分別是與之對(duì)應(yīng)的規(guī)則說(shuō)明,里面描述了計(jì)算hash時(shí)需要被排除的文件以及每個(gè)文件的權(quán)重尖殃。

files中保存的是每個(gè)文件的sha1值堰塌,而files2中同時(shí)保存了sha1和sha256,因?yàn)閟ha1在計(jì)算機(jī)硬件高度發(fā)達(dá)的今天分衫,已經(jīng)相對(duì)沒(méi)有那么安全了场刑,因此最新的簽名算法中,引入了sha256蚪战。注意牵现,這里的hash值都是base64編碼的明文,有些文章說(shuō)這些值是使用私鑰加密的哈希邀桑,這是很不負(fù)責(zé)任的錯(cuò)誤說(shuō)法瞎疼,通過(guò)幾條簡(jiǎn)單的命令就可以進(jìn)行驗(yàn)證:

$ cat Base.lproj/Main.storyboardc/Info.plist | shasum -a 1
303aca16f156ae84dbd3e2846d04a105ca01be8e  -
$ echo -n 'MDrKFvFWroTb0+KEbQShBcoBvo4=' | base64 -D | hexdump
0000000 30 3a ca 16 f1 56 ae 84 db d3 e2 84 6d 04 a1 05
0000010 ca 01 be 8e
$ # =========== 分割線 ===========
$ cat Base.lproj/Main.storyboardc/Info.plist | shasum -a 256
3e9bdaa408d1eb6ae5e989b813a8644e0a4a981202c536905de52a7291e69aa4  -
$ echo -n 'PpvapAjR62rl6Ym4E6hkTgpKmBICxTaQXeUqcpHmmqQ=' | base64 -D | hexdump
0000000 3e 9b da a4 08 d1 eb 6a e5 e9 89 b8 13 a8 64 4e
0000010 0a 4a 98 12 02 c5 36 90 5d e5 2a 72 91 e6 9a a4

_CodeSignature/CodeResources文件的主要作用是保存簽名時(shí)每個(gè)文件的哈希值,而這些哈希值并不需要都進(jìn)行加密壁畸,因?yàn)榉菍?duì)稱加密的性能是比較差的贼急,全部都加密只會(huì)拖慢簽名和校驗(yàn)的速度。其實(shí)只需要確保這個(gè)文件沒(méi)有被篡改捏萍,自然也就可以確保每個(gè)文件都是簽名時(shí)的原始狀態(tài)太抓,這一點(diǎn)在后續(xù)的內(nèi)容中可以得到驗(yàn)證。

LC_CODE_SIGNATURE

使用otool -l對(duì)比簽名前后的二進(jìn)制文件令杈,可以發(fā)現(xiàn)簽名后二進(jìn)制文件多了一個(gè)名為LC_CODE_SIGNATURE的Load ?

$ otool -l TestCodeSign | tail -n 5
Load ? 21
      cmd LC_CODE_SIGNATURE
  cmdsize 16
  dataoff 54016
 datasize 19888

MachOView中查看如下

代碼簽名是一段純二進(jìn)制的數(shù)據(jù)走敌,可以在https://opensource.apple.com/source/Security/Security-55471/sec/Security/Tool/codesign.c.auto.html 看到一些結(jié)構(gòu)定義,結(jié)合數(shù)據(jù)定義來(lái)分析

// 紅色部分①  Offset: 0xD300 = 54016 LC_CODE_SIGNATURE->dataoff
struct __SuperBlob {
    uint32_t magic;   /* 0xFADE0CC0 = CSMAGIC_EMBEDDED_SIGNATURE */
    uint32_t length;  /* 0x1A1E -> 6686 */
    uint32_t count;   /* 5 */
    CS_BlobIndex index[];  /* 藍(lán)色部分 */
}
// 藍(lán)色部分②  5個(gè)BlobIndex
struct __BlobIndex {
    uint32_t type;    /* 0x0 -> Code Directory */
    uint32_t offset;  /* 0x34 -> 0xD300 + 0x34 = 0xD334 指向綠色③*/
}
struct __BlobIndex {
    uint32_t type;    /* 0x2 -> Requirements */
    uint32_t offset;  /* 0x221 -> 0xD300 + 0x221 = 0xD521 */
}
struct __BlobIndex {
    uint32_t type;    /* 0x5 -> Entitlements */
    uint32_t offset;  /* 0x2CD -> 0xD300 + 0x2CD = 0xD5CD */
}
struct __BlobIndex {
    uint32_t type;    /* 0x1000 -> Code Directory */
    uint32_t offset;  /* 0x475 -> 0xD300 + 0x475 = 0xD775 */
}
struct __BlobIndex {
    uint32_t type;    /* 0x10000 -> CMS Signature */
    uint32_t offset;  /* 0x746 -> 0xD300 + 0x746 = 0xDA46 */
}

這部分是典型的數(shù)據(jù)頭結(jié)構(gòu)逗噩,聲明了5個(gè)Blob掉丽,以及每個(gè)Blob的類型和相對(duì)簽名頭部的偏移量跌榔。接下來(lái)把每個(gè)部分分別提取出來(lái)進(jìn)行分析。

CodeDirectory

CodeDirectory是簽名數(shù)據(jù)中最終要的部分捶障,直譯過(guò)來(lái)就是代碼目錄僧须,其實(shí)里面是整個(gè)MachO文件的哈希值,這里的哈希并不是一次性對(duì)整個(gè)文件進(jìn)行哈希项炼,而是將MachO文件按照pageSize(一般是4k也就是4096字節(jié))進(jìn)行分頁(yè)皆辽,每一頁(yè)單獨(dú)計(jì)算哈希,并按照順序保存下來(lái)芥挣,就像目錄一樣驱闷。

細(xì)心的同學(xué)會(huì)發(fā)現(xiàn)上面的數(shù)據(jù)中出現(xiàn)了兩個(gè)CodeDirectory,type分別是0x00x1000空免,這也是歷史遺留問(wèn)題空另,0x0對(duì)應(yīng)的是舊版本的代碼簽名,使用sha1算法進(jìn)行哈希值的計(jì)算蹋砚,而0x1000是后來(lái)引入的扼菠,采用sha256作為哈希算法,除了算法和哈希的長(zhǎng)度不同之外坝咐,其他內(nèi)容基本是一樣的循榆。取第一個(gè)進(jìn)行分析:

// 綠色部分③ Offset: 0xD334
struct __CodeDirectory {
    uint32_t magic;         /* 0xFADE0C02 -> CSMAGIC_CODEDIRECTORY */
    uint32_t length;        /* 0x1ED -> 493 */
    uint32_t version;       /* 0x00020400 -> v2.4.0 */
    uint32_t flags;         /* 0 */
    uint32_t hashOffset;    /* 0xD5 -> 0xD334 + 0xD5 = 0xD409 指向⑤*/
    uint32_t identOffset;   /* 0x58 -> 0xD334 + 0x58 = 0xD38B 指向④*/
    uint32_t nSpecialSlots; /* 5 */
    uint32_t nCodeSlots;    /* 0xE -> 14 */
    uint32_t codeLimit;     /* 0xD300 */
    uint8_t hashSize;       /* 0x14 -> 20bytes -> 160bits (sha1) */
    uint8_t hashType;       /* 0x01 (sha1) */
    uint8_t spare1;         /* unused (must be zero) */
    uint8_t pageSize;       /* 0x0C -> 2 ^ 0x0C = 0x1000 = 4096 */
    uint32_t spare2;        /* unused (must be zero) */
    /* followed by dynamic content as located by offset fields above */
}

hashOffset就是"目錄"第一頁(yè)的偏移,從這個(gè)位置(0xD409)可以提取到一串20字節(jié)的sha1值(圖中黃色⑤):

9D452342F9ED06189E4F099BCA7CB68D6432F775

這個(gè)值代表的就是該文件第一頁(yè)的哈希值墨坚,通過(guò)以下命令計(jì)算文件前4096字節(jié)的sha1可進(jìn)行驗(yàn)證

$ dd bs=1 skip=0 count=0x1000 if=TestCodeSign 2>/dev/null | shasum -a 1
9d452342f9ed06189e4f099bca7cb68d6432f775  -

而緊接著的20個(gè)字節(jié)就是第二頁(yè)的哈希值秧饮,以此類推,直到原始文件的最后一頁(yè)泽篮。

由于文件不一定是pageSize的整數(shù)倍盗尸,最后一頁(yè)往往不足"一整頁(yè)"的大小,因此需要額外的字段codeLimit記錄文件的實(shí)際大小帽撑,也就是需要簽名的數(shù)據(jù)的實(shí)際大小泼各,通過(guò)這個(gè)值計(jì)算出最后一頁(yè)的實(shí)際大小,并提取相應(yīng)數(shù)據(jù)計(jì)算最后一頁(yè)的簽名亏拉。例子中codeLimit=0xD300扣蜻,很容易得出最后一頁(yè)大小為0x300

$ dd bs=1 skip=0xD000 count=0x300 if=TestCodeSign 2>/dev/null | shasum -a 1
9dc960fc86f803c1fa100f2a1145cf7cbe58e803  -

計(jì)算出最后一頁(yè)的sha1值與CodeDirectory中(圖中黃色⑥)一致。

nCodeSlots記錄了文件的總頁(yè)數(shù)14及塘,可通過(guò)0xD300 / 0x1000 = 13.1875得出確實(shí)是14頁(yè)莽使。

細(xì)心的朋友已經(jīng)發(fā)現(xiàn)了,④ identifier和 ⑤ hashSlots 之間有一段多出的數(shù)據(jù)⑦磷蛹,并且CodeDirectory中還有一個(gè)奇怪的值nSpecialSlots=5吮旅,整個(gè)文件的哈希值都已經(jīng)包含在⑤和⑥之間了溪烤,這多出來(lái)的數(shù)據(jù)是怎么回事呢味咳?

原來(lái)庇勃,在第一頁(yè)的前面,還有5個(gè)特殊的負(fù)數(shù)頁(yè)槽驶,用來(lái)保存這些額外信息的哈希值责嚷。

序號(hào) 對(duì)應(yīng)內(nèi)容
-1 App根目錄的Info.plist文件
-2 Requirements(代碼簽名的第二部分)
-3 Resource Directory (_CodeSignature/CodeResources文件)
-4 暫未使用
-5 Entitlements (代碼簽名的第三部分)

同樣地,出于性能考慮掂铐,這些哈希值并未經(jīng)過(guò)任何加密罕拂,只需要確保這些哈希值未經(jīng)篡改,就可以說(shuō)明代碼本身沒(méi)有被篡改全陨。

Requirements

用于指定簽名校驗(yàn)時(shí)的一些額外的約束爆班,簽名時(shí)codesign命令會(huì)自動(dòng)生成這部分?jǐn)?shù)據(jù),但目前并沒(méi)有看到什么地方使用了它辱姨,就不深入分析了柿菩,官方文檔有對(duì)這部分內(nèi)容的詳細(xì)描述

Entitlements

通過(guò)頭部的偏移定位到數(shù)據(jù)的位置,顯然雨涛,這是一個(gè)Blob結(jié)構(gòu)

struct __Blob {       /* Address: 0xD5CD */
    uint32_t magic;   /* 0xFADE7171 -> CSMAGIC_ENTITLEMENT */
    uint32_t length;  /* 0x1A8 -> 424 */
}

之前由Xcode生成的Entitlements文件被整個(gè)嵌入到簽名數(shù)據(jù)中枢舶。

CMS Signature

CMS是Cryptographic Message Syntax的縮寫(xiě),是一種標(biāo)準(zhǔn)的簽名格式替久,由RFC3852定義凉泄。還記得Provisioning Profile的簽名嗎?它們是相同的格式蚯根。CMS格式的簽名中后众,除了包含前面我們推導(dǎo)出的加密哈希和證書(shū)之外,還承載了一些其他的信息颅拦。由于是二進(jìn)制格式吼具,不方便分析,可以將其內(nèi)容從MachO文件中剝離出來(lái)矩距,再找合適的工具進(jìn)行解析拗盒。根據(jù)偏移量定位到CMS Signature的位置0xDA46

struct __Blob {       /* Address: 0xDA46 */
    uint32_t magic;   /* 0xFADE0B01 -> CSMAGIC_BLOBWRAPPER */
    uint32_t length;  /* 0x12D8 -> 4824 */
}

除去頭部的8個(gè)字節(jié),把對(duì)應(yīng)的內(nèi)容提取出來(lái)

$ dd bs=1 skip=0xDA4E count=0x12D0 if=TestCodeSign of=cms_signature

可以將導(dǎo)出的cms_signature文件上傳到在線ASN.1解析工具(支持CMS格式解析)進(jìn)行分析

文件被解析為樹(shù)狀結(jié)構(gòu)锥债,看起來(lái)還是不夠直觀陡蝇,因?yàn)檫@個(gè)工具只是按照數(shù)據(jù)格式把內(nèi)容進(jìn)行了格式化,但是并沒(méi)有標(biāo)注所有字段的確切含義哮肚。其實(shí)我們還可以使用openssl進(jìn)行查看登夫,但是因?yàn)镸ac上自帶的openssl以及通過(guò)HomeBrew安裝的openssl都是沒(méi)有開(kāi)啟cms支持的,所以可以將文件拷貝到linux機(jī)器上或者自行編譯openssl進(jìn)行查看允趟,具體方法在此不表恼策。

$ openssl cms -cmsout -print -inform DER -in cms_signature
CMS_ContentInfo:
  contentType: pkcs7-signedData (1.2.840.113549.1.7.2)
  d.signedData:
    version: 1
    digestAlgorithms:
        algorithm: sha256 (2.16.840.1.101.3.4.2.1)
        parameter: NULL
    encapContentInfo:
      eContentType: pkcs7-data (1.2.840.113549.1.7.1)
      eContent: <ABSENT>
    certificates:
      ... [stripped] Apple Worldwide Developer Relations Certification Authority
      ... [stripped] Apple Root CA
      ... [stripped] iPhone Developer: xxxxxxx
    signerInfos:
        version: 1
        d.issuerAndSerialNumber:
          issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority
          serialNumber: 1008862887770590428
        digestAlgorithm:
          algorithm: sha256 (2.16.840.1.101.3.4.2.1)
          parameter: NULL
        signedAttrs:
            ... [stripped]
              SEQUENCE:
    0:d=0  hl=2 l=  29 cons: SEQUENCE
    2:d=1  hl=2 l=   5 prim:  OBJECT            :sha1
    9:d=1  hl=2 l=  20 prim:  OCTET STRING      [HEX DUMP]:669421362B2F2B5303BCEBB47D793A75A6BBD32F

            ... [stripped]
        signatureAlgorithm:
          algorithm: rsaEncryption (1.2.840.113549.1.1.1)
          parameter: NULL
        signature:
          0000 - 77 00 50 9c 5c 6d 50 1e-cb 4b ca b7 91 d3 5b   w.P.\mP..K....[
          000f - 2e 28 fe f3 5d 20 73 ef-0a 59 ac 2e ed bd 2a   .(..] s..Y....*
          ... [stripped]
        unsignedAttrs:
          <EMPTY>

由于輸出內(nèi)容太多,將部分內(nèi)容做了刪減,可以觀察到簽名中主要包含了這些內(nèi)容

  • contentType涣楷, 表明消息的類型分唾,有6種取值,這里使用的是表示簽名的signedData類型
    • Data
    • SignedData
    • EnvelopedData
    • DigestedData
    • EncryptedData
    • AuthenticatedData
  • content狮斗,SignedData類型的數(shù)據(jù)
    • version等:略
    • certificates: 證書(shū)鏈绽乔,包含用于簽名的開(kāi)發(fā)者證書(shū)及所有上游CA的證書(shū)
    • signerInfos:真正的簽名信息!
      • version:版本號(hào)
      • issuerAndSerialNumber:簽名者信息碳褒,根據(jù)簽名者的名稱找到證書(shū)鏈中對(duì)應(yīng)的證書(shū)折砸,使用證書(shū)中的公鑰即可驗(yàn)證簽名是否有效
      • digestAlgorithm:哈希算法
      • signedAttrs:需要簽名的屬性, 是可選項(xiàng),為空表示被簽名的數(shù)據(jù)是原始文件的內(nèi)容沙峻,如果不為空則至少要包含原始文件的類型以及其哈希值睦授,此時(shí)被簽名的數(shù)據(jù)就是signedAttrs的內(nèi)容
      • signatureAlgorithm:簽名算法,這里指對(duì)哈希值進(jìn)行加密所使用的算法
      • signature:加密后的哈希值

由于在Code Directory中已經(jīng)保存了所有資源及代碼的哈希值摔寨,那么我們只需要確保CodeDirectory不被篡改睹逃,即可確保整個(gè)app的完整性, 因此CMS Signature中只需要對(duì)CodeDirectory進(jìn)行簽名即可祷肯。而signedAttrs中支持這樣一種特性:可以先計(jì)算被簽名數(shù)據(jù)的哈希沉填,然后再對(duì)哈希值進(jìn)行簽名。聽(tīng)起來(lái)有點(diǎn)繞佑笋,不過(guò)仔細(xì)體會(huì)一下應(yīng)該不難理解翼闹。

我們把CodeDirectory的內(nèi)容摳出來(lái),計(jì)算其哈希值蒋纬,以第一個(gè)CodeDirectory為例猎荠,計(jì)算其sha1:

$ dd bs=1 skip=0xD334 count=0x1ED if=TestCodeSign 2>/dev/null | shasum -a 1
669421362b2f2b5303bcebb47d793a75a6bbd32f  -

這個(gè)值叫做CDHash(Code Directory's Hash),對(duì)比前面從cms_signature中解析出的 signedAttrs蜀备,會(huì)發(fā)現(xiàn)這兩個(gè)值是一樣的关摇,也就是說(shuō)CodeDirectory的哈希值被放在了signerInfos->signedAttrs中,作為最終真正被簽名(計(jì)算哈希并加密)的內(nèi)容碾阁。

至此输虱,我們已經(jīng)從頭到尾剖析了iOS代碼簽名的生成方式及數(shù)據(jù)結(jié)構(gòu),在這個(gè)過(guò)程中脂凶,至少存在4次計(jì)算哈希的行為宪睹,并且是環(huán)環(huán)相扣的

  1. _CodeSignature/CodeResources中對(duì)每個(gè)資源文件計(jì)算哈希
  2. Code Directory 中對(duì)MachO文件本身的每個(gè)分頁(yè),以及Info.plist蚕钦、CodeResources亭病、Entitlements等文件計(jì)算哈希
  3. CMS Signature的signedAttrs中對(duì)Code Directory計(jì)算哈希
  4. 對(duì)signedAttrs計(jì)算哈希并使用開(kāi)發(fā)者的私鑰加密

只有最后一步的哈希值是被加密的, 前面幾步的哈希值是否加密都不影響簽名的效果嘶居,只要任意內(nèi)容有變化罪帖,均會(huì)因某個(gè)環(huán)節(jié)的哈希不匹配而導(dǎo)致簽名校驗(yàn)的失敗。

jtool

相信上面的二進(jìn)制分析已經(jīng)讓你眼花繚亂了,不過(guò)已經(jīng)有大神做出了jtool這個(gè)工具整袁,它是一款強(qiáng)大的MachO二進(jìn)制分析工具菠齿,用來(lái)替代otool、nm葬项、segedit等命令泞当,也包括codesign的部分功能迹蛤。通過(guò)以下命令可以將代碼簽名解析為可讀的文本格式

$ jtool --sig -vv TestCodeSign
Blob at offset: 54016 (19888 bytes) is an embedded signature of 6686 bytes, and 5 blobs
    Blob 0: Type: 0 @52: Code Directory (493 bytes)
        Version:     20400
        Flags:       none (0x0)
        CodeLimit:   0xd300
        Identifier:  test.CodeSign (0x58)
        Team ID:     xxxxxxxxxx (0x66)
        Executable Segment: Base 0x00000000 Limit: 0x00000000 Flags: 0x00000000
        CDHash:      669421362b2f2b5303bcebb47d793a75a6bbd32f (computed)
        # of Hashes: 14 code + 5 special
        Hashes @213 size: 20 Type: SHA-1
            Entitlements blob:  19a92ca549e53593b384681245de14897df2a9dd (OK)
            Application Specific:   Not Bound
            Resource Directory: fb7df05e17f3b347d6b64868f468def49feecf25 (OK)
            Requirements blob:  9d58965211c9cd83b208fffd575d741881ff81e4 (OK)
            Bound Info.plist:   89e1951413c3eb05fab8f6a5f06c13b48926eabe (OK)
            Slot   0 (File page @0x0000):   9d452342f9ed06189e4f099bca7cb68d6432f775 (OK)
            ... [stripped]
    ... [stripped]
    Blob 4: Type: 10000 @1862: Blob Wrapper (4824 bytes) (0x10000 is CMS (RFC3852) signature)
CA: Apple Certification Authority CN: Apple Root CA
... [stripped]
Time: 190122095805Z

Distribute App

在Xcode Organizer中導(dǎo)出或者提交App時(shí)民珍,Xcode會(huì)將Entitlements文件及embedded.mobileprovision文件替換為對(duì)應(yīng)的版本,并使用對(duì)應(yīng)的證書(shū)重新簽名盗飒,主要區(qū)別如下

類型 Entitlements Provisioning Profile 證書(shū)
AppStore 不可調(diào)試嚷量,推送為生產(chǎn)環(huán)境 無(wú)ProvisionedDevices 發(fā)布證書(shū)
Ad Hoc 不可調(diào)試,推送為生產(chǎn)環(huán)境 允許安裝到已注冊(cè)的測(cè)試設(shè)備 發(fā)布證書(shū)
Development 可調(diào)試逆趣,推送為測(cè)試環(huán)境 允許安裝到已注冊(cè)的測(cè)試設(shè)備 開(kāi)發(fā)證書(shū)
Enterprise 不可調(diào)試蝶溶,推送為生產(chǎn)環(huán)境 ProvisionAllDevices 企業(yè)級(jí)發(fā)布證書(shū)

本篇完。


下一篇:細(xì)說(shuō)iOS代碼簽名(四):簽名校驗(yàn)宣渗、越獄抖所、重簽名

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市痕囱,隨后出現(xiàn)的幾起案子田轧,更是在濱河造成了極大的恐慌,老刑警劉巖鞍恢,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傻粘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡帮掉,警方通過(guò)查閱死者的電腦和手機(jī)弦悉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蟆炊,“玉大人稽莉,你說(shuō)我怎么就攤上這事∩辏” “怎么了肩祥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)缩膝。 經(jīng)常有香客問(wèn)我混狠,道長(zhǎng),這世上最難降的妖魔是什么疾层? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任将饺,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘予弧。我一直安慰自己刮吧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布掖蛤。 她就那樣靜靜地躺著杀捻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚓庭。 梳的紋絲不亂的頭發(fā)上致讥,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音器赞,去河邊找鬼垢袱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛港柜,可吹牛的內(nèi)容都是我干的请契。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼夏醉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼爽锥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起畔柔,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤氯夷,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后释树,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體肠槽,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年奢啥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秸仙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桩盲,死狀恐怖寂纪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情赌结,我是刑警寧澤捞蛋,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站柬姚,受9級(jí)特大地震影響拟杉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜量承,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一搬设、第九天 我趴在偏房一處隱蔽的房頂上張望穴店。 院中可真熱鬧,春花似錦拿穴、人聲如沸泣洞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)球凰。三九已至,卻和暖如春腿宰,著一層夾襖步出監(jiān)牢的瞬間呕诉,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工酗失, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留义钉,地道東北人昧绣。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓规肴,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親夜畴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拖刃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容