18 个版本 (6 个破坏性更新)
0.9.4 | 2022 年 3 月 24 日 |
---|---|
0.9.1 | 2021 年 11 月 16 日 |
#423 在 开发工具
58KB
896 行
什么是 toy-arms?
这是一个工具包,专为那些厌倦了用 C++ 编写游戏破解,但仍想以优雅的方式完成的人而设计。由于这个库封装了许多常用的 Windows API,您可以构建破解而无需与它们苦苦挣扎。通过使用它,您在编写底层代码时的许多压力都不会出现。
但请注意,由于我既不是专业的 Rust 编程人员,也不是专业的游戏破解人员,这个库可能仍然包含一些有缺陷的代码,这些代码可能导致意外的行为。如果您能通过发现它们并提交 PR 或 issue 来帮助我改进 toy-arms,我将不胜感激。
📌 目录
💕 支持我
通过 GitHub Sponsors 赞助我 是支持我和这个项目的最佳方式。您也可以通过 收藏此项目 或任何类型的 PR(无论是重构此项目还是添加新功能)来支持我,这将让我感到非常兴奋!
🔥 开始使用
但在实际测试示例之前,我将向您展示一些您应该了解的准备工作。
步骤1
首先,在 Cargo.toml
中将 toy-arms
包含在依赖项表中。
目前,toy-arms 有两个功能:internal
和 external
。默认情况下,internal
功能标志是开启的,所以当您想使用 external
时,您必须指定它。
内部使用
[dependencies]
toy-arms = "0.9.4"
# This annotation below is to tell the compiler to compile this into dll. MUST.
[lib]
crate-type = ["cdylib"]
外部使用
[dependencies]
toy-arms = {version = "0.9.4", features = ["external"]}
步骤2
其次,由于大多数测试都是针对 "csgo.exe(x86)" 游戏的,您可能需要根据示例构建 x86 架构的代码。您可以在 .cargo/config.toml
中指定如下:
[build]
target = "i686-pc-windows-msvc"
或者每次构建代码时都使用 --target i686-pc-windows-msvc
标志。
📜 实际示例
在本节中,我将向您展示各种不同情况下内部和外部功能的示例。找到适合您目的的一个。
请注意,所有这些示例都是针对 CSGO:反恐精英:全球攻势 的,所以请确保您拥有它并使用它进行测试。
内部
欢迎来到内部黑客示例。通过构建这些示例,将生成一个.dll文件,使用您拥有的任何.dll注入器注入它。
最简单的.dll(内部)
使用这个crate,创建最小的可注入.dll就像这样简单
cargob --examplein_simplest_dll --targeti686-pc-windows-msvc
// A neat macro which defines entry point instead of you.
// Also, you dont have to alloc/free console by yourself, console will show up when u compile into debug build.
toy_arms::create_entrypoint!(hack_main_thread);
// Main thread
fn hack_main_thread() {
// YOUR STUNNING CODE'S SUPPOSED TO BE HERE;
for i in 0..30000 {
println!("using toy-arms {}", i);
}
}
自动射击(内部)
这是覆盖csgo.exe中DW_FORCE_ATTACK值的代码,每次循环将其设置为0x5。注意,您必须检查DW_FORCE_ATTACK地址是否最新。
cargob --examplein_auto_shoot --targeti686-pc-windows-msvc
use toy_arms::VirtualKeyCode;
use toy_arms::external::Process;
use toy_arms::external::{ read, write };
fn main() {
// This const has to be up to date.
const DW_CLIENT_STATE: usize = 0x58CFC4;
const DW_CLIENT_STATE_STATE: usize = 0x108;
const DW_FORCE_ATTACK: usize = 0x31FE33C;
// Getting process information
let process = Process::from_process_name("csgo.exe");
println!(
"process id = {}, \nprocess handle = {:?}",
process.process_id, process.process_handle
);
// You can get module information by using get_module_info
let module_info = process.get_module_info("client.dll").unwrap();
println!("{}", module_info.module_name);
// read fetches the value at where the address is pointing.
// U have to specify the type of the value with turbofish
println!(
"{:x}",
read::<i32>(process.process_handle, read::<u32>(process.process_handle, process.get_module_base("engine.dll").unwrap() + DW_CLIENT_STATE).unwrap() as usize + DW_CLIENT_STATE_STATE).unwrap()
);
loop {
// write helps you tamper with the value.
write::<u32>(
process.process_handle,
process.get_module_base("client.dll").unwrap() + DW_FORCE_ATTACK as usize,
&mut 0x5,
)
.unwrap();
// Exit this loop by pressing INSERT
if toy_arms::detect_keypress(VirtualKeyCode::VK_INSERT) {
break;
}
}
}
获取本地玩家生命值(内部)
以下代码将检索csgo.exe中LocalPlayer对象的健康值。注意,您必须更新DW_LOCAL_PLAYER的偏移量。
cargob --examplein_localplayer_health --targeti686-pc-windows-msvc
use toy_arms::GameObject;
use toy_arms::{cast, create_entrypoint, VirtualKeyCode};
use toy_arms::internal::Module;
use toy_arms_derive::GameObject;
create_entrypoint!(hack_main_thread);
// This macro provides from_raw() func that ensures the base address is not null.
#[derive(GameObject)]
struct LocalPlayer {
pointer: *const usize, // Denote the base address of LocalPlayer to use it later in get_health() function.
}
impl LocalPlayer {
unsafe fn get_health(&self) -> u16 {
*cast!(self.pointer as usize + 0x100, u16)
}
}
// This offset has to be up to date.
const DW_LOCAL_PLAYER: i32 = 0xDB25DC;
fn hack_main_thread() {
let module = Module::from_module_name("client.dll").unwrap();
unsafe {
//let dw_local_player = memory.read_mut::<LocalPlayer>(0xDA244C);
loop {
if let Some(i) = LocalPlayer::from_raw(module.read(DW_LOCAL_PLAYER)) {
println!("health = {:?}", (*i).get_health());
};
if toy_arms::detect_keypress(VirtualKeyCode::VK_INSERT) {
break;
}
}
}
}
模式扫描(内部)
这是模式扫描示例,其中模式是针对csgo中的dwForceAttack。
cargob --examplein_pattern_scanning --targeti686-pc-windows-msvc
use toy_arms::{
detect_keypress,
internal::{
Module
},
VirtualKeyCode
};
toy_arms::create_entrypoint!(hack_main_thread);
const DW_FORCE_ATTACK_PATTERN: &str = "89 0D ? ? ? ? 8B 0D ? ? ? ? 8B F2 8B C1 83 CE 04";
fn hack_main_thread() {
let mut once = false;
let client = Module::from_module_name("client.dll").unwrap();
match client.find_pattern(DW_FORCE_ATTACK_PATTERN) {
Some(i) => println!("address: 0x{:x}", i),
None => println!("Pattern not found"),
}
match client.pattern_scan(
DW_FORCE_ATTACK_PATTERN,
2,
0,
) {
Some(i) => println!("address: 0x{:x}", i),
None => println!("Offset not found"),
}
loop {
if !once {
println!("Press INSERT to exit...");
once = !once;
}
// To exit this hack loop when you input INSEERT KEY
if detect_keypress(VirtualKeyCode::VK_INSERT) {
break;
}
}
}
外部
另一方面,以下代码展示了如何在外部篡改内存。
自动射击(外部)
这是覆盖csgo.exe中DW_FORCE_ATTACK值的代码,每次循环将其设置为0x5。注意,您必须检查DW_FORCE_ATTACK地址是否最新。
cargor --exampleex_auto_shoot --功能外部 --no-default-features
use toy_arms::VirtualKeyCode;
use toy_arms::external::Process;
use toy_arms::external::{ read, write };
fn main() {
// This const has to be up to date.
const DW_CLIENT_STATE: usize = 0x58CFC4;
const DW_CLIENT_STATE_STATE: usize = 0x108;
const DW_FORCE_ATTACK: usize = 0x31FE33C;
// Getting process information
let process = Process::from_process_name("csgo.exe");
println!(
"process id = {}, \nprocess handle = {:?}",
process.process_id, process.process_handle
);
// You can get module information by using get_module_info
let module_info = process.get_module_info("client.dll").unwrap();
println!("{}", module_info.module_name);
// read fetches the value at where the address is pointing.
// U have to specify the type of the value with turbofish
println!(
"{:x}",
read::<i32>(process.process_handle, read::<u32>(process.process_handle, process.get_module_base("engine.dll").unwrap() + DW_CLIENT_STATE).unwrap() as usize + DW_CLIENT_STATE_STATE).unwrap()
);
loop {
// write helps you tamper with the value.
write::<u32>(
process.process_handle,
process.get_module_base("client.dll").unwrap() + DW_FORCE_ATTACK as usize,
&mut 0x5,
)
.unwrap();
// Exit this loop by pressing INSERT
if toy_arms::detect_keypress(VirtualKeyCode::VK_INSERT) {
break;
}
}
}
获取本地玩家生命值(外部)
以下是获取本地玩家生命值演示。快捷提示:您不想使用usize作为指针类型,因为外部程序本身就是64位,因此缓冲区大小将是8字节,而实际指针是4字节。使用u32或DWORD。
cargor --exampleex_get_localplayer_health --功能外部 --no-default-features
use toy_arms::external::{Module, Process, read};
use toy_arms::external::error::TAExternalError::ReadMemoryFailed;
const DW_LOCAL_PLAYER: u32 = 0xDB35DC;
fn main() {
let csgo: Process;
match Process::from_process_name("csgo.exe") {
Ok(p) => csgo = p,
Err(e) => {
println!("{}", e);
return;
},
}
let client: Module;
match csgo.get_module_info("client.dll") {
Ok(m) => client = m,
Err(e) => {
println!("{}", e);
return;
},
}
println!("module_base: {:x}", client.module_base_address);
println!("localplayer pointer: 0x{:x}", client.module_base_address + DW_LOCAL_PLAYER as usize);
let localplayer = read::<u32>(csgo.process_handle, client.module_base_address + DW_LOCAL_PLAYER as usize);
match localplayer {
Ok(l) => {
println!("localplayer address: 0x{:x}", l);
// 0x100 is the offset of the health in player entity class.
let health = read::<u16>(csgo.process_handle, l as usize + 0x100);
match health {
// This is what we wanted.
Ok(h) => println!("localplayer's health: {}", h),
Err(ReadMemoryFailed(e)) => println!("{}", e),
Err(_) => println!("some error"),
}
},
Err(e) => println!("error: {}", e),
}
}
模式扫描(外部)
这是模式扫描示例,其中模式是针对csgo中的dwForceAttack。
cargor --exampleex_pattern_scanning --功能外部 --no-default-features
use toy_arms::{ VirtualKeyCode };
use toy_arms::external::Process;
const DW_FORCE_ATTACK_PATTERN: &str = "89 0D ? ? ? ? 8B 0D ? ? ? ? 8B F2 8B C1 83 CE 04";
fn main() {
let mut once = false;
// Getting process information
let process = Process::from_process_name("csgo.exe");
// You can get module information by using get_client
let client = process.get_module_info("client.dll").unwrap();
let address = client.find_pattern(DW_FORCE_ATTACK_PATTERN);
match address {
Some(i) => println!("found pattern at 0x{:x}", i),
None => println!("NOTHING FOUND"),
}
let offset = client.pattern_scan(
DW_FORCE_ATTACK_PATTERN,
2,
0,
);
match offset {
Some(i) => println!("found offset at 0x{:x}", i),
None => println!("NOTHING FOUND"),
}
loop {
if !once {
println!("Press INSERT to exit...");
once = !once;
}
// Exit this loop by pressing INSERT
if toy_arms::detect_keydown!(VirtualKeyCode::VK_INSERT) {
break;
}
}
}
🗃️ 其他示例?
是的!查看示例目录,您将看到更多示例!
然而,您可能需要手动更新一些示例中的偏移量。
始终参考hazedumper以获取最新的CSGO偏移量。
在x86架构中构建示例
cargo build --example EXAMPLE_NAME --target i686-pc-windows-msvc
依赖关系
~1.1–1.7MB
~37K SLoC