# 15.Inlinehook:Dobby

### 一、Dobby

[GitHub:Dobby](https://github.com/jmpews/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

![](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F05d5f54492b55d4b4390cdddb21bca5e403e80ea.png?generation=1621582616988884\&alt=media)

通过`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 参考

[利用纯地址进行HOOK](https://mp.weixin.qq.com/s?__biz=MzU5OTcyMzc5MQ==\&mid=2247486601\&idx=1\&sn=62ccc070f715b3c13e30becb081f998a\&chksm=feb1d6e9c9c65fff7cf5f5290299b4e5abbcd2b4f6d53d605601d79d9d800ce82e5e0c98e48b\&scene=21#wechat_redirect)
