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
22
Cargo.toml
22
Cargo.toml
|
@ -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]
|
||||||
poggers = {version = "*", path = "../poggers"}
|
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"
|
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;
|
#![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);
|
||||||
|
}
|
||||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue