mirror of https://github.com/pozm/gdke.git
[BROKEN] push new mechanism
This commit is contained in:
parent
627c4f0ce8
commit
48fde349b7
File diff suppressed because it is too large
Load Diff
20
Cargo.toml
20
Cargo.toml
|
@ -1,3 +1,4 @@
|
|||
workspace = { members = ["gdkeinj"] }
|
||||
[package]
|
||||
name = "gdke"
|
||||
version = "0.1.0"
|
||||
|
@ -14,11 +15,22 @@ inherits = "release"
|
|||
debug = true
|
||||
strip = false
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[workspace]
|
||||
members = [
|
||||
"gdke-gui",
|
||||
]
|
||||
# [workspace]
|
||||
# members = ["gdke-gui"]
|
||||
|
||||
[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" }
|
||||
crossbeam = "0.8.2"
|
|
@ -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= ".."}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
use std::error::Error;
|
||||
|
||||
pub mod app;
|
||||
|
||||
|
||||
pub enum Data {
|
||||
Pid(u32),
|
||||
Key(String),
|
||||
Failure(String),
|
||||
EXIT
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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/" }
|
|
@ -0,0 +1,4 @@
|
|||
#[poggers_derive::create_entry(no_free)]
|
||||
pub fn main() {
|
||||
println!("hi");
|
||||
}
|
162
src/lib.rs
162
src/lib.rs
|
@ -1,69 +1,101 @@
|
|||
use std::error::Error;
|
||||
|
||||
use poggers::{
|
||||
structures::{
|
||||
modules::Module,
|
||||
process::{implement::utils::ProcessUtils, External, Process},
|
||||
},
|
||||
traits::{Mem, MemError},
|
||||
#![feature(offset_of)]
|
||||
use std::{
|
||||
error::Error,
|
||||
ffi::{c_void, CStr, CString},
|
||||
mem::{size_of, transmute},
|
||||
ptr::{addr_of, null, null_mut},
|
||||
time::Duration,
|
||||
};
|
||||
/// # 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>> {
|
||||
let proc = Process::find_pid(pid)?;
|
||||
let bm = proc.get_base_module()?;
|
||||
// println!("Base module: {:X?}", bm);
|
||||
for sig in &SIGS {
|
||||
let timer = std::time::Instant::now();
|
||||
let res = bm.scan(sig);
|
||||
println!("Scan took: {}ms", timer.elapsed().as_millis());
|
||||
if let Ok(Some(x)) = res {
|
||||
println!("hey! something was found!");
|
||||
let data = unsafe { resolve_relative_ptr(&bm, x + 3, 4) };
|
||||
if let Ok(x) = data {
|
||||
println!("found key @ {:X}", x);
|
||||
let mut key_data = [0u8; 32];
|
||||
if unsafe { proc.raw_read(x, &mut key_data as *mut u8, 32) }.is_ok()
|
||||
&& !key_data.is_empty()
|
||||
{
|
||||
let mut data_string = String::new();
|
||||
for i in &key_data[..] {
|
||||
data_string.push_str(&format!("{:02X}", i));
|
||||
}
|
||||
return Ok(data_string);
|
||||
}
|
||||
} else {
|
||||
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())
|
||||
use dll_syringe::{process::OwnedProcess, Syringe};
|
||||
use poggers::{structures::process::Process, traits::Mem};
|
||||
use windows::Win32::System::{
|
||||
Diagnostics::Debug::{GetThreadContext, CONTEXT, IMAGE_NT_HEADERS64},
|
||||
Threading::{ResumeThread, SuspendThread},
|
||||
};
|
||||
use windows::{
|
||||
core::{PCSTR, PSTR},
|
||||
Win32::{
|
||||
Foundation::{BOOL, HINSTANCE},
|
||||
System::{
|
||||
ProcessStatus::{K32GetModuleInformation, MODULEINFO},
|
||||
SystemServices::IMAGE_DOS_HEADER,
|
||||
Threading::{
|
||||
CreateProcessA, NtQueryInformationProcess, ProcessBasicInformation,
|
||||
TerminateProcess, CREATE_SUSPENDED, PEB, PROCESS_BASIC_INFORMATION,
|
||||
PROCESS_INFORMATION, STARTUPINFOA,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
fn create_pstr(c_str: &CStr) -> PSTR {
|
||||
PSTR::from_raw(c_str.as_ptr() as *mut u8)
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -1,15 +1,8 @@
|
|||
// use poggers::{external::process::ExProcess, traits::Mem};
|
||||
|
||||
use poggers::structures::process::Process;
|
||||
use gdke::spawn_and_inject;
|
||||
|
||||
fn main() {
|
||||
let mut pid = 0;
|
||||
{
|
||||
let proc = Process::find_by_name("pog.exe").unwrap();
|
||||
pid = proc.get_pid();
|
||||
unsafe {
|
||||
spawn_and_inject("./z421.exe");
|
||||
}
|
||||
|
||||
let key = gdke::get_from_pid(pid).expect("unable to find key");
|
||||
|
||||
println!("Key: {}", key);
|
||||
println!("hi");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue