12、HOOK原理(下)--- InlineHook

在上一節(jié)11、HOOK原理(上)--- fishHook中我們使用了fishHookNSLog進行了HOOK,但是在結(jié)尾的時候我們也留下了一個疑問,那就是對于靜態(tài)方法我們要怎么去HOOK。
今天我們就要去解決這個問題,這就要引入我們今天的主題InlineHook(內(nèi)聯(lián)鉤子)

InlineHook:所謂InlinHook就是直接修改目標函數(shù)的頭部代碼。讓它跳轉(zhuǎn)到我們自定義的函數(shù)里面執(zhí)行我們的代碼,從而達到HOOK的目的。這種HOOK計數(shù)一般用在靜態(tài)語言HOOK上面。


Dobby

在進行InlineHook的時候,有一個很不錯的框架:Dobby,這是一個跨平臺的框架,所以項目并不是一個Xcode工程,我們要使用cmake將這個工程編譯成Xcode工程。

  • 首先我們將代碼clone下來:
git clone https://github.com/jmpews/Dobby.git --depth=1
// depth用于指定克隆的深度,為1表示只克隆最近一個commit
  • 進入Dobby目錄,創(chuàng)建一個文件夾,然后cmake編譯工程。
$ cd Dobby-master && mkdir build_for_ios_arm64 && cd build_for_ios_arm64
$ cmake .. -G Xcode \
-DCMAKE_TOOLCHAIN_FILE=cmake/ios.toolchain.cmake \
-DPLATFORM=OS64 -DARCHS='arm64' \
-DCMAKE_SYSTEM_PROCESSOR=arm64 \
-DENABLE_BITCODE=0 \
-DENABLE_ARC=0 \
-DENABLE_VISIBILITY=1 \
-DDEPLOYMENT_TARGET=9.3 \
-DDynamicBinaryInstrument=ON \
-DNearBranch=ON \
-DPlugin.SymbolResolver=ON \
-DPlugin.Darwin.HideLibrary=ON \
-DPlugin.Darwin.ObjectiveC=ON

編譯成功之后,文件夾里面是這個樣子的:


build_for_ios_arm64
  • 接下來編譯Xcode工程,生成我們的Framework
    選擇自己的開發(fā)者賬號,編譯一下就可以了:

    Dobby編譯

Dobby的使用

我們新建一個工程開始使用Dobby。

  • bitcode問題,這里有的人可能會遇到一個常見的bitcode問題,解決辦法也很簡單,有兩種:
    i:讓我們的編譯的Framework支持bitcode。
    ii:我們的Demo工程,關(guān)閉bitcode。
    bitcode設(shè)置

bitcode是蘋果獨有的一層中間代碼。包含bitcode配置的程序會在App Store上被編譯和鏈接。
bitcode允許蘋果在后期重新優(yōu)化我們程序的二進制文件,也就是說蘋果會將這個bitcode編譯為可執(zhí)行的64位或32位程序。

  • 將Dobby的Framework導(dǎo)入到Demo工程
    DobbyX.framework

    此時如果運行Demo會遇到一個問題:

    會發(fā)現(xiàn)Demo運行的過程中,dyld找不到我們剛剛導(dǎo)入的DobbyX.framework。這是因為,我們手動將DobbyX.framework拖入工程的時候,Xcode并不會幫我們?nèi)タ截悾\行時發(fā)現(xiàn)庫并沒有打包進入APP包,如下:

    此時我們需要手動添加拷貝:

  • 在Demo中使用Dobby
    我們先定義一個簡單的靜態(tài)函數(shù)來測試一下是否成功,可以看到我們HOOK成功了。

    到這里我們的Dobby使用已經(jīng)沒有什么問題了。

DobbyHook參數(shù)解析:

int DobbyHook(void *address, void *replace_call, void **origin_call);
  • address:需要HOOK的函數(shù)地址,函數(shù)名稱就是函數(shù)地址
  • replace_call:新函數(shù)的地址
  • origin_call:將原來的函數(shù)地址存放到sum_p(我們自己定義的函數(shù)指針)這個函數(shù)指針中,因為要給指針賦值,所以取指針的地址,so:二級指針。

但是新的問題就出來了,我們在HOOK別人的靜態(tài)函數(shù)的時候,拿不到符號名改怎么辦,能不能根據(jù)地址去HOOK?當然是可以的?。?!

根據(jù)函數(shù)地址HOOK

要拿到函數(shù)的地址,這個時候就要借助工具了,這里我們使用的MachOView。

  • 首先我們要計算出函數(shù)的偏移地址
    sum原始函數(shù)處設(shè)置斷點,然后運行查看匯編代碼:
    sum斷點

    sum函數(shù)虛擬內(nèi)存地址

    得到sum的虛擬內(nèi)存地址為:0x100e75d04
  • 通過lldb指令image list獲取鏡像列表,查看主程序MachO的首地址0x0000000100e70000
    主程序MachO的首地址

    sum函數(shù)的偏移地址 = sum函數(shù)地址 - 主程序首地址 ----
  • MachOView中查找當前函數(shù)
    我們打開MachOView,可以看到這里就是sum函數(shù)的開始位置,所以我們驗證了sum函數(shù)的文件偏移地址就是0x5D04。那么我們就用這個地址進行接下來的HOOK
  • HOOK前的準備
    • 準備一個指針
      注意:由于要方便我們的計算,這里定義函數(shù)指針不要定義成為函數(shù)的結(jié)構(gòu),而是uintptr_t
      類型
//定義指針,表示sum函數(shù)的偏移地址
//地址前面的10000是 pagezero,用來適配32位系統(tǒng)
static uintptr_t sumP = 0x100005D04;
  • 動態(tài)獲取ASLR
    首先導(dǎo)入#import <mach-o/dyld.h>
    然后使用函數(shù)_dyld_get_image_vmaddr_slide獲取ASLR:
//獲取ASLR,讓sumP變成準確的地址
//參數(shù)0代表 imagelist 中的主程序(自己)
uintptr_t aslr = _dyld_get_image_vmaddr_slide(0);
sumP += aslr;
    
//HOOK sum
DobbyHook((void *)sumP, mySum, (void *)&sum_p);

?? 警告:這里有一個細節(jié)大家要注意,由于我們剛剛修改了代碼,所以sum函數(shù)的偏移地址可能發(fā)生了改變,這個時候我們要從新去獲取這個偏移地址。


將新的地址替換就可以了。

輸出結(jié)果:


HOOK成功了

到這里,我們通過純地址的HOOK也完成了。
可是還有一個問題。我們在HOOK別人代碼的時候,并不是在別人的代碼中去寫我們的代碼?;貞浺幌挛覀冎暗拇a注入,是通過Framework的注入來完成的。既然我們驗證了靜態(tài)函數(shù)也是可以HOOK的,那么不妨我們就用代碼注入的形式去HOOK一下。

通過代碼注入的形式HOOK
  • 首先創(chuàng)建一個DemoAPP
    創(chuàng)建DemoAPP,并在DemoAPP中添加如下代碼:

    DemoAPP

    ?? 注意:編譯完成之后,在這里獲取sum函數(shù)的準確地址。記錄一下。
    模擬實戰(zhàn)環(huán)節(jié),我們將DemoAPP的符號脫掉。
    脫符號

  • 創(chuàng)建HOOK工程
    創(chuàng)建HOOK工程,并創(chuàng)建Framework。可參考9、應(yīng)用重簽名原理
    &10、代碼的注入
    這個時候我們在將DobbyX.framework拖入到HOOK工程的時候(拖入到主工程下),除了上面所要注意的地方之外,在Targets -> JaxHOOK中還有兩個地方需要注意:
    1、 Other Linker Flags需要配置一下

    Other Linker Flags

    2、 Framework Search Paths需要配置一下
    Framework Search Paths

  • 接下來我們就可以在JaxHOOK里面去寫我們的HOOK代碼了

    JaxHOOK

  • 此時我們運行工程,會出現(xiàn)下面的現(xiàn)象,這是因為我們并沒有將測試APP引入進來。這個時候就需要結(jié)合我們之前的知識,對測試APP進行重簽名和代碼注入。
    在這里先出本次用到的腳本:

# 0 ----- 準備
ASSETS_PATH="${SRCROOT}/APP"

# 1 ----- 拿到APP的路徑
# 拿到臨時APP的路徑
TEMP_APP_PATH=$(set -- "${ASSETS_PATH}/"*.app;echo "$1")
# 打印臨時APP的路徑
echo "TEMP_APP_PATH路徑:$TEMP_APP_PATH"

# 2 ----- 將.app拷貝進工程下
# TARGET_NAME --- target名稱
# BUILT_PRODUCTS_DIR 工程生成的APP包的路徑
TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
# 打印工程生成的APP包的路徑
echo "自己的app的路徑:$TARGET_APP_PATH"

# 清空路徑下的文件夾
rm -rf $TARGET_APP_PATH
# 創(chuàng)建文件夾
mkdir -p $TARGET_APP_PATH
# 將 TEMP_APP_PATH 拷貝到 TARGET_APP_PATH
cp -rf $TEMP_APP_PATH/ $TARGET_APP_PATH

# 3 ----- 刪除 extension 和 watchAPP,個人證書無法簽名 extension
rm -rf "$TARGET_APP_PATH/PlugIns"
rm -rf "$TARGET_APP_PATH/Watch"

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

# 5 ----- 給MachO文件上執(zhí)行權(quán)限
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

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

# 7 ----- 注入 (注意,在重簽名APP之前,先注釋下面的代碼,等到重簽名完成之后,再去注入代碼)
./yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/JaxHOOK.framework/JaxHOOK"

注意,腳本中最后一行指令,代碼注入在重簽名的時候要先注釋掉。

  • 在做好準備工作之后,我們來梳理一下整個的操作流程。
    ① :創(chuàng)建 HOOK工程 & 帶注入的代碼(JaxHOOK),并運行。目的是讓手機認證描述文件。
    ② :創(chuàng)建 測試APP
    ③ :在HOOK工程的目錄下,創(chuàng)建APP文件夾;將yololib可以執(zhí)行文件拖入工程目錄下;創(chuàng)建appSign.sh腳本文件。
    ④ :將DobbyX.framework,引入工程,并撰寫HOOK代碼,此時先注釋掉HOOK代碼。
    ⑤ :在TARGETS -> JaxHOOKDemo -> Buid Phases中配置腳本信息;運行工程,對APP進行重簽名。
    ⑥ :打開注入命令,打開HOOK代碼;運行工程,進行HOOK。

Demo鏈接

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

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

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