前言
以前想獲取應(yīng)用的 .ipa 文件可以從 iTunes 下載,macOS 上的 iTunes 升級(jí)成 12.7 后,無(wú)法再獲得 .ipa 文件, 而iOS 9 后就不能從 iTools 之類(lèi)的輔助工具中導(dǎo)出 .ipa 文件。
后面 Apple 官網(wǎng)又提供了一個(gè) 12.6.3 的鏈接
出于好奇心,想試試直接導(dǎo)出.ipa文件,并重簽名安裝到未越獄的設(shè)備上。
環(huán)境
macOS Sierra 10.12.6
iPhone 6 Plus (11.0)
Xcode Version 9.0 (9A235)
iPhone 5s(9.3.3 已越獄)
越獄設(shè)備中導(dǎo)出 .ipa
SSH 到越獄設(shè)備,使用Cycript 找到xxx.app 的位置
iPhone:~ root# ps -ef | grep WeChat
501 714 1 0 0:00.00 ?? 0:29.04 /var/containers/Bundle/Application/41A6836F-CFC9-4DC1-8A9C-ED4DE09F9A66/WeChat.app/WeChat
0 807 805 0 0:00.00 ttys001 0:00.01 grep WeChat
找到后使用 tar 將 xxx.app 打包
iPhone:~ root# cd /var/containers/Bundle/Application/41A6836F-CFC9-4DC1-8A9C-ED4DE09F9A66/
iPhone:/var/containers/Bundle/Application/41A6836F-CFC9-4DC1-8A9C-ED4DE09F9A66 root# ls
WeChat.app iTunesArtwork iTunesMetadata.plist
iPhone:/var/containers/Bundle/Application/41A6836F-CFC9-4DC1-8A9C-ED4DE09F9A66 root# tar -cvf /tmp/WeChat.tar ./
./
./.com.apple.mobile_container_manager.metadata.plist
./WeChat.app/
./WeChat.app/AppIcon60x60@2x.png
...
./WeChat.app/zh_TW.lproj/network_setting.html
./iTunesArtwork
./iTunesMetadata.plist
使用 scp 發(fā)送打包文件到 mac 上
? ~ scp root@192.168.199.132:/tmp/WeChat.tar ~/Desktop/WeChat.tar
root@192.168.199.132's password:
WeChat.tar 100% 97MB 1.7MB/s 00:58
重簽名要求可執(zhí)行文件要先脫殼
// 獲得沙盒地址
iPhone:~ root# cycript -p WeChat
cy# [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0]
#"file://s"
cy# exit(0)
// 獲得應(yīng)用地址
iPhone:~ root# ps -ef | grep WeChat
501 714 1 0 0:00.00 ?? 0:03.25 /var/containers/Bundle/Application/41A6836F-CFC9-4DC1-8A9C-ED4DE09F9A66/WeChat.app/WeChat
0 717 699 0 0:00.00 ttys000 0:00.01 grep WeChat
// DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib path/to/App
iPhone:/var/mobile/Containers/Data/Application/E7DE74DA-2FC9-4A86-A4D7-F993A88AB225/Documents root# su mobile
iPhone:~/Containers/Data/Application/E7DE74DA-2FC9-4A86-A4D7-F993A88AB225/Documents mobile$ DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/containers/Bundle/Application/41A6836F-CFC9-4DC1-8A9C-ED4DE09F9A66/WeChat.app/WeChat
mach-o decryption dumper
DISCLAIMER: This tool is only meant for security research purposes, not for application crackers.
[+] detected 64bit ARM binary in memory.
[+] offset to cryptid found: @0x100028ca8(from 0x100028000) = ca8
[+] Found encrypted data at address 00004000 of length 56131584 bytes - type 1.
[+] Opening /private/var/containers/Bundle/Application/41A6836F-CFC9-4DC1-8A9C-ED4DE09F9A66/WeChat.app/WeChat for reading.
[+] Reading header
[+] Detecting header type
[+] Executable is a plain MACH-O image
[+] Opening WeChat.decrypted for writing.
[+] Copying the not encrypted start of the file
[+] Dumping the decrypted data into the file
[+] Copying the not encrypted remainder of the file
[+] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset ca8
[+] Closing original file
[+] Closing dump file
原版的 dumpdecrypted 無(wú)法應(yīng)對(duì)有 Frameworks 的情況,不過(guò)有一個(gè)分支版本dumpdecrypted 提供了解決的方法,但是還有Plugins,幸而還有一個(gè)分支提供了使用dumpdecryptd 對(duì) .extension 文件進(jìn)行脫殼(today那種小插件,用這個(gè)版本脫殼嘗試不成功,找了XX助手去下載脫殼的部分),詳情可參考App Extension的脫殼辦法。都能支持的版本也已經(jīng)有了dumpdecrypted
分支
對(duì) dumpdecrypted 有些部分的代碼不理解
- 原版的
dumptofile的函數(shù)參數(shù)是怎么來(lái)的? -
Frameworks分支版本做了什么? -
extension分支版本做了什么?
在這個(gè)dumpdecrypted的Frameworks 分支版本中
__attribute__((constructor))
static void dumpexecutable() {
...
_dyld_register_func_for_add_image(&image_added);
}
__attribute__((constructor))
根據(jù) attribute((constructor))用法解析,得到的GNU的文檔 可知 dumpexecutable() 方法在 main 函數(shù)之前執(zhí)行
_dyld_register_func_for_add_image
找了 github 上的 dyld
/*
* _dyld_register_func_for_add_image registers the specified function to be
* called when a new image is added (a bundle or a dynamic shared library) to
* the program. When this function is first registered it is called for once
* for each image that is currently part of the program.
*/
void
_dyld_register_func_for_add_image(
void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
{
DYLD_LOCK_THIS_BLOCK;
typedef void (*callback_t)(const struct mach_header *mh, intptr_t vmaddr_slide);
static void (*p)(callback_t func) = NULL;
if(p == NULL)
_dyld_func_lookup("__dyld_register_func_for_add_image", (void**)&p);
p(func);
}
dyld 會(huì)負(fù)責(zé)傳遞 mh 和 intptr_t 參數(shù)
// usr/include/sys/_types/_intptr_t.h
typedef __darwin_intptr_t intptr_t;
// usr/include/arm/_types.h
typedef long __darwin_intptr_t;
因此 intptr_t 就是 long 類(lèi)型
static void image_added(const struct mach_header *mh, intptr_t slide) {
Dl_info image_info;
int result = dladdr(mh, &image_info);
dumptofile(image_info.dli_fname, mh);
}
調(diào)用 dumptofile 函數(shù), 在 _dyld_register_func_for_add_image 函數(shù)的注釋中提到了 called when a new image is added (a bundle or a dynamic shared library) 因此可以將 framework 也一起導(dǎo)出。
查找 dyld 后發(fā)現(xiàn)在 ImageLoader.h 頭文件中,有
typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[], const ProgramVars* vars);
在 ImageLoaderMachO.cpp 中有如下的函數(shù)實(shí)現(xiàn)
void ImageLoaderMachO::doImageInit(const LinkContext& context)
{
if ( fHasDashInit ) {
const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
const struct load_command* cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
switch (cmd->cmd) {
case LC_ROUTINES_COMMAND:
Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
// <rdar://problem/8543820&9228031> verify initializers are in image
if ( ! this->containsAddress((void*)func) ) {
dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
}
if ( context.verboseInit )
dyld::log("dyld: calling -init function %p in %s\n", func, this->getPath());
func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
break;
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
}
}
}
根據(jù)函數(shù)命名知道這應(yīng)該是給鏡像做初始化的,里面 func 函數(shù)是 Initializer 類(lèi)型的,通過(guò) context 參數(shù)獲取上下文信息,原版的 dumptofile 函數(shù)的參數(shù)列表為什么會(huì)是 (int argc, const char **argv, const char **envp, const char **apple, struct ProgramVars *pvars) 到這里就可知一二。
.extension 脫殼的 dumpdecrypted 版本與原版的區(qū)別主要是
...
strlcpy(npath, cachePath.UTF8String, sizeof(npath));
strlcat(npath, tmp, sizeof(npath));
strlcat(npath, ".decrypted", sizeof(npath));
strlcpy(buffer, npath, sizeof(buffer));
...
指明將脫殼的包導(dǎo)出到應(yīng)用沙盒的 .../Library/Caches 目錄下
/Library/MobileSubstrate/DynamicLibraries/ 下的動(dòng)態(tài)庫(kù)會(huì)被MobileSubstrate.dylib 自動(dòng)加載。
在原版的 dumpdecrypted 添加一些輸出,使用 printf 時(shí),據(jù)說(shuō)在后面添加一個(gè) \n 可以在日志中看到,但是試了似乎沒(méi)效果,因此使用 NSLog 進(jìn)行輸出,添加
#import <Foundation/Foundation.h>
同時(shí)修改 Makefile 文件, 指明要鏈接 Foundation 框架
-framework Foundation
make && ldid 簽名,發(fā)送到 /Library/MobileSubstrate/DynamicLibraries/ 配置好對(duì)應(yīng)的 .plist 文件,啟動(dòng),然后閃退,查看日志
Nov 20 09:13:29 Jasons-iPhone QQReaderUI[1237] <Notice>: MS:Notice: Injecting: com.tencent.qqreaderiphone [QQReaderUI] (1290.11)
Nov 20 09:13:29 Jasons-iPhone QQReaderUI[1237] <Notice>: MS:Notice: Loading: /Library/MobileSubstrate/DynamicLibraries/dumpdecrypted.dylib
Nov 20 09:13:29 Jasons-iPhone QQReaderUI[1237] <Warning>: [TEST]:rpath = /private/var/containers/Bundle/Application/E276C2C9-20FE-4450-915A-86EBE07798AC/QQReaderUI.app/QQReaderUI
Nov 20 09:13:29 Jasons-iPhone QQReaderUI[1237] <Warning>: [TEST]:fd = 4
Nov 20 09:13:29 Jasons-iPhone QQReaderUI[1237] <Warning>: [TEST]:npath = QQReaderUI
Nov 20 09:13:29 Jasons-iPhone QQReaderUI[1237] <Warning>: [TEST]:npath = QQReaderUI.decrypted
Nov 20 09:13:29 Jasons-iPhone QQReaderUI[1237] <Warning>: [TEST]:outfd = -1
Nov 20 09:13:29 Jasons-iPhone QQReaderUI[1237] <Warning>: [TEST]:outfd = -1
Nov 20 09:13:29 Jasons-iPhone com.apple.xpc.launchd[1] (UIKitApplication:com.tencent.qqreaderiphone[0xc2a3][1237]) <Warning>: Service exited with abnormal code: 1
第一個(gè) outfd = -1
outfd = open(npath, O_RDWR|O_CREAT|O_TRUNC, 0644);
NSLog(@"[TEST]:outfd = %d\n",outfd);
嘗試在當(dāng)前目錄下(/Library/MobileSubstrate/DynamicLibraries/),打開(kāi)(創(chuàng)建)一個(gè) QQReaderUI.decrypted,因?yàn)闄?quán)限的問(wèn)題失敗了。
第二個(gè) outfd = -1
后面 dumpdecrypted.dylib 還會(huì)判斷是不是在/private/var/mobile/Applications(通過(guò)AppStore和iTunes安裝的程序都在里面。),但顯然不是,因此也失敗了
調(diào)用 _exit(1) 閃退
找到一個(gè)比較具體的解釋,排版不太好...
回到正題
將脫殼后的可執(zhí)行文件同樣的發(fā)送到 mac 上
? ~ scp root@192.168.199.132:/var/mobile/Containers/Data/Application/E7DE74DA-2FC9-4A86-A4D7-F993A88AB225/Documents/WeChat.decrypted ~/Desktop
root@192.168.199.132's password:
WeChat.decrypted 100% 68MB 444.4KB/s 02:36
? ~ cd Desktop
? Desktop file WeChat.decrypted
WeChat.decrypted: Mach-O 64-bit executable arm64
如何判斷是否已脫殼
判斷二進(jìn)制是否被加密可以使用 otool 工具
otool - object file displaying tool
otool可以輸出app的load commands,然后通過(guò)查看cryptid這個(gè)標(biāo)志位來(lái)判斷app是否被加密。1代表加密了,0代表被解密了
// 直接從手機(jī)中導(dǎo)出的 WeChat
? Wechat otool -l WeChat.app/WeChat | grep -B 2 crypt
(standard input)-489- cmd LC_ENCRYPTION_INFO
(standard input)-490- cmdsize 20
(standard input):491: cryptoff 16384
(standard input):492: cryptsize 46907392
(standard input):493: cryptid 1
// 脫殼后的 WeChat
? Wechat otool -l WeChat.decrypted | grep -B 2 crypt
(standard input):1:WeChat.decrypted:
--
(standard input)-489- cmd LC_ENCRYPTION_INFO
(standard input)-490- cmdsize 20
(standard input):491: cryptoff 16384
(standard input):492: cryptsize 46907392
(standard input):493: cryptid 0
可以看出手機(jī)導(dǎo)出的只有當(dāng)前架構(gòu)的,而脫殼也只針對(duì)當(dāng)前運(yùn)行的架構(gòu),直接從 iTunes 下載的 .ipa 文件中的二進(jìn)制文件大小大約是從手機(jī)導(dǎo)出的兩倍,因?yàn)樗似渌募軜?gòu)。
了解重簽名
學(xué)習(xí)一般都是從模仿開(kāi)始的,看看 Xcode 是怎么簽名的,創(chuàng)建新工程,? + B 編譯一下,然后查看日志
/// 簽名
CodeSign /Users/Jason/Library/Developer/Xcode/DerivedData/JustForTest-ggxnkdgkdklojofwwsifymqzfwqo/Build/Products/Debug-iphoneos/JustForTest.app
/// cd 到工程目錄
cd path/to/project
/// 擴(kuò)展環(huán)境變量
export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
/// 簽名的身份 + 描述文件說(shuō)明
Signing Identity: "iPhone Developer: 開(kāi)發(fā)者名 (開(kāi)發(fā)者ID)"
Provisioning Profile: "iOS Team Provisioning Profile: com.coder.bk123"
(c8748c6c-9d07-41ce-8d55-ff5ca9999999)
// 使用 codesign 執(zhí)行簽名操作
/usr/bin/codesign --force --sign 簽名值 --entitlements /Users/Jason/Library/Developer/Xcode/DerivedData/JustForTest-ggxnkdgkdklojofwwsifymqzfwqo/Build/Intermediates.noindex/JustForTest.build/Debug-iphoneos/JustForTest.build/JustForTest.app.xcent --timestamp=none /Users/Jason/Library/Developer/Xcode/DerivedData/JustForTest-ggxnkdgkdklojofwwsifymqzfwqo/Build/Products/Debug-iphoneos/JustForTest.app
--force
強(qiáng)制代替已存在的簽名
--timestamp
時(shí)間戳
--sign
-s, --sign identity
Sign the code at the path(s) given using this identity. See SIGNING IDENTI-
TIES below.
詳情可使用 man codesign 查看
打開(kāi)鑰匙串應(yīng)用,找到開(kāi)發(fā)者證書(shū),因?yàn)槲沂?code>Debug狀態(tài)下運(yùn)行的,所以看開(kāi)發(fā)證書(shū),sign 的值就是指紋中的 SHA1 簽名,20個(gè)16進(jìn)制 正好是40位
--entitlements
參數(shù)值對(duì)應(yīng)的 xxx.app.xcent 文件內(nèi)容如下
<?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>XXXXX.包名</string>
<key>com.apple.developer.team-identifier</key>
<string>XXXXX</string>
<key>get-task-allow</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>XXXXX.包名</string>
</array>
</dict>
</plist>
其中 XXXXX 是發(fā)布證書(shū)中開(kāi)發(fā)者的身份ID 即 com.apple.developer.team-identifier 中的字段值
在 WWDC16 Session 401 What's New in Xcode App Signing 有如下的內(nèi)容
There are three things that you need in order to sign your apps. The first thing is a signing certificate. Signing certificates establish your identity as a developer.
Provisioning profiles are all about your apps, and they grant permissions. And entitlements declare support for capabilities.
Like iCloud or Wallet. So certificates. These are issued by Apple.
And this is important because the device needs a trust chain back to Apple so it can install the app. And certificates come in two forms.
signing certificate: 開(kāi)發(fā)者身份是否可信
Provisioning profiles: 哪些設(shè)備可安裝
entitlements: 有哪些能力,比如推送,應(yīng)用間分享....
在新創(chuàng)建的工程 Product 目錄下 Show in Finder 來(lái)查看 xxx.app 文件,可以發(fā)現(xiàn)里面包含一個(gè) embedded.mobileprovision 文件,可以通過(guò)
? security cms -D -i embedded.mobileprovision
結(jié)果如下:
<?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>AppIDName</key>
<string>Resign01</string>
<key>ApplicationIdentifierPrefix</key>
<array>
<string>發(fā)布時(shí)的開(kāi)發(fā)者ID</string>
</array>
<key>CreationDate</key>
<date>2017-11-15T03:42:41Z</date>
<key>Platform</key>
<array>
<string>iOS</string>
</array>
<key>DeveloperCertificates</key>
<array>
<data>簽名證書(shū)</data>
<data>...</data>
</array>
<key>Entitlements</key>
<dict>
<key>keychain-access-groups</key>
<array>
<string>發(fā)布時(shí)的開(kāi)發(fā)者ID.*</string>
</array>
<key>get-task-allow</key>
<true/>
<key>application-identifier</key>
<string>發(fā)布時(shí)的開(kāi)發(fā)者ID.com.coder.Resign01</string>
<key>com.apple.developer.healthkit</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.coder.Resign01</string>
</array>
<key>com.apple.developer.team-identifier</key>
<string>發(fā)布時(shí)的開(kāi)發(fā)者ID</string>
<key>aps-environment</key>
<string>development</string>
</dict>
<key>ExpirationDate</key>
<date>2018-11-15T03:42:41Z</date>
<key>Name</key>
<string>iOS Team Provisioning Profile: com.coder.Resign01</string>
<key>ProvisionedDevices</key>
<array>
<string>允許安裝的設(shè)備的UDID</string>
<string>....</string>
</array>
<key>TeamIdentifier</key>
<array>
<string>發(fā)布時(shí)的開(kāi)發(fā)者ID</string>
</array>
<key>TeamName</key>
<string>開(kāi)發(fā)者名</string>
<key>TimeToLive</key>
<integer>365</integer>
<key>UUID</key> <-- 描述文件 -->
<string>c8748c6c-9d07-41ce-8d55-ff5ca999999</string>
<key>Version</key>
<integer>1</integer>
</dict>
</plist>
通過(guò) Xcode 日志的描述文件序列號(hào)在 ~/Library/MobileDevice/Provisioning Profiles/ 目錄查找,然后用對(duì)比工具進(jìn)行比較,發(fā)現(xiàn)兩者是相同的,
從中可以看出,開(kāi)發(fā)的情況下,簽名的過(guò)程會(huì)將我們從 Apple 開(kāi)發(fā)者后臺(tái)下載的描述文件embedded.mobileprovision 放到包中,用于安裝時(shí)的驗(yàn)證。
我們?cè)?Apple 開(kāi)發(fā)者后臺(tái)生成證書(shū)時(shí)要求上傳一個(gè) .csr 文件,Certificate_signing_request
Before creating a CSR, the applicant first generates a key pair, keeping the private key secret. The CSR contains information identifying the applicant (such as a distinguished name in the case of an X.509 certificate) which must be signed using the applicant's private key. The CSR also contains the public key chosen by the applicant. The CSR may be accompanied by other credentials or proofs of identity required by the certificate authority, and the certificate authority may contact the applicant for further information.
創(chuàng)建 .csr 文件前,會(huì)用非對(duì)稱(chēng)加密算法生成一對(duì)密鑰,分別是公鑰和私鑰,私鑰存放在本地,而公鑰與一些表明能自身身份的信息一起用于生成 .csr 文件。
Apple 開(kāi)發(fā)者后臺(tái)相當(dāng)于一個(gè) CA
Trusted certificates can be used to create secure connections to a server via the Internet. A certificate is essential in order to circumvent a malicious party which happens to be on the route to a target server which acts as if it were the target. Such a scenario is commonly referred to as a man-in-the-middle attack. The client uses the CA certificate to authenticate the CA signature on the server certificate, as part of the authorizations before launching a secure connection. Usually, client software—for example, browsers—include a set of trusted CA certificates. This makes sense, as many users need to trust their client software. A malicious or compromised client can skip any security check and still fool its users into believing otherwise.
關(guān)于簽名的原理,請(qǐng)看下圖

來(lái)自-iOS App 簽名的原理
測(cè)試環(huán)境下(Ad Hoc)如何保證應(yīng)用能正常運(yùn)行?

證書(shū)和 device ID 一般應(yīng)該都不會(huì)有問(wèn)題,都是從 Apple 開(kāi)發(fā)者后臺(tái)獲取的,所以主要去考慮的是 bundle ID 和 entitlements
后面實(shí)踐發(fā)現(xiàn)對(duì) entitlements.plist 文件添加權(quán)限,刪除權(quán)限,會(huì)影響到對(duì)應(yīng)的embedded.mobileprovision,但是依然可以成功安裝并運(yùn)行。
看了文字的說(shuō)明
The app successfully launches if the app’s bundle ID matches the App ID, the signature matches the distribution certificate, and the device is in the device list of the ad hoc provisioning profile.
只提到了 3 點(diǎn),包名匹配,證書(shū)匹配(--sign 對(duì)應(yīng)的證書(shū)簽名embedded.mobileprovision 文件中包含的證書(shū)),描述文件的設(shè)備列表包含當(dāng)前設(shè)備
哪些文件需要參與簽名
Nested code , 比如 .a 靜態(tài)庫(kù), .frameworks (先簽名)
Mach-O executables , 二進(jìn)制可執(zhí)行文件
Resources , 資源文件,就是 CodeResources 的部分
To apply the signature, the codesign utility adds the signature directly to the executable file.
.ipa 包里有一個(gè) _CodeSignature 的文件夾,其中有個(gè) CodeResources 文件
<?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>files</key>
<dict>
...
</dict>
<key>files2</key>
<dict>
...
</dict>
<key>rules</key>
<dict>
...
</dict>
<key>rules2</key>
<dict>
...
</dict>
</dict>
</plist>
rules 和 files 是為老版本準(zhǔn)備的,而 files2 和 rules2是為新的第二版的代碼簽名準(zhǔn)備的。最主要的區(qū)別是在新版本中你無(wú)法再將某些資源文件排除在代碼簽名之外。+
二進(jìn)制的簽名會(huì)被放到可執(zhí)行文件中
參考的那篇文章的鏈接掛了...
https://xiuchundao.me/post/code-resources-and-embedded-mobileprovision-included-in-ipa-file
Mach-O executables. ... To apply the signature, the codesign utility adds the signature directly to the executable file.
可以知道二進(jìn)制文件的簽名確實(shí)是直接在文件中的
總結(jié)
- 簽名工具:
codesign,需要提供 證書(shū)的SHA1簽名值 和 entitlements.plist -
embedded.mobileprovision就是從Apple開(kāi)發(fā)者后臺(tái)下載的描述文件, 同時(shí)在編譯時(shí)會(huì)被拷貝到包中 - 重簽名的應(yīng)用要成功運(yùn)行要保證包名匹配,證書(shū)匹配(
--sign對(duì)應(yīng)的證書(shū)簽名embedded.mobileprovision文件中包含的證書(shū)),描述文件的設(shè)備列表包含當(dāng)前設(shè)備 - 參與簽名的有內(nèi)嵌的框架,資源文件,二進(jìn)制可執(zhí)行文件