# 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

![](/files/-MaCqlJRc8I0N8jkuSqT)

通过`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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ryukiedev.gitbook.io/wiki/ni-xiang/15.inlinehook-dobby.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
