1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-24 18:16:24 +01:00

add bofloader folder

This commit is contained in:
Kevin Clark 2022-08-20 13:56:55 -07:00
parent 9d11bb84b1
commit 327125a3a4
16 changed files with 1728 additions and 0 deletions

@ -0,0 +1,61 @@
name: Release
on:
push:
tags: ["v[1-9]+.[0-9]+.[0-9]+"]
branches: [main]
jobs:
dll-build:
name: Build the DLL
if: startsWith( github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: OS Packages
run: |
sudo apt-get update --fix-missing && sudo apt-get -y install \
git build-essential zlib1g zlib1g-dev wget zip unzip \
mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib jq
- name: Minisign
run: |
MINISIGN_TMP=`mktemp -d`
cd $MINISIGN_TMP
wget https://github.com/aead/minisign/releases/download/v0.2.0/minisign-linux-amd64.tar.gz
tar xvf minisign-linux-amd64.tar.gz
mv ./minisign ~/minisign
- name: Check out code
uses: actions/checkout@v2
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
- name: Build artifacts
run: |
make clean
make all-dll
mkdir artifacts
VERSION=$(git describe --tags --abbrev=0)
cat extension.json | jq ".version |= \"$VERSION\"" > ./artifacts/extension.json
cp LICENSE.txt ./artifacts/LICENSE
mv *.dll ./artifacts/
cd artifacts
tar -czvf ../coff-loader.tar.gz .
- name: Sign Package
run: |
touch ~/minisign.key && chmod 600 ~/minisign.key
echo -e "${{ secrets.MINISIGN_PRIVATE_KEY }}" > ~/minisign.key
MANIFEST=$(cat ./artifacts/extension.json | base64 -w 0)
bash -c "echo \"\" | ~/minisign -s ~/minisign.key -S -m ./coff-loader.tar.gz -t \"$MANIFEST\" -x coff-loader.minisig"
- name: "Publish Release"
uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
files: |
./coff-loader.tar.gz
./coff-loader.minisig

@ -0,0 +1,4 @@
*.exe
*.out
*.dll
.vscode

@ -0,0 +1,613 @@
/*
* COFF Loader Project
* -------------------
* This is a re-implementation of a COFF loader, with a BOF compatibility layer
* it's meant to provide functional example of loading a COFF file in memory
* and maybe be useful.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#if defined(_WIN32)
#include <windows.h>
#include "beacon_compatibility.h"
#endif
#include "COFFLoader.h"
/* Enable or disable debug output if testing or adding new relocation types */
#ifdef DEBUG
#define DEBUG_PRINT(x, ...) printf(x, ##__VA_ARGS__)
#else
#define DEBUG_PRINT(x, ...)
#endif
/* Defining symbols for the OS version, will try to define anything that is
* different between the arch versions by specifying them here. */
#if defined(__x86_64__) || defined(_WIN64)
#define PREPENDSYMBOLVALUE "__imp_"
#else
#define PREPENDSYMBOLVALUE "__imp__"
#endif
unsigned char *unhexlify(unsigned char *value, int *outlen)
{
unsigned char *retval = NULL;
char byteval[3] = {0};
int counter = 0;
int counter2 = 0;
char character = 0;
if (value == NULL)
{
return NULL;
}
DEBUG_PRINT("Unhexlify Strlen: %lu\n", (long unsigned int)strlen((char *)value));
if (value == NULL || strlen((char *)value) % 2 != 0)
{
DEBUG_PRINT("Either value is NULL, or the hexlified string isn't valid\n");
goto errcase;
}
retval = calloc(strlen((char *)value) + 1, 1);
if (retval == NULL)
{
goto errcase;
}
counter2 = 0;
for (counter = 0; counter < strlen((char *)value); counter += 2)
{
memcpy(byteval, value + counter, 2);
character = strtol(byteval, NULL, 16);
memcpy(retval + counter2, &character, 1);
counter2++;
}
*outlen = counter2;
errcase:
return retval;
}
/* Helper to just get the contents of a file, used for testing. Real
* implementations of this in an agent would use the tasking from the
* C2 server for this */
unsigned char *getContents(char *filepath, uint32_t *outsize)
{
FILE *fin = NULL;
uint32_t fsize = 0;
uint32_t readsize = 0;
unsigned char *buffer = NULL;
unsigned char *tempbuffer = NULL;
fin = fopen(filepath, "rb");
if (fin == NULL)
{
return NULL;
}
fseek(fin, 0, SEEK_END);
fsize = ftell(fin);
fseek(fin, 0, SEEK_SET);
tempbuffer = calloc(fsize, 1);
if (tempbuffer == NULL)
{
return NULL;
}
memset(tempbuffer, 0, fsize);
readsize = fread(tempbuffer, 1, fsize, fin);
fclose(fin);
buffer = calloc(readsize, 1);
if (buffer == NULL)
{
return NULL;
}
memset(buffer, 0, readsize);
memcpy(buffer, tempbuffer, readsize - 1);
free(tempbuffer);
*outsize = fsize;
return buffer;
}
/* Helper function to process a symbol string, determine what function and
* library its from, and return the right function pointer. Will need to
* implement in the loading of the beacon internal functions, or any other
* internal functions you want to have available. */
void *process_symbol(char *symbolstring)
{
void *functionaddress = NULL;
char localcopy[1024] = {0};
char *locallib = NULL;
char *localfunc = NULL;
#if defined(_WIN32)
int tempcounter = 0;
HMODULE llHandle = NULL;
#endif
memcpy(localcopy, symbolstring, strlen(symbolstring));
if (strncmp(symbolstring, PREPENDSYMBOLVALUE "Beacon", strlen(PREPENDSYMBOLVALUE "Beacon")) == 0 || strncmp(symbolstring, PREPENDSYMBOLVALUE "toWideChar", strlen(PREPENDSYMBOLVALUE "toWideChar")) == 0 ||
strncmp(symbolstring, PREPENDSYMBOLVALUE "GetProcAddress", strlen(PREPENDSYMBOLVALUE "GetProcAddress")) == 0 || strncmp(symbolstring, PREPENDSYMBOLVALUE "LoadLibraryA", strlen(PREPENDSYMBOLVALUE "LoadLibraryA")) == 0 ||
strncmp(symbolstring, PREPENDSYMBOLVALUE "GetModuleHandleA", strlen(PREPENDSYMBOLVALUE "GetModuleHandleA")) == 0 || strncmp(symbolstring, PREPENDSYMBOLVALUE "FreeLibrary", strlen(PREPENDSYMBOLVALUE "FreeLibrary")) == 0)
{
localfunc = symbolstring + strlen(PREPENDSYMBOLVALUE);
DEBUG_PRINT("\t\tInternalFunction: %s\n", localfunc);
/* TODO: Get internal symbol here and set to functionaddress, then
* return the pointer to the internal function*/
#if defined(_WIN32)
for (tempcounter = 0; tempcounter < 29; tempcounter++)
{
if (InternalFunctions[tempcounter][0] != NULL)
{
if (strcmp(localfunc, (char *)(InternalFunctions[tempcounter][0])) == 0)
{
functionaddress = (void *)InternalFunctions[tempcounter][1];
return functionaddress;
}
}
}
#endif
}
else if (strncmp(symbolstring, PREPENDSYMBOLVALUE, strlen(PREPENDSYMBOLVALUE)) == 0)
{
DEBUG_PRINT("\t\tYep its an external symbol\n");
locallib = localcopy + strlen(PREPENDSYMBOLVALUE);
locallib = strtok(locallib, "$");
localfunc = strtok(NULL, "$");
DEBUG_PRINT("\t\tLibrary: %s\n", locallib);
localfunc = strtok(localfunc, "@");
DEBUG_PRINT("\t\tFunction: %s\n", localfunc);
/* Resolve the symbols here, and set the functionpointervalue */
#if defined(_WIN32)
llHandle = LoadLibraryA(locallib);
DEBUG_PRINT("\t\tHandle: 0x%lx\n", llHandle);
functionaddress = GetProcAddress(llHandle, localfunc);
DEBUG_PRINT("\t\tProcAddress: 0x%p\n", functionaddress);
#endif
}
return functionaddress;
}
int LoadAndRun(char *argsBuffer, uint32_t bufferSize, goCallback callback)
{
#if defined(_WIN32)
// argsBuffer: functionname |coff_data | args_data
datap parser;
char *functionName;
unsigned char *coff_data = NULL;
unsigned char *arguments_data = NULL;
int filesize = 0;
int arguments_size = 0;
BeaconDataParse(&parser, argsBuffer, bufferSize);
functionName = BeaconDataExtract(&parser, NULL);
if (functionName == NULL)
{
return 1;
}
coff_data = (unsigned char *)BeaconDataExtract(&parser, &filesize);
if (coff_data == NULL)
{
return 1;
}
arguments_data = (unsigned char *)BeaconDataExtract(&parser, &arguments_size);
if (arguments_data == NULL)
{
return 1;
}
return RunCOFF(functionName, coff_data, filesize, arguments_data, arguments_size, callback);
#else
return 0;
#endif
}
// #endif
/* Just a generic runner for testing, this is pretty much just a reference
* implementation, return values will need to be checked, more relocation
* types need to be handled, and needs to have different arguments for use
* in any agent. */
int RunCOFF(char *functionname, unsigned char *coff_data, uint32_t filesize, unsigned char *argumentdata, int argumentSize, goCallback callback)
{
coff_file_header_t *coff_header_ptr = NULL;
coff_sect_t *coff_sect_ptr = NULL;
coff_reloc_t *coff_reloc_ptr = NULL;
coff_sym_t *coff_sym_ptr = NULL;
char *outdata = NULL;
int outdataSize = 0;
int retcode = 0;
int counter = 0;
int reloccount = 0;
int tempcounter = 0;
uint32_t symptr = 0;
long unsigned int old_prot = 0;
uint32_t protect = 0;
uint32_t protect_index = 0;
#ifdef _WIN32
void *funcptrlocation = NULL;
int32_t offsetvalue = 0;
#endif
char *entryfuncname = functionname;
#if defined(__x86_64__) || defined(_WIN64)
#ifdef _WIN32
uint64_t longoffsetvalue = 0;
#endif
#else
/* Set the input function name to match the 32 bit version */
entryfuncname = calloc(strlen(functionname) + 2, 1);
if (entryfuncname == NULL)
{
return 1;
}
(void)sprintf(entryfuncname, "_%s", functionname);
#endif
#ifdef _WIN32
/* NOTE: I just picked a size, look to see what is max/normal. */
char *sectionMapping[25] = {0};
#ifdef DEBUG
int sectionSize[25] = {0};
#endif
void (*foo)(char *in, unsigned long datalen);
char *functionMapping = NULL;
int functionMappingCount = 0;
#endif
if (coff_data == NULL)
{
DEBUG_PRINT("Can't execute NULL\n");
return 1;
}
coff_header_ptr = (coff_file_header_t *)coff_data;
DEBUG_PRINT("Machine 0x%X\n", coff_header_ptr->Machine);
DEBUG_PRINT("Number of sections: %d\n", coff_header_ptr->NumberOfSections);
DEBUG_PRINT("TimeDateStamp : %X\n", coff_header_ptr->TimeDateStamp);
DEBUG_PRINT("PointerToSymbolTable : 0x%X\n", coff_header_ptr->PointerToSymbolTable);
DEBUG_PRINT("NumberOfSymbols: %d\n", coff_header_ptr->NumberOfSymbols);
DEBUG_PRINT("OptionalHeaderSize: %d\n", coff_header_ptr->SizeOfOptionalHeader);
DEBUG_PRINT("Characteristics: %d\n", coff_header_ptr->Characteristics);
DEBUG_PRINT("\n");
coff_sym_ptr = (coff_sym_t *)(coff_data + coff_header_ptr->PointerToSymbolTable);
/* Handle the allocation and copying of the sections we're going to use
* for right now I'm just VirtualAlloc'ing memory, this can be changed to
* other methods, but leaving that up to the person implementing it. */
for (counter = 0; counter < coff_header_ptr->NumberOfSections; counter++)
{
coff_sect_ptr = (coff_sect_t *)(coff_data + sizeof(coff_file_header_t) + (sizeof(coff_sect_t) * counter));
DEBUG_PRINT("Name: %s\n", coff_sect_ptr->Name);
DEBUG_PRINT("VirtualSize: 0x%X\n", coff_sect_ptr->VirtualSize);
DEBUG_PRINT("VirtualAddress: 0x%X\n", coff_sect_ptr->VirtualAddress);
DEBUG_PRINT("SizeOfRawData: 0x%X\n", coff_sect_ptr->SizeOfRawData);
DEBUG_PRINT("PointerToRelocations: 0x%X\n", coff_sect_ptr->PointerToRelocations);
DEBUG_PRINT("PointerToRawData: 0x%X\n", coff_sect_ptr->PointerToRawData);
DEBUG_PRINT("NumberOfRelocations: %d\n", coff_sect_ptr->NumberOfRelocations);
/* NOTE: When changing the memory loading information of the loader,
* you'll want to use this field and the defines from the Section
* Flags table of Microsofts page, some defined in COFFLoader.h */
DEBUG_PRINT("Characteristics: %x\n", coff_sect_ptr->Characteristics);
#ifdef _WIN32
DEBUG_PRINT("Allocating 0x%x bytes\n", coff_sect_ptr->VirtualSize);
/* NOTE: Might want to allocate as PAGE_READWRITE and VirtualProtect
* before execution to either PAGE_READWRITE or PAGE_EXECUTE_READ
* depending on the Section Characteristics. Parse them all again
* before running and set the memory permissions. */
sectionMapping[counter] = VirtualAlloc(NULL, coff_sect_ptr->SizeOfRawData, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
#ifdef DEBUG
sectionSize[counter] = coff_sect_ptr->SizeOfRawData;
#endif
if (sectionMapping[counter] == NULL)
{
DEBUG_PRINT("Failed to allocate memory\n");
}
DEBUG_PRINT("Allocated section %d at %p\n", counter, sectionMapping[counter]);
memcpy(sectionMapping[counter], coff_data + coff_sect_ptr->PointerToRawData, coff_sect_ptr->SizeOfRawData);
#endif
}
/* Allocate and setup the GOT for functions, same here as above. */
#ifdef _WIN32
#ifdef _WIN64
functionMapping = VirtualAlloc(NULL, 2048, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
#else
functionMapping = VirtualAlloc(NULL, 2048, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
#endif
#endif
/* Start parsing the relocations, and *hopefully* handle them correctly. */
for (counter = 0; counter < coff_header_ptr->NumberOfSections; counter++)
{
DEBUG_PRINT("Doing Relocations of section: %d\n", counter);
coff_sect_ptr = (coff_sect_t *)(coff_data + sizeof(coff_file_header_t) + (sizeof(coff_sect_t) * counter));
coff_reloc_ptr = (coff_reloc_t *)(coff_data + coff_sect_ptr->PointerToRelocations);
for (reloccount = 0; reloccount < coff_sect_ptr->NumberOfRelocations; reloccount++)
{
DEBUG_PRINT("\tVirtualAddress: 0x%X\n", coff_reloc_ptr->VirtualAddress);
DEBUG_PRINT("\tSymbolTableIndex: 0x%X\n", coff_reloc_ptr->SymbolTableIndex);
DEBUG_PRINT("\tType: 0x%X\n", coff_reloc_ptr->Type);
if (coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].first.Name[0] != 0)
{
symptr = coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].first.value[1];
DEBUG_PRINT("\tSymPtr: 0x%X\n", symptr);
DEBUG_PRINT("\tSymName: %s\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].first.Name);
DEBUG_PRINT("\tSectionNumber: 0x%X\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber);
/* This is the code for relative offsets in other sections of the COFF file. */
#ifdef _WIN32
#ifdef _WIN64
/* Type == 1 relocation is the 64-bit VA of the relocation target */
if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_ADDR64)
{
memcpy(&longoffsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(uint64_t));
DEBUG_PRINT("\tReadin longOffsetValue : 0x%llX\n", longoffsetvalue);
longoffsetvalue = (uint64_t)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + (uint64_t)longoffsetvalue);
DEBUG_PRINT("\tModified longOffsetValue : 0x%llX Base Address: %p\n", longoffsetvalue, sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1]);
memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &longoffsetvalue, sizeof(uint64_t));
}
/* This is Type == 3 relocation code */
else if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_ADDR32NB)
{
memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t));
DEBUG_PRINT("\tReadin OffsetValue : 0x%0X\n", offsetvalue);
DEBUG_PRINT("\t\tReferenced Section: 0x%X\n", sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue);
DEBUG_PRINT("\t\tEnd of Relocation Bytes: 0x%X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4);
if (((char *)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue) - (char *)(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff)
{
DEBUG_PRINT("Relocations > 4 gigs away, exiting\n");
retcode = 1;
goto cleanup;
}
offsetvalue = ((char *)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] + offsetvalue) - (char *)(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4));
DEBUG_PRINT("\tOffsetValue : 0x%0X\n", offsetvalue);
DEBUG_PRINT("\t\tSetting 0x%X to %X\n", sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue);
memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t));
}
/* This is Type == 4 relocation code, needed to make global variables to work correctly */
else if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_REL32)
{
memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t));
DEBUG_PRINT("\t\tReadin offset value: 0x%X\n", offsetvalue);
if ((sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff)
{
DEBUG_PRINT("Relocations > 4 gigs away, exiting\n");
retcode = 1;
goto cleanup;
}
offsetvalue += (sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4));
DEBUG_PRINT("\t\tRelative address: 0x%X\n", offsetvalue);
memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t));
}
else
{
DEBUG_PRINT("No code for relocation type: %d\n", coff_reloc_ptr->Type);
}
#else
/* This is Type == IMAGE_REL_I386_DIR32 relocation code */
memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t));
DEBUG_PRINT("\tReadin OffsetValue : 0x%0X\n", offsetvalue);
offsetvalue = (uint32_t)(sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1]) + offsetvalue;
memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t));
#endif // WIN64 statement close
#endif // WIN32 statement close
}
else
{
symptr = coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].first.value[1];
DEBUG_PRINT("\tSymPtr: 0x%X\n", symptr);
DEBUG_PRINT("\tSymVal: %s\n", ((char *)(coff_sym_ptr + coff_header_ptr->NumberOfSymbols)) + symptr);
DEBUG_PRINT("\tSectionNumber: 0x%X\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber);
/* This is the code to handle functions themselves, so using a makeshift Global Offset Table for it */
#ifdef _WIN32
funcptrlocation = process_symbol(((char *)(coff_sym_ptr + coff_header_ptr->NumberOfSymbols)) + symptr);
if (funcptrlocation == NULL)
{
DEBUG_PRINT("Failed to resolve symbol\n");
retcode = 1;
goto cleanup;
}
#ifdef _WIN64
if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_REL32 && funcptrlocation != NULL)
{
/* This is Type == 4 relocation code */
DEBUG_PRINT("Doing function relocation\n");
if (((functionMapping + (functionMappingCount * 8)) - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff)
{
DEBUG_PRINT("Relocations > 4 gigs away, exiting\n");
retcode = 1;
goto cleanup;
}
memcpy(functionMapping + (functionMappingCount * 8), &funcptrlocation, sizeof(uint64_t));
offsetvalue = (int32_t)((functionMapping + (functionMappingCount * 8)) - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4));
DEBUG_PRINT("\t\tRelative address : 0x%x\n", offsetvalue);
memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t));
functionMappingCount++;
}
else if (coff_reloc_ptr->Type == IMAGE_REL_AMD64_REL32)
{
/* This shouldn't be needed here, but incase there's a defined symbol
* that somehow doesn't have a function, try to resolve it here.*/
memcpy(&offsetvalue, sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, sizeof(int32_t));
if ((sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4)) > 0xffffffff)
{
DEBUG_PRINT("Relocations > 4 gigs away, exiting\n");
retcode = 1;
goto cleanup;
}
DEBUG_PRINT("\t\tReadin offset value: 0x%X\n", offsetvalue);
offsetvalue += (sectionMapping[coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber - 1] - (sectionMapping[counter] + coff_reloc_ptr->VirtualAddress + 4));
DEBUG_PRINT("\t\tRelative address: 0x%X\n", offsetvalue);
memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t));
}
else
{
DEBUG_PRINT("No code for relocation type: %d\n", coff_reloc_ptr->Type);
}
#else
/* This is Type == IMAGE_REL_I386_DIR32 relocation code */
memcpy(functionMapping + (functionMappingCount * 4), &funcptrlocation, sizeof(uint32_t));
offsetvalue = (int32_t)(functionMapping + (functionMappingCount * 4));
memcpy(sectionMapping[counter] + coff_reloc_ptr->VirtualAddress, &offsetvalue, sizeof(uint32_t));
functionMappingCount++;
#endif
#endif
}
DEBUG_PRINT("\tValueNumber: 0x%X\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].Value);
DEBUG_PRINT("\tSectionNumber: 0x%X\n", coff_sym_ptr[coff_reloc_ptr->SymbolTableIndex].SectionNumber);
coff_reloc_ptr = (coff_reloc_t *)(((char *)coff_reloc_ptr) + sizeof(coff_reloc_t));
DEBUG_PRINT("\n");
}
DEBUG_PRINT("\n");
}
/* Some debugging code to see what the sections look like in memory */
#if DEBUG
#ifdef _WIN32
for (tempcounter = 0; tempcounter < 10; tempcounter++)
{
DEBUG_PRINT("Section: %d\n", tempcounter);
if (sectionMapping[tempcounter] != NULL)
{
DEBUG_PRINT("\t");
for (counter = 0; counter < sectionSize[tempcounter]; counter++)
{
DEBUG_PRINT("%02X ", (uint8_t)(sectionMapping[tempcounter][counter]));
}
DEBUG_PRINT("\n");
}
}
#endif
#endif
// Apply proper page permissions
for (counter = 0; counter < coff_header_ptr->NumberOfSections; counter++)
{
coff_sect_ptr = (coff_sect_t *)(coff_data + sizeof(coff_file_header_t) + (sizeof(coff_sect_t) * counter));
if (coff_sect_ptr->SizeOfRawData > 0)
{
protect_index = coff_sect_ptr->Characteristics >> 29;
protect = ProtectionFlags[protect_index];
DEBUG_PRINT("New page prot flag: 0x%08x\n", protect);
if ((coff_sect_ptr->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0)
{
protect |= PAGE_NOCACHE;
}
if (VirtualProtect(sectionMapping[counter], coff_sect_ptr->SizeOfRawData, protect, &old_prot) == 0)
{
#if DEBUG
DWORD error = GetLastError();
DEBUG_PRINT("Could not change page protection: %08x\n", error);
#endif
return 1;
}
}
}
if (VirtualProtect(functionMapping, 2048, PAGE_EXECUTE_READ, &old_prot) == 0)
{
#if DEBUG
DWORD error = GetLastError();
DEBUG_PRINT("Could not change page protection on functionMapping: %08x\n", error);
#endif
return 1;
}
DEBUG_PRINT("Symbols:\n");
for (tempcounter = 0; tempcounter < coff_header_ptr->NumberOfSymbols; tempcounter++)
{
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);
if (strcmp(coff_sym_ptr[tempcounter].first.Name, entryfuncname) == 0)
{
DEBUG_PRINT("\t\tFound entry!\n");
#ifdef _WIN32
/* So for some reason VS 2017 doesn't like this, but char* casting works, so just going to do that */
#ifdef _MSC_VER
foo = (char *)(sectionMapping[coff_sym_ptr[tempcounter].SectionNumber - 1] + coff_sym_ptr[tempcounter].Value);
#else
foo = (void (*)(char *, unsigned long))(sectionMapping[coff_sym_ptr[tempcounter].SectionNumber - 1] + coff_sym_ptr[tempcounter].Value);
#endif
// sectionMapping[coff_sym_ptr[tempcounter].SectionNumber-1][coff_sym_ptr[tempcounter].Value+7] = '\xcc';
DEBUG_PRINT("Trying to run: %p\n", foo);
foo((char *)argumentdata, argumentSize);
#endif
}
}
DEBUG_PRINT("Back\n");
/* Cleanup the allocated memory */
#ifdef _WIN32
if (callback != NULL)
{
outdata = BeaconGetOutputData(&outdataSize);
if (outdata != NULL)
{
DEBUG_PRINT("[COFFLoader] Calling Go callback at %p\n", callback);
(*callback)(outdata, outdataSize);
}
}
cleanup:
for (tempcounter = 0; tempcounter < 25; tempcounter++)
{
if (sectionMapping[tempcounter])
{
VirtualFree(sectionMapping[tempcounter], 0, MEM_RELEASE);
}
}
VirtualFree(functionMapping, 0, MEM_RELEASE);
#endif
DEBUG_PRINT("Returning\n");
return retcode;
}
#ifdef COFF_STANDALONE
int main(int argc, char *argv[])
{
char *coff_data = NULL;
unsigned char *arguments = NULL;
int argumentSize = 0;
#ifdef _WIN32
char *outdata = NULL;
int outdataSize = 0;
#endif
uint32_t filesize = 0;
int checkcode = 0;
if (argc < 3)
{
printf("ERROR: %s go /path/to/object/file.o (arguments)\n", argv[0]);
return 1;
}
coff_data = (char *)getContents(argv[2], &filesize);
if (coff_data == NULL)
{
printf("ERROR: empty bof file\n");
return 1;
}
printf("Got contents of COFF file\n");
arguments = unhexlify((unsigned char *)argv[3], &argumentSize);
printf("Running/Parsing the COFF file\n");
checkcode = RunCOFF(argv[1], (unsigned char *)coff_data, filesize, arguments, argumentSize, NULL);
if (checkcode == 0)
{
#ifdef _WIN32
printf("Ran/parsed the coff\n");
outdata = BeaconGetOutputData(&outdataSize);
if (outdata != NULL)
{
printf("Outdata Below:\n\n%s\n", outdata);
}
#endif
}
else
{
printf("Failed to run/parse the COFF file\n");
}
if (coff_data)
{
free(coff_data);
}
return 0;
}
#endif

@ -0,0 +1,135 @@
#ifndef COFFLOADER_H_
#define COFFLOADER_H_
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
/* These seem to be the same sizes across architectures, relocations are different though. Defined both sets of types. */
/* sizeof 20 */
typedef struct coff_file_header
{
uint16_t Machine;
uint16_t NumberOfSections;
uint32_t TimeDateStamp;
uint32_t PointerToSymbolTable;
uint32_t NumberOfSymbols;
uint16_t SizeOfOptionalHeader;
uint16_t Characteristics;
} coff_file_header_t;
/* AMD64 should always be here */
#define MACHINETYPE_AMD64 0x8664
#pragma pack(push, 1)
/* Size of 40 */
typedef struct coff_sect
{
char Name[8];
uint32_t VirtualSize;
uint32_t VirtualAddress;
uint32_t SizeOfRawData;
uint32_t PointerToRawData;
uint32_t PointerToRelocations;
uint32_t PointerToLineNumbers;
uint16_t NumberOfRelocations;
uint16_t NumberOfLinenumbers;
uint32_t Characteristics;
} coff_sect_t;
typedef struct coff_reloc
{
uint32_t VirtualAddress;
uint32_t SymbolTableIndex;
uint16_t Type;
} coff_reloc_t;
typedef struct coff_sym
{
union
{
char Name[8];
uint32_t value[2];
} first;
uint32_t Value;
uint16_t SectionNumber;
uint16_t Type;
uint8_t StorageClass;
uint8_t NumberOfAuxSymbols;
} coff_sym_t;
uint32_t ProtectionFlags[8] = {
PAGE_NOACCESS, // not writeable, not readable, not executable
PAGE_EXECUTE, // not writeable, not readable, executable
PAGE_READONLY, // not writeable, readable, not executable
PAGE_EXECUTE_READ, // not writeable, readable, executable
PAGE_WRITECOPY, // writeable, not readable, not executable
PAGE_EXECUTE_WRITECOPY, // writeable, not readable, executable
PAGE_READWRITE, // writeable, readable, not executable
PAGE_EXECUTE_READWRITE, // writeable, readable, executable
};
#pragma pack(pop)
/* AMD64 Specific types */
#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
#define IMAGE_REL_AMD64_ADDR64 0x0001
#define IMAGE_REL_AMD64_ADDR32 0x0002
#define IMAGE_REL_AMD64_ADDR32NB 0x0003
/* Most common from the looks of it, just 32-bit relative address from the byte following the relocation */
#define IMAGE_REL_AMD64_REL32 0x0004
/* Second most common, 32-bit address without an image base. Not sure what that means... */
#define IMAGE_REL_AMD64_REL32_1 0x0005
#define IMAGE_REL_AMD64_REL32_2 0x0006
#define IMAGE_REL_AMD64_REL32_3 0x0007
#define IMAGE_REL_AMD64_REL32_4 0x0008
#define IMAGE_REL_AMD64_REL32_5 0x0009
#define IMAGE_REL_AMD64_SECTION 0x000A
#define IMAGE_REL_AMD64_SECREL 0x000B
#define IMAGE_REL_AMD64_SECREL7 0x000C
#define IMAGE_REL_AMD64_TOKEN 0x000D
#define IMAGE_REL_AMD64_SREL32 0x000E
#define IMAGE_REL_AMD64_PAIR 0x000F
#define IMAGE_REL_AMD64_SSPAN32 0x0010
/*i386 Relocation types */
#define IMAGE_REL_I386_ABSOLUTE 0x0000
#define IMAGE_REL_I386_DIR16 0x0001
#define IMAGE_REL_I386_REL16 0x0002
#define IMAGE_REL_I386_DIR32 0x0006
#define IMAGE_REL_I386_DIR32NB 0x0007
#define IMAGE_REL_I386_SEG12 0x0009
#define IMAGE_REL_I386_SECTION 0x000A
#define IMAGE_REL_I386_SECREL 0x000B
#define IMAGE_REL_I386_TOKEN 0x000C
#define IMAGE_REL_I386_SECREL7 0x000D
#define IMAGE_REL_I386_REL32 0x0014
/* Section Characteristic Flags */
#define IMAGE_SCN_MEM_WRITE 0x80000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
#define IMAGE_SCN_MEM_SHARED 0x10000000
#define IMAGE_SCN_CNT_CODE 0x00000020
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
unsigned char *unhexlify(unsigned char *value, int *outlen);
typedef int (*goCallback)(char *, int);
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
EXPORT int __cdecl LoadAndRun(char *argsBuffer, uint32_t bufferSize, goCallback callback);
#else
/* EXE import */
#define EXPORT __declspec(dllimport)
#endif
int RunCOFF(char *functionname, unsigned char *coff_data, uint32_t filesize, unsigned char *argumentdata, int argumentSize, goCallback data);
#endif

@ -0,0 +1,25 @@
Copyright 2020, COFFLoader by TrustedSec, LLC
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
* Neither the name of TrustedSec, LLC nor the names of its contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The above licensing was taken from the BSD licensing and is applied to COFFLoader as well.
Note that the COFFLoader is provided as is, and is a royalty free open-source application.
Feel free to modify, use, change, market, do whatever you want with it as long as you give the appropriate credit where credit
is due (which means giving the authors the credit they deserve for writing it).

@ -0,0 +1,36 @@
all: bof bof32
all-dll: dll dll32
debug: debug32 debug64
dll:
x86_64-w64-mingw32-gcc -shared -Wall -DBUILD_DLL dll.c beacon_compatibility.c COFFLoader.c -o COFFLoader.x64.dll
x86_64-w64-mingw32-gcc -c test.c -o test64.out
dll32:
i686-w64-mingw32-gcc -shared -Wall -DBUILD_DLL dll.c beacon_compatibility.c COFFLoader.c -o COFFLoader.x86.dll
i686-w64-mingw32-gcc -c test.c -o test32.out
bof:
x86_64-w64-mingw32-gcc -Wall -DCOFF_STANDALONE beacon_compatibility.c COFFLoader.c -o COFFLoader64.exe
x86_64-w64-mingw32-gcc -c test.c -o test64.out
bof32:
i686-w64-mingw32-gcc -Wall -DCOFF_STANDALONE beacon_compatibility.c COFFLoader.c -o COFFLoader32.exe
i686-w64-mingw32-gcc -c test.c -o test32.out
debug64:
x86_64-w64-mingw32-gcc -DCOFF_STANDALONE -DDEBUG beacon_compatibility.c COFFLoader.c -o COFFLoader64.exe
x86_64-w64-mingw32-gcc -c test.c -o test64.out
debug32:
i686-w64-mingw32-gcc -DCOFF_STANDALONE -DDEBUG beacon_compatibility.c COFFLoader.c -o COFFLoader32.exe
i686-w64-mingw32-gcc -c test.c -o test32.out
nix:
gcc -DCOFF_STANDALONE -Wall -DDEBUG beacon_compatibility.c COFFLoader.c -o COFFLoader.out
clean:
rm -f COFFLoader64.exe COFFLoader32.exe COFFLoader.out
rm -f test32.out test64.out
rm -f *.dll

@ -0,0 +1,47 @@
# COFF Loader
This is a quick and dirty COFF loader (AKA Beacon Object Files). Currently can run un-modified BOF's so it can be used for testing without a CS agent running it. The only exception is that the injection related beacon compatibility functions are just empty.
The main goal is to provide a working example and maybe be useful to someone.
## Parts
There are a few parts to it they are listed below.
- beacon_compatibility: This is the beacon internal functions so that you can load BOF files and run them.
- COFFLoader: This is the actual coff loader, and when built for nix just loads the 64 bit object file and parses it.
- test: This is the example "COFF" file, will build to the COFF file for you when make is called.
- beacon_generate: This is a helper script to build strings/arguments compatible with the beacon_compatibility functions.
## Beacon Generate
This is used to generate arguments for the COFFLoader code, if the BOF takes arguments simply add the arguments with the type expected with this and generate the hex string for use.
Example usage here:
```
COFFLoader % python3 beacon_generate.py
Beacon Argument Generator
Beacon>help
Documented commands (type help <topic>):
========================================
addString addWString addint addshort exit generate help reset
Beacon>addWString test
Beacon>addint 4
Beacon>generate
b'120000000a0000007400650073007400000004000000'
Beacon>reset
Beacon>addint 5
Beacon>generate
b'0400000005000000'
Beacon>exit
```
## Running
An example of how to run a BOF is below.
```
COFFLoader64.exe go test64.out
COFFLoader64.exe go ..\CS-Situational-Awareness-BOF\SA\whoami\whoami.x64.o
```

@ -0,0 +1,61 @@
/*
* Beacon Object Files (BOF)
* -------------------------
* A Beacon Object File is a light-weight post exploitation tool that runs
* with Beacon's inline-execute command.
*
* Cobalt Strike 4.1.
*/
/* data API */
typedef struct {
char * original; /* the original buffer [so we can free it] */
char * buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} datap;
DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size);
DECLSPEC_IMPORT int BeaconDataInt(datap * parser);
DECLSPEC_IMPORT short BeaconDataShort(datap * parser);
DECLSPEC_IMPORT int BeaconDataLength(datap * parser);
DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size);
/* format API */
typedef struct {
char * original; /* the original buffer [so we can free it] */
char * buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} formatp;
DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz);
DECLSPEC_IMPORT void BeaconFormatReset(formatp * format);
DECLSPEC_IMPORT void BeaconFormatFree(formatp * format);
DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len);
DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...);
DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size);
DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value);
/* Output Functions */
#define CALLBACK_OUTPUT 0x0
#define CALLBACK_OUTPUT_OEM 0x1e
#define CALLBACK_ERROR 0x0d
#define CALLBACK_OUTPUT_UTF8 0x20
DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...);
DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len);
/* Token Functions */
DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token);
DECLSPEC_IMPORT void BeaconRevertToken();
DECLSPEC_IMPORT BOOL BeaconIsAdmin();
/* Spawn+Inject Functions */
DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
/* Utility Functions */
DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max);

@ -0,0 +1,351 @@
/*
* Cobalt Strike 4.X BOF compatibility layer
* -----------------------------------------
* The whole point of these files are to allow beacon object files built for CS
* to run fine inside of other tools without recompiling.
*
* Built off of the beacon.h file provided to build for CS.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#ifdef _WIN32
#include <windows.h>
#include "beacon_compatibility.h"
#define DEFAULTPROCESSNAME "rundll32.exe"
#ifdef _WIN64
#define X86PATH "SysWOW64"
#define X64PATH "System32"
#else
#define X86PATH "System32"
#define X64PATH "sysnative"
#endif
/* Data Parsing */
unsigned char* InternalFunctions[29][2] = {
{(unsigned char*)"BeaconDataParse", (unsigned char*)BeaconDataParse},
{(unsigned char*)"BeaconDataInt", (unsigned char*)BeaconDataInt},
{(unsigned char*)"BeaconDataShort", (unsigned char*)BeaconDataShort},
{(unsigned char*)"BeaconDataLength", (unsigned char*)BeaconDataLength},
{(unsigned char*)"BeaconDataExtract", (unsigned char*)BeaconDataExtract},
{(unsigned char*)"BeaconFormatAlloc", (unsigned char*)BeaconFormatAlloc},
{(unsigned char*)"BeaconFormatReset", (unsigned char*)BeaconFormatReset},
{(unsigned char*)"BeaconFormatFree", (unsigned char*)BeaconFormatFree},
{(unsigned char*)"BeaconFormatAppend", (unsigned char*)BeaconFormatAppend},
{(unsigned char*)"BeaconFormatPrintf", (unsigned char*)BeaconFormatPrintf},
{(unsigned char*)"BeaconFormatToString", (unsigned char*)BeaconFormatToString},
{(unsigned char*)"BeaconFormatInt", (unsigned char*)BeaconFormatInt},
{(unsigned char*)"BeaconPrintf", (unsigned char*)BeaconPrintf},
{(unsigned char*)"BeaconOutput", (unsigned char*)BeaconOutput},
{(unsigned char*)"BeaconUseToken", (unsigned char*)BeaconUseToken},
{(unsigned char*)"BeaconRevertToken", (unsigned char*)BeaconRevertToken},
{(unsigned char*)"BeaconIsAdmin", (unsigned char*)BeaconIsAdmin},
{(unsigned char*)"BeaconGetSpawnTo", (unsigned char*)BeaconGetSpawnTo},
{(unsigned char*)"BeaconSpawnTemporaryProcess", (unsigned char*)BeaconSpawnTemporaryProcess},
{(unsigned char*)"BeaconInjectProcess", (unsigned char*)BeaconInjectProcess},
{(unsigned char*)"BeaconInjectTemporaryProcess", (unsigned char*)BeaconInjectTemporaryProcess},
{(unsigned char*)"BeaconCleanupProcess", (unsigned char*)BeaconCleanupProcess},
{(unsigned char*)"toWideChar", (unsigned char*)toWideChar},
{(unsigned char*)"LoadLibraryA", (unsigned char*)LoadLibraryA},
{(unsigned char*)"GetProcAddress", (unsigned char*)GetProcAddress},
{(unsigned char*)"GetModuleHandleA", (unsigned char*)GetModuleHandleA},
{(unsigned char*)"FreeLibrary", (unsigned char*)FreeLibrary}
};
uint32_t swap_endianess(uint32_t indata) {
uint32_t testint = 0xaabbccdd;
uint32_t outint = indata;
if (((unsigned char*)&testint)[0] == 0xdd) {
((unsigned char*)&outint)[0] = ((unsigned char*)&indata)[3];
((unsigned char*)&outint)[1] = ((unsigned char*)&indata)[2];
((unsigned char*)&outint)[2] = ((unsigned char*)&indata)[1];
((unsigned char*)&outint)[3] = ((unsigned char*)&indata)[0];
}
return outint;
}
char* beacon_compatibility_output = NULL;
int beacon_compatibility_size = 0;
int beacon_compatibility_offset = 0;
void BeaconDataParse(datap* parser, char* buffer, int size) {
if (parser == NULL) {
return;
}
parser->original = buffer;
parser->buffer = buffer;
parser->length = size - 4;
parser->size = size - 4;
parser->buffer += 4;
return;
}
int BeaconDataInt(datap* parser) {
int32_t fourbyteint = 0;
if (parser->length < 4) {
return 0;
}
memcpy(&fourbyteint, parser->buffer, 4);
parser->buffer += 4;
parser->length -= 4;
return (int)fourbyteint;
}
short BeaconDataShort(datap* parser) {
int16_t retvalue = 0;
if (parser->length < 2) {
return 0;
}
memcpy(&retvalue, parser->buffer, 2);
parser->buffer += 2;
parser->length -= 2;
return (short)retvalue;
}
int BeaconDataLength(datap* parser) {
return parser->length;
}
char* BeaconDataExtract(datap* parser, int* size) {
uint32_t length = 0;
char* outdata = NULL;
/*Length prefixed binary blob, going to assume uint32_t for this.*/
if (parser->length < 4) {
return NULL;
}
memcpy(&length, parser->buffer, 4);
parser->buffer += 4;
outdata = parser->buffer;
if (outdata == NULL) {
return NULL;
}
parser->length -= 4;
parser->length -= length;
parser->buffer += length;
if (size != NULL && outdata != NULL) {
*size = length;
}
return outdata;
}
/* format API */
void BeaconFormatAlloc(formatp* format, int maxsz) {
if (format == NULL) {
return;
}
format->original = calloc(maxsz, 1);
format->buffer = format->original;
format->length = 0;
format->size = maxsz;
return;
}
void BeaconFormatReset(formatp* format) {
memset(format->original, 0, format->size);
format->buffer = format->original;
format->length = format->size;
return;
}
void BeaconFormatFree(formatp* format) {
if (format == NULL) {
return;
}
if (format->original) {
free(format->original);
format->original = NULL;
}
format->buffer = NULL;
format->length = 0;
format->size = 0;
return;
}
void BeaconFormatAppend(formatp* format, char* text, int len) {
memcpy(format->buffer, text, len);
format->buffer += len;
format->length += len;
return;
}
void BeaconFormatPrintf(formatp* format, char* fmt, ...) {
/*Take format string, and sprintf it into here*/
va_list args;
int length = 0;
va_start(args, fmt);
length = vsnprintf(NULL, 0, fmt, args);
va_end(args);
if (format->length + length > format->size) {
return;
}
va_start(args, fmt);
(void)vsnprintf(format->buffer, length, fmt, args);
va_end(args);
format->length += length;
format->buffer += length;
return;
}
char* BeaconFormatToString(formatp* format, int* size) {
*size = format->length;
return format->original;
}
void BeaconFormatInt(formatp* format, int value) {
uint32_t indata = value;
uint32_t outdata = 0;
if (format->length + 4 > format->size) {
return;
}
outdata = swap_endianess(indata);
memcpy(format->buffer, &outdata, 4);
format->length += 4;
format->buffer += 4;
return;
}
/* Main output functions */
void BeaconPrintf(int type, char* fmt, ...) {
/* Change to maintain internal buffer, and return after done running. */
int length = 0;
char* tempptr = NULL;
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
va_start(args, fmt);
length = vsnprintf(NULL, 0, fmt, args);
va_end(args);
tempptr = realloc(beacon_compatibility_output, beacon_compatibility_size + length + 1);
if (tempptr == NULL) {
return;
}
beacon_compatibility_output = tempptr;
memset(beacon_compatibility_output + beacon_compatibility_offset, 0, length + 1);
va_start(args, fmt);
length = vsnprintf(beacon_compatibility_output + beacon_compatibility_offset, length +1, fmt, args);
beacon_compatibility_size += length;
beacon_compatibility_offset += length;
va_end(args);
return;
}
void BeaconOutput(int type, char* data, int len) {
char* tempptr = NULL;
tempptr = realloc(beacon_compatibility_output, beacon_compatibility_size + len + 1);
beacon_compatibility_output = tempptr;
if (tempptr == NULL) {
return;
}
memset(beacon_compatibility_output + beacon_compatibility_offset, 0, len + 1);
memcpy(beacon_compatibility_output + beacon_compatibility_offset, data, len);
beacon_compatibility_size += len;
beacon_compatibility_offset += len;
return;
}
/* Token Functions */
BOOL BeaconUseToken(HANDLE token) {
/* Probably needs to handle DuplicateTokenEx too */
SetThreadToken(NULL, token);
return TRUE;
}
void BeaconRevertToken(void) {
if (!RevertToSelf()) {
#ifdef DEBUG
printf("RevertToSelf Failed!\n");
#endif
}
return;
}
BOOL BeaconIsAdmin(void) {
/* Leaving this to be implemented by people needing it */
#ifdef DEBUG
printf("BeaconIsAdmin Called\n");
#endif
return FALSE;
}
/* Injection/spawning related stuffs
*
* These functions are basic place holders, and if implemented into something
* real should be just calling internal functions for your tools. */
void BeaconGetSpawnTo(BOOL x86, char* buffer, int length) {
char* tempBufferPath = NULL;
if (buffer == NULL) {
return;
}
if (x86) {
tempBufferPath = "C:\\Windows\\"X86PATH"\\"DEFAULTPROCESSNAME;
if (strlen(tempBufferPath) > length) {
return;
}
memcpy(buffer, tempBufferPath, strlen(tempBufferPath));
}
else {
tempBufferPath = "C:\\Windows\\"X64PATH"\\"DEFAULTPROCESSNAME;
if (strlen(tempBufferPath) > length) {
return;
}
memcpy(buffer, tempBufferPath, strlen(tempBufferPath));
}
return;
}
BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * sInfo, PROCESS_INFORMATION * pInfo) {
BOOL bSuccess = FALSE;
if (x86) {
bSuccess = CreateProcessA(NULL, (char*)"C:\\Windows\\"X86PATH"\\"DEFAULTPROCESSNAME, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, sInfo, pInfo);
}
else {
bSuccess = CreateProcessA(NULL, (char*)"C:\\Windows\\"X64PATH"\\"DEFAULTPROCESSNAME, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, sInfo, pInfo);
}
return bSuccess;
}
void BeaconInjectProcess(HANDLE hProc, int pid, char* payload, int p_len, int p_offset, char * arg, int a_len) {
/* Leaving this to be implemented by people needing/wanting it */
return;
}
void BeaconInjectTemporaryProcess(PROCESS_INFORMATION* pInfo, char* payload, int p_len, int p_offset, char* arg, int a_len) {
/* Leaving this to be implemented by people needing/wanting it */
return;
}
void BeaconCleanupProcess(PROCESS_INFORMATION* pInfo) {
(void)CloseHandle(pInfo->hThread);
(void)CloseHandle(pInfo->hProcess);
return;
}
BOOL toWideChar(char* src, wchar_t* dst, int max) {
/* Leaving this to be implemented by people needing/wanting it */
return FALSE;
}
char* BeaconGetOutputData(int *outsize) {
char* outdata = beacon_compatibility_output;
*outsize = beacon_compatibility_size;
beacon_compatibility_output = NULL;
beacon_compatibility_size = 0;
beacon_compatibility_offset = 0;
return outdata;
}
#endif

@ -0,0 +1,66 @@
/*
* Cobalt Strike 4.X BOF compatibility layer
* -----------------------------------------
* The whole point of these files are to allow beacon object files built for CS
* to run fine inside of other tools without recompiling.
*
* Built off of the beacon.h file provided to build for CS.
*/
#ifndef BEACON_COMPATIBILITY_H_
/* Structures as is in beacon.h */
extern unsigned char* InternalFunctions[29][2];
typedef struct {
char * original; /* the original buffer [so we can free it] */
char * buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} datap;
typedef struct {
char * original; /* the original buffer [so we can free it] */
char * buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} formatp;
void BeaconDataParse(datap * parser, char * buffer, int size);
int BeaconDataInt(datap * parser);
short BeaconDataShort(datap * parser);
int BeaconDataLength(datap * parser);
char * BeaconDataExtract(datap * parser, int * size);
void BeaconFormatAlloc(formatp * format, int maxsz);
void BeaconFormatReset(formatp * format);
void BeaconFormatFree(formatp * format);
void BeaconFormatAppend(formatp * format, char * text, int len);
void BeaconFormatPrintf(formatp * format, char * fmt, ...);
char * BeaconFormatToString(formatp * format, int * size);
void BeaconFormatInt(formatp * format, int value);
#define CALLBACK_OUTPUT 0x0
#define CALLBACK_OUTPUT_OEM 0x1e
#define CALLBACK_ERROR 0x0d
#define CALLBACK_OUTPUT_UTF8 0x20
void BeaconPrintf(int type, char * fmt, ...);
void BeaconOutput(int type, char * data, int len);
/* Token Functions */
BOOL BeaconUseToken(HANDLE token);
void BeaconRevertToken();
BOOL BeaconIsAdmin();
/* Spawn+Inject Functions */
void BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * sInfo, PROCESS_INFORMATION * pInfo);
void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
/* Utility Functions */
BOOL toWideChar(char * src, wchar_t * dst, int max);
uint32_t swap_endianess(uint32_t indata);
char* BeaconGetOutputData(int *outsize);
#endif

@ -0,0 +1,96 @@
from struct import pack, calcsize
import binascii
import cmd
class BeaconPack:
def __init__(self):
self.buffer = b''
self.size = 0
def getbuffer(self):
return pack("<L", self.size) + self.buffer
def addshort(self, short):
self.buffer += pack("<h", short)
self.size += 2
def addint(self, dint):
self.buffer += pack("<i", dint)
self.size += 4
def addstr(self, s):
if isinstance(s, str):
s = s.encode("utf-8")
fmt = "<L{}s".format(len(s) + 1)
self.buffer += pack(fmt, len(s)+1, s)
self.size += calcsize(fmt)
def addWstr(self, s):
if isinstance(s, str):
s = s.encode("utf-16_le")
fmt = "<L{}s".format(len(s) + 2)
self.buffer += pack(fmt, len(s)+2, s)
self.size += calcsize(fmt)
class MainLoop(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
self.BeaconPack = BeaconPack()
self.intro = "Beacon Argument Generator"
self.prompt = "Beacon>"
def do_addWString(self, text):
'''addWString String here
Append the wide string to the text.
'''
self.BeaconPack.addWstr(text)
def do_addString(self, text):
'''addString string here
Append the utf-8 string here.
'''
self.BeaconPack.addstr(text)
def do_generate(self, text):
'''generate
Generate the buffer for the BOF arguments
'''
outbuffer = self.BeaconPack.getbuffer()
print(binascii.hexlify(outbuffer))
def do_addint(self, text):
'''addint integer
Add an int32_t to the buffer
'''
try:
converted = int(text)
self.BeaconPack.addint(converted)
except:
print("Failed to convert to int\n");
def do_addshort(self, text):
'''addshort integer
Add an uint16_t to the buffer
'''
try:
converted = int(text)
self.BeaconPack.addshort(converted)
except:
print("Failed to convert to short\n");
def do_reset(self, text):
'''reset
Reset the buffer here.
'''
self.BeaconPack.buffer = b''
self.BeaconPack.size = 0
def do_exit(self, text):
'''exit
Exit the console
'''
return True
if __name__ == "__main__":
cmdloop = MainLoop()
cmdloop.cmdloop()

@ -0,0 +1,30 @@
#include <stdio.h>
#include <windows.h>
//extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID LPV) {
//This one was only necessary if you were using a C++ compiler
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// Code to run when the DLL is loaded
break;
case DLL_PROCESS_DETACH:
// Code to run when the DLL is freed
break;
case DLL_THREAD_ATTACH:
// Code to run when a thread is created during the DLL's lifetime
break;
case DLL_THREAD_DETACH:
// Code to run when a thread ends normally.
break;
}
return TRUE;
}

@ -0,0 +1,22 @@
{
"name": "COFF Loader",
"command_name": "coff-loader",
"version": "0.0.0",
"extension_author": "lesnuages",
"original_author": "TrustedSec",
"repo_url": "https://github.com/sliverarmory/COFFLoader",
"help": "Load and execute Beacon Object Files (BOFs) in memory.",
"entrypoint": "LoadAndRun",
"files": [
{
"os": "windows",
"arch": "386",
"path": "COFFLoader.x86.dll"
},
{
"os": "windows",
"arch": "amd64",
"path": "COFFLoader.x64.dll"
}
]
}

@ -0,0 +1,44 @@
#include <windows.h>
#include <stdio.h>
#include <lm.h>
#include <dsgetdc.h>
#include "beacon.h"
DECLSPEC_IMPORT DWORD WINAPI NETAPI32$DsGetDcNameA(LPVOID, LPVOID, LPVOID, LPVOID, ULONG, LPVOID);
DECLSPEC_IMPORT DWORD WINAPI NETAPI32$NetApiBufferFree(LPVOID);
WINBASEAPI int __cdecl MSVCRT$printf(const char * __restrict__ _Format,...);
char* TestGlobalString = "This is a global string";
/* Can't do stuff like "int testvalue;" in a coff file, because it assumes that
* the symbol is like any function, so you would need to allocate a section of bss
* (without knowing the size of it), and then resolve the symbol to that. So safer
* to just not support that */
int testvalue = 0;
int test(void){
MSVCRT$printf("Test String from test\n");
testvalue = 1;
return 0;
}
int test2(void){
MSVCRT$printf("Test String from test2\n");
return 0;
}
void go(char * args, unsigned long alen) {
DWORD dwRet;
PDOMAIN_CONTROLLER_INFO pdcInfo;
BeaconPrintf(1, "This GlobalString \"%s\"\n", TestGlobalString);
MSVCRT$printf("Test Value: %d\n", testvalue);
(void)test();
MSVCRT$printf("Test ValueBack: %d\n", testvalue);
(void)test2();
dwRet = NETAPI32$DsGetDcNameA(NULL, NULL, NULL, NULL, 0, &pdcInfo);
if (ERROR_SUCCESS == dwRet) {
MSVCRT$printf("%s", pdcInfo->DomainName);
}
NETAPI32$NetApiBufferFree(pdcInfo);
}

@ -0,0 +1,122 @@
/*!
* @file main.c
* @brief Entry point for the kiwi extension.
*/
#include "common.h"
#include "common_metapi.h"
// Required so that use of the API works.
MetApi* met_api = NULL;
#define RDIDLL_NOEXPORT
#include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"
#include "main.h"
extern int LoadAndRun(char *argsBuffer, uint32_t bufferSize, goCallback callback);
DWORD request_exec_cmd(Remote *remote, Packet *packet);
//DWORD request_kerberos_ticket_use(Remote *remote, Packet *packet);
/*! @brief The enabled commands for this extension. */
Command customCommands[] =
{
COMMAND_REQ(COMMAND_ID_BOFLOADER_EXEC_CMD, request_exec_cmd),
COMMAND_TERMINATOR
};
/*!
* @brief Handler for the generic command execution function.
* @param remote Pointer to the \c Remote instance.
* @param packet Pointer to the incoming packet.
* @returns \c ERROR_SUCCESS
*/
DWORD request_exec_cmd(Remote *remote, Packet *packet)
{
DWORD result = ERROR_SUCCESS;
Packet * response = met_api->packet.create_response(packet);
wchar_t* cmd = met_api->packet.get_tlv_value_wstring(packet, TLV_TYPE_BOFLOADER_CMD);
if (cmd != NULL)
{
dprintf("[BOF] Executing command: %S", cmd);
// While this implies that powershell is in use, this is just a naming thing,
// it's not actually using powershell.
wchar_t* output = powershell_reflective_mimikatz(cmd);
dprintf("[BOF] Executed command: %S", cmd);
if (output != NULL)
{
met_api->packet.add_tlv_wstring(response, TLV_TYPE_KIWI_CMD_RESULT, output);
}
else
{
result = ERROR_OUTOFMEMORY;
}
//LocalFree(cmd);
}
else
{
result = ERROR_INVALID_PARAMETER;
}
dprintf("[KIWI] Dumped, transmitting response.");
met_api->packet.transmit_response(result, remote, response);
dprintf("[KIWI] Done.");
return ERROR_SUCCESS;
}
/*!
* @brief Initialize the server extension.
* @param api Pointer to the Meterpreter API structure.
* @param remote Pointer to the remote instance.
* @return Indication of success or failure.
*/
DWORD InitServerExtension(MetApi* api, Remote* remote)
{
met_api = api;
SET_LOGGING_CONTEXT(api)
dprintf("[KIWI] Init server extension - initorclean");
mimikatz_initOrClean(TRUE);
dprintf("[KIWI] Init server extension - register");
met_api->command.register_all(customCommands);
return ERROR_SUCCESS;
}
/*!
* @brief Deinitialize the server extension.
* @param remote Pointer to the remote instance.
* @return Indication of success or failure.
*/
DWORD DeinitServerExtension(Remote *remote)
{
met_api->command.deregister_all(customCommands);
return ERROR_SUCCESS;
}
/*!
* @brief Do a stageless initialisation of the extension.
* @param ID of the extension that the init was intended for.
* @param buffer Pointer to the buffer that contains the init data.
* @param bufferSize Size of the \c buffer parameter.
* @return Indication of success or failure.
*/
DWORD StagelessInit(UINT extensionId, const LPBYTE buffer, DWORD bufferSize)
{
return ERROR_SUCCESS;
}
/*!
* @brief Callback for when a command has been added to the meterpreter instance.
* @param commandId The ID of the command that has been added.
*/
VOID CommandAdded(UINT commandId)
{
}

@ -0,0 +1,15 @@
/*!
* @file main.h
* @brief TLV related bits for the KIWI extension.
*/
#ifndef _METERPRETER_SOURCE_EXTENSION_BOF_BOF_H
#define _METERPRETER_SOURCE_EXTENSION_BOF_BOF_H
#include "../../common/common.h"
#define TLV_TYPE_EXTENSION_BOF 0
#define TLV_TYPE_BOFLOADER_CMD MAKE_CUSTOM_TLV(TLV_META_TYPE_RAW, TLV_TYPE_EXTENSION_BOF, TLV_EXTENSIONS + 100)
#define TLV_TYPE_BOFLOADER_CMD_RESULT MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_BOF, TLV_EXTENSIONS + 101)
#endif