iOS App 簽名過程及重簽

iOS App 簽名

目的:

保證 iOS 平臺(tái)對(duì)第三方 APP 有絕對(duì)的控制權(quán),每一個(gè)安裝到 iOS 上的 APP 都是經(jīng)過蘋果官方允許的。

簽名過程

image.png
  1. 在你的 Mac 開發(fā)機(jī)器生成一對(duì)公私鑰,這里稱為公鑰L,私鑰L。L:Local
  2. 蘋果自己有固定的一對(duì)公私鑰,跟上面 AppStore 例子一樣,私鑰在蘋果后臺(tái),公鑰在每個(gè) iOS 設(shè)備上。這里稱為公鑰A,私鑰A。A:Apple
  3. 把公鑰 L 傳到蘋果后臺(tái),用蘋果后臺(tái)里的私鑰 A 去簽名公鑰 L。得到一份數(shù)據(jù)包含了公鑰 L 以及其簽名,把這份數(shù)據(jù)稱為證書。
  4. 在蘋果后臺(tái)申請(qǐng) AppID,配置好設(shè)備 ID 列表和 APP 可使用的權(quán)限,再加上第③步的證書,組成的數(shù)據(jù)用私鑰 A 簽名,把數(shù)據(jù)和簽名一起組成一個(gè) Provisioning Profile 文件,下載到本地 Mac 開發(fā)機(jī)。
  5. 在開發(fā)時(shí),編譯完一個(gè) APP 后,用本地的私鑰 L 對(duì)這個(gè) APP 進(jìn)行簽名,同時(shí)把第④步得到的 Provisioning Profile 文件打包進(jìn) APP 里,文件名為 embedded.mobileprovision,把 APP 安裝到手機(jī)上。
  6. 在安裝時(shí),iOS 系統(tǒng)取得證書,通過系統(tǒng)內(nèi)置的公鑰 A,去驗(yàn)證 embedded.mobileprovision 的數(shù)字簽名是否正確,里面的證書簽名也會(huì)再驗(yàn)一遍。
  7. 確保了 embedded.mobileprovision 里的數(shù)據(jù)都是蘋果授權(quán)以后,就可以取出里面的數(shù)據(jù),做各種驗(yàn)證,包括用公鑰 L 驗(yàn)證APP簽名,驗(yàn)證設(shè)備 ID 是否在 ID 列表上,AppID 是否對(duì)應(yīng)得上,權(quán)限開關(guān)是否跟 APP 里的 Entitlements 對(duì)應(yīng)等。

概念和操作

上面的步驟對(duì)應(yīng)到我們平常具體的操作和概念是這樣的:

  1. 第 1 步對(duì)應(yīng)的是 keychain 里的 “從證書頒發(fā)機(jī)構(gòu)請(qǐng)求證書”,這里就本地生成了一對(duì)公私鑰,保存的 CertificateSigningRequest 就是公鑰,私鑰保存在本地電腦里。
  2. 第 2 步蘋果處理,不用管。
  3. 第 3 步對(duì)應(yīng)把 CertificateSigningRequest 傳到蘋果后臺(tái)生成證書,并下載到本地。這時(shí)本地有兩個(gè)證書,一個(gè)是第 1 步生成的,一個(gè)是這里下載回來的,keychain 會(huì)把這兩個(gè)證書關(guān)聯(lián)起來,因?yàn)樗麄児借€是對(duì)應(yīng)的,在XCode選擇下載回來的證書時(shí),實(shí)際上會(huì)找到 keychain 里對(duì)應(yīng)的私鑰去簽名。這里私鑰只有生成它的這臺(tái) Mac 有,如果別的 Mac 也要編譯簽名這個(gè) App 怎么辦?答案是把私鑰導(dǎo)出給其他 Mac 用,在 keychain 里導(dǎo)出私鑰,就會(huì)存成 .p12 文件,其他 Mac 打開后就導(dǎo)入了這個(gè)私鑰。
  4. 第 4 步都是在蘋果網(wǎng)站上操作,配置 AppID / 權(quán)限 / 設(shè)備等,最后下載 Provisioning Profile 文件。
  5. 第 5 步 XCode 會(huì)通過第 3 步下載回來的證書(存著公鑰),在本地找到對(duì)應(yīng)的私鑰(第一步生成的),用本地私鑰去簽名 App,并把 Provisioning Profile 文件命名為 embedded.mobileprovision 一起打包進(jìn)去。這里對(duì) App 的簽名數(shù)據(jù)保存分兩部分,Mach-O 可執(zhí)行文件會(huì)把簽名直接寫入這個(gè)文件里,其他資源文件則會(huì)保存在 _CodeSignature 目錄下。
  6. 第 6 – 7 步的打包和驗(yàn)證都是 Xcode 和 iOS 系統(tǒng)自動(dòng)做的事。

這里再總結(jié)一下這些概念:

  1. 證書:內(nèi)容是公鑰或私鑰,由其他機(jī)構(gòu)對(duì)其簽名組成的數(shù)據(jù)包。
  2. Entitlements:包含了 App 權(quán)限開關(guān)列表。
  3. CertificateSigningRequest:本地公鑰。
  4. p12:本地私鑰,可以導(dǎo)入到其他電腦。
  5. Provisioning Profile:包含了 證書 / Entitlements 等數(shù)據(jù),并由蘋果后臺(tái)私鑰簽名的數(shù)據(jù)包。

iOS APP 重簽名具體操作(手動(dòng))

  1. 干掉插件Plugins文件夾里面的內(nèi)容!

  2. Watch 文件刪除

  3. 對(duì) Frameworks 進(jìn)行簽名!

    `$ codesign -fs "證書" xxx.framework`
    
  4. 給可執(zhí)行文件執(zhí)行權(quán)限! chmod +x WeChat

  5. 拷貝描述文件(可新建工程,獲取app包中embedded.mobileprovision)

  6. 修改info.plist 的Bundle ID(與描述文件工程一致)

  7. 生成plist的權(quán)限文件en.plist(復(fù)制embedded.mobileprovision權(quán)限內(nèi)容),放到Payload目錄下

    <key>keychain-access-groups</key>
            <array>
                <string>X7Y****CQ.*</string>
            </array>
            <key>get-task-allow</key>
            <true/>
            <key>application-identifier</key>
            <string>X7Y****JCQ.*</string>
            <key>com.apple.developer.team-identifier</key>
            <string>X7Y****CQ</string>
    
  8. 簽名整個(gè)APP!

    $ codesign -fs "iPhone Developer: xxxxxx (6ZBE4C573L)"  --no-strict --entitlements=en.plist WeChat.app
    
  9. 打包其實(shí)就是一個(gè)zip

    $ zip -ry WeChat.ipa Payload
    

iPhone Developer: shan jingjing (3QDN5929LL)

  1. 安裝到手機(jī)

Xcode->Window->Devices and Simulators->Devices INSTALL APP 點(diǎn)擊+選中WeChat.ipa

iOS APP 利用Xcode重簽名

  1. 創(chuàng)建工程,替換Product下的app

  2. 修改Bundle identifier與新建工程一致

  3. Plugins、Watch 文件刪除

  4. Framework重簽名

    `$ codesign -fs "證書" xxx.framework`
    
  5. 給可執(zhí)行文件執(zhí)行權(quán)限! chmod +x WeChat

  6. Xcode 運(yùn)行安裝至手機(jī)

iOS APP 腳本自動(dòng)化重簽名

  1. 新建工程,添加Run Script腳本
image.png
# ${SRCROOT} 它是工程文件所在的目錄
TEMP_PATH="${SRCROOT}/Temp"
#資源文件夾
ASSETS_PATH="${SRCROOT}/TargetAPP"
#ipa包路徑
TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa"

#新建Temp文件夾
rm -rf "${SRCROOT}/Temp"
mkdir -p "${SRCROOT}/Temp"

#----------------------------------------
# 1. 解壓IPA到Temp下
unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
# 拿到解壓的臨時(shí)的APP的路徑
TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
# echo "路徑是:$TEMP_APP_PATH"


#----------------------------------------
# 2. 將解壓出來的.app拷貝進(jìn)入工程下
# BUILT_PRODUCTS_DIR 工程生成的APP包的路徑
# TARGET_NAME target名稱
TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
echo "app路徑:$TARGET_APP_PATH"

rm -rf "$TARGET_APP_PATH"
mkdir -p "$TARGET_APP_PATH"
cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH"


#----------------------------------------
# 3. 刪除extension和WatchAPP.個(gè)人證書沒法簽名Extention
rm -rf "$TARGET_APP_PATH/PlugIns"
rm -rf "$TARGET_APP_PATH/Watch"


#----------------------------------------
# 4. 更新info.plist文件 CFBundleIdentifier
#  設(shè)置:"Set : KEY Value" "目標(biāo)文件路徑"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"


#----------------------------------------
# 5. 給MachO文件上執(zhí)行權(quán)限
# 拿到MachO文件的路徑
APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`
#上可執(zhí)行權(quán)限
chmod +x "$TARGET_APP_PATH/$APP_BINARY"


#----------------------------------------
# 6. 重簽名第三方 FrameWorks
TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks"

if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ];
then
for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*
do

if test -f  $FRAMEWORK
    then
    #簽名
    /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
    fi
done
fi



命令

查看描述文件信息:$ security cms -D -i 描述文件路徑

查看APP的簽名信息
$ codesign -vv -d APP路徑(.app)

查看本機(jī)所有證書
$ security find-identity -v -p codesigning

查看可執(zhí)行文件的加密信息!
$ otool -l WeChat | grep crypt

簽名
$ codesign -fs "證書" 需要簽名的文件

參考

iOS App 簽名的原理

[toc]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容