Compare commits
5 Commits
893f7917ef
...
main
Author | SHA1 | Date | |
---|---|---|---|
18c6c3d235 | |||
a7f5828f96 | |||
03a4e89918 | |||
9a07551a22 | |||
f777d9ecf8 |
3
analyzer/.vscode/settings.json
vendored
3
analyzer/.vscode/settings.json
vendored
@ -1,3 +0,0 @@
|
||||
{
|
||||
"python.analysis.typeCheckingMode": "standard"
|
||||
}
|
File diff suppressed because one or more lines are too long
BIN
arrows.xcf
Normal file
BIN
arrows.xcf
Normal file
Binary file not shown.
BIN
diagram.xcf
Normal file
BIN
diagram.xcf
Normal file
Binary file not shown.
0
runner/.gitignore → injector/.gitignore
vendored
0
runner/.gitignore → injector/.gitignore
vendored
74
runner/Cargo.lock → injector/Cargo.lock
generated
74
runner/Cargo.lock → injector/Cargo.lock
generated
@ -2,78 +2,13 @@
|
||||
# It is not intended for manual editing.
|
||||
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]]
|
||||
name = "runner"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
@ -146,12 +81,3 @@ name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winres"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
|
||||
dependencies = [
|
||||
"toml",
|
||||
]
|
@ -3,8 +3,16 @@ name = "runner"
|
||||
version = "0.1.0"
|
||||
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]
|
||||
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
3
injector/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-arg=-s")
|
||||
}
|
BIN
injector/squeak.bat
Normal file
BIN
injector/squeak.bat
Normal file
Binary file not shown.
@ -1,11 +1,13 @@
|
||||
use core::str;
|
||||
use std::ffi::{c_void, CStr};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
use std::{fs::File, io::Read};
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::ffi::{c_void, CStr};
|
||||
use core::marker::PhantomData;
|
||||
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::ToolHelp::{self, PROCESSENTRY32};
|
||||
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 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() }
|
||||
0
|
||||
}
|
||||
|
||||
struct Reader<'a> {
|
||||
@ -40,11 +44,11 @@ impl<'a> Reader<'a> {
|
||||
}
|
||||
self.ptr = self.ptr.byte_add(1);
|
||||
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,
|
||||
base: *mut u8,
|
||||
ptr: *mut u8,
|
||||
@ -53,20 +57,18 @@ 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) };
|
||||
let bytes = unsafe { core::mem::transmute::<*const c_void, [u8; 8]>(ptr) };
|
||||
self.write(&bytes)
|
||||
}
|
||||
|
||||
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 {
|
||||
let addr = self.ptr;
|
||||
for u in u8s {
|
||||
@ -98,7 +100,6 @@ unsafe fn write_imports(
|
||||
reader: &mut Reader,
|
||||
) {
|
||||
let entry_point = reader.read::<u32>();
|
||||
println!("entry point: {}", entry_point);
|
||||
// push rbp
|
||||
prelude.write(&[0x55]);
|
||||
// mov rbp, rsp
|
||||
@ -114,7 +115,6 @@ unsafe fn write_imports(
|
||||
if dll.len() == 1 {
|
||||
break;
|
||||
}
|
||||
println!("import dll: {:?}", str::from_utf8(dll).unwrap());
|
||||
let library_addr = strings.write(dll);
|
||||
strings.write(&[0]);
|
||||
|
||||
@ -123,7 +123,6 @@ unsafe fn write_imports(
|
||||
if symbol.len() == 1 {
|
||||
break;
|
||||
}
|
||||
println!("import symbol: {:?}", str::from_utf8(symbol).unwrap());
|
||||
|
||||
let dest = reader.read::<u32>();
|
||||
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 {
|
||||
// RLE: repeat
|
||||
let byte = reader.read::<u8>();
|
||||
for i in 0..code {
|
||||
for _ in 0..code {
|
||||
*out = byte;
|
||||
out = out.byte_add(1);
|
||||
}
|
||||
@ -204,18 +203,12 @@ unsafe fn _main_remote() {
|
||||
&mut measuring_reader,
|
||||
);
|
||||
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 {
|
||||
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 = 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 prelude = strings.byte_add(string_measurer.count);
|
||||
let mut strings_writer = LocalWriter {
|
||||
let mut strings_writer = Writer {
|
||||
binary: remote_address_space as *mut u8,
|
||||
base: local_address_space 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,
|
||||
base: local_address_space as *mut u8,
|
||||
ptr: prelude as *mut u8,
|
||||
};
|
||||
println!("writing imports");
|
||||
write_imports(
|
||||
&mut strings_writer,
|
||||
&mut prelude_writer,
|
||||
&mut loading_reader,
|
||||
);
|
||||
println!("writing starting state");
|
||||
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(
|
||||
remote,
|
||||
remote_address_space,
|
||||
@ -271,17 +256,13 @@ unsafe fn _main_remote() {
|
||||
total_size,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
println!("error: {}", GetLastError());
|
||||
println!("Creating remote thread");
|
||||
|
||||
let entry_point =
|
||||
remote_address_space.byte_offset(prelude.byte_offset_from(local_address_space));
|
||||
println!("Entry point: {:?}", entry_point);
|
||||
Threading::CreateRemoteThread(
|
||||
remote,
|
||||
ptr::null(),
|
||||
0,
|
||||
Some(std::mem::transmute::<
|
||||
Some(core::mem::transmute::<
|
||||
*mut c_void,
|
||||
unsafe extern "system" fn(*mut c_void) -> u32,
|
||||
>(entry_point)),
|
||||
@ -289,20 +270,16 @@ unsafe fn _main_remote() {
|
||||
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;
|
||||
entry.assume_init_mut().dwSize = core::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);
|
||||
}
|
||||
@ -310,3 +287,9 @@ unsafe fn identify_victim() -> Option<u32> {
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
@ -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");
|
||||
*/
|
||||
}
|
Binary file not shown.
@ -4,4 +4,4 @@
|
||||
|
||||
[number of bytes in starting state as a uint32_t]
|
||||
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
|
@ -1,9 +1,7 @@
|
||||
import base64
|
||||
from dataclasses import dataclass
|
||||
from io import BytesIO
|
||||
import json
|
||||
from typing import Generator
|
||||
import pefile
|
||||
from pefile import PE, Structure
|
||||
|
||||
@dataclass
|
||||
class Import:
|
||||
@ -36,41 +34,40 @@ def _single[T](ts: Generator[T]) -> T:
|
||||
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
|
||||
assert isinstance(optional_header, pefile.Structure)
|
||||
text_section = _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")
|
||||
rdata_section = _single_or_none(i for i in subject.sections if i.Name == b".rdata\0\0")
|
||||
assert isinstance(optional_header, Structure)
|
||||
text_section: Structure = _single(i for i in subject.sections if i.Name == b".text\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: 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:
|
||||
raise ValueError("no sections to plot")
|
||||
print([(i.VirtualAddress, i) for i in relevant_sections])
|
||||
min_address = min(i.VirtualAddress for i in relevant_sections)
|
||||
max_address = max(_round_up_to_page(i.VirtualAddress + i.SizeOfRawData) for i in relevant_sections)
|
||||
min_address = min(getattr(i, "VirtualAddress") for i in relevant_sections)
|
||||
max_address = max(getattr(i, "VirtualAddress") + getattr(i, "SizeOfRawData") for i in relevant_sections)
|
||||
|
||||
buffer = bytearray(max_address - min_address)
|
||||
for section in relevant_sections:
|
||||
data = section.get_data() # TODO: De-pad the text section from 0xccs
|
||||
start = section.VirtualAddress - min_address
|
||||
data = getattr(section, "get_data")()
|
||||
start = getattr(section, "VirtualAddress") - min_address
|
||||
buffer[start:start+len(data)] = data
|
||||
|
||||
starting_state = bytes(buffer)
|
||||
|
||||
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] = []
|
||||
for entry in getattr(subject, "DIRECTORY_ENTRY_IMPORT"):
|
||||
library: bytes = entry.dll
|
||||
entry: Structure
|
||||
library: bytes = getattr(entry, "dll")
|
||||
procedures: list[tuple[bytes, int]] = []
|
||||
for imp in entry.imports:
|
||||
# print(dir(imp))
|
||||
import_address_rva = imp.address - getattr(optional_header, "ImageBase")
|
||||
for imp in getattr(entry, "imports"):
|
||||
imp: Structure
|
||||
import_address_rva = getattr(imp, "address") - getattr(optional_header, "ImageBase")
|
||||
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))
|
||||
|
||||
@ -96,9 +93,7 @@ def _encode_binary(binary: Binary) -> bytes:
|
||||
|
||||
_write_u32(binary.entry_point)
|
||||
for i in binary.imports:
|
||||
print(i.library)
|
||||
_write_zt(i.library)
|
||||
print(i.procedures)
|
||||
for (procedure, address) in i.procedures:
|
||||
_write_zt(procedure)
|
||||
_write_u32(address)
|
||||
@ -156,16 +151,12 @@ def _encode_binary(binary: Binary) -> bytes:
|
||||
return out.getbuffer()
|
||||
|
||||
def main():
|
||||
subject = pefile.PE("subjects\\main.exe")
|
||||
subject = PE("subjects\\main.exe")
|
||||
|
||||
binary = _create_binary(subject)
|
||||
code = _encode_binary(binary)
|
||||
with open("binaries\\main.dat", "wb") as f:
|
||||
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__":
|
||||
main()
|
BIN
thumbnail.png
Normal file
BIN
thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 341 KiB |
8
thumbnail.txt
Normal file
8
thumbnail.txt
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
.\ /.
|
||||
'. \_ _/ .'
|
||||
'o. .o'
|
||||
'"'
|
||||
|
||||
|
||||
|
BIN
thumbnail.xcf
Normal file
BIN
thumbnail.xcf
Normal file
Binary file not shown.
BIN
vampiric.xcf
Normal file
BIN
vampiric.xcf
Normal file
Binary file not shown.
Reference in New Issue
Block a user