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

在上一节11、HOOK原理(上)--- fishHook中我们使用了fishHookNSLog进行了HOOK,但是在结尾的时候我们也留下了一个疑问,那就是对于静态方法我们要怎么去HOOK
今天我们就要去解决这个问题,这就要引入我们今天的主题InlineHook(内联钩子)

InlineHook:所谓InlinHook就是直接修改目标函数的头部代码。让它跳转到我们自定义的函数里面执行我们的代码,从而达到HOOK的目的。这种HOOK计数一般用在静态语言HOOK上面。


Dobby

在进行InlineHook的时候,有一个很不错的框架:Dobby,这是一个跨平台的框架,所以项目并不是一个Xcode工程,我们要使用cmake将这个工程编译成Xcode工程。

  • 首先我们将代码clone下来:
git clone https://github.com/jmpews/Dobby.git --depth=1
// depth用于指定克隆的深度,为1表示只克隆最近一个commit
  • 进入Dobby目录,创建一个文件夹,然后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
    选择自己的开发者账号,编译一下就可以了:

    Dobby编译

Dobby的使用

我们新建一个工程开始使用Dobby

  • bitcode问题,这里有的人可能会遇到一个常见的bitcode问题,解决办法也很简单,有两种:
    i:让我们的编译的Framework支持bitcode
    ii:我们的Demo工程,关闭bitcode
    bitcode设置

bitcode是苹果独有的一层中间代码。包含bitcode配置的程序会在App Store上被编译和链接
bitcode允许苹果在后期重新优化我们程序的二进制文件,也就是说苹果会将这个bitcode编译为可执行的64位或32位程序。

  • 将Dobby的Framework导入到Demo工程
    DobbyX.framework

    此时如果运行Demo会遇到一个问题:

    会发现Demo运行的过程中,dyld找不到我们刚刚导入的DobbyX.framework。这是因为,我们手动将DobbyX.framework拖入工程的时候,Xcode并不会帮我们去拷贝,运行时发现库并没有打包进入APP包,如下:

    此时我们需要手动添加拷贝:

  • 在Demo中使用Dobby
    我们先定义一个简单的静态函数来测试一下是否成功,可以看到我们HOOK成功了。

    到这里我们的Dobby使用已经没有什么问题了。

DobbyHook参数解析:

int DobbyHook(void *address, void *replace_call, void **origin_call);
  • address:需要HOOK的函数地址,函数名称就是函数地址
  • replace_call:新函数的地址
  • origin_call:将原来的函数地址存放到sum_p(我们自己定义的函数指针)这个函数指针中,因为要给指针赋值,所以取指针的地址,so:二级指针

但是新的问题就出来了,我们在HOOK别人的静态函数的时候,拿不到符号名改怎么办,能不能根据地址去HOOK?当然是可以的!!!

根据函数地址HOOK

要拿到函数的地址,这个时候就要借助工具了,这里我们使用的MachOView

  • 首先我们要计算出函数的偏移地址
    sum原始函数处设置断点,然后运行查看汇编代码:
    sum断点

    sum函数虚拟内存地址

    得到sum的虚拟内存地址为:0x100e75d04
  • 通过lldb指令image list获取镜像列表,查看主程序MachO的首地址0x0000000100e70000
    主程序MachO的首地址

    sum函数的偏移地址 = sum函数地址 - 主程序首地址 ----
  • MachOView中查找当前函数
    我们打开MachOView,可以看到这里就是sum函数的开始位置,所以我们验证了sum函数的文件偏移地址就是0x5D04。那么我们就用这个地址进行接下来的HOOK
  • HOOK前的准备
    • 准备一个指针
      注意:由于要方便我们的计算,这里定义函数指针不要定义成为函数的结构,而是uintptr_t
      类型
//定义指针,表示sum函数的偏移地址
//地址前面的10000是 pagezero,用来适配32位系统
static uintptr_t sumP = 0x100005D04;
  • 动态获取ASLR
    首先导入#import <mach-o/dyld.h>
    然后使用函数_dyld_get_image_vmaddr_slide获取ASLR:
//获取ASLR,让sumP变成准确的地址
//参数0代表 imagelist 中的主程序(自己)
uintptr_t aslr = _dyld_get_image_vmaddr_slide(0);
sumP += aslr;
    
//HOOK sum
DobbyHook((void *)sumP, mySum, (void *)&sum_p);

⚠️ 警告:这里有一个细节大家要注意,由于我们刚刚修改了代码,所以sum函数的偏移地址可能发生了改变,这个时候我们要从新去获取这个偏移地址。


将新的地址替换就可以了。

输出结果:


HOOK成功了

到这里,我们通过纯地址的HOOK也完成了。
可是还有一个问题。我们在HOOK别人代码的时候,并不是在别人的代码中去写我们的代码。回忆一下我们之前的代码注入,是通过Framework的注入来完成的。既然我们验证了静态函数也是可以HOOK的,那么不妨我们就用代码注入的形式去HOOK一下。

通过代码注入的形式HOOK
  • 首先创建一个DemoAPP
    创建DemoAPP,并在DemoAPP中添加如下代码:

    DemoAPP

    ⚠️ 注意:编译完成之后,在这里获取sum函数的准确地址。记录一下。
    模拟实战环节,我们将DemoAPP的符号脱掉。
    脱符号

  • 创建HOOK工程
    创建HOOK工程,并创建Framework。可参考9、应用重签名原理
    &10、代码的注入
    这个时候我们在将DobbyX.framework拖入到HOOK工程的时候(拖入到主工程下),除了上面所要注意的地方之外,在Targets -> JaxHOOK中还有两个地方需要注意:
    1、 Other Linker Flags需要配置一下

    Other Linker Flags

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

  • 接下来我们就可以在JaxHOOK里面去写我们的HOOK代码了

    JaxHOOK

  • 此时我们运行工程,会出现下面的现象,这是因为我们并没有将测试APP引入进来。这个时候就需要结合我们之前的知识,对测试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
# 创建文件夹
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
# 设置 "Set : KEY Value" "目标文件路径"
/usr/libexec/PlistBuddy -c "Set : CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"

# 5 ----- 给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

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

注意,脚本中最后一行指令,代码注入在重签名的时候要先注释掉。

  • 在做好准备工作之后,我们来梳理一下整个的操作流程。
    ① :创建 HOOK工程 & 带注入的代码(JaxHOOK),并运行。目的是让手机认证描述文件。
    ② :创建 测试APP
    ③ :在HOOK工程的目录下,创建APP文件夹;将yololib可以执行文件拖入工程目录下;创建appSign.sh脚本文件。
    ④ :将DobbyX.framework,引入工程,并撰写HOOK代码,此时先注释掉HOOK代码。
    ⑤ :在TARGETS -> JaxHOOKDemo -> Buid Phases中配置脚本信息;运行工程,对APP进行重签名。
    ⑥ :打开注入命令,打开HOOK代码;运行工程,进行HOOK

Demo链接

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容