iOS逆向 - shell 指令碼自動重簽名與程式碼注入
前言:
本篇文章建立在上篇部落格 :
iOS逆向 - 應用簽名原理及重簽名 (重籤微信應用實戰) 的基礎知識之上的,不瞭解的同學歡迎去閱讀 . 本篇會講述如何利用 shell
指令碼自動重簽名和應用除錯 .
如果篇幅不過長的話,我們再來玩一玩程式碼注入 .
另外 筆者使用的是 Xcode 11
,所以 Xcode 新版本目前沒發現有問題 . 一樣玩 .
利用 Xcode 重簽名和除錯
這裡之所以要用 Xcode
來做一次重籤,有以下幾個目的 :
- 節省自己建立描述檔案 / 重簽名應用的步驟 .
- 有了工程可以看得到部分列印.
- 方便我們自己新增程式碼執行 .
- ... 等等
利用 Xcode
重籤的原理和上篇部落格中基本一樣 ( 因為我們也提到過,Xcode
codeSign
來做的 ),因此,我這邊快速過一遍,不過多講述了 .
步驟 1 : 新建同名工程
之所以要用同名工程,因為是有一些坑的 .
( 不使用同名工程時,每次 build
會重新建立一個 Mach-O
,也就是說此時你就算更換了包,但是這個包裡有兩個 Mach-O
,而執行的還會是你自己的空工程,所以在我們已經下載到 ipa
看得到包裡的 Mach-O
的情況下,我們就起和它一樣的名字就好 )
ok,新建工程,選擇開發者,選擇真機,直接 run
.
run
成功之後檢視生產的 app
包
看完前面一篇部落格的同學應該都清楚,這一步是為了把描述檔案安裝到手機裡 .
步驟 2 : 替換 App 包
找到之前從pp助手裡下載好的 已經砸過殼的微信應用包,直接替換.
步驟 3 : 刪外掛
這一步跟我們之前自己純手動操作一樣 .
-
開啟
WeChat
,顯示包內容 . 找到PlugIns
資料夾,直接刪除 外掛普通賬號是籤不了的 . -
找到
Watch
資料夾,因為這裡也有外掛,我們暫時不需要Watch
,直接刪掉 .
步驟 4 : 重籤 FrameWork
進入 FrameWork
資料夾
利用 CodeSign
,使用我們的證書進行重簽名.
codesign -fs "複製的你自己的證書名字" 要重籤的FrameWork名稱
複製程式碼
例如:
codesign -fs "iPhone Developer: ha ha (123456)" andromeda.framework
複製程式碼
把 FrameWork
資料夾下所有的庫全部重籤.
注意 ⚠️:
這個時候 App 包裡的Bundle ID 還是微信的,但是我們先不改,直接執行 .
重籤成功
注意看原本我們的空工程,在手機上已經安裝上了微信的包,
那麼你再去檢視微信包裡的 Info.plist
裡的 Bundle ID
,已經被自動替換成我們的包名了 .
那麼對比一下我們純手寫的重籤,這個顯然更加簡單且實用 . 但是每次重籤都這麼搞一下也不太合適,當我們理解了重籤原理之後,就沒有必要每次這麼搞了 .
而且我也不一定能保證我確實是同名工程,我希望我隨便叫什麼名字都可以重籤 .
ok. 進入 Shell
部分 .
利用 Shell 指令碼自動重簽名
Shell 以及 Shell 指令碼
為了統一大家前導知識的前提,我們還是先來介紹下 SHELL
指令碼,已經熟悉的同學可以自行跳過 .
-
Shell
是一種特殊的互動式工具,它為使用者提供了啟動程式、管理檔案系統中檔案以及執行在系統上的程序的途徑。 -
Shell
一般是指命令列工具。它允許你輸入文字命令,然後解釋命令,並在核心中執行。 -
Shell
指令碼,也就是用各類命令預先放入到一個文字檔案中,方便一次性執行的一個指令碼檔案。
簡單來說,大家可以理解為我們平時在 終端
/ iTerm2
中寫的命令的集合 . 當然,它就必不可少的設計到環境變數和許可權等問題 .
在
MAC
系統中,預設使用的shell
是bash
. 我們使用iTerm
的時候,經常會配置另一個shell
叫zsh
. 當然,還有一些其他的shell
.我們需要知道的是
bash
的初始化檔案是家目錄下的.bash_profile
zsh
的初始化檔案同樣是家目錄下的.zshrc
. 裡面配置了一些環境變數.
寫一個簡單的 shell 指令碼
例如我們經常有以下操作 :
mkdir test
cd test
touch 123.txt
cd ..
複製程式碼
那麼我們想將這些指令打包在一起,統一執行 . 類似於資料庫中事務一樣 .
輸入命令 :
vi 123.sh
複製程式碼
輸入檔案內容:
mkdir test
cd test
touch 123.txt
複製程式碼
好,此時 我們已經生成了一個最簡單的指令碼 123.sh
.
那麼如何執行呢 . 方法有很多種
-
- 使用
MAC
自帶的bash
shell
:
bash 123.sh 複製程式碼
- 使用
指令碼執行完,我們的檔案也建立好了 .
-
zsh
zsh 123.sh 複製程式碼
-
source
source 123.sh 複製程式碼
-
./
./123.sh 複製程式碼
注意 :
source
執行完之後停留在子目錄裡 .
./
可能會報沒有執行許可權的問題 . +x
即可
區別
-
$source FileName
- 意思:在當前
shell
環境中讀取並執行FileName
中的命令 - 特點:
- 命令可以強行讓一個指令碼去立即影響當前的環境(一般用於載入配置檔案)。
- 命令會強制執行指令碼中的全部命令,而忽略檔案的許可權。
- 意思:在當前
-
$bash FileName
/$zsh FileName
- 意思:重新建立一個子
shell
,在子shell
中執行腳本里面的句子。
- 意思:重新建立一個子
-
$./FileName
- 意思:讀取並執行檔案中的命令。但有一個前提,指令碼檔案需要有可執行許可權。
shell 重簽名
步驟 1. 新建工程
名稱隨意,新建完畢選擇開發者 . 證書
複製程式碼
執行一下空工程 ( 將描述檔案安裝到手機上 )
步驟 2. 準備要重籤的包
- 在工程根目錄下新建
APP
資料夾,也可以起其他名稱,與Shell
指令碼中的檔名對應起來就可以. - 將下載好的砸殼應用
ipa
放入APP
資料夾中.
步驟 3. 新建 Run Script Phase
可以看到他預設使用的是 sh
的 shell
.
當然 大家可以先隨便寫點 然後 build
一下看看有沒有執行.
開始編寫指令碼 :
# ${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檔案的路徑WeChat
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
複製程式碼
指令碼中步驟都有詳細註釋說明. 那麼我們來總結一下這個指令碼做了什麼.
其實跟我們手動重籤的步驟是一模一樣的.
1 在工程跟目錄中找到
APP
資料夾. 找到裡面的字尾為.ipa
的檔案路徑,建立並清空Temp
資料夾 . (以便後面存放解壓ipa包的內容)2 將
ipa
解壓到Temp
路徑中,找到其中app
包的路徑. ( Palyod 裡的 .app 包) 並將解壓出來的.app
包拷貝進入工程下 ( 其實就是替換掉工程 build 產生的.app 包)3 刪除
PlugIns
和WatchAPP
.4 更新
info.plist
檔案CFBundleIdentifier
5 給
MachO
檔案上執行許可權6 重簽名第三方 FrameWorks
( shell
中新增 echo
可以進行列印輸出,在 build
記錄中 )
當然,你可以直接在 Run Script Phase
裡寫完這些 shell
,也可以寫到一個 app.sh
指令碼檔案中,然後在 Run Script Phase
裡寫一個 ./app.sh
即可 .
如果你遇到
相信你已經知道怎麼解決了. 是的 chmod +x app.sh
重籤成功 !
framework 程式碼注入
一般修改原始的程式,是利用程式碼注入的方式,注入程式碼就會選擇利用 FrameWork
或者 Dylib
等三方庫的方式注入。
當然,也可以直接修改 Mach-O
檔案,這個涉及到彙編以及二進位制,後面會考慮要不要繼續解讀 .
首先我們需要知道的是 Mach-O 檔案擁有固定的格式,而對於 iOS
系統應用來說,需要通過 dyld
去讀取 Mach-O
,從而決定檔案包需要載入哪些庫,如何去載入等等,
後續我會專門講一講 Mach-O
檔案 以及 dyld
連結流程 和 符號表的一些內容.
使用 MachOView
視覺化預覽 Mach-O
檔案內容 ( otools 命令也可以 ) .
那麼因此,我們可以思考 :
如果我可以修改 Mach-O
檔案的 Load Commands
( 載入指令,就是告訴 dyld
如何去載入 ) ,往其中新增一條,新增一條指令讓其去載入 我們自己生成的 framework
,是否可行呢 .
答案是肯定的 .
步驟 1 : 工程準備
準備好已經重簽完的工程 或者上述 準備好了 shell
和 ipa
的工程.
步驟 2 : 新建 framework
File - New - Target
選 Cocoa Touch Framework
,我這裡取名 LBHook
步驟 3 : framework 中新建一個類
在 .m
檔案中寫 load
方法 .
熟悉 load
方法機制的同學都知道,load
方法是在 main
函式之前,dyld
載入 _objc_init
時就會呼叫的. ( 不清楚的同學可以去閱讀一下 iOS load方法呼叫機制解析 這篇文章 )
步驟 4 : cmd + B 編譯一下
編譯後開啟包內容,檢視 Frameworks 資料夾,可以看到我們的 framework 已經放進去了 .
但是沒用啊,微信的 Mach-O
的 載入指令 load Commands
裡並不會去載入我的這個庫 .
步驟 5 : 修改 Mach-O
-
給當前
Mach-O
新增指令 讓其載入我們的framework
. 這裡要使用一個工具 yololib 提取碼 : wxvv -
下載完畢後,將其複製到
usr/local/bin
中,這樣環境變數就可以在任意路徑下使用yololib
了. -
隨便找一個
Mach-O
檔案,go2shell
,或者手動cd
到這個目錄. -
yololib Wechat Frameworks/你的framework名稱路徑/你的framework
- 例 :
yololib Wechat Frameworks/LBHook.framework/LBHook
- 注意 這個
framework
路徑是相當於前面macho
檔案的路徑 .
- 例 :
修改完畢後可以利用 MachOView 來看下我們的載入指令新增進去了沒.
- 那麼實驗完畢可以新增指令,我們就來修改一下微信的原包裡的
Mach-O
,讓其載入我們的framework
. - 開啟我們
APP
路徑下的ipa
包,改為zip
,解壓,Payload
裡的包,顯示包內容,找到Mach-O
. yololib Wechat Frameworks/LBHook.framework/LBHook
- 修改完畢後 重新壓縮 使用
zip -ry Wechat.ipa Payload
( 其實不重新壓縮也可以 跟我們shell
腳本里對應起來就好了 ) .
見證奇蹟的時刻 :
cmd + r
執行 . 看控制檯列印
思考題
那麼既然我們可以注入程式碼 . 那我們可以做什麼 ?
給個思路 :
可以注入程式碼,我們就可以
hook
微信的方法 . 上一篇文章我提到過view Debug
,我們是可以看得到點選登入
/註冊
的時候,呼叫的具體是什麼方法的 . 又有黑魔法的存在,我們可以做的很多 . 大家自己去玩 .
補充
- 程式碼注入時修改 Mach-O 的
load commands
我們是使用手動注入的 . 其實我們在把yololib
環境變數配置好之後,完全可以在之前的 shell 腳本里做注入 .- 上面
shell
指令碼中最後一行 加上 yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/HankHook.framework/HankHook"
- framework 的名稱注意去修改就行
- 這樣的話,我們做重簽名和程式碼注入只需要 新建個空工程 執行,然後下載完微信的
ipa
,根目錄新建個APP
資料夾,放進去執行即可.
- 上面
dylib 程式碼注入
有些工具做程式碼注入的是 Library
就是 dylib
的庫,其實它的原理和我們注入 framework
是一樣的,只不過步驟上略有不同.
我們就使用 shell
簡單帶過一下.
另外,iOS
現在已經不能新增 dylib
,只能從 macOS
新增
工程準備
同樣是準備好已經重簽完的工程 或者上述 準備好了 shell
和 ipa
的工程 .
新建庫
File - New - Target
選 macOS
- Library
,我這裡取名 LBHookDylib
配置
- 開啟
Build Settings
,選擇target
,找到Base SDK
,選擇iOS
. - 找到
Code Sign Identity
,選擇iOS
的證書 - 選擇
Build Phases
,切換為主工程的target
,新建Copy Files
- 新增
-
Destination
選擇Frameworks
-
shell
指令碼中最後一行多加一句yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/libLBHookDylib.dylib"
-
執行,程式碼注入成功 .