Compare commits

..

5 Commits

32 changed files with 69 additions and 191 deletions

View File

@ -1,3 +0,0 @@
{
"python.analysis.typeCheckingMode": "standard"
}

File diff suppressed because one or more lines are too long

BIN
arrows.xcf Normal file

Binary file not shown.

BIN
diagram.xcf Normal file

Binary file not shown.

View File

@ -2,78 +2,13 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "runner" name = "runner"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"windows-sys", "windows-sys",
"winres",
] ]
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.59.0" version = "0.59.0"
@ -146,12 +81,3 @@ 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",
]

View File

@ -3,8 +3,16 @@ name = "runner"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
[profile.dev]
panic = "abort"
[profile.release]
# source: https://github.com/johnthagen/min-sized-rust
panic = "abort"
opt-level = "z"
strip = true
lto = true
codegen-units = 1
[dependencies] [dependencies]
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"]} 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"

3
injector/build.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
println!("cargo:rustc-link-arg=-s")
}

BIN
injector/squeak.bat Normal file

Binary file not shown.

View File

@ -1,11 +1,13 @@
use core::str; #![no_std]
use std::ffi::{c_void, CStr}; #![no_main]
use std::marker::PhantomData;
use std::mem::MaybeUninit; use core::ffi::{c_void, CStr};
use std::ptr; use core::marker::PhantomData;
use std::{fs::File, io::Read}; use core::mem::MaybeUninit;
#[cfg(not(test))]
use core::panic::PanicInfo;
use core::ptr;
use windows_sys::Win32::Foundation::GetLastError;
use windows_sys::Win32::System::Diagnostics::Debug; use windows_sys::Win32::System::Diagnostics::Debug;
use windows_sys::Win32::System::Diagnostics::ToolHelp::{self, PROCESSENTRY32}; use windows_sys::Win32::System::Diagnostics::ToolHelp::{self, PROCESSENTRY32};
use windows_sys::Win32::System::Memory; use windows_sys::Win32::System::Memory;
@ -15,8 +17,10 @@ use windows_sys::Win32::System::{LibraryLoader, Threading};
const LOAD_LIBRARY_A: *const c_void = LibraryLoader::LoadLibraryA as *const c_void; 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; const GET_PROC_ADDRESS: *const c_void = LibraryLoader::GetProcAddress as *const c_void;
fn main() { #[no_mangle]
pub extern "C" fn WinMain() -> i32 {
unsafe { _main_remote() } unsafe { _main_remote() }
0
} }
struct Reader<'a> { struct Reader<'a> {
@ -40,11 +44,11 @@ impl<'a> Reader<'a> {
} }
self.ptr = self.ptr.byte_add(1); self.ptr = self.ptr.byte_add(1);
n += 1; // include the null terminator n += 1; // include the null terminator
return std::slice::from_raw_parts(start, n); return core::slice::from_raw_parts(start, n);
} }
} }
struct LocalWriter { struct Writer {
binary: *mut u8, binary: *mut u8,
base: *mut u8, base: *mut u8,
ptr: *mut u8, ptr: *mut u8,
@ -53,20 +57,18 @@ struct Measurer {
count: usize, count: usize,
} }
impl Measurer {}
trait CodeGen { trait CodeGen {
unsafe fn write(&mut self, u8s: &[u8]) -> *const c_void; unsafe fn write(&mut self, u8s: &[u8]) -> *const c_void;
unsafe fn write_ptr(&mut self, ptr: *const c_void) -> *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) }; let bytes = unsafe { core::mem::transmute::<*const c_void, [u8; 8]>(ptr) };
self.write(&bytes) self.write(&bytes)
} }
unsafe fn address_in_binary(&mut self, offset: usize) -> *const c_void; unsafe fn address_in_binary(&mut self, offset: usize) -> *const c_void;
} }
impl CodeGen for LocalWriter { impl CodeGen for Writer {
unsafe fn write(&mut self, u8s: &[u8]) -> *const c_void { unsafe fn write(&mut self, u8s: &[u8]) -> *const c_void {
let addr = self.ptr; let addr = self.ptr;
for u in u8s { for u in u8s {
@ -98,7 +100,6 @@ unsafe fn write_imports(
reader: &mut Reader, reader: &mut Reader,
) { ) {
let entry_point = reader.read::<u32>(); let entry_point = reader.read::<u32>();
println!("entry point: {}", entry_point);
// push rbp // push rbp
prelude.write(&[0x55]); prelude.write(&[0x55]);
// mov rbp, rsp // mov rbp, rsp
@ -114,7 +115,6 @@ unsafe fn write_imports(
if dll.len() == 1 { if dll.len() == 1 {
break; break;
} }
println!("import dll: {:?}", str::from_utf8(dll).unwrap());
let library_addr = strings.write(dll); let library_addr = strings.write(dll);
strings.write(&[0]); strings.write(&[0]);
@ -123,7 +123,6 @@ unsafe fn write_imports(
if symbol.len() == 1 { if symbol.len() == 1 {
break; break;
} }
println!("import symbol: {:?}", str::from_utf8(symbol).unwrap());
let dest = reader.read::<u32>(); let dest = reader.read::<u32>();
let symbol_addr = strings.write(symbol); let symbol_addr = strings.write(symbol);
@ -173,7 +172,7 @@ unsafe fn write_starting_state(mut out: *mut u8, reader: &mut Reader) {
if code > 0 { if code > 0 {
// RLE: repeat // RLE: repeat
let byte = reader.read::<u8>(); let byte = reader.read::<u8>();
for i in 0..code { for _ in 0..code {
*out = byte; *out = byte;
out = out.byte_add(1); out = out.byte_add(1);
} }
@ -204,18 +203,12 @@ unsafe fn _main_remote() {
&mut measuring_reader, &mut measuring_reader,
); );
let starting_state_len = measuring_reader.read::<u32>() as usize; let starting_state_len = measuring_reader.read::<u32>() as usize;
println!("starting state len: {}", starting_state_len);
// string_measurer.round_up();
// code_measurer.round_up();
// TODO: Alignment
let Some(victim) = identify_victim() else { let Some(victim) = identify_victim() else {
println!("couldn't find victim");
return; return;
}; };
let remote = Threading::OpenProcess(PROCESS_ALL_ACCESS, 0, victim); let remote = Threading::OpenProcess(PROCESS_ALL_ACCESS, 0, victim);
if remote == ptr::null_mut() { if remote == ptr::null_mut() {
println!("got null");
return; return;
} }
let total_size = starting_state_len as usize + string_measurer.count + code_measurer.count; let total_size = starting_state_len as usize + string_measurer.count + code_measurer.count;
@ -240,30 +233,22 @@ unsafe fn _main_remote() {
let strings = local_address_space.byte_add(starting_state_len); let strings = local_address_space.byte_add(starting_state_len);
let prelude = strings.byte_add(string_measurer.count); let prelude = strings.byte_add(string_measurer.count);
let mut strings_writer = LocalWriter { let mut strings_writer = Writer {
binary: remote_address_space as *mut u8, binary: remote_address_space as *mut u8,
base: local_address_space as *mut u8, base: local_address_space as *mut u8,
ptr: strings as *mut u8, ptr: strings as *mut u8,
}; };
let mut prelude_writer = LocalWriter { let mut prelude_writer = Writer {
binary: remote_address_space as *mut u8, binary: remote_address_space as *mut u8,
base: local_address_space as *mut u8, base: local_address_space as *mut u8,
ptr: prelude as *mut u8, ptr: prelude as *mut u8,
}; };
println!("writing imports");
write_imports( write_imports(
&mut strings_writer, &mut strings_writer,
&mut prelude_writer, &mut prelude_writer,
&mut loading_reader, &mut loading_reader,
); );
println!("writing starting state");
write_starting_state(local_address_space as *mut u8, &mut loading_reader); write_starting_state(local_address_space as *mut u8, &mut loading_reader);
println!("done!");
println!("error: {}", GetLastError());
println!(
"Copying memory to foreign process (at {:?} from {:?} get {:?})",
remote_address_space, local_address_space, total_size
);
Debug::WriteProcessMemory( Debug::WriteProcessMemory(
remote, remote,
remote_address_space, remote_address_space,
@ -271,17 +256,13 @@ unsafe fn _main_remote() {
total_size, total_size,
ptr::null_mut(), ptr::null_mut(),
); );
println!("error: {}", GetLastError());
println!("Creating remote thread");
let entry_point = let entry_point =
remote_address_space.byte_offset(prelude.byte_offset_from(local_address_space)); remote_address_space.byte_offset(prelude.byte_offset_from(local_address_space));
println!("Entry point: {:?}", entry_point);
Threading::CreateRemoteThread( Threading::CreateRemoteThread(
remote, remote,
ptr::null(), ptr::null(),
0, 0,
Some(std::mem::transmute::< Some(core::mem::transmute::<
*mut c_void, *mut c_void,
unsafe extern "system" fn(*mut c_void) -> u32, unsafe extern "system" fn(*mut c_void) -> u32,
>(entry_point)), >(entry_point)),
@ -289,20 +270,16 @@ unsafe fn _main_remote() {
0, 0,
ptr::null_mut(), ptr::null_mut(),
); );
println!("error: {}", GetLastError());
println!("Done!");
} }
unsafe fn identify_victim() -> Option<u32> { unsafe fn identify_victim() -> Option<u32> {
let snapshot = ToolHelp::CreateToolhelp32Snapshot(ToolHelp::TH32CS_SNAPPROCESS, 0); let snapshot = ToolHelp::CreateToolhelp32Snapshot(ToolHelp::TH32CS_SNAPPROCESS, 0);
let mut entry: MaybeUninit<PROCESSENTRY32> = MaybeUninit::uninit(); let mut entry: MaybeUninit<PROCESSENTRY32> = MaybeUninit::uninit();
entry.assume_init_mut().dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32; entry.assume_init_mut().dwSize = core::mem::size_of::<PROCESSENTRY32>() as u32;
let mut process = ToolHelp::Process32First(snapshot, entry.as_mut_ptr()); let mut process = ToolHelp::Process32First(snapshot, entry.as_mut_ptr());
println!("error: {}; process: {}", GetLastError(), process);
while process != 0 { while process != 0 {
let entry_ref = entry.assume_init_ref(); let entry_ref = entry.assume_init_ref();
let name = CStr::from_ptr(entry_ref.szExeFile.as_ptr()); 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")) { if name.eq(CStr::from_bytes_with_nul_unchecked(b"notepad.exe\x00")) {
return Some(entry_ref.th32ProcessID); return Some(entry_ref.th32ProcessID);
} }
@ -310,3 +287,9 @@ unsafe fn identify_victim() -> Option<u32> {
} }
return None; return None;
} }
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}

View File

@ -1,22 +0,0 @@
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");
*/
}

View File

@ -4,4 +4,4 @@
[number of bytes in starting state as a uint32_t] [number of bytes in starting state as a uint32_t]
00 [00-ff] <bytes>: Use the following 00-ff bytes literally 00 [00-ff] <bytes>: Use the following 00-ff bytes literally
[01-ff] <byte>: Repeat the next byte 02 to ff times [01-ff] <byte>: Repeat the next byte 01 to ff times

View File

@ -1,9 +1,7 @@
import base64
from dataclasses import dataclass from dataclasses import dataclass
from io import BytesIO from io import BytesIO
import json
from typing import Generator from typing import Generator
import pefile from pefile import PE, Structure
@dataclass @dataclass
class Import: class Import:
@ -36,41 +34,40 @@ def _single[T](ts: Generator[T]) -> T:
raise ValueError(f"expected 1, got {len(items)}") raise ValueError(f"expected 1, got {len(items)}")
def _create_binary(subject: pefile.PE) -> Binary: def _create_binary(subject: PE) -> Binary:
optional_header = subject.OPTIONAL_HEADER optional_header = subject.OPTIONAL_HEADER
assert isinstance(optional_header, pefile.Structure) assert isinstance(optional_header, Structure)
text_section = _single(i for i in subject.sections if i.Name == b".text\0\0\0") text_section: Structure = _single(i for i in subject.sections if i.Name == b".text\0\0\0")
data_section = _single_or_none(i for i in subject.sections if i.Name == b".data\0\0\0") data_section: Structure | None = _single_or_none(i for i in subject.sections if i.Name == b".data\0\0\0")
rdata_section = _single_or_none(i for i in subject.sections if i.Name == b".rdata\0\0") rdata_section: Structure | None = _single_or_none(i for i in subject.sections if i.Name == b".rdata\0\0")
relevant_sections = [section for section in (text_section, data_section, rdata_section) if section is not None] relevant_sections: list[Structure] = [section for section in (text_section, data_section, rdata_section) if section is not None]
if len(relevant_sections) == 0: if len(relevant_sections) == 0:
raise ValueError("no sections to plot") raise ValueError("no sections to plot")
print([(i.VirtualAddress, i) for i in relevant_sections]) min_address = min(getattr(i, "VirtualAddress") for i in relevant_sections)
min_address = min(i.VirtualAddress for i in relevant_sections) max_address = max(getattr(i, "VirtualAddress") + getattr(i, "SizeOfRawData") for i in relevant_sections)
max_address = max(_round_up_to_page(i.VirtualAddress + i.SizeOfRawData) for i in relevant_sections)
buffer = bytearray(max_address - min_address) buffer = bytearray(max_address - min_address)
for section in relevant_sections: for section in relevant_sections:
data = section.get_data() # TODO: De-pad the text section from 0xccs data = getattr(section, "get_data")()
start = section.VirtualAddress - min_address start = getattr(section, "VirtualAddress") - min_address
buffer[start:start+len(data)] = data buffer[start:start+len(data)] = data
starting_state = bytes(buffer) starting_state = bytes(buffer)
entry_point_rva = getattr(optional_header, "AddressOfEntryPoint") entry_point_rva = getattr(optional_header, "AddressOfEntryPoint")
print(entry_point_rva) entry_point = entry_point_rva - min_address
entry_point = (entry_point_rva - min_address)
imports: list[Import] = [] imports: list[Import] = []
for entry in getattr(subject, "DIRECTORY_ENTRY_IMPORT"): for entry in getattr(subject, "DIRECTORY_ENTRY_IMPORT"):
library: bytes = entry.dll entry: Structure
library: bytes = getattr(entry, "dll")
procedures: list[tuple[bytes, int]] = [] procedures: list[tuple[bytes, int]] = []
for imp in entry.imports: for imp in getattr(entry, "imports"):
# print(dir(imp)) imp: Structure
import_address_rva = imp.address - getattr(optional_header, "ImageBase") import_address_rva = getattr(imp, "address") - getattr(optional_header, "ImageBase")
import_address = import_address_rva - min_address import_address = import_address_rva - min_address
procedures.append((imp.name, import_address)) procedures.append((getattr(imp, "name"), import_address))
imports.append(Import(library, procedures)) imports.append(Import(library, procedures))
@ -96,9 +93,7 @@ def _encode_binary(binary: Binary) -> bytes:
_write_u32(binary.entry_point) _write_u32(binary.entry_point)
for i in binary.imports: for i in binary.imports:
print(i.library)
_write_zt(i.library) _write_zt(i.library)
print(i.procedures)
for (procedure, address) in i.procedures: for (procedure, address) in i.procedures:
_write_zt(procedure) _write_zt(procedure)
_write_u32(address) _write_u32(address)
@ -156,16 +151,12 @@ def _encode_binary(binary: Binary) -> bytes:
return out.getbuffer() return out.getbuffer()
def main(): def main():
subject = pefile.PE("subjects\\main.exe") subject = PE("subjects\\main.exe")
binary = _create_binary(subject) binary = _create_binary(subject)
code = _encode_binary(binary) code = _encode_binary(binary)
with open("binaries\\main.dat", "wb") as f: with open("binaries\\main.dat", "wb") as f:
f.write(code) f.write(code)
def _round_up_to_page(x: int):
# TODO: Is this the page size on x64? I think it is
return ((x + 0x1000 - 1) // 0x1000) * 0x1000
if __name__ == "__main__": if __name__ == "__main__":
main() main()

BIN
thumbnail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

8
thumbnail.txt Normal file
View File

@ -0,0 +1,8 @@
.\ /.
'. \_ _/ .'
'o. .o'
'"'

BIN
thumbnail.xcf Normal file

Binary file not shown.

BIN
vampiric.xcf Normal file

Binary file not shown.