iOS逆向(3)-APP重簽名

一縷清風揚萬里發表於2019-03-05

作為一名iOS開發者肯定知道iOS開發證書,那麼證書具體是什麼呢?為什麼到我們本地的不是證書本身,而是一個稱之為描述檔案的東西。而這「描述檔案」又具體是什麼呢?
在知道這「描述檔案」後,我們是不是可以通過將「描述檔案」替換為我們自己的「描述檔案」進行一些有意思的事情呢?比如這篇文章的主題,對一個APP進行重簽名,讓他在我們的XCode中執行起來,運用我們強大的LLDB進行除錯,分析其UI和部分邏輯。當然作為一個正直的開發者,我們在這片文章肯定不會對她進「程式碼注入」這樣讓人不(興)齒(奮)的事情的(下一篇就會 O(∩_∩)O哈哈~)。

片頭先給福利:點選下載Demo:AppReSign,使用方法詳見demo的Readme

接下來我們會從以下幾點來玩一玩「APP重簽名」

  • 分析Apple對App加密的需求
  • 什麼是雙層簽名
  • 手動對APP進行重簽名
  • 使用Shell指令碼進行重籤

1、分析Apple對App加密的需求

首先明確一點,對App加密肯定是用要非對稱加密而不是對稱加密!這我預設大家都懂了,應該不用解釋。

Step 1 安裝App到手機的渠道分析

如果所有的APP都是從App Store下載的那麼,這就簡單了,只需要對APP進行一層RSA加密就可以了,App Store持有私鑰,我們iPhone持有公鑰。那麼問題就解決了。但事實上肯定不是這樣,我們已知的渠道除了App Store就包括XCode打包,ADHOC證書分發,企業證書分發等等。為了解決這個問題,我們就得先了解Apple的具體需求是什麼。

Step 2 分析需求

  • App Store下載
  • XCode直接安裝
  • 限制ADHoc打包的APP安裝裝置
  • ...等等

2、什麼是雙層簽名

針對以上三種(包括但不只)場景,蘋果給出「雙層簽名」的機制。
什麼是「雙層簽名」,先上一張PPT。

雙層簽名流程圖.png

看不懂?沒關係,下面會一步步,詳細的接受雙層簽名的始末。

1、向伺服器申請證書
  • 什麼是CSR檔案 申請過開發者證書的都知道,要申請證書,都有「Mac本地通過CSR檔案向伺服器」這樣的一步。那麼這一步到底做了寫什麼呢? 先看看什麼是CSR

CSR是Certificate Signing Request的英文縮寫,即證書請求檔案,也就是證書申請者在申請數字證書時由CSP(加密服務提供者)在生成私鑰的同時也生成證書請求檔案,證書申請者只要把CSR檔案提交給證書頒發機構後,證書頒發機構使用其根證書私鑰簽名就生成了證書公鑰檔案,也就是頒發給使用者的證書。

通俗一點,就是Mac本地有一對公鑰(公鑰M)和私鑰(私鑰M)(什麼是公鑰私鑰?),在Mac上對公鑰M進行了一層包裝,這包裝後的新東西就是CSR。

  • 伺服器通過CSR返回證書 本地有了CSR檔案之後,將CSR上傳到Apple的伺服器。 Apple伺服器其實也是有一對公鑰(公鑰A)和私鑰(私鑰A),在收到Mac上傳過來的的CSR檔案之後,取出其中的公鑰M,用Apple伺服器的私鑰A對公鑰M進行一次數字簽名(什麼是數字簽名?)得到開發證書,然後將開發證書附入描述檔案(描述檔案還有哪些東西下文會有講到),最後將描述檔案傳回給我們的Mac電腦。
2、描述檔案

配置描述檔案是 XML 檔案,包含以下內容:裝置的安全策略和限制、VPN 配置資訊、無線區域網設定、電子郵件帳戶和日曆帳戶以及可允許 iPhone、iPod touch 和 iPad 配合您的企業系統使用的鑑定憑證。配置描述檔案能快速地將設定和授權資訊載入到裝置上。有些 VPN 和無線區域網設定只能使用配置描述檔案來設定,而且如果您使用的不是 Microsoft Exchange,則將需要使用配置描述檔案來設定裝置密碼策略。 描述檔案包括的東西,如:

  • 開發證書
  • APP的Bundle Id
  • 證書所信任的Device Id
  • 還有一些許可權檔案(如:Apple Pay,通知,VPN,iCloud)
3、Mac打包APP

在Mac本地有了描述檔案之後,就可以對APP進行打包了,打包這個過程除了對APP的壓縮之外,更重要的其實是指對APP的加密。 之前本地把公鑰M傳送給Apple伺服器,本地剩下的私鑰M就是用來加密APP的,得到一個APP的簽名檔案,再將上一步得到的描述檔案,以及MachO檔案一起打包壓縮,最終就得到了我們的ipa包了。 所以ipa其實包含以下三種東西

  • MachO檔案
  • APP的簽名檔案
  • 描述檔案
4、iPhone驗證ipa檔案

上文提到的私鑰A是用來加密了公鑰M,與之對應的公鑰A其實在我們啟用iPhone的同時已經下載好了,一直躺在我們的iPhone裡面。 有了公鑰M,那麼一切就簡單了,

  • 公鑰A解開ipa中攜帶的描述檔案中的證書得到公鑰M
  • 對公鑰M進行Hash,對比證書中的Hash
  • 對比通過之後,用公鑰M對加密的APP進行解密,得到最終APP。

3、手動對APP進行重簽名 (如果不想看具體過程,可以跳到本節末尾,有流程總結)

從上面可以得知,雙層簽名其實本質就是如下三個步驟:

  • APP的Bundle id的驗證
  • 描述檔案本身的驗證
  • 對APP簽名的驗證

注:對APP進行重新簽名,前提是這個APP已經被砸殼了。 下載已經砸殼成功的APP,以下例子用微信舉例:越獄版本微信7.0.2 提取碼: 2w87

具體步驟:

Step 1 進入WeChat目錄

解壓出 Wechat7.0.2越獄 ,進入WeChat目錄

// 進入WeChat的目錄
cd /Users/dengbin/Desktop/分享/主目錄/資料/Wechat7.0.2越獄/Payload
複製程式碼

Step 2 檢視APP的證書情況

codesign -d -vv「WeChat.app路徑」
複製程式碼

檢視APP證書情況.png

Step 3 檢視驗證APP是否被加密

進入APP的包內容可以看到其中有一個WeChat的可執行檔案,也就是是MachO檔案,就是要檢視這個MachO檔案時候被加密

WeChat目錄.png
WeChat_MachO.png

otool -l WeChat | grep cryp
複製程式碼

其中cryptid0代表已經砸殼,即解密,為1或者2表示以第1類或者第2類加密方案加密。

Step 4 檢視本地證書並記錄需要用到的證書

security find-identity -v -p codesigning
複製程式碼

本地證書列表.png

Step 5 刪除不可簽名的外掛(還有Watch中的外掛)

由於本地存在一些外掛,這些外掛是不可被我們重籤,並且這個過程我們用不著,所以我們索性就刪掉。 其中包括:整個目錄PlugIns目錄和整個Watch目錄(因為Watch.app中也有個PlugIns)

PlugIns.png
Watch.png

Step 6 Framework重簽名

這一步就是比較繁瑣的了,需要將Frameworks下的所有Framework進行重簽名,運用到XCode提供的codesign指令,引數中的證書就是Step 4中的一個。具體使用哪個就看個人了

codesign –fs 「證書串」 「檔名」
複製程式碼

Frameworks.png
Frameworks證書重籤.png

Step 7 給MachO新增可執行許可權

由於MachO本身就有可執行許可權,所以這一步跳過。

Step 8 App重簽名

  • 新建一個WeChat同名工程(下文稱NewWeChat,原來的微信APP稱之為WeChat)

  • Build NewWeChat工程,進入被編譯出的WeChat.App目錄,找到其中的embedded.mobileprovision檔案,將其複製到WeChat.App(越獄微信)中

    Build後的WeChat.png
    embedded.mobileprovision檔案.png
    複製後的結果.png

  • 在WeChat.App找到info.plist,並修改其中的BundleId為NewWeChat的BundleId

    更改BundleId.png

  • 檢視embedded檔案

security cms -D -i 「 embedded檔案路徑」
複製程式碼

找到其中的entitlements欄位,並且複製entitlements欄位和其中的內容

檢視embedded.png
entitlements欄位.png

  • 在NewWeChat中新建entitlements.plist檔案,將上一步複製得到的「entitlements欄位內容」拷貝入新的entitlements.plist檔案,然後將entitlements.plist複製到WeChat.app的同級目錄下。

    拷貝entitlements.png
    複製entitlements.png

  • 對APP重新簽名 進入WeChat目錄,對APP使用新的描述檔案進行重籤

codesign -fs 「證書串」 --no-strict --entitlements=entitlements.plist
複製程式碼

對App進行重籤.png

  • 壓縮Playload
 zip –ry 「輸出檔名」 「輸入檔名」
複製程式碼

壓縮Playload.png

Step 9 安裝新的ipa

可以通過各種途徑安裝ipa,如Xcode,PP助手,fir,iTunes等等, 如果手機上有正版的微信,在安裝完我們重簽名的ipa包後會發現手機上就有兩個微信啦!!!

如果想用LLDB除錯微信,可以將重籤後的WeChat.app替換NewWeChat Build後的WeChat.app,然後直接執行(Run)專案,就會發現我們可以用LLDB了。

Step 10 再次驗證新的ipa是否真的重籤成功

這一步其實是重複Step 3

codesign -d -vv「WeChat.app路徑」
複製程式碼

步驟總結:

1、cd WeChat // 進入WeChat的目錄
2、codesign -d -vv「WeChat.app路徑」 // 檢視APP的證書情況
3、otool –l WeChat | grep cryp // 檢視APP是否被加密
4、security find-identity -v -p codesigning // 檢視本地證書
5、刪除不可簽名的外掛(還有Watch中的外掛)
6、codesign –fs 「證書串」 「檔名」 // Framework重簽名
7、chmod +x 可執行檔案   // 給檔案新增許可權
8、App重簽名
	 ① 新建一個專案並且命名為 WeChat(下文稱NewWeChat,原來的微信APP稱之為WeChat) -> Build -> 找到APP中的許可權檔案 embedded.mobileprovision
	 ② 複製embedded.mobileprovision到WeChat.app中
	 ③ 修改WeChat.app中info.plist的BundleId
	 ④ security cms -D -i 「 embedded檔案路徑」 //檢視WeChat中的embedded檔案,複製WeChat中entitlements.plist檔案的entitlements欄位
	 ⑤ 在NewWeChat中新建entitlements.plist檔案,將上一步複製得到的「entitlements欄位和其中的內容」拷貝入新的entitlements.plist檔案
	 ⑥ codesign -fs 「證書串」 --no-strict --entitlements=entitlements.plist //複製新的entitlements到WeChat.app的同級目錄,並且對APP重新簽名
	 ⑦ zip –ry 「輸出檔名」 「輸入檔名」 // 壓縮Playload
9、安裝ipa 
10、再次驗證新的ipa是否真的重籤成功
複製程式碼
  • 注意:有些人會安裝失敗,或者安裝成功會有Crash的問題,這是因為當前描述檔案在我們的手機還不受信任,用新工程NewWeChat在手機上跑一遍,然後刪除NewWeChat,在嘗試安裝新的ipa,問題可以解決。

4、使用Shell指令碼進行重籤

上面所有的步驟其實是固定不變的,而且所有需要操作的檔案相對於ipa檔案的「相對地址」也是固定的,所以就可以用指令碼來代替所有的操作。 以下指令碼適用於適用XCode直接除錯,點選下載Demo:AppReSign,使用方法詳見demo的Readme

附上指令碼程式碼

# ${SRCROOT} 它是工程檔案所在的目錄
TEMP_PATH="${SRCROOT}/Temp"
#資原始檔夾,我們提前在工程目錄下新建一個APP資料夾,裡面放ipa包
ASSETS_PATH="${SRCROOT}/APP"
#目標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"
# 拿到解壓的臨時的APP的路徑
TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
# echo "路徑是:$TEMP_APP_PATH"

#----------------------------------------
# 2. 將解壓出來的.app拷貝進入工程下
# 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.個人證書沒法簽名Extention
rm -rf "$TARGET_APP_PATH/PlugIns"
rm -rf "$TARGET_APP_PATH/Watch"

#----------------------------------------
# 4. 更新info.plist檔案 CFBundleIdentifier
#  設定:"Set : KEY Value" "目標檔案路徑"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"
#----------------------------------------

# 5. 給MachO檔案上執行許可權
# 拿到MachO檔案的路徑
APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`
#上可執行許可權
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

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

複製程式碼

這邊文章主要講了關於雙層簽名的原理,已經利用雙層簽名的原理對APP(已越獄)進行重籤,但其實其中有一點非常非常重要的內容在這片文章知識被一筆帶過,那就是LLDB,能夠用LLDB除錯我們的APP意味著無限的可能。 所以對LLDB運用,也是我們們逆向的必經之路。後續文章也會提到,待更新。

注意!!!
警告!!!
警告!!!
警告!!!
重籤後不要用自己的賬號登入,有封號的危險!!!

相關文章