H0llyW00dzZ/dynoffsets
GitHub: H0llyW00dzZ/dynoffsets
一个Rust库,在调用时动态解析内存模式并支持字面量回退,简化游戏与软件逆向中的地址管理。
Stars: 0 | Forks: 0
# dynoffsets
[](https://codecov.io/gh/H0llyW00dzZ/dynoffsets)
[](https://crates.io/crates/dynoffsets)
[](https://docs.rs/dynoffsets)
在调用时使用字面量回退解析偏移量、全局变量、接口和按钮。
## 当前版本
- 官方权威来源:GitHub
- 仓库:
本项目旨在 GitHub 上公开发源。如果您在其他地方看到相同的源码,例如在 UC 论坛上,请将其视为本仓库的非官方转载或副本,除非 GitHub 仓库明确链接到该处。
## 安装
**推荐**:
```
cargo add dynoffsets
cargo add dynoffsets --features runtime # for runtime discovery
```
**在发布之前**,使用 git 依赖:
```
cargo add --git https://github.com/H0llyW00dzZ/dynoffsets
cargo add --git https://github.com/H0llyW00dzZ/dynoffsets --features runtime
```
**本地开发**(当您有 dynoffsets 的本地副本时):
```
dynoffsets = { path = "../dynoffsets" }
```
当您同时在开发 dynoffsets 本身和另一个项目时使用此方式。
推荐用法(使用宏):
```
#[schema]
pub mod C_BaseEntity {
pub const m_iHealth: usize = 0xDEAD_BEEF;
}
#[globals]
pub mod client_dll {
pub const dw_entity_list: usize = 0xDEAD_BEEF;
}
// Access as functions (live value or dead)
let hp = C_BaseEntity::m_iHealth();
let list = client_dll::dw_entity_list();
```
使用 `runtime` 特性 + `Process` 实现时,您将获得实时值。否则得到字面量。`no_std` + `alloc` 也可工作。
### 自定义内存后端
dynoffsets 是**后端无关的** — 您必须自带 `Process` 实现:
```
impl Process for MyBackend { ... } // usermode, kernel, DMA, etc.
dynoffsets::init(MyBackend::new());
```
支持的后端包括(但不限于):
- 用户态 `ReadProcessMemory`
- 内核驱动程序(任意 IOCTL、物理内存等)
- DMA / PCIe 卡、FPGA、Thunderbolt DMA
- 虚拟机监控器 / 虚拟机内省
现在对运行时全局变量和相关发现的模式扫描通过 reader 支持的 `pe-sigscan` API 进行,因此自定义后端也支持扫描,而不仅仅是基本读取。
如果您的后端是纯本地的并且可以安全解引用当前进程中的模块内存,请重写 `Process::scan_text` 和 `Process::resolve_rel32_at` 以调用直接的 `pe-sigscan` 快速路径以获得最佳性能。
请参阅 docs.rs 了解四个属性宏和 `Process` trait。
## 与 MinHook 一起使用
`dynoffsets` 不附带 detour API 或 MinHook 绑定。它的工作是解析地址;您的 hook 层负责安装钩子。
最常见的模式是:
1. 使用 `#[interfaces]` 解析活动的接口指针。
2. 读取您想要钩挂的方法的 vtable 槽位。
3. 将该函数入口地址传递给 MinHook。
`#[schema]`、`#[globals]` 和 `#[buttons]` 通常解析数据地址,而不是本身作为 hook 目标。
使用 `minhook-sys` 的示例框架:
```
use core::{ffi::c_void, mem, ptr};
use dynoffsets::interfaces;
use minhook_sys::{MH_CreateHook, MH_EnableHook, MH_Initialize, MH_OK};
#[interfaces("engine2.dll")]
mod engine2 {
pub const Source2EngineToClient001: usize = 0;
}
type TargetFn = unsafe extern "system" fn(this: *mut c_void, arg: i32) -> i32;
static mut ORIGINAL_TARGET: Option = None;
unsafe extern "system" fn hk_target(this: *mut c_void, arg: i32) -> i32 {
let original = ORIGINAL_TARGET.expect("hook not installed");
original(this, arg)
}
unsafe fn vfunc(instance: usize, index: usize) -> *mut c_void {
let vtable = *(instance as *const *const usize);
*vtable.add(index) as *mut c_void
}
unsafe fn install_hook() {
let iface = engine2::Source2EngineToClient001();
assert_ne!(iface, 0, "interface was not resolved");
// Replace 42 with the real vtable index for the method you want.
let target = vfunc(iface, 42);
assert_eq!(MH_Initialize(), MH_OK);
let mut original = ptr::null_mut();
assert_eq!(
MH_CreateHook(target, hk_target as *mut c_void, &mut original),
MH_OK,
);
ORIGINAL_TARGET = Some(mem::transmute(original));
assert_eq!(MH_EnableHook(target), MH_OK);
}
```
同样的想法也适用于导出函数:使用您自己的后端或模块逻辑解析函数入口,然后将该地址交给 MinHook。
## 代办事项
- [ ] 原生 Linux 支持。该 crate 目前仅适用于 Windows。
## cs2-dumper 与 dynoffsets 对比
[cs2-dumper](https://github.com/a2x/cs2-dumper) 是一个外部分析工具,用于生成静态偏移头文件。dynoffsets 是库替代方案:它将相同的模式烘焙到二进制文件中,并在加载时解析它们(当禁用 runtime 特性时回退到您编写的字面量)。仅移动地址的小型游戏更新通常可以无需重新生成头文件而存活。
MSRV 1.72. [MIT](./LICENSE).
| ``` _ __ __ _ __| |_ _ _ __ ___ / _|/ _|___ ___| |_ ___ / _` | | | | '_ \ / _ \ |_| |_/ __|/ _ \ __/ __| | (_| | |_| | | | | (_) | _| _\__ \ __/ |_\__ \ \__,_|\__, |_| |_|\___/|_| |_| |___/\___|\__|___/ |___/ dynoffsets by H0llyW00dzZ (@github.com/H0llyW00dzZ) ``` |
标签:CS:GO, Hook, Rust, 云资产清单, 偏移量, 全局变量, 内存偏移, 动态解析, 可视化界面, 字面后备, 宏, 延迟绑定, 按钮, 接口, 游戏作弊, 游戏修改, 网络流量审计, 运行时, 逆向工程, 通知系统