Links
Comment on page

15.Inlinehook:Dobby

一、Dobby

按文档生成一个Xcode工程。获取DobbyX.framework。一个跨平台的用于Hook静态语言的框架。
cd Dobby && 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

二、将framework集成进工程

  • 将上面获取到的DobbyX.framework,拖进项目。
  • Build Phases 中添加 Copy file,添加DobbyX.framework,类型为framework

三、使用

3.1 int DobbyHook(void *address, void *replace_call, void **origin_call);

  • address
    • 需要hook的函数地址
  • replace_call
    • 新函数地址
  • origin_call
    • 原始函数指针的地址
由于静态语言没有符号,直接通过地址来进行hook

3.2 试验一下

下面就是简单的使用方式
#import "ViewController.h"
#import "DobbyX.framework/Headers/dobby.h"
@interface ViewController ()
@end
@implementation ViewController
int test_sum(int a, int b) {
return a + b;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
DobbyHook(test_sum, new_sum, (void *)&old_sum_p);
}
/// 原始函数指针
static int (*old_sum_p)(int a, int b);
// 新函数地址
int new_sum(int a, int b) {
int right = old_sum_p(a, b);
NSLog(@"Hook了!正确的结果是:%d",right);
return right + 1;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"结果:%d",test_sum(1, 1));
}
@end
控制台输出:
[*] ================================
[*] Dobby
[*] ================================
[*] dobby in debug log mode, disable with cmake flag "-DDOBBY_DEBUG=OFF"
[*] [DobbyHook] Initialize at 0x104d31d90
[*] [trampoline] Generate trampoline buffer 0x104d31d90 -> 0x104d31e74
[*] [insn relocate] origin 0x104d31d90 - 12
[*] [insn relocate] relocated 0x10d2c0000 - 32
[*] [intercept routing] Active patch 0x104d31d90
2021-05-19 08:33:00.081796+0800 DobbyDemo[4207:1785806] Hook了!正确的结果是:2
2021-05-19 08:33:00.081972+0800 DobbyDemo[4207:1785806] 结果:3

四、流程分析

4.1 汇编分析 test_sum

a. 原始函数的汇编
DobbyDemo`test_sum:
0x104a71dc4 <+0>: sub sp, sp, #0x10 ; =0x10
0x104a71dc8 <+4>: str w0, [sp, #0xc]
0x104a71dcc <+8>: str w1, [sp, #0x8]
-> 0x104a71dd0 <+12>: ldr w8, [sp, #0xc]
0x104a71dd4 <+16>: ldr w9, [sp, #0x8]
0x104a71dd8 <+20>: add w0, w8, w9
0x104a71ddc <+24>: add sp, sp, #0x10 ; =0x10
0x104a71de0 <+28>: ret
b. Hook后的汇编
DobbyDemo`test_sum:
0x104c7dd90 <+0>: adrp x17, 0
0x104c7dd94 <+4>: add x17, x17, #0xe74 ; =0xe74
0x104c7dd98 <+8>: br x17
-> 0x104c7dd9c <+12>: ldr w8, [sp, #0xc]
0x104c7dda0 <+16>: ldr w9, [sp, #0x8]
0x104c7dda4 <+20>: add w0, w8, w9
0x104c7dda8 <+24>: add sp, sp, #0x10 ; =0x10
0x104c7ddac <+28>: ret
c. 分析
我们可以发现,前面三行指令不一样了。下面我们从调用方法断点开始调试
touchbegin
...
0x102b7df1c <+76>: bl 0x102b7e554 ; symbol stub for: objc_storeStrong
0x102b7df20 <+80>: mov w10, #0x1
0x102b7df24 <+84>: mov x0, x10
0x102b7df28 <+88>: mov x1, x10
-> 0x102b7df2c <+92>: bl 0x102b7dd90 ; test_sum at ViewController.m:17
...
test_sum
DobbyDemo`test_sum:
0x102b7dd90 <+0>: adrp x17, 0
0x102b7dd94 <+4>: add x17, x17, #0xe74 ; =0xe74
-> 0x102b7dd98 <+8>: br x17
0x102b7dd9c <+12>: ldr w8, [sp, #0xc]
0x102b7dda0 <+16>: ldr w9, [sp, #0x8]
0x102b7dda4 <+20>: add w0, w8, w9
0x102b7dda8 <+24>: add sp, sp, #0x10 ; =0x10
0x102b7ddac <+28>: ret
(lldb) register read x17
x17 = 0x0000000102b7de74 DobbyDemo`new_sum at ViewController.m:31
这里发现x17已经编程了new_sum了!跳到new_sum中了。
在调用原函数指针的时候才会继续执行->下面的指令
d. 原理
  • 实际上是对一段Text进行了替换(内存中的)!
  • Text段无法修改!
  • 原始MachO无变化!

五、将符号替换成地址

在实战的时候,更多情况下我们并不能像上面的Demo中一样简单的拿到方法进行替换。
所以我们需要将符号替换城地址!

5.1 定位函数地址

-> 0x1025f1f3c <+84>: mov x0, x10
0x1025f1f40 <+88>: mov x1, x10
0x1025f1f44 <+92>: bl 0x1025f1dc4 ; test_sum at ViewController.m:17
a.函数地址
通过汇编断点我们看到真实的函数地址为:0x1025f1dc4
b.MachO中的偏移量
我们可以通过函数地址定位到它在MachO中的偏移量
ASLR
(lldb) image list
[ 0] 6B1471FE-409A-37F0-93ED-86FDFDEE421E 0x00000001025ec000 /Users/RyukieW/Library/Developer/Xcode/DerivedData/DobbyDemo-fyyzoosecpnxmcakyfrtrxocpawl/Build/Products/Debug-iphoneos/DobbyDemo.app/DobbyDemo
offset 0x1025f1dc4 - 0x00000001025ec000 = 0x5DC4
通过MachOView验证我们的计算没有问题。

5.2 代码实现上面的逆向流程

a.通过代码获取ASLR
uintptr_t aslr = _dyld_get_image_vmaddr_slide(0);
你可能会遇到下面的问题
Implicit declaration of function '_dyld_get_image_vmaddr_slide' is invalid in C99
#import <mach-o/dyld.h> 即可
b.获得函数在MachO中的Offset
通过断点调试计算出偏移量,记录下来
static uintptr_t addrSum = 0x100005D40;
c. 通过地址进行hook
完整HOOK代码:
static uintptr_t addrSum = 0x100005D40;
uintptr_t aslr = _dyld_get_image_vmaddr_slide(0);
addrSum += aslr;
DobbyHook((void *)addrSum, new_sum, (void *)&old_sum_p);
d. 结果
2021-05-21 11:30:34.318180+0800 DobbyDemo[5521:2140764] Hook了!正确的结果是:2
2021-05-21 11:30:34.318525+0800 DobbyDemo[5521:2140764] 结果:3

5.3 注意点

  • 对于自己的工程,每次修改代码,都会导致MachO内的偏移量改变,所以调试的时候需要注意
    • 调整变量内容不会变
  • 对于IPA包,同一个IPA包是不会变的,但是不同版本的会不一样
    • 所以插件的话只能针对某个特定版本

5.4 参考