2个版本
0.1.5 | 2021年10月6日 |
---|---|
0.1.0 | 2021年10月6日 |
#12 在 #cheat
每月26次 下载
在 toy-arms 中使用
2KB
什么是toy-arms?
这个库是为了测试Rust在游戏作弊方面的能力而创建的。你知道这有点偏离常规编程,对吧?然而,因为我太懒惰,又是初学者,所以这个库相对较高层次,这意味着它不使用Nt或Zw API,并且只能执行用户模式应用程序能够执行的事情。不要期望有什么花哨的功能,而应该将这视为我对Rust的训练,不能保证代码的质量。哦,而且永远不要提及那个奇怪的项目结构,即使它看起来很令人作呕。我的错。
📌 目录
🔥 开始
但在实际测试示例之前,我会向你展示一些你应该知道的准备步骤。
步骤1
首先,在Cargo.toml
中的依赖项表中包含toy-arms
。
截至目前,toy-arms有2个功能,分别是internal
和external
。默认情况下,internal
功能标志是开启的,所以当你想使用它时,你必须指定external
。
内部使用
[dependencies]
toy-arms = {git = "version = "https://github.com/pseuxide/toy-arms"}
# This annotation below is to tell the compiler to compile this into dll. MUST.
[lib]
crate-type = ["cdylib"]
外部使用
[dependencies]
toy-arms = {git = "https://github.com/pseuxide/toy-arms", features = ["external"]}
步骤2
其次,由于大多数测试都是针对“csgo.exe(x86)”游戏,你可能必须根据示例构建32位架构的代码。你可以在.cargo/config.toml
中指定,如下所示
[build]
target = "i686-pc-windows-msvc"
或者每次构建代码时都使用--target i686-pc-windows-msvc
标志。
如果你没有32位msvc的工具链,请执行以下操作
rustup target add i686-pc-windows-msvc
📜 实际示例
在本节中,我将展示各种不同情况下内部和外部特性的各种示例。找到适合您需求的示例。
请注意,所有这些示例都是针对 CSGO:反恐精英全球攻势 的,所以请确保您已经获取它并使用它进行测试。
内部
欢迎来到内部黑客示例。通过构建这些示例,将生成一个dll文件,使用您拥有的任何dll注入器将其注入。
最简单的dll(内部)
使用这个crate,制作可能最小的可注入dll就像这样简单
cargob --examplein_simplest_dll --targeti686-pc-windows-msvc
/*
This is the demonstration of how to make the simplest hack with toy-arms.
*/
// 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.
internal::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
/*
This is the demonstration of how to use internal analysis feature in toy-arms.
This code gets module handle and function address of the func called MessageBoxA as an example.
Then read the value called dwForceAttack and overwrite it to make player shoot.
The offset DW_FORCE_ATTACK works as of the day i wrote this but it might not be up to date in your case.
*/
use toy_arms::internal::cast;
use toy_arms::utils::detect_keydown;
use toy_arms::utils::keyboard::{detect_keypress, VirtualKeyCode};
use internal::common::get_module_handle;
use winapi::shared::minwindef::HMODULE;
internal::create_entrypoint!(hack_main_thread);
// This offset has to be up to date.
const DW_FORCE_ATTACK: usize = 0x320BDE8;
fn hack_main_thread() {
let mut once = false;
// Gets module handle
let module_handle: HMODULE = get_module_handle("client.dll").unwrap();
println!("module handle = {:?}", module_handle as usize);
let shoot_flag = cast!(mut module_handle as usize + DW_FORCE_ATTACK, u8);
loop {
if !once {
println!("Press INSERT to exit...");
once = !once;
}
unsafe {
// Auto shoot
*shoot_flag = 5u8;
}
// To exit this hack loop when you input INSEERT KEY
if detect_keypress(VirtualKeyCode::VK_INSERT) {
break;
}
// just flexing this neat function xd.
if detect_keydown!(VirtualKeyCode::VK_HOME) {
println!("HOME is both pressed");
}
}
}
获取本地玩家健康(内部)
以下代码将检索csgo.exe中LocalPlayer对象的健康值。请注意,您必须更新DW_LOCAL_PLAYER
的偏移量。
cargob --examplein_get_localplayer_health --targeti686-pc-windows-msvc
/*
This example is the demonstration of getting player health with toy-arms internal memory analysis feature.
Make sure that you inject this image to csgo.exe.
also, the offset of DW_LOCAL_PLAYER works as of the day i wrote this but it might not be up to date in your case.
*/
use internal::cast;
use internal::module::Module;
use internal::GameObject;
use toy_arms::derive::GameObject;
use utils::keyboard::VirtualKeyCode;
internal::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: u32 = 0xDBF4BC;
fn hack_main_thread() {
let module = Module::from_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 as usize)) {
println!("health = {:?}", (*i).get_health());
};
if toy_arms::utils::keyboard::detect_keypress(VirtualKeyCode::VK_INSERT) {
break;
}
}
}
}
模式扫描(内部)
这是一个模式扫描示例,模式是针对csgo中的dwForceAttack。
cargob --examplein_pattern_scan --targeti686-pc-windows-msvc
/*
This is an example to demonstrate how to use powerful pattern scan feature in toy-arms.
Make sure you inject this image to csgo.exe.
The model pattern is for dwForceAttack.
*/
use internal::module::Module;
use toy_arms::utils::keyboard::{detect_keypress, VirtualKeyCode};
internal::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 mut client = Module::from_name("client.dll").unwrap();
match client.find_pattern(DW_FORCE_ATTACK_PATTERN) {
Some(i) => println!("[+] *dwForceAttack address: 0x{:x}", i),
None => println!("[-] Pattern not found"),
}
match client.pattern_scan(DW_FORCE_ATTACK_PATTERN, 2, 0) {
Some(i) => println!("[+] dwForceAttack 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
/*
This is the demonstration of how to use external feature of toy-arms.
Following code is trying to get process id and process handle first, then getting a value called dwClientState_state.
Then showing the way to overwrite value at dwForceAttack to make player shoot.
The offset DW_CLIENT_STATE, DW_CLIENT_STATE_STATE and DW_FORCE_ATTACK work as of the day i wrote this but it might not be up to date in your case.
*/
use toy_arms::external::process::Process;
use toy_arms::external::{read, write};
use toy_arms::utils::keyboard::VirtualKeyCode;
fn main() {
// This const has to be up to date.
const DW_FORCE_ATTACK: u32 = 0x320BDE8;
// Getting process information
let process = Process::from_process_name("csgo.exe").unwrap();
println!(
"[+] process id: {}, \n[+] process handle: {:?}",
process.id, process.handle
);
// You can get module information by using get_module_info
let module_info = process.get_module_info("client.dll").unwrap();
println!("[+] module name: {}", module_info.name);
loop {
// write helps you tamper with the value.
write::<u32>(
&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::utils::keyboard::detect_keypress(VirtualKeyCode::VK_INSERT) {
break;
}
}
}
获取本地玩家健康(外部)
获取本地玩家健康演示如下。小贴士:您不想使用usize作为指针类型,因为外部程序本身就是64位,因此缓冲区大小将是8字节,而实际的指针是4字节。使用u32或DWORD代替。
cargor --exampleex_get_localplayer_health --功能外部 --no-default-features
use external::error::{ReadWriteMemoryFailedDetail, TAExternalError};
use std::mem::size_of;
use toy_arms::external::error::TAExternalError::ReadMemoryFailed;
use toy_arms::external::module::Module;
use toy_arms::external::process::Process;
use toy_arms::external::read;
const DW_LOCAL_PLAYER: u32 = 0xDBF4BC;
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.base_address);
println!(
"[+] localplayer pointer pointer: 0x{:x}",
client.base_address + DW_LOCAL_PLAYER as usize
);
let mut localplayer: u32 = 0;
let ok = read::<u32>(
&csgo.handle,
client.base_address + DW_LOCAL_PLAYER as usize,
size_of::<u32>(),
&mut localplayer as *mut u32,
);
match ok {
Ok(_ok) => {
println!("[+] localplayer pointer: 0x{:x}", localplayer);
let mut health: u16 = 0;
// 0x100 is the offset of the health in player entity class.
let ok2 = read::<u16>(
&csgo.handle,
localplayer as usize + 0x100,
size_of::<u16>(),
&mut health as *mut u16,
);
match ok2 {
// This is what we wanted.
Ok(h) => println!("[+] localplayer's health: {}", health),
Err(ReadMemoryFailed(e)) => println!("{}", e),
Err(_) => println!("[-] some error"),
}
}
Err(e) => match e {
TAExternalError::ReadMemoryFailed(ReadWriteMemoryFailedDetail::ErrorPartialCopy) => {
println!("Partial Copy. Probably the address is protected")
}
TAExternalError::ReadMemoryFailed(ReadWriteMemoryFailedDetail::ErrorInvalidAddress) => {
println!("Invalid Address")
}
TAExternalError::ReadMemoryFailed(ReadWriteMemoryFailedDetail::ErrorInvalidHandle) => {
println!("Invalid Handle")
}
TAExternalError::ReadMemoryFailed(ReadWriteMemoryFailedDetail::UnknownError {
error_code,
}) => println!("Unknown Error: {}", error_code),
_ => println!(
"[-] error: {}\n[-] Maybe non-updated offset are the reason. update it yourself.",
e
),
},
}
}
模式扫描(外部)
这是一个模式扫描示例,模式是针对csgo中的dwForceAttack。
cargor --exampleex_pattern_scan --功能外部 --no-default-features
use toy_arms::external::process::Process;
use toy_arms::utils::keyboard::VirtualKeyCode;
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").unwrap();
// You can get module information by using get_client
let mut client = process.get_module_info("client.dll").unwrap();
let address = client.find_pattern(DW_FORCE_ATTACK_PATTERN);
match address {
Some(i) => println!("[+] found *dwForceAttack pattern at 0x{:x}", i),
None => println!("[-] NOTHING FOUND"),
}
let offset = client.pattern_scan::<u32>(DW_FORCE_ATTACK_PATTERN, 2, 0);
match offset {
Some(i) => println!("[+] found dwForceAttack 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::utils::detect_keydown!(VirtualKeyCode::VK_INSERT) {
break;
}
}
}
🗃️ 其他示例?
是的,您做到了!看看示例目录,您会看到更多示例!
但是,您可能需要手动更新一些示例中包含的偏移量。
始终参考hazedumper以获取最新的CSGO偏移量。
构建x86架构中的示例
cargo build --example EXAMPLE_NAME --target i686-pc-windows-msvc
🌿 API信息
外部 read()
函数
fn read<T>(
process_handle: &HANDLE,
base_address: usize,
size: usize,
buffer: *mut T,
)
确保按以下方式传递缓冲区
let mut buffer: u32 = 0; // Declare with mut keyword
read::<u32>(
&handle,
base_address,
size_of::<u32>(),
&mut buffer as *mut u32, // Must be the form of &mut buffer as *mut T
// These are equivalent to &buffer in C++.
);
内部 read()
函数和 cast!()
宏
在示例中,它们都是条件使用的。它们针对不同的用途。
cast!()
是基本的解引用,您当然可以使用它。
read()
是Module结构的成员方法。它允许您只需传递从模块基本地址要获取的偏移量,它会为您添加它们。cast!()
在幕后使用。
承认
hazedumper-rs - 作为模式扫描的参考模型
依赖项
~1.5MB
~36K SLoC