├── README.md ├── bof └── __init__.py └── src ├── setup.py └── source ├── APIResolve.c ├── APIResolve.h ├── COFFLoader.c ├── COFFLoader.h ├── LICENSE.txt ├── _bof.c ├── beacon.h ├── beacon_compatibility.c ├── beacon_compatibility.h └── beacon_generate.py /README.md: -------------------------------------------------------------------------------- 1 | # `PyBOF` 2 | ## Run Beacon Object files through python 3 | 4 | in-memory loading and execution of BOFs 5 | 6 | `PyBOF` enables Python3 to load Beacon Object Files via bytes and execute a target BOF function in a Python interpreter 7 | 8 | ## Basic Usage 9 | 10 | ### Run a simple BOF with no required arguments 11 | ```python 12 | data = open(r'c:\path\to\example.o', 'rb').read() 13 | bof.run(data) 14 | ``` 15 | 16 | ### Pass a raw string argument into BOF 17 | ```python 18 | data = open(r'c:\path\to\example.o', 'rb').read() 19 | bof.run(data, args=["foo"], raw=True) 20 | # Raw cannot be used with function kwarg 21 | ``` 22 | 23 | ### Pass packed/formatted arguments into BOF 24 | ```python 25 | data = open(r'c:\path\to\example.o', 'rb').read() 26 | bof.run(data, args=[r"c:\users"], format="Z") 27 | ``` 28 | 29 | ## Practical example of execution 30 | ```python 31 | import bof 32 | from urllib.request import urlopen 33 | data = urlopen("https://github.com/trustedsec/CS-Situational-Awareness-BOF/raw/master/SA/dir/dir.x64.o").read() 34 | bof.run(data, args=[r"c:\users"], format="Z") 35 | ``` 36 | 37 | ## Args/Kwargs 38 | There are several args that can be used with PyBOF, they are described in more detail below 39 | 40 | ### data 41 | Mandatory first positional argument which must be a byte object which contains the raw contents of a BOF 42 | 43 | ### args 44 | Optional keyword arg which is a list of arguments to pass into the target BOF function 45 | 46 | ### function 47 | Optional keyword arg which is the string formatted name of target function to execute from the supplied BOF, this defaults to `go` 48 | 49 | ### format (NOTICE - These have recently been updated) 50 | Optional keyword arg is a string, which informs the BOF argument packer of the argument types as they are packed into the buffer. This is similar to the format arg from `struct.pack`. The only valid format options are as follows:\ 51 | `i` for integer\ 52 | `s` for short\ 53 | `z` for string\ 54 | `b` for binary\ 55 | `Z` for wide 56 | 57 | At least one format type must be supplied for each arg in the args list. This keyword arg cannot be used in conjunction with `raw` 58 | 59 | ### raw 60 | Optional keyword arg which is a boolean that passes args as a space-joined string without packing it instead of attempting to pack formatted args for the BOF function. This keyword arg cannot be used in conjunction with `format` 61 | 62 | ## Building 63 | Clone this repo 64 | 65 | ```cmd 66 | git clone https://github.com/rkbennett/pybof.git 67 | ``` 68 | 69 | Build the _bof c extension 70 | ```cmd 71 | cd pybof\src 72 | python .\setup.py build 73 | ``` 74 | 75 | Copy the resulting pyd file into the bof directory 76 | ```cmd 77 | copy build\lib.win-xxx-cpython-3xx\_bof.cp3xx-win_xxxx.pyd ..\bof\ 78 | ``` 79 | 80 | Change directory to parent of bof directory, import and have fun 81 | ```cmd 82 | cd ..\ 83 | python 84 | >>> import bof 85 | >>> from urllib.request import urlopen 86 | >>> data = urlopen("https://github.com/trustedsec/CS-Situational-Awareness-BOF/raw/master/SA/dir/dir.x64.o").read() 87 | >>> bof.run(data, args=[r"c:\users"], format="Z") 88 | ``` 89 | 90 | ## Gotchas 91 | If a BOF function does not return a value, I raise a warning alerting the user to the fact nothing was returned. I assume this is likely not the intended outcome of an execution, but didn't want to throw hard errors. `If you run a BOF function and receive the no output warning, keep in mind that your args formatting may need defined or may be defined incorrectly` which can cause this issue (specifically using string instead of wide) 92 | 93 | ## Special Thanks 94 | * [natesubra](https://github.com/natesubra) - For answering my random questions 95 | * [trustedsec](https://github.com/trustedsec) - For the COFFLoader I wrapped into my PyBof module (licensing included in src/source) -------------------------------------------------------------------------------- /bof/__init__.py: -------------------------------------------------------------------------------- 1 | from struct import pack, calcsize 2 | from ._bof import run as bof_runner 3 | 4 | 5 | class BeaconPack: 6 | def __init__(self): 7 | self.buffer = b'' 8 | self.size = 0 9 | 10 | def getbuffer(self): 11 | return pack("e_lfanew); 72 | data_dir = (PIMAGE_DATA_DIRECTORY)&nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 73 | export_dir = (PIMAGE_EXPORT_DIRECTORY)(dll_base + (uint64_t)data_dir->VirtualAddress); 74 | 75 | ptr_exportadrtable = (uint32_t*)(dll_base + (uint64_t)export_dir->AddressOfFunctions); 76 | ptr_namepointertable = (uint32_t*)(dll_base + (uint64_t)export_dir->AddressOfNames); 77 | ptr_ordinaltable = (uint16_t*)(dll_base + (uint64_t)export_dir->AddressOfNameOrdinals); 78 | 79 | for(idx_functions = 0; idx_functions < export_dir->NumberOfNames; idx_functions++){ 80 | 81 | ptr_function_name = (unsigned char*)dll_base + (ptr_namepointertable[idx_functions]); 82 | if (djb2(ptr_function_name) == function_hash) { 83 | WORD nameord = ptr_ordinaltable[idx_functions]; 84 | DWORD rva = ptr_exportadrtable[nameord]; 85 | return dll_base + rva; 86 | } 87 | 88 | } 89 | 90 | return 0; 91 | } 92 | 93 | 94 | 95 | static uint64_t 96 | getDllBase(unsigned long dll_hash) { 97 | 98 | _PPEB ptr_peb = NULL; 99 | PPEB_LDR_DATA ptr_ldr_data = NULL; 100 | PLDR_DATA_TABLE_ENTRY ptr_module_entry = NULL, ptr_start_module = NULL; 101 | PUNICODE_STR dll_name = NULL; 102 | 103 | ptr_peb = (_PEB*)__readgsqword(0x60); 104 | ptr_ldr_data = ptr_peb->pLdr; 105 | ptr_module_entry = ptr_start_module = (PLDR_DATA_TABLE_ENTRY)ptr_ldr_data->InMemoryOrderModuleList.Flink; 106 | 107 | do{ 108 | 109 | dll_name = &ptr_module_entry->BaseDllName; 110 | 111 | if (dll_name->pBuffer == NULL) 112 | return 0; 113 | 114 | if (unicode_djb2(toLower(dll_name->pBuffer)) == dll_hash) 115 | return (uint64_t)ptr_module_entry->DllBase; 116 | 117 | ptr_module_entry = (PLDR_DATA_TABLE_ENTRY)ptr_module_entry->InMemoryOrderModuleList.Flink; 118 | 119 | } while (ptr_module_entry != ptr_start_module); 120 | 121 | return 0; 122 | 123 | } 124 | 125 | static unsigned long 126 | djb2(unsigned char* str) 127 | { 128 | unsigned long hash = 5381; 129 | int c; 130 | 131 | while ((c = *str++)) 132 | hash = ((hash << 5) + hash) + c; 133 | 134 | return hash; 135 | } 136 | 137 | unsigned long 138 | unicode_djb2(const wchar_t* str) 139 | { 140 | 141 | unsigned long hash = 5381; 142 | DWORD val; 143 | 144 | while (*str != 0) { 145 | val = (DWORD)*str++; 146 | hash = ((hash << 5) + hash) + val; 147 | } 148 | 149 | return hash; 150 | 151 | } 152 | 153 | static WCHAR* 154 | toLower(WCHAR *str) 155 | { 156 | 157 | WCHAR* start = str; 158 | 159 | while (*str) { 160 | 161 | if (*str <= L'Z' && *str >= 'A') { 162 | *str += 32; 163 | } 164 | 165 | str += 1; 166 | 167 | } 168 | 169 | return start; 170 | 171 | } -------------------------------------------------------------------------------- /src/source/APIResolve.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "windows.h" 5 | 6 | #include "wininet.h" 7 | 8 | uint64_t getFunctionPtr(unsigned long, unsigned long); 9 | 10 | // ---- KERNEL32 ---- 11 | #define HASH_KERNEL32 0x7040ee75 12 | #define HASH_VirtualFree 0x668fcf2e 13 | #define HASH_VirtualAlloc 0x382c0f97 14 | #define HASH_LoadLibraryA 0x5fbff0fb 15 | #define HASH_GetProcAddress 0xcf31bb1f 16 | #define HASH_CreateProcessA 0xaeb52e19 17 | #define HASH_CloseHandle 0x3870ca07 18 | #define HASH_GetStdHandle 0xf178843c 19 | #define HASH_WriteFile 0x663cecb0 20 | 21 | typedef HMODULE(WINAPI* tLoadLibraryA)(LPCSTR); 22 | typedef BOOL(WINAPI* tVirtualFree)(LPVOID, SIZE_T, DWORD); 23 | typedef LPVOID(WINAPI* tVirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD); 24 | typedef FARPROC(WINAPI* tGetProcAddress)(HMODULE, LPCSTR); 25 | typedef BOOL(WINAPI* tCreateProcessA)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION); 26 | typedef BOOL(WINAPI* tCloseHandle)(HANDLE); 27 | typedef HANDLE(WINAPI* tGetStdHandle)(DWORD); 28 | typedef BOOL(WINAPI* tWriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED ); 29 | 30 | // -- MSVCRT -- 31 | #define HASH_MSVCRT 0xff6c2f6e 32 | #define HASH_printf 0x156b2bb8 33 | 34 | typedef int(__CRTDECL* tprintf)(LPCSTR, ...); 35 | 36 | // -- ADVAPI32 -- 37 | #define HASH_ADVAPI32 0x48b4de29 38 | 39 | #define HASH_SetThreadToken 0x575b17ca 40 | typedef BOOL(WINAPI* tSetThreadToken)(PHANDLE, HANDLE); 41 | 42 | #define HASH_RevertToSelf 0x58cf32aa 43 | typedef BOOL(WINAPI* tRevertToSelf)(); 44 | 45 | typedef struct _UNICODE_STR { 46 | USHORT Length; 47 | USHORT MaximumLength; 48 | PWSTR pBuffer; 49 | } UNICODE_STR, * PUNICODE_STR; 50 | 51 | typedef struct _PEB_LDR_DATA 52 | { 53 | DWORD dwLength; 54 | DWORD dwInitialized; 55 | LPVOID lpSsHandle; 56 | LIST_ENTRY InLoadOrderModuleList; 57 | LIST_ENTRY InMemoryOrderModuleList; 58 | LIST_ENTRY InInitializationOrderModuleList; 59 | LPVOID lpEntryInProgress; 60 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 61 | 62 | typedef struct _LDR_DATA_TABLE_ENTRY 63 | { 64 | LIST_ENTRY InMemoryOrderModuleList; 65 | LIST_ENTRY InInitializationOrderModuleList; 66 | PVOID DllBase; 67 | PVOID EntryPoint; 68 | ULONG SizeOfImage; 69 | UNICODE_STR FullDllName; 70 | UNICODE_STR BaseDllName; 71 | ULONG Flags; 72 | SHORT LoadCount; 73 | SHORT TlsIndex; 74 | LIST_ENTRY HashTableEntry; 75 | ULONG TimeDateStamp; 76 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 77 | 78 | typedef struct _PEB_FREE_BLOCK 79 | { 80 | struct _PEB_FREE_BLOCK* pNext; 81 | DWORD dwSize; 82 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 83 | 84 | typedef struct __PEB 85 | { 86 | BYTE bInheritedAddressSpace; 87 | BYTE bReadImageFileExecOptions; 88 | BYTE bBeingDebugged; 89 | BYTE bSpareBool; 90 | LPVOID lpMutant; 91 | LPVOID lpImageBaseAddress; 92 | PPEB_LDR_DATA pLdr; 93 | LPVOID lpProcessParameters; 94 | LPVOID lpSubSystemData; 95 | LPVOID lpProcessHeap; 96 | PRTL_CRITICAL_SECTION pFastPebLock; 97 | LPVOID lpFastPebLockRoutine; 98 | LPVOID lpFastPebUnlockRoutine; 99 | DWORD dwEnvironmentUpdateCount; 100 | LPVOID lpKernelCallbackTable; 101 | DWORD dwSystemReserved; 102 | DWORD dwAtlThunkSListPtr32; 103 | PPEB_FREE_BLOCK pFreeList; 104 | DWORD dwTlsExpansionCounter; 105 | LPVOID lpTlsBitmap; 106 | DWORD dwTlsBitmapBits[2]; 107 | LPVOID lpReadOnlySharedMemoryBase; 108 | LPVOID lpReadOnlySharedMemoryHeap; 109 | LPVOID lpReadOnlyStaticServerData; 110 | LPVOID lpAnsiCodePageData; 111 | LPVOID lpOemCodePageData; 112 | LPVOID lpUnicodeCaseTableData; 113 | DWORD dwNumberOfProcessors; 114 | DWORD dwNtGlobalFlag; 115 | LARGE_INTEGER liCriticalSectionTimeout; 116 | DWORD dwHeapSegmentReserve; 117 | DWORD dwHeapSegmentCommit; 118 | DWORD dwHeapDeCommitTotalFreeThreshold; 119 | DWORD dwHeapDeCommitFreeBlockThreshold; 120 | DWORD dwNumberOfHeaps; 121 | DWORD dwMaximumNumberOfHeaps; 122 | LPVOID lpProcessHeaps; 123 | LPVOID lpGdiSharedHandleTable; 124 | LPVOID lpProcessStarterHelper; 125 | DWORD dwGdiDCAttributeList; 126 | LPVOID lpLoaderLock; 127 | DWORD dwOSMajorVersion; 128 | DWORD dwOSMinorVersion; 129 | WORD wOSBuildNumber; 130 | WORD wOSCSDVersion; 131 | DWORD dwOSPlatformId; 132 | DWORD dwImageSubsystem; 133 | DWORD dwImageSubsystemMajorVersion; 134 | DWORD dwImageSubsystemMinorVersion; 135 | DWORD dwImageProcessAffinityMask; 136 | DWORD dwGdiHandleBuffer[34]; 137 | LPVOID lpPostProcessInitRoutine; 138 | LPVOID lpTlsExpansionBitmap; 139 | DWORD dwTlsExpansionBitmapBits[32]; 140 | DWORD dwSessionId; 141 | ULARGE_INTEGER liAppCompatFlags; 142 | ULARGE_INTEGER liAppCompatFlagsUser; 143 | LPVOID lppShimData; 144 | LPVOID lpAppCompatInfo; 145 | UNICODE_STR usCSDVersion; 146 | LPVOID lpActivationContextData; 147 | LPVOID lpProcessAssemblyStorageMap; 148 | LPVOID lpSystemDefaultActivationContextData; 149 | LPVOID lpSystemAssemblyStorageMap; 150 | DWORD dwMinimumStackCommit; 151 | } _PEB, * _PPEB; 152 | -------------------------------------------------------------------------------- /src/source/COFFLoader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * COFF Loader Project 3 | * ------------------- 4 | * This is a re-implementation of a COFF loader, with a BOF compatibility layer 5 | * it's meant to provide functional example of loading a COFF file in memory 6 | * and maybe be useful. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #if defined(_WIN32) 14 | #include "APIResolve.h" 15 | #include 16 | #include "beacon_compatibility.h" 17 | #endif 18 | 19 | #include "COFFLoader.h" 20 | 21 | /* Enable or disable debug output if testing or adding new relocation types */ 22 | #ifdef DEBUG 23 | #define DEBUG_PRINT(x, ...) printf(x, ##__VA_ARGS__) 24 | #else 25 | #define DEBUG_PRINT(x, ...) 26 | #endif 27 | 28 | /* Defining symbols for the OS version, will try to define anything that is 29 | * different between the arch versions by specifying them here. */ 30 | #if defined(__x86_64__) || defined(_WIN64) 31 | #define PREPENDSYMBOLVALUE "__imp_" 32 | #else 33 | #define PREPENDSYMBOLVALUE "__imp__" 34 | #endif 35 | 36 | unsigned char* unhexlify(unsigned char* value, int *outlen) { 37 | unsigned char* retval = NULL; 38 | char byteval[3] = { 0 }; 39 | unsigned int counter = 0; 40 | int counter2 = 0; 41 | char character = 0; 42 | if (value == NULL) { 43 | return NULL; 44 | } 45 | 46 | DEBUG_PRINT("Unhexlify Strlen: %lu\n", (long unsigned int)strlen((char*)value)); 47 | if (value == NULL || strlen((char*)value) % 2 != 0) { 48 | DEBUG_PRINT("Either value is NULL, or the hexlified string isn't valid\n"); 49 | goto errcase; 50 | } 51 | 52 | retval = calloc(strlen((char*)value) + 1, 1); 53 | if (retval == NULL) { 54 | goto errcase; 55 | } 56 | 57 | counter2 = 0; 58 | for (counter = 0; counter < strlen((char*)value); counter += 2) { 59 | memcpy(byteval, value + counter, 2); 60 | character = (char)strtol(byteval, NULL, 16); 61 | memcpy(retval + counter2, &character, 1); 62 | counter2++; 63 | } 64 | 65 | *outlen = counter2; 66 | 67 | errcase: 68 | return retval; 69 | } 70 | 71 | 72 | 73 | /* Helper to just get the contents of a file, used for testing. Real 74 | * implementations of this in an agent would use the tasking from the 75 | * C2 server for this */ 76 | unsigned char* getContents(char* filepath, uint32_t* outsize) { 77 | FILE *fin = NULL; 78 | uint32_t fsize = 0; 79 | size_t readsize = 0; 80 | unsigned char* buffer = NULL; 81 | unsigned char* tempbuffer = NULL; 82 | 83 | fin = fopen(filepath, "rb"); 84 | if (fin == NULL) { 85 | return NULL; 86 | } 87 | fseek(fin, 0, SEEK_END); 88 | fsize = ftell(fin); 89 | fseek(fin, 0, SEEK_SET); 90 | tempbuffer = calloc(fsize, 1); 91 | if (tempbuffer == NULL) { 92 | return NULL; 93 | } 94 | memset(tempbuffer, 0, fsize); 95 | readsize = fread(tempbuffer, 1, fsize, fin); 96 | 97 | fclose(fin); 98 | buffer = calloc(readsize, 1); 99 | if (buffer == NULL) { 100 | return NULL; 101 | } 102 | memset(buffer, 0, readsize); 103 | memcpy(buffer, tempbuffer, readsize - 1); 104 | free(tempbuffer); 105 | *outsize = fsize; 106 | return buffer; 107 | } 108 | 109 | static BOOL starts_with(const char* string, const char* substring) { 110 | return strncmp(string, substring, strlen(substring)) == 0; 111 | } 112 | 113 | /* Helper function to process a symbol string, determine what function and 114 | * library its from, and return the right function pointer. Will need to 115 | * implement in the loading of the beacon internal functions, or any other 116 | * internal functions you want to have available. */ 117 | void* process_symbol(char* symbolstring) { 118 | void* functionaddress = NULL; 119 | char localcopy[1024] = { 0 }; 120 | char* locallib = NULL; 121 | char* localfunc = NULL; 122 | #if defined(_WIN32) 123 | int tempcounter = 0; 124 | HMODULE llHandle = NULL; 125 | #endif 126 | 127 | strncpy(localcopy, symbolstring, sizeof(localcopy) - 1); 128 | if (starts_with(symbolstring, PREPENDSYMBOLVALUE"Beacon") || starts_with(symbolstring, PREPENDSYMBOLVALUE"toWideChar") || 129 | starts_with(symbolstring, PREPENDSYMBOLVALUE"GetProcAddress") || starts_with(symbolstring, PREPENDSYMBOLVALUE"LoadLibraryA") || 130 | starts_with(symbolstring, PREPENDSYMBOLVALUE"GetModuleHandleA") || starts_with(symbolstring, PREPENDSYMBOLVALUE"FreeLibrary")) { 131 | localfunc = symbolstring + strlen(PREPENDSYMBOLVALUE); 132 | DEBUG_PRINT("\t\tInternalFunction: %s\n", localfunc); 133 | /* TODO: Get internal symbol here and set to functionaddress, then 134 | * return the pointer to the internal function*/ 135 | #if defined(_WIN32) 136 | for (tempcounter = 0; tempcounter < 29; tempcounter++) { 137 | if (InternalFunctions[tempcounter][0] != NULL) { 138 | if (starts_with(localfunc, (char*)(InternalFunctions[tempcounter][0]))) { 139 | functionaddress = (void*)InternalFunctions[tempcounter][1]; 140 | return functionaddress; 141 | } 142 | } 143 | } 144 | #endif 145 | } 146 | else if (strncmp(symbolstring, PREPENDSYMBOLVALUE, strlen(PREPENDSYMBOLVALUE)) == 0) { 147 | DEBUG_PRINT("\t\tYep its an external symbol\n"); 148 | locallib = localcopy + strlen(PREPENDSYMBOLVALUE); 149 | 150 | locallib = strtok(locallib, "$"); 151 | localfunc = strtok(NULL, "$"); 152 | DEBUG_PRINT("\t\tLibrary: %s\n", locallib); 153 | localfunc = strtok(localfunc, "@"); 154 | DEBUG_PRINT("\t\tFunction: %s\n", localfunc); 155 | /* Resolve the symbols here, and set the functionpointervalue */ 156 | #if defined(_WIN32) 157 | llHandle = LoadLibraryA(locallib); 158 | DEBUG_PRINT("\t\tHandle: 0x%lx\n", llHandle); 159 | functionaddress = GetProcAddress(llHandle, localfunc); 160 | DEBUG_PRINT("\t\tProcAddress: 0x%p\n", functionaddress); 161 | #endif 162 | } 163 | return functionaddress; 164 | } 165 | 166 | /* Just a generic runner for testing, this is pretty much just a reference 167 | * implementation, return values will need to be checked, more relocation 168 | * types need to be handled, and needs to have different arguments for use 169 | * in any agent. */ 170 | int RunCOFF(char* functionname, unsigned char* coff_data, uint32_t filesize, unsigned char* argumentdata, int argumentSize) { 171 | coff_file_header_t *coff_header_ptr = NULL; 172 | coff_sect_t *coff_sect_ptr = NULL; 173 | coff_reloc_t *coff_reloc_ptr = NULL; 174 | coff_sym_t * coff_sym_ptr = NULL; 175 | int retcode = 0; 176 | int counter = 0; 177 | int reloccount = 0; 178 | unsigned int tempcounter = 0; 179 | uint32_t symptr = 0; 180 | #ifdef _WIN32 181 | void* funcptrlocation = NULL; 182 | size_t offsetvalue = 0; 183 | #endif 184 | char* entryfuncname = functionname; 185 | #if defined(__x86_64__) || defined(_WIN64) 186 | #ifdef _WIN32 187 | uint64_t longoffsetvalue = 0; 188 | #endif 189 | #else 190 | /* Set the input function name to match the 32 bit version */ 191 | entryfuncname = calloc(strlen(functionname) + 2, 1); 192 | if (entryfuncname == NULL) { 193 | return 1; 194 | } 195 | (void)sprintf(entryfuncname, "_%s", functionname); 196 | #endif 197 | 198 | #ifdef _WIN32 199 | /* NOTE: I just picked a size, look to see what is max/normal. */ 200 | char* sectionMapping[25] = { 0 }; 201 | #ifdef DEBUG 202 | int sectionSize[25] = { 0 }; 203 | #endif 204 | void(*foo)(char* in, unsigned long datalen); 205 | char* functionMapping = NULL; 206 | int functionMappingCount = 0; 207 | #endif 208 | 209 | if (coff_data == NULL) { 210 | DEBUG_PRINT("Can't execute NULL\n"); 211 | return 1; 212 | } 213 | coff_header_ptr = (coff_file_header_t*)coff_data; 214 | DEBUG_PRINT("Machine 0x%X\n", coff_header_ptr->Machine); 215 | DEBUG_PRINT("Number of sections: %d\n", coff_header_ptr->NumberOfSections); 216 | DEBUG_PRINT("TimeDateStamp : %X\n", coff_header_ptr->TimeDateStamp); 217 | DEBUG_PRINT("PointerToSymbolTable : 0x%X\n", coff_header_ptr->PointerToSymbolTable); 218 | DEBUG_PRINT("NumberOfSymbols: %d\n", coff_header_ptr->NumberOfSymbols); 219 | DEBUG_PRINT("OptionalHeaderSize: %d\n", coff_header_ptr->SizeOfOptionalHeader); 220 | DEBUG_PRINT("Characteristics: %d\n", coff_header_ptr->Characteristics); 221 | DEBUG_PRINT("\n"); 222 | coff_sym_ptr = (coff_sym_t*)(coff_data + coff_header_ptr->PointerToSymbolTable); 223 | 224 | /* Handle the allocation and copying of the sections we're going to use 225 | * for right now I'm just VirtualAlloc'ing memory, this can be changed to 226 | * other methods, but leaving that up to the person implementing it. */ 227 | for (counter = 0; counter < coff_header_ptr->NumberOfSections; counter++) { 228 | coff_sect_ptr = (coff_sect_t*)(coff_data + sizeof(coff_file_header_t) + (sizeof(coff_sect_t) * counter)); 229 | DEBUG_PRINT("Name: %s\n", coff_sect_ptr->Name); 230 | DEBUG_PRINT("VirtualSize: 0x%X\n", coff_sect_ptr->VirtualSize); 231 | DEBUG_PRINT("VirtualAddress: 0x%X\n", coff_sect_ptr->VirtualAddress); 232 | DEBUG_PRINT("SizeOfRawData: 0x%X\n", coff_sect_ptr->SizeOfRawData); 233 | DEBUG_PRINT("PointerToRelocations: 0x%X\n", coff_sect_ptr->PointerToRelocations); 234 | DEBUG_PRINT("PointerToRawData: 0x%X\n", coff_sect_ptr->PointerToRawData); 235 | DEBUG_PRINT("NumberOfRelocations: %d\n", coff_sect_ptr->NumberOfRelocations); 236 | /* NOTE: When changing the memory loading information of the loader, 237 | * you'll want to use this field and the defines from the Section 238 | * Flags table of Microsofts page, some defined in COFFLoader.h */ 239 | DEBUG_PRINT("Characteristics: %x\n", coff_sect_ptr->Characteristics); 240 | #ifdef _WIN32 241 | DEBUG_PRINT("Allocating 0x%x bytes\n", coff_sect_ptr->VirtualSize); 242 | /* NOTE: Might want to allocate as PAGE_READWRITE and VirtualProtect 243 | * before execution to either PAGE_READWRITE or PAGE_EXECUTE_READ 244 | * depending on the Section Characteristics. Parse them all again 245 | * before running and set the memory permissions. */ 246 | sectionMapping[counter] = VirtualAlloc(NULL, coff_sect_ptr->SizeOfRawData, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); 247 | #ifdef DEBUG 248 | sectionSize[counter] = coff_sect_ptr->SizeOfRawData; 249 | #endif 250 | if (sectionMapping[counter] == NULL) { 251 | DEBUG_PRINT("Failed to allocate memory\n"); 252 | } 253 | DEBUG_PRINT("Allocated section %d at %p\n", counter, sectionMapping[counter]); 254 | memcpy(sectionMapping[counter], coff_data + coff_sect_ptr->PointerToRawData, coff_sect_ptr->SizeOfRawData); 255 | #endif 256 | } 257 | 258 | /* Allocate and setup the GOT for functions, same here as above. */ 259 | #ifdef _WIN32 260 | #ifdef _WIN64 261 | functionMapping = VirtualAlloc(NULL, 2048, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); 262 | #else 263 | functionMapping = VirtualAlloc(NULL, 2048, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); 264 | #endif 265 | #endif 266 | 267 | /* Start parsing the relocations, and *hopefully* handle them correctly. */ 268 | for (counter = 0; counter < coff_header_ptr->NumberOfSections; counter++) { 269 | DEBUG_PRINT("Doing Relocations of section: %d\n", counter); 270 | coff_sect_ptr = (coff_sect_t*)(coff_data + sizeof(coff_file_header_t) + (sizeof(coff_sect_t) * counter)); 271 | coff_reloc_ptr = (coff_reloc_t*)(coff_data + coff_sect_ptr->PointerToRelocations); 272 | for (reloccount = 0; reloccount < coff_sect_ptr->NumberOfRelocations; reloccount++) { 273 | DEBUG_PRINT("\tVirtualAddress: 0x%X\n", coff_reloc_ptr->VirtualAddress); 274 | DEBUG_PRINT("\tSymbolTableIndex: 0x%X\n", coff_reloc_ptr->SymbolTableIndex); 275 | DEBUG_PRINT("\tType: 0x%X\n", coff_reloc_ptr->Type); 276 | if (coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].first.Name[0] != 0) { 277 | symptr = coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].first.value[1]; 278 | DEBUG_PRINT("\tSymPtr: 0x%X\n", symptr); 279 | DEBUG_PRINT("\tSymName: %s\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].first.Name); 280 | DEBUG_PRINT("\tSectionNumber: 0x%X\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber); 281 | 282 | /* This is the code for relative offsets in other sections of the COFF file. */ 283 | #ifdef _WIN32 284 | #ifdef _WIN64 285 | /* Type == 1 relocation is the 64-bit VA of the relocation target */ 286 | if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_ADDR64) { 287 | memcpy(&longoffsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(uint64_t)); 288 | DEBUG_PRINT("\tReadin longOffsetValue : 0x%llX\n", longoffsetvalue); 289 | longoffsetvalue = (uint64_t)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + (uint64_t)longoffsetvalue); 290 | DEBUG_PRINT("\tModified longOffsetValue : 0x%llX Base Address: %p\n", longoffsetvalue, sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1]); 291 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &longoffsetvalue, sizeof(uint64_t)); 292 | } 293 | /* This is Type == 3 relocation code */ 294 | else if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_ADDR32NB) { 295 | memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t)); 296 | DEBUG_PRINT("\tReadin OffsetValue : 0x%0X\n", offsetvalue); 297 | DEBUG_PRINT("\t\tReferenced Section: 0x%X\n", sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue); 298 | DEBUG_PRINT("\t\tEnd of Relocation Bytes: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4); 299 | if (((char*)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue) - (char*)(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff) { 300 | DEBUG_PRINT("Relocations > 4 gigs away, exiting\n"); 301 | retcode = 1; 302 | goto cleanup; 303 | } 304 | offsetvalue = ((char*)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue) - (char*)(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)); 305 | DEBUG_PRINT("\tSetting 0x%p to OffsetValue: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 306 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 307 | } 308 | /* This is Type == 4 relocation code, needed to make global variables to work correctly */ 309 | else if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_REL32) { 310 | memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t)); 311 | DEBUG_PRINT("\t\tReadin offset value: 0x%X\n", offsetvalue); 312 | if ((sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff) { 313 | DEBUG_PRINT("Relocations > 4 gigs away, exiting\n"); 314 | retcode = 1; 315 | goto cleanup; 316 | } 317 | offsetvalue += (sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)); 318 | offsetvalue += coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].Value; 319 | DEBUG_PRINT("\t\tSetting 0x%p to relative address: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 320 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 321 | } 322 | else { 323 | DEBUG_PRINT("No code for relocation type: %d\n", coff_reloc_ptr->Type); 324 | } 325 | #else 326 | /* This is Type == IMAGE_REL_I386_DIR32 relocation code */ 327 | if (coff_reloc_ptr->Type == IMAGE_REL_I386_DIR32){ 328 | memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t)); 329 | DEBUG_PRINT("\tReadin OffsetValue : 0x%0X\n", offsetvalue); 330 | offsetvalue = (uint32_t)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1]) + offsetvalue; 331 | offsetvalue += coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].Value; 332 | DEBUG_PRINT("\tSetting 0x%p to: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 333 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 334 | } 335 | else if (coff_reloc_ptr->Type == IMAGE_REL_I386_REL32){ 336 | memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t)); 337 | DEBUG_PRINT("\tReadin OffsetValue : 0x%0X\n", offsetvalue); 338 | offsetvalue += (sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)); 339 | offsetvalue += coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].Value; 340 | DEBUG_PRINT("\tSetting 0x%p to relative address: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 341 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 342 | 343 | } 344 | #endif //WIN64 statement close 345 | #endif //WIN32 statement close 346 | } 347 | else { 348 | symptr = coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].first.value[1]; 349 | DEBUG_PRINT("\tSymPtr: 0x%X\n", symptr); 350 | DEBUG_PRINT("\tSymVal: %s\n", ((char*)(coff_sym_ptr + coff_header_ptr->NumberOfSymbols)) + symptr); 351 | DEBUG_PRINT("\tSectionNumber: 0x%X\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber); 352 | 353 | /* This is the code to handle functions themselves, so using a makeshift Global Offset Table for it */ 354 | #ifdef _WIN32 355 | funcptrlocation = process_symbol(((char*)(coff_sym_ptr + coff_header_ptr->NumberOfSymbols)) + symptr); 356 | if (funcptrlocation == NULL && coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber == 0) { 357 | DEBUG_PRINT("Failed to resolve symbol\n"); 358 | retcode = 1; 359 | goto cleanup; 360 | } 361 | #ifdef _WIN64 362 | if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_ADDR64) { 363 | memcpy(&longoffsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(uint64_t)); 364 | DEBUG_PRINT("\tReadin longOffsetValue : 0x%llX\n", longoffsetvalue); 365 | longoffsetvalue = (uint64_t)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + (uint64_t)longoffsetvalue); 366 | DEBUG_PRINT("\tModified longOffsetValue : 0x%llX Base Address: %p\n", longoffsetvalue, sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1]); 367 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &longoffsetvalue, sizeof(uint64_t)); 368 | } 369 | 370 | else if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_REL32 && funcptrlocation != NULL) { 371 | /* This is Type == 4 relocation code */ 372 | DEBUG_PRINT("Doing function relocation\n"); 373 | if (((functionMapping + (functionMappingCount * 8)) - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff) { 374 | DEBUG_PRINT("Relocations > 4 gigs away, exiting\n"); 375 | retcode = 1; 376 | goto cleanup; 377 | } 378 | memcpy(functionMapping + (functionMappingCount * 8), &funcptrlocation, sizeof(uint64_t)); 379 | offsetvalue = (int32_t)((functionMapping + (functionMappingCount * 8)) - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)); 380 | DEBUG_PRINT("\t\tSetting 0x%p to relative address: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 381 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 382 | functionMappingCount++; 383 | } 384 | else if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_REL32) { 385 | /* This shouldn't be needed here, but incase there's a defined symbol 386 | * that somehow doesn't have a function, try to resolve it here.*/ 387 | memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t)); 388 | if ((sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff) { 389 | DEBUG_PRINT("Relocations > 4 gigs away, exiting\n"); 390 | retcode = 1; 391 | goto cleanup; 392 | } 393 | DEBUG_PRINT("\t\tReferenced Section: 0x%X\n", sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue); 394 | DEBUG_PRINT("\t\tReadin offset value: 0x%X\n", offsetvalue); 395 | DEBUG_PRINT("\t\tVirtualAddressOffset: 0x%X\n", (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)); 396 | offsetvalue += (sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)); 397 | offsetvalue += coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].Value; 398 | DEBUG_PRINT("\t\tSetting 0x%p to relative address: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 399 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 400 | } 401 | else if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_ADDR32NB) { 402 | memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t)); 403 | DEBUG_PRINT("\tReadin OffsetValue : 0x%0X\n", offsetvalue); 404 | DEBUG_PRINT("\t\tReferenced Section: 0x%X\n", sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue); 405 | DEBUG_PRINT("\t\tEnd of Relocation Bytes: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4); 406 | if (((char*)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue) - (char*)(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff) { 407 | DEBUG_PRINT("Relocations > 4 gigs away, exiting\n"); 408 | retcode = 1; 409 | goto cleanup; 410 | } 411 | offsetvalue = ((char*)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue) - (char*)(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)); 412 | DEBUG_PRINT("\tSetting 0x%p to OffsetValue: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 413 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 414 | } 415 | else { 416 | DEBUG_PRINT("No code for relocation type: %d\n", coff_reloc_ptr->Type); 417 | } 418 | #else 419 | if (coff_reloc_ptr->Type == IMAGE_REL_I386_DIR32 && funcptrlocation != NULL){ 420 | /* This is Type == IMAGE_REL_I386_DIR32 relocation code */ 421 | memcpy(functionMapping + (functionMappingCount * 4), &funcptrlocation, sizeof(uint32_t)); 422 | offsetvalue = (int32_t)(functionMapping + (functionMappingCount * 4)); 423 | DEBUG_PRINT("\tSetting 0x%p to virtual address: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 424 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 425 | functionMappingCount++; 426 | } 427 | else if (coff_reloc_ptr->Type == IMAGE_REL_I386_DIR32) { 428 | memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t)); 429 | DEBUG_PRINT("\tReadin OffsetValue : 0x%0X\n", offsetvalue); 430 | offsetvalue = (uint32_t)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1]) + offsetvalue; 431 | offsetvalue += coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].Value; 432 | DEBUG_PRINT("\tSetting 0x%p to virtual address: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 433 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 434 | } 435 | else if (coff_reloc_ptr->Type == IMAGE_REL_I386_REL32){ 436 | memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t)); 437 | DEBUG_PRINT("\tReadin OffsetValue : 0x%0X\n", offsetvalue); 438 | offsetvalue += (sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)); 439 | offsetvalue += coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].Value; 440 | DEBUG_PRINT("\tSetting 0x%p to relative address: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, offsetvalue); 441 | memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t)); 442 | 443 | } 444 | else { 445 | DEBUG_PRINT("No code for relocation type: %d\n", coff_reloc_ptr->Type); 446 | } 447 | #endif 448 | #endif 449 | } 450 | DEBUG_PRINT("\tValueNumber: 0x%X\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].Value); 451 | DEBUG_PRINT("\tSectionNumber: 0x%X\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber); 452 | coff_reloc_ptr = (coff_reloc_t*)(((char*)coff_reloc_ptr) + sizeof(coff_reloc_t)); 453 | DEBUG_PRINT("\n"); 454 | } 455 | DEBUG_PRINT("\n"); 456 | } 457 | 458 | /* Some debugging code to see what the sections look like in memory */ 459 | #if DEBUG 460 | #ifdef _WIN32 461 | for (tempcounter = 0; tempcounter < 10; tempcounter++) { 462 | DEBUG_PRINT("Section: %d\n", tempcounter); 463 | if (sectionMapping[tempcounter] != NULL) { 464 | DEBUG_PRINT("\t"); 465 | for (counter = 0; counter < sectionSize[tempcounter]; counter++) { 466 | DEBUG_PRINT("%02X ", (uint8_t)(sectionMapping[tempcounter][counter])); 467 | } 468 | DEBUG_PRINT("\n"); 469 | } 470 | } 471 | #endif 472 | #endif 473 | DEBUG_PRINT("Symbols:\n"); 474 | for (tempcounter = 0; tempcounter < coff_header_ptr->NumberOfSymbols; tempcounter++) { 475 | DEBUG_PRINT("\t%s: Section: %d, Value: 0x%X\n", coff_sym_ptr[tempcounter].first.Name, coff_sym_ptr[tempcounter].SectionNumber, coff_sym_ptr[tempcounter].Value); 476 | if (strcmp(coff_sym_ptr[tempcounter].first.Name, entryfuncname) == 0) { 477 | DEBUG_PRINT("\t\tFound entry!\n"); 478 | #ifdef _WIN32 479 | /* So for some reason VS 2017 doesn't like this, but char* casting works, so just going to do that */ 480 | #ifdef _MSC_VER 481 | foo = (void(__cdecl*)(char*, unsigned long))(sectionMapping[coff_sym_ptr[tempcounter].SectionNumber - 1] + coff_sym_ptr[tempcounter].Value); 482 | #else 483 | foo = (void(*)(char *, unsigned long))(sectionMapping[coff_sym_ptr[tempcounter].SectionNumber - 1] + coff_sym_ptr[tempcounter].Value); 484 | #endif 485 | //sectionMapping[coff_sym_ptr[tempcounter].SectionNumber-1][coff_sym_ptr[tempcounter].Value+7] = '\xcc'; 486 | DEBUG_PRINT("Trying to run: %p\n", foo); 487 | foo((char*)argumentdata, argumentSize); 488 | #endif 489 | } 490 | } 491 | DEBUG_PRINT("Back\n"); 492 | 493 | /* Cleanup the allocated memory */ 494 | #ifdef _WIN32 495 | cleanup : 496 | for (tempcounter = 0; tempcounter < 25; tempcounter++) { 497 | if (sectionMapping[tempcounter]) { 498 | VirtualFree(sectionMapping[tempcounter], 0, MEM_RELEASE); 499 | } 500 | } 501 | VirtualFree(functionMapping, 0, MEM_RELEASE); 502 | #endif 503 | DEBUG_PRINT("Returning\n"); 504 | return retcode; 505 | } 506 | 507 | #ifdef COFF_STANDALONE 508 | int main(int argc, char* argv[]) { 509 | char* coff_data = NULL; 510 | unsigned char* arguments = NULL; 511 | int argumentSize = 0; 512 | #ifdef _WIN32 513 | char* outdata = NULL; 514 | int outdataSize = 0; 515 | #endif 516 | uint32_t filesize = 0; 517 | int checkcode = 0; 518 | if (argc < 3) { 519 | printf("ERROR: %s go /path/to/object/file.o (arguments)\n", argv[0]); 520 | return 1; 521 | } 522 | 523 | coff_data = (char*)getContents(argv[2], &filesize); 524 | if (coff_data == NULL) { 525 | return 1; 526 | } 527 | printf("Got contents of COFF file\n"); 528 | arguments = unhexlify((unsigned char*)argv[3], &argumentSize); 529 | printf("Running/Parsing the COFF file\n"); 530 | checkcode = RunCOFF(argv[1], (unsigned char*)coff_data, filesize, arguments, argumentSize); 531 | if (checkcode == 0) { 532 | #ifdef _WIN32 533 | printf("Ran/parsed the coff\n"); 534 | outdata = BeaconGetOutputData(&outdataSize); 535 | if (outdata != NULL) { 536 | 537 | printf("Outdata Below:\n\n%s\n", outdata); 538 | } 539 | #endif 540 | } 541 | else { 542 | printf("Failed to run/parse the COFF file\n"); 543 | } 544 | if (coff_data) { 545 | free(coff_data); 546 | } 547 | return 0; 548 | } 549 | 550 | #endif 551 | -------------------------------------------------------------------------------- /src/source/COFFLoader.h: -------------------------------------------------------------------------------- 1 | #ifndef COFFLOADER_H_ 2 | #define COFFLOADER_H_ 3 | #include 4 | #include 5 | 6 | /* These seem to be the same sizes across architectures, relocations are different though. Defined both sets of types. */ 7 | 8 | /* sizeof 20 */ 9 | typedef struct coff_file_header { 10 | uint16_t Machine; 11 | uint16_t NumberOfSections; 12 | uint32_t TimeDateStamp; 13 | uint32_t PointerToSymbolTable; 14 | uint32_t NumberOfSymbols; 15 | uint16_t SizeOfOptionalHeader; 16 | uint16_t Characteristics; 17 | } coff_file_header_t; 18 | 19 | /* AMD64 should always be here */ 20 | #define MACHINETYPE_AMD64 0x8664 21 | 22 | #pragma pack(push,1) 23 | 24 | /* Size of 40 */ 25 | typedef struct coff_sect { 26 | char Name[8]; 27 | uint32_t VirtualSize; 28 | uint32_t VirtualAddress; 29 | uint32_t SizeOfRawData; 30 | uint32_t PointerToRawData; 31 | uint32_t PointerToRelocations; 32 | uint32_t PointerToLineNumbers; 33 | uint16_t NumberOfRelocations; 34 | uint16_t NumberOfLinenumbers; 35 | uint32_t Characteristics; 36 | } coff_sect_t; 37 | 38 | 39 | typedef struct coff_reloc { 40 | uint32_t VirtualAddress; 41 | uint32_t SymbolTableIndex; 42 | uint16_t Type; 43 | } coff_reloc_t; 44 | 45 | typedef struct coff_sym { 46 | union { 47 | char Name[8]; 48 | uint32_t value[2]; 49 | } first; 50 | uint32_t Value; 51 | uint16_t SectionNumber; 52 | uint16_t Type; 53 | uint8_t StorageClass; 54 | uint8_t NumberOfAuxSymbols; 55 | 56 | } coff_sym_t; 57 | 58 | #pragma pack(pop) 59 | /* AMD64 Specific types */ 60 | #define IMAGE_REL_AMD64_ABSOLUTE 0x0000 61 | #define IMAGE_REL_AMD64_ADDR64 0x0001 62 | #define IMAGE_REL_AMD64_ADDR32 0x0002 63 | #define IMAGE_REL_AMD64_ADDR32NB 0x0003 64 | /* Most common from the looks of it, just 32-bit relative address from the byte following the relocation */ 65 | #define IMAGE_REL_AMD64_REL32 0x0004 66 | /* Second most common, 32-bit address without an image base. Not sure what that means... */ 67 | #define IMAGE_REL_AMD64_REL32_1 0x0005 68 | #define IMAGE_REL_AMD64_REL32_2 0x0006 69 | #define IMAGE_REL_AMD64_REL32_3 0x0007 70 | #define IMAGE_REL_AMD64_REL32_4 0x0008 71 | #define IMAGE_REL_AMD64_REL32_5 0x0009 72 | #define IMAGE_REL_AMD64_SECTION 0x000A 73 | #define IMAGE_REL_AMD64_SECREL 0x000B 74 | #define IMAGE_REL_AMD64_SECREL7 0x000C 75 | #define IMAGE_REL_AMD64_TOKEN 0x000D 76 | #define IMAGE_REL_AMD64_SREL32 0x000E 77 | #define IMAGE_REL_AMD64_PAIR 0x000F 78 | #define IMAGE_REL_AMD64_SSPAN32 0x0010 79 | 80 | /*i386 Relocation types */ 81 | 82 | #define IMAGE_REL_I386_ABSOLUTE 0x0000 83 | #define IMAGE_REL_I386_DIR16 0x0001 84 | #define IMAGE_REL_I386_REL16 0x0002 85 | #define IMAGE_REL_I386_DIR32 0x0006 86 | #define IMAGE_REL_I386_DIR32NB 0x0007 87 | #define IMAGE_REL_I386_SEG12 0x0009 88 | #define IMAGE_REL_I386_SECTION 0x000A 89 | #define IMAGE_REL_I386_SECREL 0x000B 90 | #define IMAGE_REL_I386_TOKEN 0x000C 91 | #define IMAGE_REL_I386_SECREL7 0x000D 92 | #define IMAGE_REL_I386_REL32 0x0014 93 | 94 | /* Section Characteristic Flags */ 95 | 96 | #define IMAGE_SCN_MEM_WRITE 0x80000000 97 | #define IMAGE_SCN_MEM_READ 0x40000000 98 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000 99 | #define IMAGE_SCN_ALIGN_16BYTES 0x00500000 100 | #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 101 | #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 102 | #define IMAGE_SCN_MEM_SHARED 0x10000000 103 | #define IMAGE_SCN_CNT_CODE 0x00000020 104 | #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 105 | #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 106 | 107 | int RunCOFF(char* functionname, unsigned char* coff_data, uint32_t filesize, unsigned char* argumentdata, int argumentSize); 108 | unsigned char* unhexlify(unsigned char* value, int *outlen); 109 | #endif 110 | -------------------------------------------------------------------------------- /src/source/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2020, COFFLoader by TrustedSec, LLC 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 8 | in the documentation and/or other materials provided with the distribution. 9 | * Neither the name of TrustedSec, LLC nor the names of its contributors may be used to endorse or promote products derived from 10 | this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 13 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 14 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 15 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 16 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 17 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | 19 | The above licensing was taken from the BSD licensing and is applied to COFFLoader as well. 20 | 21 | Note that the COFFLoader is provided as is, and is a royalty free open-source application. 22 | 23 | Feel free to modify, use, change, market, do whatever you want with it as long as you give the appropriate credit where credit 24 | is due (which means giving the authors the credit they deserve for writing it). 25 | 26 | -------------------------------------------------------------------------------- /src/source/_bof.c: -------------------------------------------------------------------------------- 1 | // Need to define these to be able to use SetDllDirectory. 2 | #define _WIN32_WINNT 0x0502 3 | #define NTDDI_VERSION 0x05020000 4 | #define PY_SSIZE_T_CLEAN 5 | #include 6 | #include "APIResolve.h" 7 | #include 8 | #include "beacon_compatibility.h" 9 | 10 | static char module_doc[] = 11 | "Loader for BOF"; 12 | char builtin_name[] = "builtins"; 13 | 14 | #include "COFFLoader.h" 15 | 16 | #ifndef STANDALONE 17 | extern wchar_t dirname[]; // executable/dll directory 18 | #endif 19 | 20 | static PyObject * 21 | run(PyObject *self, PyObject *args) 22 | { 23 | char *bofArgs; 24 | char *function; 25 | size_t size; 26 | size_t argSize; 27 | int resp; 28 | int outdataSize = 0; 29 | char* outdata = NULL; 30 | unsigned char *data; 31 | 32 | 33 | if (!PyArg_ParseTuple(args, "ss#|z#", 34 | &function, &data, &size, &bofArgs, &argSize)) 35 | return NULL; 36 | 37 | resp = RunCOFF(function, data, size, bofArgs, argSize); 38 | if (resp == 0) { 39 | outdata = BeaconGetOutputData(&outdataSize); 40 | if (outdata != NULL) { 41 | return PyUnicode_FromString(outdata); 42 | } 43 | } 44 | PyErr_WarnEx(PyExc_RuntimeError, "BOF had no return value", 1); 45 | return PyUnicode_FromString(""); 46 | } 47 | 48 | static PyObject * 49 | get_verbose_flag(PyObject *self, PyObject *args) 50 | { 51 | return PyLong_FromLong(Py_VerboseFlag); 52 | } 53 | 54 | static PyMethodDef methods[] = { 55 | { "run", run, METH_VARARGS, 56 | "Loads and runs BOF function from memory" }, 57 | { NULL, NULL }, /* Sentinel */ 58 | }; 59 | 60 | static struct PyModuleDef moduledef = { 61 | PyModuleDef_HEAD_INIT, 62 | "_bof", /* m_name */ 63 | module_doc, /* m_doc */ 64 | -1, /* m_size */ 65 | methods, /* m_methods */ 66 | NULL, /* m_reload */ 67 | NULL, /* m_traverse */ 68 | NULL, /* m_clear */ 69 | NULL, /* m_free */ 70 | }; 71 | 72 | PyMODINIT_FUNC PyInit__bof(void) 73 | { 74 | return PyModule_Create(&moduledef); 75 | }; 76 | 77 | INT APIENTRY DllMain(HMODULE hModule, 78 | DWORD ul_reason_for_call, 79 | LPVOID lpReserved 80 | ) 81 | { 82 | switch (ul_reason_for_call) 83 | { 84 | case DLL_PROCESS_ATTACH: 85 | PyGILState_STATE gstate; 86 | gstate = PyGILState_Ensure(); 87 | if (PyImport_AppendInittab("_bof", PyInit__bof) == -1) { 88 | fprintf(stderr, "Error: could not extend in-built modules table\n"); 89 | exit(1); 90 | } 91 | Py_Initialize(); 92 | PyObject *Module = PyInit__bof(); 93 | PyObject *builtin_module = PyImport_ImportModule(builtin_name); 94 | PyModule_AddObject(builtin_module, "_bof", Module); 95 | PyGILState_Release(gstate); 96 | break; 97 | case DLL_THREAD_ATTACH: 98 | case DLL_THREAD_DETACH: 99 | case DLL_PROCESS_DETACH: 100 | break; 101 | } 102 | return 1; 103 | } -------------------------------------------------------------------------------- /src/source/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Cobalt Strike 4.1. 8 | */ 9 | 10 | /* data API */ 11 | typedef struct { 12 | char * original; /* the original buffer [so we can free it] */ 13 | char * buffer; /* current pointer into our buffer */ 14 | int length; /* remaining length of data */ 15 | int size; /* total size of this buffer */ 16 | } datap; 17 | 18 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 19 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 20 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 21 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 22 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 23 | 24 | /* format API */ 25 | typedef struct { 26 | char * original; /* the original buffer [so we can free it] */ 27 | char * buffer; /* current pointer into our buffer */ 28 | int length; /* remaining length of data */ 29 | int size; /* total size of this buffer */ 30 | } formatp; 31 | 32 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 33 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 34 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 35 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 36 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 37 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 38 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 39 | 40 | /* Output Functions */ 41 | #define CALLBACK_OUTPUT 0x0 42 | #define CALLBACK_OUTPUT_OEM 0x1e 43 | #define CALLBACK_ERROR 0x0d 44 | #define CALLBACK_OUTPUT_UTF8 0x20 45 | 46 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 47 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 48 | 49 | /* Token Functions */ 50 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 51 | DECLSPEC_IMPORT void BeaconRevertToken(); 52 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 56 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 57 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 58 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 59 | 60 | /* Utility Functions */ 61 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 62 | -------------------------------------------------------------------------------- /src/source/beacon_compatibility.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Cobalt Strike 4.X BOF compatibility layer 3 | * ----------------------------------------- 4 | * The whole point of these files are to allow beacon object files built for CS 5 | * to run fine inside of other tools without recompiling. 6 | * 7 | * Built off of the beacon.h file provided to build for CS. 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "APIResolve.h" 14 | #ifdef _WIN32 15 | #include 16 | #include "beacon_compatibility.h" 17 | 18 | #define DEFAULTPROCESSNAME "rundll32.exe" 19 | #ifdef _WIN64 20 | #define X86PATH "SysWOW64" 21 | #define X64PATH "System32" 22 | #else 23 | #define X86PATH "System32" 24 | #define X64PATH "sysnative" 25 | #endif 26 | 27 | 28 | /* Data Parsing */ 29 | unsigned char* InternalFunctions[29][2] = { 30 | {(unsigned char*)"BeaconDataParse", (unsigned char*)BeaconDataParse}, 31 | {(unsigned char*)"BeaconDataInt", (unsigned char*)BeaconDataInt}, 32 | {(unsigned char*)"BeaconDataShort", (unsigned char*)BeaconDataShort}, 33 | {(unsigned char*)"BeaconDataLength", (unsigned char*)BeaconDataLength}, 34 | {(unsigned char*)"BeaconDataExtract", (unsigned char*)BeaconDataExtract}, 35 | {(unsigned char*)"BeaconFormatAlloc", (unsigned char*)BeaconFormatAlloc}, 36 | {(unsigned char*)"BeaconFormatReset", (unsigned char*)BeaconFormatReset}, 37 | {(unsigned char*)"BeaconFormatFree", (unsigned char*)BeaconFormatFree}, 38 | {(unsigned char*)"BeaconFormatAppend", (unsigned char*)BeaconFormatAppend}, 39 | {(unsigned char*)"BeaconFormatPrintf", (unsigned char*)BeaconFormatPrintf}, 40 | {(unsigned char*)"BeaconFormatToString", (unsigned char*)BeaconFormatToString}, 41 | {(unsigned char*)"BeaconFormatInt", (unsigned char*)BeaconFormatInt}, 42 | {(unsigned char*)"BeaconPrintf", (unsigned char*)BeaconPrintf}, 43 | {(unsigned char*)"BeaconOutput", (unsigned char*)BeaconOutput}, 44 | {(unsigned char*)"BeaconUseToken", (unsigned char*)BeaconUseToken}, 45 | {(unsigned char*)"BeaconRevertToken", (unsigned char*)BeaconRevertToken}, 46 | {(unsigned char*)"BeaconIsAdmin", (unsigned char*)BeaconIsAdmin}, 47 | {(unsigned char*)"BeaconGetSpawnTo", (unsigned char*)BeaconGetSpawnTo}, 48 | {(unsigned char*)"BeaconSpawnTemporaryProcess", (unsigned char*)BeaconSpawnTemporaryProcess}, 49 | {(unsigned char*)"BeaconInjectProcess", (unsigned char*)BeaconInjectProcess}, 50 | {(unsigned char*)"BeaconInjectTemporaryProcess", (unsigned char*)BeaconInjectTemporaryProcess}, 51 | {(unsigned char*)"BeaconCleanupProcess", (unsigned char*)BeaconCleanupProcess}, 52 | {(unsigned char*)"toWideChar", (unsigned char*)toWideChar}, 53 | {(unsigned char*)"LoadLibraryA", (unsigned char*)LoadLibraryA}, 54 | {(unsigned char*)"GetProcAddress", (unsigned char*)GetProcAddress}, 55 | {(unsigned char*)"GetModuleHandleA", (unsigned char*)GetModuleHandleA}, 56 | {(unsigned char*)"FreeLibrary", (unsigned char*)FreeLibrary} 57 | }; 58 | 59 | uint32_t swap_endianess(uint32_t indata) { 60 | uint32_t testint = 0xaabbccdd; 61 | uint32_t outint = indata; 62 | if (((unsigned char*)&testint)[0] == 0xdd) { 63 | ((unsigned char*)&outint)[0] = ((unsigned char*)&indata)[3]; 64 | ((unsigned char*)&outint)[1] = ((unsigned char*)&indata)[2]; 65 | ((unsigned char*)&outint)[2] = ((unsigned char*)&indata)[1]; 66 | ((unsigned char*)&outint)[3] = ((unsigned char*)&indata)[0]; 67 | } 68 | return outint; 69 | } 70 | 71 | char* beacon_compatibility_output = NULL; 72 | int beacon_compatibility_size = 0; 73 | int beacon_compatibility_offset = 0; 74 | 75 | void BeaconDataParse(datap* parser, char* buffer, int size) { 76 | if (parser == NULL) { 77 | return; 78 | } 79 | parser->original = buffer; 80 | parser->buffer = buffer; 81 | parser->length = size - 4; 82 | parser->size = size - 4; 83 | parser->buffer += 4; 84 | return; 85 | } 86 | 87 | int BeaconDataInt(datap* parser) { 88 | int32_t fourbyteint = 0; 89 | if (parser->length < 4) { 90 | return 0; 91 | } 92 | memcpy(&fourbyteint, parser->buffer, 4); 93 | parser->buffer += 4; 94 | parser->length -= 4; 95 | return (int)fourbyteint; 96 | } 97 | 98 | short BeaconDataShort(datap* parser) { 99 | int16_t retvalue = 0; 100 | if (parser->length < 2) { 101 | return 0; 102 | } 103 | memcpy(&retvalue, parser->buffer, 2); 104 | parser->buffer += 2; 105 | parser->length -= 2; 106 | return (short)retvalue; 107 | } 108 | 109 | int BeaconDataLength(datap* parser) { 110 | return parser->length; 111 | } 112 | 113 | char* BeaconDataExtract(datap* parser, int* size) { 114 | uint32_t length = 0; 115 | char* outdata = NULL; 116 | /*Length prefixed binary blob, going to assume uint32_t for this.*/ 117 | if (parser->length < 4) { 118 | return NULL; 119 | } 120 | memcpy(&length, parser->buffer, 4); 121 | parser->buffer += 4; 122 | 123 | outdata = parser->buffer; 124 | if (outdata == NULL) { 125 | return NULL; 126 | } 127 | parser->length -= 4; 128 | parser->length -= length; 129 | parser->buffer += length; 130 | if (size != NULL && outdata != NULL) { 131 | *size = length; 132 | } 133 | return outdata; 134 | } 135 | 136 | /* format API */ 137 | 138 | void BeaconFormatAlloc(formatp* format, int maxsz) { 139 | if (format == NULL) { 140 | return; 141 | } 142 | format->original = calloc(maxsz, 1); 143 | format->buffer = format->original; 144 | format->length = 0; 145 | format->size = maxsz; 146 | return; 147 | } 148 | 149 | void BeaconFormatReset(formatp* format) { 150 | memset(format->original, 0, format->size); 151 | format->buffer = format->original; 152 | format->length = format->size; 153 | return; 154 | } 155 | 156 | void BeaconFormatFree(formatp* format) { 157 | if (format == NULL) { 158 | return; 159 | } 160 | if (format->original) { 161 | free(format->original); 162 | format->original = NULL; 163 | } 164 | format->buffer = NULL; 165 | format->length = 0; 166 | format->size = 0; 167 | return; 168 | } 169 | 170 | void BeaconFormatAppend(formatp* format, char* text, int len) { 171 | memcpy(format->buffer, text, len); 172 | format->buffer += len; 173 | format->length += len; 174 | return; 175 | } 176 | 177 | void BeaconFormatPrintf(formatp* format, char* fmt, ...) { 178 | /*Take format string, and sprintf it into here*/ 179 | va_list args; 180 | int length = 0; 181 | 182 | va_start(args, fmt); 183 | length = vsnprintf(NULL, 0, fmt, args); 184 | va_end(args); 185 | if (format->length + length > format->size) { 186 | return; 187 | } 188 | 189 | va_start(args, fmt); 190 | (void)vsnprintf(format->buffer, length, fmt, args); 191 | va_end(args); 192 | format->length += length; 193 | format->buffer += length; 194 | return; 195 | } 196 | 197 | 198 | char* BeaconFormatToString(formatp* format, int* size) { 199 | *size = format->length; 200 | return format->original; 201 | } 202 | 203 | void BeaconFormatInt(formatp* format, int value) { 204 | uint32_t indata = value; 205 | uint32_t outdata = 0; 206 | if (format->length + 4 > format->size) { 207 | return; 208 | } 209 | outdata = swap_endianess(indata); 210 | memcpy(format->buffer, &outdata, 4); 211 | format->length += 4; 212 | format->buffer += 4; 213 | return; 214 | } 215 | 216 | /* Main output functions */ 217 | 218 | void BeaconPrintf(int type, char* fmt, ...) { 219 | /* Change to maintain internal buffer, and return after done running. */ 220 | int length = 0; 221 | char* tempptr = NULL; 222 | va_list args; 223 | va_start(args, fmt); 224 | vprintf(fmt, args); 225 | va_end(args); 226 | 227 | va_start(args, fmt); 228 | length = vsnprintf(NULL, 0, fmt, args); 229 | va_end(args); 230 | tempptr = realloc(beacon_compatibility_output, beacon_compatibility_size + length + 1); 231 | if (tempptr == NULL) { 232 | return; 233 | } 234 | beacon_compatibility_output = tempptr; 235 | memset(beacon_compatibility_output + beacon_compatibility_offset, 0, length + 1); 236 | va_start(args, fmt); 237 | length = vsnprintf(beacon_compatibility_output + beacon_compatibility_offset, length +1, fmt, args); 238 | beacon_compatibility_size += length; 239 | beacon_compatibility_offset += length; 240 | va_end(args); 241 | return; 242 | } 243 | 244 | void BeaconOutput(int type, char* data, int len) { 245 | char* tempptr = NULL; 246 | tempptr = realloc(beacon_compatibility_output, beacon_compatibility_size + len + 1); 247 | beacon_compatibility_output = tempptr; 248 | if (tempptr == NULL) { 249 | return; 250 | } 251 | memset(beacon_compatibility_output + beacon_compatibility_offset, 0, len + 1); 252 | memcpy(beacon_compatibility_output + beacon_compatibility_offset, data, len); 253 | beacon_compatibility_size += len; 254 | beacon_compatibility_offset += len; 255 | return; 256 | } 257 | 258 | /* Token Functions */ 259 | 260 | BOOL BeaconUseToken(HANDLE token) { 261 | // /* Probably needs to handle DuplicateTokenEx too */ 262 | // SetThreadToken(NULL, token); 263 | // return TRUE; 264 | /* Probably needs to handle DuplicateTokenEx too */ 265 | tSetThreadToken _SetThreadToken = (tSetThreadToken)getFunctionPtr(HASH_ADVAPI32, HASH_SetThreadToken); 266 | _SetThreadToken(NULL, token); 267 | return TRUE; 268 | } 269 | 270 | void BeaconRevertToken(void) { 271 | tRevertToSelf _RevertToSelf = (tRevertToSelf)getFunctionPtr(HASH_ADVAPI32, HASH_RevertToSelf); 272 | if (!_RevertToSelf()) { 273 | #ifdef DEBUG 274 | printf("RevertToSelf Failed!\n"); 275 | #endif 276 | } 277 | return; 278 | } 279 | 280 | BOOL BeaconIsAdmin(void) { 281 | /* Leaving this to be implemented by people needing it */ 282 | #ifdef DEBUG 283 | printf("BeaconIsAdmin Called\n"); 284 | #endif 285 | return FALSE; 286 | } 287 | 288 | /* Injection/spawning related stuffs 289 | * 290 | * These functions are basic place holders, and if implemented into something 291 | * real should be just calling internal functions for your tools. */ 292 | void BeaconGetSpawnTo(BOOL x86, char* buffer, int length) { 293 | char* tempBufferPath = NULL; 294 | if (buffer == NULL) { 295 | return; 296 | } 297 | if (x86) { 298 | tempBufferPath = "C:\\Windows\\"X86PATH"\\"DEFAULTPROCESSNAME; 299 | } 300 | else { 301 | tempBufferPath = "C:\\Windows\\"X64PATH"\\"DEFAULTPROCESSNAME; 302 | } 303 | 304 | if ((int)strlen(tempBufferPath) > length) { 305 | return; 306 | } 307 | memcpy(buffer, tempBufferPath, strlen(tempBufferPath)); 308 | return; 309 | } 310 | 311 | BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * sInfo, PROCESS_INFORMATION * pInfo) { 312 | BOOL bSuccess = FALSE; 313 | if (x86) { 314 | bSuccess = CreateProcessA(NULL, (char*)"C:\\Windows\\"X86PATH"\\"DEFAULTPROCESSNAME, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, sInfo, pInfo); 315 | } 316 | else { 317 | bSuccess = CreateProcessA(NULL, (char*)"C:\\Windows\\"X64PATH"\\"DEFAULTPROCESSNAME, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, sInfo, pInfo); 318 | } 319 | return bSuccess; 320 | } 321 | 322 | void BeaconInjectProcess(HANDLE hProc, int pid, char* payload, int p_len, int p_offset, char * arg, int a_len) { 323 | /* Leaving this to be implemented by people needing/wanting it */ 324 | return; 325 | } 326 | 327 | void BeaconInjectTemporaryProcess(PROCESS_INFORMATION* pInfo, char* payload, int p_len, int p_offset, char* arg, int a_len) { 328 | /* Leaving this to be implemented by people needing/wanting it */ 329 | return; 330 | } 331 | 332 | void BeaconCleanupProcess(PROCESS_INFORMATION* pInfo) { 333 | (void)CloseHandle(pInfo->hThread); 334 | (void)CloseHandle(pInfo->hProcess); 335 | return; 336 | } 337 | 338 | BOOL toWideChar(char* src, wchar_t* dst, int max) { 339 | if (max < sizeof(wchar_t)) 340 | return FALSE; 341 | return MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, src, -1, dst, max / sizeof(wchar_t)); 342 | } 343 | 344 | char* BeaconGetOutputData(int *outsize) { 345 | // char* outdata = beacon_compatibility_output; 346 | // *outsize = beacon_compatibility_size; 347 | // beacon_compatibility_output = NULL; 348 | // beacon_compatibility_size = 0; 349 | // beacon_compatibility_offset = 0; 350 | // return outdata; 351 | char* outdata = beacon_compatibility_output; 352 | if (outsize) 353 | *outsize = beacon_compatibility_size; 354 | beacon_compatibility_output = NULL; 355 | beacon_compatibility_size = 0; 356 | beacon_compatibility_offset = 0; 357 | return outdata; 358 | } 359 | 360 | #endif 361 | -------------------------------------------------------------------------------- /src/source/beacon_compatibility.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Cobalt Strike 4.X BOF compatibility layer 3 | * ----------------------------------------- 4 | * The whole point of these files are to allow beacon object files built for CS 5 | * to run fine inside of other tools without recompiling. 6 | * 7 | * Built off of the beacon.h file provided to build for CS. 8 | */ 9 | #ifndef BEACON_COMPATIBILITY_H_ 10 | /* Structures as is in beacon.h */ 11 | extern unsigned char* InternalFunctions[29][2]; 12 | typedef struct { 13 | char * original; /* the original buffer [so we can free it] */ 14 | char * buffer; /* current pointer into our buffer */ 15 | int length; /* remaining length of data */ 16 | int size; /* total size of this buffer */ 17 | } datap; 18 | 19 | typedef struct { 20 | char * original; /* the original buffer [so we can free it] */ 21 | char * buffer; /* current pointer into our buffer */ 22 | int length; /* remaining length of data */ 23 | int size; /* total size of this buffer */ 24 | } formatp; 25 | 26 | void BeaconDataParse(datap * parser, char * buffer, int size); 27 | int BeaconDataInt(datap * parser); 28 | short BeaconDataShort(datap * parser); 29 | int BeaconDataLength(datap * parser); 30 | char * BeaconDataExtract(datap * parser, int * size); 31 | 32 | void BeaconFormatAlloc(formatp * format, int maxsz); 33 | void BeaconFormatReset(formatp * format); 34 | void BeaconFormatFree(formatp * format); 35 | void BeaconFormatAppend(formatp * format, char * text, int len); 36 | void BeaconFormatPrintf(formatp * format, char * fmt, ...); 37 | char * BeaconFormatToString(formatp * format, int * size); 38 | void BeaconFormatInt(formatp * format, int value); 39 | 40 | #define CALLBACK_OUTPUT 0x0 41 | #define CALLBACK_OUTPUT_OEM 0x1e 42 | #define CALLBACK_ERROR 0x0d 43 | #define CALLBACK_OUTPUT_UTF8 0x20 44 | 45 | 46 | void BeaconPrintf(int type, char * fmt, ...); 47 | void BeaconOutput(int type, char * data, int len); 48 | 49 | /* Token Functions */ 50 | BOOL BeaconUseToken(HANDLE token); 51 | void BeaconRevertToken(); 52 | BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 56 | BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * sInfo, PROCESS_INFORMATION * pInfo); 57 | void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 58 | void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 59 | void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 60 | 61 | /* Utility Functions */ 62 | BOOL toWideChar(char * src, wchar_t * dst, int max); 63 | uint32_t swap_endianess(uint32_t indata); 64 | 65 | char* BeaconGetOutputData(int *outsize); 66 | #endif 67 | -------------------------------------------------------------------------------- /src/source/beacon_generate.py: -------------------------------------------------------------------------------- 1 | from struct import pack, calcsize 2 | import binascii 3 | import cmd 4 | 5 | class BeaconPack: 6 | def __init__(self): 7 | self.buffer = b'' 8 | self.size = 0 9 | 10 | def getbuffer(self): 11 | return pack("