replace hardcoded parameters with u32 bitflag
This commit is contained in:
parent
2a16a674b3
commit
030bf89a92
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = {version = "4.4.18", features = ["derive"] }
|
clap = { version = "4.4.18", features = ["derive"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
airborne-utils = { path = "../utils" }
|
airborne-utils = { path = "../utils" }
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use airborne_utils::calc_hash;
|
use airborne_utils::calc_hash;
|
||||||
use clap::Parser;
|
use clap::{ArgAction, Parser};
|
||||||
use windows_sys::Win32::{
|
use windows_sys::Win32::{
|
||||||
System::Diagnostics::Debug::IMAGE_NT_HEADERS64,
|
System::Diagnostics::Debug::IMAGE_NT_HEADERS64,
|
||||||
System::{
|
System::{
|
||||||
@ -31,9 +31,15 @@ struct Args {
|
|||||||
/// Path to the output file
|
/// Path to the output file
|
||||||
#[arg(short, long = "output")]
|
#[arg(short, long = "output")]
|
||||||
output_path: PathBuf,
|
output_path: PathBuf,
|
||||||
/// Flag to pass to the loader (by default DllMain is called)
|
/// Disable randomized delays during IAT patching
|
||||||
#[arg(long, default_value_t = 0)]
|
#[arg(short, long, action = ArgAction::SetFalse, default_value_t = true)]
|
||||||
flag: u32, // preferably set type as u32 here instead of casting it when generating bootstrap
|
no_delay: bool,
|
||||||
|
/// Disable IAT import descriptor shuffling
|
||||||
|
#[arg(short, long, action = ArgAction::SetFalse, default_value_t = true)]
|
||||||
|
no_shuffle: bool,
|
||||||
|
/// Call payload's user defined function instead of DllMain
|
||||||
|
#[arg(short, long, action = ArgAction::SetTrue, default_value_t = false)]
|
||||||
|
ufn: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: must be updated accordingly if the loader name or the bootstrap code is modified
|
// NOTE: must be updated accordingly if the loader name or the bootstrap code is modified
|
||||||
@ -43,6 +49,9 @@ const BOOTSTRAP_TOTAL_LENGTH: u32 = 79;
|
|||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
|
// (bool, bool, bool) -(OR)-> u32
|
||||||
|
let combined_flag = airborne_utils::create_u32_flag(args.no_delay, args.no_shuffle, args.ufn);
|
||||||
|
|
||||||
// preserve the path from being dropped
|
// preserve the path from being dropped
|
||||||
let output_path = args.output_path.clone();
|
let output_path = args.output_path.clone();
|
||||||
|
|
||||||
@ -77,7 +86,7 @@ fn main() {
|
|||||||
&mut payload_b,
|
&mut payload_b,
|
||||||
function_hash,
|
function_hash,
|
||||||
args.parameter,
|
args.parameter,
|
||||||
args.flag,
|
combined_flag,
|
||||||
) {
|
) {
|
||||||
Ok(sc) => sc,
|
Ok(sc) => sc,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -10,6 +10,7 @@ use core::{
|
|||||||
slice::from_raw_parts,
|
slice::from_raw_parts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use airborne_utils::Flags;
|
||||||
use windows_sys::{
|
use windows_sys::{
|
||||||
core::PWSTR,
|
core::PWSTR,
|
||||||
Win32::{
|
Win32::{
|
||||||
@ -41,10 +42,6 @@ use windows_sys::{
|
|||||||
|
|
||||||
use crate::memory::*;
|
use crate::memory::*;
|
||||||
|
|
||||||
// TODO: replace with parameters from the shellcode generator
|
|
||||||
const SHUFFLE_IMPORTS: bool = true;
|
|
||||||
const DELAY_IMPORTS: bool = true;
|
|
||||||
|
|
||||||
const MAX_IMPORT_DELAY_MS: u64 = 2000;
|
const MAX_IMPORT_DELAY_MS: u64 = 2000;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
@ -70,6 +67,8 @@ pub unsafe extern "system" fn loader(
|
|||||||
_shellcode_bin: *mut c_void,
|
_shellcode_bin: *mut c_void,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) {
|
) {
|
||||||
|
let flags = airborne_utils::parse_u32_flag(flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1.) locate the required functions and modules from exports with their hashed names
|
1.) locate the required functions and modules from exports with their hashed names
|
||||||
*/
|
*/
|
||||||
@ -139,7 +138,7 @@ pub unsafe extern "system" fn loader(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
patch_iat(base_addr_ptr, import_descriptor_ptr, &far_procs);
|
patch_iat(base_addr_ptr, import_descriptor_ptr, &far_procs, &flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
5.) finalize the sections by setting protective permissions after mapping the image
|
5.) finalize the sections by setting protective permissions after mapping the image
|
||||||
@ -151,15 +150,7 @@ pub unsafe extern "system" fn loader(
|
|||||||
6.) execute DllMain or user defined function depending on the flag passed into the shellcode by the generator
|
6.) execute DllMain or user defined function depending on the flag passed into the shellcode by the generator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if flags == 0 {
|
if flags.ufn {
|
||||||
let dll_main_addr = base_addr_ptr as usize
|
|
||||||
+ (*module_nt_headers_ptr).OptionalHeader.AddressOfEntryPoint as usize;
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let DllMain = transmute::<_, DllMain>(dll_main_addr);
|
|
||||||
|
|
||||||
DllMain(base_addr_ptr as _, DLL_PROCESS_ATTACH, module_base_ptr as _);
|
|
||||||
} else {
|
|
||||||
// UserFunction address = base address + RVA of user function
|
// UserFunction address = base address + RVA of user function
|
||||||
let user_fn_addr = get_export_addr(base_addr_ptr as _, function_hash).unwrap();
|
let user_fn_addr = get_export_addr(base_addr_ptr as _, function_hash).unwrap();
|
||||||
|
|
||||||
@ -168,6 +159,14 @@ pub unsafe extern "system" fn loader(
|
|||||||
|
|
||||||
// execution with user data passed into the shellcode by the generator
|
// execution with user data passed into the shellcode by the generator
|
||||||
UserFunction(user_data, user_data_len);
|
UserFunction(user_data, user_data_len);
|
||||||
|
} else {
|
||||||
|
let dll_main_addr = base_addr_ptr as usize
|
||||||
|
+ (*module_nt_headers_ptr).OptionalHeader.AddressOfEntryPoint as usize;
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let DllMain = transmute::<_, DllMain>(dll_main_addr);
|
||||||
|
|
||||||
|
DllMain(base_addr_ptr as _, DLL_PROCESS_ATTACH, module_base_ptr as _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,6 +417,7 @@ unsafe fn patch_iat(
|
|||||||
base_addr_ptr: *mut c_void,
|
base_addr_ptr: *mut c_void,
|
||||||
mut import_descriptor_ptr: *mut IMAGE_IMPORT_DESCRIPTOR,
|
mut import_descriptor_ptr: *mut IMAGE_IMPORT_DESCRIPTOR,
|
||||||
far_procs: &FarProcs,
|
far_procs: &FarProcs,
|
||||||
|
flags: &Flags,
|
||||||
) -> BOOL {
|
) -> BOOL {
|
||||||
/*
|
/*
|
||||||
1.) shuffle Import Directory Table entries (image import descriptors)
|
1.) shuffle Import Directory Table entries (image import descriptors)
|
||||||
@ -436,7 +436,7 @@ unsafe fn patch_iat(
|
|||||||
|
|
||||||
let id_ptr = import_descriptor_ptr;
|
let id_ptr = import_descriptor_ptr;
|
||||||
|
|
||||||
if import_count > 1 && SHUFFLE_IMPORTS {
|
if import_count > 1 && flags.shuffle {
|
||||||
// Fisher-Yates shuffle
|
// Fisher-Yates shuffle
|
||||||
for i in 0..import_count - 1 {
|
for i in 0..import_count - 1 {
|
||||||
let rn = match get_random(far_procs) {
|
let rn = match get_random(far_procs) {
|
||||||
@ -465,7 +465,7 @@ unsafe fn patch_iat(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if DELAY_IMPORTS {
|
if flags.delay {
|
||||||
// skip delay if winapi call fails
|
// skip delay if winapi call fails
|
||||||
let rn = get_random(far_procs).unwrap_or(0);
|
let rn = get_random(far_procs).unwrap_or(0);
|
||||||
let delay = rn % MAX_IMPORT_DELAY_MS;
|
let delay = rn % MAX_IMPORT_DELAY_MS;
|
||||||
|
@ -2,8 +2,44 @@
|
|||||||
|
|
||||||
// gen_xor_key isn't required to be a shared module, as it's only used in the shellcode generator
|
// gen_xor_key isn't required to be a shared module, as it's only used in the shellcode generator
|
||||||
|
|
||||||
|
const DELAY_FLAG: u32 = 0b0001;
|
||||||
|
const SHUFFLE_FLAG: u32 = 0b0010;
|
||||||
|
const UFN_FLAG: u32 = 0b0100;
|
||||||
|
|
||||||
const HASH_KEY: usize = 5381;
|
const HASH_KEY: usize = 5381;
|
||||||
|
|
||||||
|
pub struct Flags {
|
||||||
|
pub delay: bool,
|
||||||
|
pub shuffle: bool,
|
||||||
|
pub ufn: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_u32_flag(flag: u32) -> Flags {
|
||||||
|
Flags {
|
||||||
|
delay: flag & DELAY_FLAG != 0,
|
||||||
|
shuffle: flag & SHUFFLE_FLAG != 0,
|
||||||
|
ufn: flag & UFN_FLAG != 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_u32_flag(delay: bool, shuffle: bool, ufn: bool) -> u32 {
|
||||||
|
let mut flags = 0;
|
||||||
|
|
||||||
|
if delay {
|
||||||
|
flags |= DELAY_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if shuffle {
|
||||||
|
flags |= SHUFFLE_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ufn {
|
||||||
|
flags |= UFN_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags
|
||||||
|
}
|
||||||
|
|
||||||
pub fn xor_cipher(data: &mut [u8], key: &[u8]) {
|
pub fn xor_cipher(data: &mut [u8], key: &[u8]) {
|
||||||
for (i, byte) in data.iter_mut().enumerate() {
|
for (i, byte) in data.iter_mut().enumerate() {
|
||||||
*byte ^= key[i % key.len()];
|
*byte ^= key[i % key.len()];
|
||||||
|
Loading…
Reference in New Issue
Block a user