Initial commit

This commit is contained in:
Kevin Haubris
2021-02-19 13:29:38 -06:00
commit 626956ecf5
11 changed files with 1263 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
*.exe
*.out
+475
View File
@@ -0,0 +1,475 @@
/*
* 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. */
#ifdef __x86_64__
#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 ){
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 < 25; 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 = LoadLibrary(locallib);
DEBUG_PRINT("\t\tHandle: 0x%lx\n", llHandle);
functionaddress = GetProcAddress(llHandle, localfunc);
DEBUG_PRINT("\t\tProcAddress: 0x%p\n", functionaddress);
#endif
}
return functionaddress;
}
/* 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){
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;
int retcode = 0;
int counter = 0;
int reloccount = 0;
int tempcounter = 0;
uint32_t symptr = 0;
#ifdef WIN32
void* funcptrlocation = NULL;
int32_t offsetvalue = 0;
#endif
char* entryfuncname = functionname;
#ifdef __x86_64__
#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_EXECUTE_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_EXECUTE_READWRITE);
#else
functionMapping = VirtualAlloc(NULL, 2048, MEM_COMMIT|MEM_RESERVE|MEM_TOP_DOWN, PAGE_EXECUTE_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
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
foo = (void (*)(char *, unsigned long))sectionMapping[coff_sym_ptr[tempcounter].SectionNumber-1]+coff_sym_ptr[tempcounter].Value;
//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
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){
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);
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
+107
View File
@@ -0,0 +1,107 @@
#ifndef COFFLOADER_H_
#define COFFLOADER_H_
#include <stdio.h>
#include <stdint.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
/* 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;
}__attribute__((packed)) coff_sect_t;
typedef struct coff_reloc{
uint32_t VirtualAddress;
uint32_t SymbolTableIndex;
uint16_t Type;
} __attribute__((packed)) 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;
} __attribute__((packed)) coff_sym_t;
/* 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
int RunCOFF(char* functionname, unsigned char* coff_data, uint32_t filesize, unsigned char* argumentdata, int argumentSize);
unsigned char* unhexlify(unsigned char* value, int *outlen);
#endif
+25
View File
@@ -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).
+26
View File
@@ -0,0 +1,26 @@
all: bof bof32
debug: debug32 debug64
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
+14
View File
@@ -0,0 +1,14 @@
# COFF Loader
This is a quick and dirty COFF loader (AKA Beacon Object Files), will eventually get it able to run a default BOF without changes, so that it can be used for testing without a CS agent running it.
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 will be the beacon internal functions so that you can load BOF files and run them inside your own agent, currently not used.
- 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.
+61
View File
@@ -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);
+347
View File
@@ -0,0 +1,347 @@
/*
* 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[25][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}
};
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, 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
+66
View File
@@ -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[25][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
+96
View File
@@ -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()
+44
View File
@@ -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);
}