美文网首页iOS逆向
12、HOOK原理(下)--- InlineHook

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

作者: Jax_YD | 来源:发表于2021-05-13 15:20 被阅读0次

    在上一节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链接

    相关文章

      网友评论

        本文标题:12、HOOK原理(下)--- InlineHook

        本文链接:https://www.haomeiwen.com/subject/nagodltx.html