惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google DeepMind News
Google DeepMind News
T
Tenable Blog
博客园_首页
S
Securelist
Spread Privacy
Spread Privacy
Google Online Security Blog
Google Online Security Blog
Forbes - Security
Forbes - Security
Engineering at Meta
Engineering at Meta
U
Unit 42
L
LINUX DO - 热门话题
量子位
T
Threat Research - Cisco Blogs
博客园 - 【当耐特】
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
The Last Watchdog
The Last Watchdog
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
Martin Fowler
Martin Fowler
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Security Latest
Security Latest
Scott Helme
Scott Helme
V
Vulnerabilities – Threatpost
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
I
InfoQ
Know Your Adversary
Know Your Adversary
Cisco Talos Blog
Cisco Talos Blog
The Register - Security
The Register - Security
T
The Blog of Author Tim Ferriss
aimingoo的专栏
aimingoo的专栏
V2EX - 技术
V2EX - 技术
T
Tailwind CSS Blog
月光博客
月光博客
Recent Announcements
Recent Announcements
G
Google Developers Blog
F
Full Disclosure
W
WeLiveSecurity
宝玉的分享
宝玉的分享
腾讯CDC
G
GRAHAM CLULEY
Vercel News
Vercel News
Simon Willison's Weblog
Simon Willison's Weblog
美团技术团队
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Help Net Security
Help Net Security

博客园 - GKLBB

软件研发 --- AI模型 之 图片转xlsx 软件神器 --- ctf靶场 之 pwn.college 术语俗话 --- 什么是加密狗 软件神器 --- 自动电脑锁屏软件 软件研发 --- 网络安全 之 putty生成无密码登录密钥 软件神器 --- 视频剪辑 之 Avidemux MP4Joiner Shotcut 软件神器 --- 视频格式转化 之 handbrake 软件研发 --- 经验之谈 这个是什么图标,经常看到 软件研发 --- 术语俗话 之 多模态 术语俗话 --- 什么是大数据开发 软件研发 --- 术语俗话 之 什么是边缘计算 软件研发 --- 应知应会 之 什么是云计算开发 应知应会 --- 如何不装软件查看网速 常见问题解决 --- 360拦截接触 常见问题解决 --- 加入会议摄像头无法打开 网络安全 --- CTF打靶 之 ZIP伪加密 → Robot36慢扫电视 → 二维码补齐 → DeepSound隐写 → GPG解密 → Base64图片 → SilentEye隐写 软件研发 --- 应知应会 之 无错误的闪退如何解决 软件研发 --- 应知应会 之 为什么别人的软件如此复杂我的如此简单 网络安全 --- 应知应会 之 什么是旁站 应知应会 --- 如何查询备案 软件神器 --- 格式转化 之 jpg 2 svg 网络安全 --- CTF打靶 之 flag搜索 软件神器 --- 互联网测速 之 软件神器 --- 局域网测速 之 iperf 常见问题解决 --- 模拟器USG6000打开后,启动设备失败,错误40 软件研发 --- AI网络 之 ensp配置生成 软件研发 --- AI编程 之 极简流程 软件研发 --- AI生图产品比较 常见问题解答 --- 为什么我的服务一直被人DDOS 软件研发 --- 开发万能格式转化工具 网站神器 --- 在线格式转化 之 文档转md 术语俗话 --- 什么是云电脑 常见问题解决 --- 如何在没有安装杀毒软件的情况下知道这个文件是不是牧马 常见问题解决 --- Win10下VMware 17安装VMware Tools选项灰色/失效解决办法 常见问题解决 --- 云电脑报错 :PAGE FAULT IN NONPAGED AREA 记一次牧马的发现 人生感悟 --- 为什么我们生活中同一件事有多个品牌,他们到底有什么区别 软件运维 --- 云电脑安装打印机 常见问题解决 --- 网络打印默认端口 常见问题解决 --- 京瓷打印云电脑无法设置双面打印 软件研发 --- 网络安全 之 brupsuite如何设置上游袋里 术语俗话 --- 什么是同步和异步 我的目标 软件研发 --- dify配置 之 markword转word带有简单样式的方法 软件研发 --- 接口文档格式 常见问题 --- dify 的 deepseek是旧模型版本 OWASP 非营利性开源社区 计算机标准化组织 术语俗话 --- POSIX 就是 Unix 世界的"普通话",大家说同一种语言就能互相理解。 我的数字生活唯一选择 软件开发 --- 安卓开发 之 命名空间隔离 术语俗话 --- 页面对齐、 跨页 计算机的哪些人 --- 社交之王 马克·扎克伯格 计算机的哪些人 --- 重新定义新能源 之 埃隆·马斯克 软件研发 --- AI生成ppt word excel pdf的开发关键 软件研发 --- AI应用开发 之 AI生成Word 人生感悟 --- 致可悲的人 软件研发 --- pdf 表格图片 转 excel 常见问题解决 --- 装有系统的固态硬盘错误 人生感悟 --- 什么是行业黑话 术语俗话 --- Kubernetes 术语俗话 --- 什么是DBI,和hook什么区别 答疑解惑 --- 为什么苹果手机电池不允许拆卸 代码可视化技术 术语俗话 --- Wrap 函数 人生感悟 --- 逆向工程为什么十分枯燥且无聊 --- 这里引用一句逆向工程核心原理的话 人生感悟 --- 为什么干活时不见同事,活干完了就来了 软件研发 --- AI应用研发 之 提炼提示词 软件研发 --- AI应用开发 之 AI生成PPT最佳方案 基于屏幕-摄像头的单向数据传输方案设计 俗语俗话 --- 纯虚函数 硬件研发 --- 产品介绍 之 AX6 硬件研发 --- 产品大全 之 SUMAVISION CM50X 应知应会 --- 为什么U盘不识别但是还是可以数据恢复回来 应知应会 --- 为什么我删除了一个文件但是还是可以恢复回来 软件研发 --- AI UI设计 之 PC端效果比对 常见问题修复 --- chrome浏览器白屏 应用安全 --- 逆向工程 之 C++类的本质 软件研发 --- AI提示词开发 之 代码注释提示词 dobby反编译 https://www.cnblogs.com/Un1corn/p/18615567 应知应会 --- 手机作为热点,windows电脑临时作为网关,给其他电脑上网 应知应会 --- 大量小文件如何快速迁移 常见问题解决 --- apk安装过程中闪退 在线生成 APK 图标工具推荐 一个开源库 术语俗话 --- 什么是软件即服务 软件神器 --- 常用谷歌插件 应用安全 --- 逆向技巧 之 识别未知函数 人生感悟 --- 为什么两句话可以说明白的事情要500字说明 软件研发 --- Dify 生成 PPT 方案分析 应用安全 --- 逆向技巧 之 IDA未知函数如何识别 https://yuuki.cool/ 应用安全 --- 逆向技巧 之 ELF节(Section) 与 段(Segment) 硬件研发 --- 接口 人生感悟 --- 为什么ld一直爱开会 应用安全 --- 逆向技巧 之 IDA和claude反编译缺陷 应用安全 --- 逆向技巧 之 ida反编译yahfa的so和源码的差异化比对
应用安全 --- 安卓逆向 之 dobby框架
GKLBB · 2026-04-13 · via 博客园 - GKLBB

https://blog.csdn.net/qq_60933960/article/details/151935127

dobby框架本质就是so层的hook工具,通过编写c++代码替换原有的c++函数,与firda不同的是不用root并且是内部编译进入apk中的持久化的

 分为两步,第一步编译库为so  ,第二步 将so 拷贝进入你目标安卓项目

注意原仓库的无法编译为安卓so文件,我用第三方仓库编译so,在kali linux中编译通过

https://gitee.com/null_465_7266/dobby

 第一步

Android ARM64 平台 libdobby.so 编译过程总结

1. 项目概述

Dobby 是一个轻量级、跨平台、多架构的 inline hook 框架,支持 Android、iOS、Linux、Windows 等主流操作系统。

2. 编译环境准备

  • 操作系统:Linux(推荐 Kali Linux 或 Ubuntu)

  • NDK 版本:Android NDK r25b

  • CMake 版本:≥ 3.10

  • 编译器:NDK 自带的 Clang

3. 关键配置文件

CMakeLists.txt 主 CMake 构建配置 android_ndk_fixed.cmake Android NDK 工具链配置(修复版) build_android_arm64.sh 自动化构建脚本
文件作用

4. 完整编译步骤

步骤 1:设置环境变量

export ANDROID_NDK_HOME=/path/to/ndk-r25b

步骤 2:准备构建脚本

cd ~/Desktop/Dobby-Android-main
chmod +x build_android_arm64.sh

步骤 3:清理旧构建文件(重要)

rm -rf CMakeFiles CMakeCache.txt Makefile cmake_install.cmake

步骤 4:运行构建脚本

./build_android_arm64.sh

5. CMake 配置详情

构建脚本中实际执行的 CMake 命令:

cmake -S . -B build_android_ndk_arm64 \
    -DCMAKE_TOOLCHAIN_FILE=android_ndk_fixed.cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -G "Unix Makefiles"

6. 编译选项配置

CMAKE_BUILD_TYPE Release 发布模式编译 DOBBY_GENERATE_SHARED ON 生成共享库 DOBBY_DEBUG OFF 关闭调试日志 NearBranch ON 启用近分支跳板 Plugin.SymbolResolver ON 启用符号解析器 Plugin.Android.BionicLinkerUtil ON 启用 Android Bionic 链接器工具
选项说明

7. 编译产物

编译成功后,在 build_android_ndk_arm64/ 目录下生成:

libdobby.so 共享库 Android ARM64 动态链接库 libdobby.a 静态库 Android ARM64 静态链接库
文件类型说明

8. 技术要点

  • 目标架构:ARM64(arm64-v8a)

  • 最低 Android 平台版本:Android 24(Android 7.0)

  • C++ 标准:C++11

  • C++ STL:c++_shared

  • 链接库:链接 Android 日志库(-llog

9. 源文件构成

libdobby.so 包含以下核心模块:

  • 核心架构支持:CPU 特性、寄存器管理

  • 汇编器:ARM64 架构汇编器

  • 代码生成:ARM64 代码生成器

  • 内存管理:代码缓冲区、内存分配器

  • 指令重定位:ARM64 指令重定位

  • 拦截路由:函数拦截、内联 Hook

  • 平台适配:Android 用户模式支持

  • 内置插件:SymbolResolver 等

总结:按照上述步骤即可完成 Android ARM64 平台的 libdobby.so 编译。

第二步

我创建一个demo

https://gitee.com/null_465_7266/dobbyandroidproject

我这里也有将两步合并为一步的代码

https://gitee.com/null_465_7266/dobbydemo

这是上面代码精简只保留arm64的代码,方便分析原理

https://gitee.com/null_465_7266/dobbyandroid

Dobby Hook框架实现原理深度分析

一、整体架构概览

text

┌─────────────────────────────────────────────────────┐
│                   Public API Layer                   │
│         DobbyHook / DobbyInstrument / DobbyDestroy  │
└──────────────────────┬──────────────────────────────┘
┌──────────────────────▼──────────────────────────────┐
│                  Interceptor                         │
│              (Hook Entry 管理中心)                    │
│           双向链表维护所有HookEntry                   │
└──────────────────────┬──────────────────────────────┘
┌──────────────────────▼──────────────────────────────┐
│               InterceptRouting                       │
│    FunctionInlineReplace / DynamicBinaryInstrument  │
│              (路由调度核心)                           │
└──────┬───────────────┬──────────────────────────────┘
       │               │
┌──────▼──────┐ ┌──────▼──────────────────────────────┐
│ Trampoline  │ │    ClosureTrampolineBridge            │
│  跳板生成   │ │  闭包跳板+寄存器上下文保存/恢复       │
└──────┬──────┘ └──────┬──────────────────────────────┘
       │               │
┌──────▼───────────────▼──────────────────────────────┐
│           InstructionRelocation                      │
│              指令重定位引擎                           │
└──────────────────────┬──────────────────────────────┘
┌──────────────────────▼──────────────────────────────┐
│    Assembler / CodeGen / CodeBuffer / MemoryArena    │
│           底层汇编/内存管理基础设施                   │
└─────────────────────────────────────────────────────┘

二、核心数据结构

2.1 HookEntry —— Hook的基本信息单元

C

typedef struct {
    int id;
    int type;  // kFunctionWrapper / kFunctionInlineHook / kDynamicBinaryInstrument

    union {
        void *target_address;
        void *function_address;
        void *instruction_address;
    };

    void *route;  // 指向对应的InterceptRouting子类实例

    union {
        void *relocated_origin_instructions;  // 重定位后的原始指令地址
        void *relocated_origin_function;
    };

    AssemblyCodeChunkBuffer origin_chunk_;  // 保存被覆盖的原始字节
} HookEntry;

关键设计:

  • origin_chunk_保存原始指令字节,用于DobbyDestroy时恢复
  • relocated_origin_instructions指向重定位后的代码,供Hook返回时执行原始逻辑

2.2 Interceptor —— 单例Hook管理器

C++

// 使用Linux内核风格的双向循环链表管理所有HookEntry
struct list_head hook_entry_list_;  // 链表头

// 核心操作
FindHookEntry(void *address)   // 按地址查找
AddHookEntry(HookEntry *entry) // 插入链表头部
RemoveHookEntry(void *address) // 从链表删除

三、DobbyHook核心流程

DobbyHook(address, replace_call, origin_call)为例,完整执行流程:

text

DobbyHook()
    ├─1─► 创建 HookEntry
    │         type = kFunctionInlineHook
    │         function_address = address
    ├─2─► 创建 FunctionInlineReplaceRouting
    ├─3─► route->Prepare()          [空实现,留给子类扩展]
    ├─4─► route->DispatchRouting()
    │         │
    │         ├─► BuildReplaceRouting()
    │         │       SetTrampolineTarget(replace_call)
    │         │       GenerateTrampolineBuffer(target, replace_call)
    │         │             │
    │         │             └─► 生成跳转到replace_call的机器码
    │         │                 (arm64: adrp+add+br 或 ldr+br)
    │         │                 (x64:  jmp [rip+offset])
    │         │
    │         └─► GenerateRelocatedCode(tramp_size)
    │                 │
    │                 ├─► 读取target处原始指令(tramp_size字节)
    │                 ├─► 调用 GenRelocateCodeAndBranch()
    │                 │       重定位PC相关指令 + 末尾追加跳回原函数的branch
    │                 └─► 保存原始字节到 origin_chunk_
    ├─5─► Interceptor::AddHookEntry(entry)
    ├─6─► *origin_call = entry->relocated_origin_function
    └─7─► route->Commit()  =>  route->Active()
              CodePatch(target_address, trampoline_buffer, size)
              [实际写入跳转指令,劫持控制流]

四、指令重定位引擎(以ARM64为例)

这是整个框架最精密的部分。ARM64使用PC相对寻址,搬移指令时必须修正。

4.1 需要重定位的指令类型

text

┌──────────────────────┬────────────────────────────────────┐
│ 指令类型              │ 重定位策略                          │
├──────────────────────┼────────────────────────────────────┤
│ LDR (literal)        │ Mov(TMP, abs_addr) + LDR [TMP, 0]  │
│ ADR / ADRP           │ Mov(Xrd, runtime_address)           │
│ B / BL               │ Ldr(TMP, label) + BR/BLR TMP        │
│ TBZ / TBNZ           │ 反转条件 + 跳过 + Ldr + BR          │
│ CBZ / CBNZ           │ 反转条件 + 跳过 + Ldr + BR          │
│ B.cond               │ 反转条件 + 跳过 + Ldr + BR          │
│ 其他指令              │ 原样复制                            │
└──────────────────────┴────────────────────────────────────┘

4.2 条件跳转重定位原理

CBZ X0, #far_target为例,原始范围±1MB,重定位后需跳到任意地址:

asm

; 原始代码(在原地址)
CBZ X0, #far_target        ; 如果X0==0,跳到far_target

; 重定位后代码(在新地址)
CBNZ X0, #skip            ; 条件取反:如果X0!=0,跳过branch块
LDR  X17, =far_target      ; 加载绝对地址到临时寄存器
BR   X17                   ; 无条件跳转
skip:
; ... 继续执行下一条重定位指令

关键细节:条件取反(op ^ 1),固定偏移为4 * 3 = 12字节(branch_instr + ldr + br)

4.3 重定位代码末尾追加回跳

C++

// 所有需要重定位的指令处理完后
CodeGen codegen(&turbo_assembler_);
codegen.LiteralLdrBranch(curr_orig_pc);  // 跳回原函数剩余部分

五、跳板(Trampoline)生成机制

5.1 ARM64普通跳板

根据源地址和目标地址的距离选择策略:

text

距离 < 128MB (adrp范围):
    ADRP  X17, to_PAGE - from_PAGE   ; 4字节
    ADD   X17, X17, to_PAGEOFF       ; 4字节
    BR    X17                         ; 4字节
    共12字节

距离 >= 128MB:
    LDR   X17, #8        ; 4字节,从后面的label加载
    BR    X17            ; 4字节
    .quad target_addr    ; 8字节
    共16字节

5.2 ARM64近跳板(NearBranchTrampoline插件)

当启用dobby_enable_near_branch_trampoline()时,只需4字节:

asm

B #offset   ; 单条B指令,范围±128MB

如果目标超出范围,则在±128MB内分配一个快速转发跳板(fast forward trampoline),形成二级跳转:

text

原函数 --[B #near]--> 快速转发跳板 --[Adrp+Add+Br]--> 目标地址

5.3 x64跳板

使用RIP相对间接跳转(6字节):

asm

FF 25 XX XX XX XX    ; JMP [RIP + offset]
                     ; offset指向存有绝对目标地址的内存位置

六、ClosureTrampolineBridge(闭包跳板桥)

这是DobbyInstrument(DBI模式)的核心,用于在不知道具体目标函数的情况下,将任意Hook点的上下文打包传递给用户回调。

6.1 整体结构

text

ClosureTrampolineEntry {
    void *address;        // 跳板代码地址
    void *carry_data;     // 携带的数据(HookEntry*)
    void *carry_handler;  // 处理函数(instrument_routing_dispatch)
}

6.2 ARM64完整执行流程

text

原函数入口
[ClosureTrampoline 代码]
    │  SUB SP, SP, #16          ; 分配栈空间
    │  STR X30, [SP, #8]        ; 保存LR
    │  LDR X17, =entry          ; 加载ClosureTrampolineEntry*
    │  STR X17, [SP, #0]        ; 压栈(作为closure_bridge的参数)
    │  LDR X17, =closure_bridge ; 加载closure_bridge地址
    │  BLR X17                  ; 调用closure_bridge(执行后X17=next_hop)
    │  LDR X30, [SP, #8]        ; 恢复LR
    │  ADD SP, SP, #16          ; 释放栈
    │  BR  X17                  ; 跳转到next_hop(重定位后的原始指令)

[closure_bridge 代码](动态生成)
    │  ; 保存完整寄存器上下文
    │  SUB SP, SP, #(8*16)      ; 为q0-q7分配空间
    │  STP Q6, Q7, [SP, #96]
    │  ... (保存所有浮点寄存器)
    │  SUB SP, SP, #(30*8)      ; 为x1-x30分配空间
    │  STP X29, X30, [SP, #224]
    │  ... (保存所有通用寄存器)
    │  SUB SP, SP, #16
    │  STR X0, [SP, #8]         ; 保存X0
    │  ; 计算原始SP
    │  ADD X17, SP, #(2*8 + 2*8 + 30*8 + 8*16)
    │  SUB SP, SP, #16
    │  STR X17, [SP, #8]        ; 保存原始SP
    │  MOV X0, SP               ; arg1 = RegisterContext*
    │  LDR X1, [SP, #REGISTER_CONTEXT_SIZE] ; arg2 = ClosureTrampolineEntry*
    │  CALL intercept_routing_common_bridge_handler
    │  ; 恢复寄存器
    │  ADD SP, SP, #16          ; 释放SP占位
    │  LDR X0, [SP, #8]
    │  ADD SP, SP, #16          ; 释放X0占位
    │  LDP X1, X2, [SP], #16   ; 恢复x1-x30
    │  ... (恢复所有寄存器)
    │  LDP Q0, Q1, [SP], #32   ; 恢复浮点寄存器
    │  ...
    │  RET                      ; 返回ClosureTrampoline(X17已是next_hop)

6.3 RegisterContext内存布局(ARM64)

text

高地址
┌──────────────────┐  ← 原始SP
│  原始SP(8字节)  │
│  dummy(8字节)   │
├──────────────────┤
│  x0(8字节)      │
│  dummy(8字节)   │
├──────────────────┤
│  x1...x28(29*8)│
├──────────────────┤
│  fp=x29(8字节) │
│  lr=x30(8字节) │
├──────────────────┤
│  q0...q7(8*16) │
低地址(当前SP)

对应dobby.h中的RegisterContext结构体,用户回调可直接读写寄存器。

七、DBI路由处理链

text

instrument_routing_dispatch(ctx, closure_trampoline_entry)
    ├─► entry = closure_trampoline_entry->carry_data  (HookEntry*)
    └─► instrument_call_forward_handler(ctx, entry)
            ├─► route = entry->route  (DynamicBinaryInstrumentRouting*)
            ├─► 调用用户的 handler(ctx, &entry_info)
            │       用户可在此读写所有寄存器
            └─► set_routing_bridge_next_hop(ctx, entry->relocated_origin_instructions)
                    // 设置 ctx->general.x[17] = relocated_addr
                    // closure_bridge结束后BR X17跳到重定位后的原始指令

八、内存管理子系统

8.1 MemoryArena(普通内存池)

text

page_chunks (LiteMutableArray)
    ├─► PageChunk_1 (kReadExecute, 4KB)
    │       page_cursor → 当前分配位置
    │       chunks[] → [CodeChunk1, CodeChunk2, ...]
    └─► PageChunk_2 (kReadWrite, 4KB)
            ...

分配流程:

  1. 遍历已有页面,找到同权限且有剩余空间的页
  2. 没有则mmap分配新页(4KB)
  3. 从页面的page_cursor处划分内存块

8.2 NearMemoryArena(近端内存池)

pos ± alloc_range范围内寻找可用内存,两种策略:

策略1:寻找空白页面(search_near_blank_page)

text

遍历进程内存布局 → 找相邻region之间的空洞 → mmap分配

策略2:寻找代码洞(search_near_blank_memory_chunk)

text

在已有可执行页面中 → 用memmem搜索连续零字节 → 直接写入
(适用于无法分配新页的限制环境)

8.3 CodeBuffer层次结构

text

LiteMutableBuffer(动态扩容缓冲区)
    └─► CodeBufferBase(添加Emit8/16/32/64)
            ├─► CodeBuffer(ARM)   : +EmitARMInst/EmitThumb1/2Inst
            ├─► CodeBuffer(ARM64) : +EmitInst/Emit64/FixBindLabel
            ├─► CodeBuffer(x86)   : +Emit32/FixBindLabel
            └─► CodeBuffer(x64)   : +Emit32/Emit64/FixBindLabel

九、代码修补(CodePatch)多平台实现

9.1 Linux/Android

C++

mprotect(page, size, PROT_READ|PROT_WRITE|PROT_EXEC)  // 改权限
memcpy(target, buffer, size)                            // 写入
mprotect(page, size, PROT_READ|PROT_EXEC)              // 恢复权限
ClearCache(start, end)                                  // 清指令缓存

9.2 macOS/iOS(关键)

iOS不允许直接修改可执行页,使用mach_vm_remap技巧:

text

1. mmap 分配新匿名页(dummy_page)
2. memcpy 原始页内容到 dummy_page
3. 在 dummy_page 上 patch 目标字节
4. mprotect dummy_page 为 READ|EXEC
5. mach_vm_remap(self_port, &target_page, ..., dummy_page, ...)
   → 将 dummy_page 重映射覆盖到 target_page 的虚拟地址
   → 绕过 W^X 限制
6. munmap dummy_page
7. ClearCache

9.3 ARM64缓存清除关键步骤

C

// 1. 清D-cache(数据缓存到统一点)
for (addr = start; addr < end; addr += dcache_line_size)
    "dc cvau, addr"

// 2. 数据同步屏障
"dsb ish"

// 3. 清I-cache(指令缓存)
for (addr = start; addr < end; addr += icache_line_size)
    "ic ivau, addr"

// 4. 指令同步屏障
"isb sy"

十、汇编器Label系统

Dobby实现了一个两阶段label绑定系统:

text

Label状态机:
    unused (pos_=0)
        │ link_to(pos)
    linked (pos_>0)  ←─── link_to(pos) 形成链表
        │ bind_to(pos)
    bound (pos_<0)

PseudoLabel扩展了Label,记录所有引用该label的指令位置:

C++

// 前向引用场景:
Ldr(X17, &label)        // 此时label未绑定,记录当前位置到instructions_[]
...
PseudoBind(&label)       // 绑定label
EmitInt64(data)          // 发射实际数据
    └─► link_confused_instructions()
            // 回填之前所有LDR指令的偏移量
            encoded = inst32 & 0xFF00001F
            encoded |= LeftShift((offset >> 2), 19, 5)
            FixBindLabel(position, encoded)

十一、多架构跳板对比

ARM64 12B(近) / 16B(远) ADRP+ADD+BR / LDR+BR+data 4B (B #off) ARM 8B LDR PC, [PC,-4] + data 4B (B #off) x86 5B JMP rel32 - x64 6B+8B JMP [RIP+0] + abs_addr -
架构普通跳板大小指令序列近跳板大小

十二、DobbyDestroy恢复机制

C++

PUBLIC int DobbyDestroy(void *address) {
    HookEntry *entry = Interceptor::SharedInstance()->FindHookEntry(address);
    if (entry) {
        uint8_t *buffer = entry->origin_chunk_.chunk_buffer;   // 原始字节
        uint32_t size   = entry->origin_chunk_.chunk.length;   // 原始大小

        // ARM需要去掉Thumb标记位(最低bit)
        #if TARGET_ARCH_ARM
        address = (void*)((addr_t)address - 1);
        #endif

        CodePatch(address, buffer, size);  // 恢复原始指令
        Interceptor::SharedInstance()->RemoveHookEntry(address);
        return RT_SUCCESS;
    }
    return RT_FAILED;
}

十三、关键设计决策总结

Hook管理 单例+侵入式双向链表 轻量,无STL依赖 寄存器保存 动态汇编生成 灵活,支持运行时决策 指令重定位 逐条解码+重写 处理所有PC相关指令 iOS写保护绕过 mach_vm_remap 唯一合法绕过W^X的方式 近端内存 进程布局扫描+代码洞 最小化跳板大小 前向label 两阶段绑定+回填 支持不知道目标地址时先emit 跨平台 编译期宏隔离 零运行时开销
设计点实现方案原因

免责声明 本文档所有内容仅供安全研究、学术交流与技术学习使用,严禁用于任何未经授权的逆向破解、网络攻击、隐私窃取、恶意软件开发及其他违反《中华人民共和国网络安全法》《数据安全法》等法律法规的行为,使用者应确保已获得目标软件权利人的合法授权并自行承担因使用本文档内容所产生的一切法律责任与后果,作者不对任何直接或间接损害承担任何责任,继续阅读即视为您已知悉并同意上述全部条款。