iOS逆向

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

2021-05-13  本文已影响0人  Jax_YD

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

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


Dobby

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

git clone https://github.com/jmpews/Dobby.git --depth=1
// depth用于指定克隆的深度,为1表示只克隆最近一个commit
$ 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
Dobby的使用

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

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

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函数的偏移地址
//地址前面的10000是 pagezero,用来适配32位系统
static uintptr_t sumP = 0x100005D04;
//获取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
# 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"

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


Demo链接

上一篇下一篇

猜你喜欢

热点阅读