1. 程式人生 > IOS開發 >iOS逆向 - shell 指令碼自動重簽名與程式碼注入

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 系統中,預設使用的 shellbash . 我們使用 iTerm 的時候,經常會配置另一個 shellzsh . 當然,還有一些其他的 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 .

那麼如何執行呢 . 方法有很多種

    1. 使用 MAC 自帶的 bash shell :
    bash 123.sh
    複製程式碼

指令碼執行完,我們的檔案也建立好了 .

    1. zsh
    zsh 123.sh
    複製程式碼
    1. source
    source 123.sh
    複製程式碼
    1. ./
    ./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

可以看到他預設使用的是 shshell .

當然 大家可以先隨便寫點 然後 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 刪除 PlugInsWatchAPP.

  • 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 : 工程準備

準備好已經重簽完的工程 或者上述 準備好了 shellipa 的工程.

步驟 2 : 新建 framework

File - New - TargetCocoa 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 新增

工程準備

同樣是準備好已經重簽完的工程 或者上述 準備好了 shellipa 的工程 .

新建庫

File - New - TargetmacOS - 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"
  • 執行,程式碼注入成功 .