[BROKEN] push new mechanism

This commit is contained in:
pozm 2024-01-30 19:52:36 +00:00
parent 627c4f0ce8
commit 48fde349b7
No known key found for this signature in database
GPG Key ID: 5AB655AFC8AAA822
10 changed files with 151 additions and 2690 deletions

2367
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
workspace = { members = ["gdkeinj"] }
[package] [package]
name = "gdke" name = "gdke"
version = "0.1.0" version = "0.1.0"
@ -14,11 +15,22 @@ inherits = "release"
debug = true debug = true
strip = false strip = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace] # [workspace]
members = [ # members = ["gdke-gui"]
"gdke-gui",
]
[dependencies] [dependencies]
windows = { features = [
"Win32_Foundation",
"Win32_System",
"Win32_System_Threading",
"Win32_System_Diagnostics",
"Win32_System_Diagnostics_Debug",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Kernel",
"Win32_System_ProcessStatus",
"Win32_Security",
], version = "0.52" }
# dll-syringe = "*"
poggers = { version = "*", path = "../poggers" } poggers = { version = "*", path = "../poggers" }
crossbeam = "0.8.2" crossbeam = "0.8.2"

View File

@ -1,17 +0,0 @@
[package]
name = "gdke-gui"
version = "0.1.5"
edition = "2021"
[profile.release]
lto = true
strip = true
opt-level = "z"
codegen-units = 1
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
egui = "0.21.0"
eframe = { version = "0.21.3" }
poggers = {version = "*", path = "../../poggers"}
gdke = {path= ".."}

View File

@ -1,175 +0,0 @@
use std::{
borrow::BorrowMut,
cell::RefCell,
ops::Deref,
rc::Rc,
sync::mpsc::{Receiver, Sender},
};
use eframe::CreationContext;
use egui::{TextEdit, TextStyle};
use poggers::structures::{
create_snapshot::{STProcess, ToolSnapshot},
process::{External, Process},
};
use crate::Data;
pub struct gdkeApp {
procs: Rc<RefCell<Vec<STProcess>>>,
selected: Option<STProcess>,
awaiting: bool,
last_key: String,
process: Option<Process<External>>,
search_query: String,
rx: Option<std::sync::mpsc::Receiver<Data>>,
tx: Option<std::sync::mpsc::Sender<Data>>,
}
impl Default for gdkeApp {
fn default() -> Self {
let procs = if let Ok(procs) = ToolSnapshot::new_process().map(|x| x.collect()) {
procs
} else {
Vec::new()
};
Self {
procs: Rc::new(RefCell::new(procs)),
selected: None,
process: None,
search_query: String::new(),
rx: None,
awaiting: false,
last_key: String::new(),
tx: None,
}
}
}
impl gdkeApp {
pub fn new(cc: &CreationContext<'_>, rx: Receiver<Data>, tx: Sender<Data>) -> gdkeApp {
Self {
tx: Some(tx),
rx: Some(rx),
..Default::default()
}
}
}
impl eframe::App for gdkeApp {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
let Self {
last_key,
awaiting,
rx,
tx,
procs,
selected,
process,
search_query,
} = self;
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("GDKE");
ui.separator();
egui::Window::new("Key")
.collapsible(false)
.resizable(true)
.open(awaiting)
.show(ctx, |ui| {
ui.label("Getting key, please wait...");
if !last_key.is_empty() {
let mut keyda = last_key.clone();
TextEdit::singleline(&mut keyda).show(ui);
ui.label("Close this window when done.");
} else if let Ok(data) = rx.as_ref().unwrap().try_recv() {
match data {
Data::Key(key) => {
println!("Got key: {}", key);
*last_key = key;
}
Data::Failure(e) => {
println!("Failed to get key");
*last_key = format!("Failed to get key: {}", e);
}
Data::Pid(_) => {
unreachable!()
}
Data::EXIT => {
unreachable!()
}
}
} else {
ui.centered_and_justified(|ui| {
ui.spinner();
});
}
});
if !*awaiting {
ui.label("Select a Godot process to find the encryption key for.");
egui::TextEdit::singleline(&mut self.search_query)
.hint_text("Search...")
.show(ui);
let text_style = TextStyle::Body;
let row_height = ui.text_style_height(&text_style);
if ui.button("refresh processes").clicked() {
procs.clone().borrow_mut().replace(
if let Ok(procs) = ToolSnapshot::new_process().map(|x| x.collect()) {
procs
} else {
Vec::new()
},
);
}
let mut procsrn = procs.clone();
let proca = procsrn.borrow();
let filtered_procs = if self.search_query.is_empty() {
proca.iter().collect::<Vec<&STProcess>>()
} else {
proca
.iter()
.filter(|p| {
p.exe_path.contains(&self.search_query)
|| p.id.to_string().contains(&self.search_query)
})
.collect()
};
let selval = selected.clone();
ui.separator();
egui::ScrollArea::vertical()
.max_height(if selval.is_none() {
f32::INFINITY
} else {
260f32
})
.auto_shrink([false; 2])
.show_rows(
ui,
row_height,
filtered_procs.len(),
move |ui, row_range| {
for row in row_range {
if let Some(proc) = (&filtered_procs).get(row) {
let owner_proc = proc.deref();
ui.selectable_value(
selected,
Some(owner_proc.clone()),
&proc.exe_path,
);
}
}
},
);
if let Some(selected) = selval {
ui.separator();
if ui
.button(format!("get key for {}", selected.exe_path))
.clicked()
{
tx.as_ref().unwrap().send(Data::Pid(selected.id)).unwrap();
*awaiting = true;
last_key.clear();
}
}
}
});
}
}

View File

@ -1,11 +0,0 @@
use std::error::Error;
pub mod app;
pub enum Data {
Pid(u32),
Key(String),
Failure(String),
EXIT
}

View File

@ -1,54 +0,0 @@
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use std::error::Error;
use gdke_gui::{app::gdkeApp, Data};
fn main() {
let (stx, srx) = std::sync::mpsc::channel::<Data>();
let (ctx, crx) = std::sync::mpsc::channel::<Data>();
let jh = std::thread::spawn(move || {
loop {
if let Ok(x) = crx.try_recv() {
match x {
Data::Pid(pid) => {
println!("Got pid: {}", pid);
match (|| -> Result<(), Box<dyn Error>> {
let key = gdke::get_from_pid(pid)?;
stx.send(Data::Key(key)).unwrap();
Ok(())
// Err("Failed to find key".into())
})() {
Ok(_) => {}
Err(er) => {
println!("Error: {}", er);
stx.send(Data::Failure(er.to_string())).unwrap();
continue;
}
}
}
Data::EXIT => {
break;
}
_ => {}
}
}
std::thread::sleep(std::time::Duration::from_millis(1000));
}
});
let native_options = eframe::NativeOptions::default();
let ctx2 = ctx.clone();
eframe::run_native(
"gdke",
native_options,
Box::new(move |cc| Box::new(gdkeApp::new(cc, srx, ctx2))),
);
ctx.send(Data::EXIT).unwrap();
jh.join();
}

12
gdkeinj/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "gdkeinj"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
[dependencies]
poggers = { path = "../../poggers" }
poggers-derive = { path = "../../poggers/poggers-derive/" }

4
gdkeinj/src/lib.rs Normal file
View File

@ -0,0 +1,4 @@
#[poggers_derive::create_entry(no_free)]
pub fn main() {
println!("hi");
}

View File

@ -1,69 +1,101 @@
use std::error::Error; #![feature(offset_of)]
use std::{
use poggers::{ error::Error,
structures::{ ffi::{c_void, CStr, CString},
modules::Module, mem::{size_of, transmute},
process::{implement::utils::ProcessUtils, External, Process}, ptr::{addr_of, null, null_mut},
}, time::Duration,
traits::{Mem, MemError},
}; };
/// # Safety
/// this is a private crate so stooop clippy
pub unsafe fn resolve_relative_ptr(
proc: &Module<Process<External>>,
addr: usize,
offset: usize,
) -> Result<usize, MemError> {
let real_offset = proc.get_owner().read::<u32>(addr)?;
println!("Real offset: {:X?}", real_offset);
let rel = (addr - proc.get_base_address()) + offset;
let real = rel + real_offset as usize;
println!("Real: {:X?}", real);
Ok(proc.get_base_address() + real)
// Err(anyhow!("lazy"))
}
pub const SIGS: [&str; 6] = [
"BA 20 00 00 00 4C 89 ? ? 48 8D", // GD 4.2 (from master branch)
"48 8D 1D ? ? ? ? 4C 8D 2D ? ? ? ? 48 8D 35", // godot 4.0.0
"48 8D 3D ? ? ? ? 48 85 C0 74 3B",
"48 8D 05 ? ? ? ? 41 8A 04 04",
"48 8D 05 ? ? ? ? 0F B6 ? 03",
"4C 8D 05 ? ? ? ? 0F 1F 40 00",
];
pub fn get_from_pid(pid: u32) -> Result<String, Box<dyn Error>> { use dll_syringe::{process::OwnedProcess, Syringe};
let proc = Process::find_pid(pid)?; use poggers::{structures::process::Process, traits::Mem};
let bm = proc.get_base_module()?; use windows::Win32::System::{
// println!("Base module: {:X?}", bm); Diagnostics::Debug::{GetThreadContext, CONTEXT, IMAGE_NT_HEADERS64},
for sig in &SIGS { Threading::{ResumeThread, SuspendThread},
let timer = std::time::Instant::now(); };
let res = bm.scan(sig); use windows::{
println!("Scan took: {}ms", timer.elapsed().as_millis()); core::{PCSTR, PSTR},
if let Ok(Some(x)) = res { Win32::{
println!("hey! something was found!"); Foundation::{BOOL, HINSTANCE},
let data = unsafe { resolve_relative_ptr(&bm, x + 3, 4) }; System::{
if let Ok(x) = data { ProcessStatus::{K32GetModuleInformation, MODULEINFO},
println!("found key @ {:X}", x); SystemServices::IMAGE_DOS_HEADER,
let mut key_data = [0u8; 32]; Threading::{
if unsafe { proc.raw_read(x, &mut key_data as *mut u8, 32) }.is_ok() CreateProcessA, NtQueryInformationProcess, ProcessBasicInformation,
&& !key_data.is_empty() TerminateProcess, CREATE_SUSPENDED, PEB, PROCESS_BASIC_INFORMATION,
{ PROCESS_INFORMATION, STARTUPINFOA,
let mut data_string = String::new(); },
for i in &key_data[..] { },
data_string.push_str(&format!("{:02X}", i)); },
} };
return Ok(data_string);
} fn create_pstr(c_str: &CStr) -> PSTR {
} else { PSTR::from_raw(c_str.as_ptr() as *mut u8)
return Err("Unable to resolve lea relative ptr".into());
}
// println!("Found sig: {:X}", x);
} else {
println!("Failed to find with sig: {}", sig);
// return Err("Failed to find with sig".into());
}
}
// Ok(())
Err("Failed to find key".into())
} }
pub unsafe fn spawn_and_inject(proc: &str) {
let cmd_line_c = CString::new(proc).expect("invalid cstr");
let start_up_info = STARTUPINFOA {
..Default::default()
};
let mut proc_info = PROCESS_INFORMATION {
..Default::default()
};
let mod_name = PCSTR::null();
CreateProcessA(
mod_name,
create_pstr(cmd_line_c.as_c_str()),
None,
None,
BOOL(0),
CREATE_SUSPENDED,
None,
mod_name,
&start_up_info,
&mut proc_info,
);
// patch entry point...
let mut ptr_to_pbi: PROCESS_BASIC_INFORMATION = std::mem::zeroed();
let stat = NtQueryInformationProcess(
proc_info.hProcess,
ProcessBasicInformation,
&mut ptr_to_pbi as *mut _ as *mut c_void,
size_of::<PROCESS_BASIC_INFORMATION>() as u32,
&mut 0,
);
let proc = Process::find_pid(proc_info.dwProcessId).unwrap();
let pebby: PEB = proc.read(ptr_to_pbi.PebBaseAddress as usize).expect("the");
let pImage = pebby.Reserved3[1] as usize;
let e_lf: u32 = proc
.read(pImage + std::mem::offset_of!(IMAGE_DOS_HEADER, e_lfanew))
.expect("bruh");
let entry: u32 = proc
.read(
pImage
+ e_lf as usize
+ std::mem::offset_of!(IMAGE_NT_HEADERS64, OptionalHeader.AddressOfEntryPoint),
)
.expect("bruh");
let entry = pImage + entry as usize;
println!("entry = {:x}", entry);
let entry_insts: [u8; 2] = proc.read(entry).expect("failed to read entry");
let pay_load: [u8; 2] = [0xEB, 0xFE];
proc.write(entry, &pay_load);
println!("{:x?}", entry_insts);
//
// resume the thread
ResumeThread(proc_info.hThread);
// wait until trapped... and inject
let target = OwnedProcess::from_pid(proc.get_pid()).unwrap();
let syrnge = Syringe::for_process(target);
let injmod = syrnge.inject("./gdkeinj.dll").unwrap();
// we're done. let's kill the process.
println!("waiting 2secs ");
std::thread::sleep(Duration::from_secs(2));
println!("waited 2secs, restoring..",);
println!("{:?}", injmod.handle());
proc.write(entry, &entry_insts);
// TerminateProcess(proc_info.hProcess, 1);
}

View File

@ -1,15 +1,8 @@
// use poggers::{external::process::ExProcess, traits::Mem}; use gdke::spawn_and_inject;
use poggers::structures::process::Process;
fn main() { fn main() {
let mut pid = 0; unsafe {
{ spawn_and_inject("./z421.exe");
let proc = Process::find_by_name("pog.exe").unwrap();
pid = proc.get_pid();
} }
println!("hi");
let key = gdke::get_from_pid(pid).expect("unable to find key");
println!("Key: {}", key);
} }