363 lines
13 KiB
C++
363 lines
13 KiB
C++
#include "bof_loader.h"
|
|
#include "ProcLoader.h"
|
|
#include "utils.h"
|
|
#include "Boffer.h"
|
|
|
|
#define llabs(n) ((n) < 0 ? -(n) : (n))
|
|
|
|
#if defined(__x86_64__) || defined(_WIN64)
|
|
int IMP_LENGTH = 6;
|
|
#else
|
|
int IMP_LENGTH = 7;
|
|
#endif
|
|
|
|
int my_strncpy_s(char* dest, unsigned int destsz, const char* src, unsigned int count) {
|
|
if (!dest || !src) return 1;
|
|
if (destsz == 0) return 2;
|
|
|
|
unsigned int i = 0;
|
|
for (; i < count && i < destsz - 1 && src[i] != '\0'; ++i)
|
|
dest[i] = src[i];
|
|
|
|
if (i < count && src[i] != '\0') {
|
|
dest[0] = '\0';
|
|
return 3;
|
|
}
|
|
dest[i] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
void InitBofOutputData()
|
|
{
|
|
if (bofOutputPacker == NULL)
|
|
bofOutputPacker = new Packer();
|
|
}
|
|
|
|
#define BEACON_FUNCTIONS_COUNT 32
|
|
|
|
BOF_API BeaconFunctions[BEACON_FUNCTIONS_COUNT] = {
|
|
|
|
/// 5 - Data Parser API
|
|
|
|
{ HASH_FUNC_BEACONDATAPARSE, (LPVOID) BeaconDataParse },
|
|
{ HASH_FUNC_BEACONDATAINT, (LPVOID) BeaconDataInt },
|
|
{ HASH_FUNC_BEACONDATASHORT, (LPVOID) BeaconDataShort },
|
|
{ HASH_FUNC_BEACONDATALENGTH, (LPVOID) BeaconDataLength },
|
|
{ HASH_FUNC_BEACONDATAEXTRACT, (LPVOID) BeaconDataExtract },
|
|
|
|
/// 2 - Output API
|
|
|
|
{ HASH_FUNC_BEACONOUTPUT, (LPVOID) BeaconOutput },
|
|
{ HASH_FUNC_BEACONPRINTF, (LPVOID) BeaconPrintf },
|
|
|
|
/// 7 - Format API
|
|
|
|
{ HASH_FUNC_BEACONFORMATALLOC, (LPVOID) BeaconFormatAlloc },
|
|
{ HASH_FUNC_BEACONFORMATRESET, (LPVOID) BeaconFormatReset },
|
|
{ HASH_FUNC_BEACONFORMATAPPEND, (LPVOID) BeaconFormatAppend },
|
|
{ HASH_FUNC_BEACONFORMATPRINTF, (LPVOID) BeaconFormatPrintf },
|
|
{ HASH_FUNC_BEACONFORMATTOSTRING, (LPVOID) BeaconFormatToString },
|
|
{ HASH_FUNC_BEACONFORMATFREE, (LPVOID) BeaconFormatFree },
|
|
{ HASH_FUNC_BEACONFORMATINT, (LPVOID) BeaconFormatInt },
|
|
|
|
/// 7 - Internal APIs
|
|
|
|
{ HASH_FUNC_BEACONUSETOKEN, (LPVOID) BeaconUseToken },
|
|
{ HASH_FUNC_BEACONREVERTTOKEN, (LPVOID) BeaconRevertToken },
|
|
{ HASH_FUNC_BEACONISADMIN, (LPVOID) BeaconIsAdmin },
|
|
//{ HASH_FUNC_BEACONGETSPAWNTO, BeaconGetSpawnTo },
|
|
//{ HASH_FUNC_BEACONSPAWNTEMPORARYPROCESS, BeaconSpawnTemporaryProcess },
|
|
//{ HASH_FUNC_BEACONINJECTPROCESS, BeaconInjectProcess },
|
|
//{ HASH_FUNC_BEACONINJECTTEMPORARYPROCESS, BeaconInjectTemporaryProcess },
|
|
//{ HASH_FUNC_BEACONCLEANUPPROCESS, BeaconCleanupProcess },
|
|
//{ HASH_FUNC_BEACONINFORMATION, BeaconInformation },
|
|
{ HASH_FUNC_TOWIDECHAR, (LPVOID) toWideChar },
|
|
{ HASH_FUNC_BEACONADDVALUE, (LPVOID) BeaconAddValue },
|
|
{ HASH_FUNC_BEACONGETVALUE, (LPVOID) BeaconGetValue },
|
|
{ HASH_FUNC_BEACONREMOVEVALUE, (LPVOID) BeaconRemoveValue },
|
|
|
|
/// 2 - Adaptix APIs
|
|
{ HASH_FUNC_AXADDSCREENSHOT, (LPVOID) AxAddScreenshot },
|
|
{ HASH_FUNC_AXDOWNLOADMEMORY, (LPVOID) AxDownloadMemory },
|
|
|
|
/// 3 - Async BOF APIs
|
|
{ HASH_FUNC_BEACONREGISTERTHREADCALLBACK, (LPVOID) BeaconRegisterThreadCallback },
|
|
{ HASH_FUNC_BEACONUNREGISTERTHREADCALLBACK, (LPVOID) BeaconUnregisterThreadCallback },
|
|
{ HASH_FUNC_BEACONWAKEUP, (LPVOID) BeaconWakeup },
|
|
{ HASH_FUNC_BEACONGETSTOPJOBEVENT, (LPVOID) BeaconGetStopJobEvent },
|
|
|
|
/// 5 - Other APIs
|
|
|
|
{ HASH_FUNC_LOADLIBRARYA, (LPVOID) proxy_LoadLibraryA },
|
|
{ HASH_FUNC_GETMODULEHANDLEA, (LPVOID) proxy_GetModuleHandleA },
|
|
{ HASH_FUNC_FREELIBRARY, (LPVOID) proxy_FreeLibrary },
|
|
{ HASH_FUNC_GETPROCADDRESS, (LPVOID) proxy_GetProcAddress },
|
|
{ HASH_FUNC___C_SPECIFIC_HANDLER, NULL }, // GetProcAddress(kern, "__C_specific_handler");
|
|
};
|
|
|
|
void* FindProcBySymbol(char* symbol)
|
|
{
|
|
if ( StrLenA(symbol) > IMP_LENGTH) {
|
|
ULONG funcHash = Djb2A((PUCHAR) symbol + IMP_LENGTH);
|
|
for (int i = 0; i < BEACON_FUNCTIONS_COUNT; i++) {
|
|
if (funcHash == BeaconFunctions[i].hash) {
|
|
if ( BeaconFunctions[i].proc != NULL )
|
|
return BeaconFunctions[i].proc;
|
|
}
|
|
}
|
|
|
|
char symbolCopy[1024] = { 0 };
|
|
memcpy(symbolCopy, symbol, StrLenA(symbol));
|
|
|
|
CHAR c1[] = { '$',0 };
|
|
CHAR c2[] = { '@',0 };
|
|
|
|
char* moduleName = symbolCopy + IMP_LENGTH;
|
|
moduleName = StrTokA(moduleName, c1);
|
|
|
|
char* funcName = StrTokA(NULL, c1);
|
|
funcName = StrTokA(funcName, c2);
|
|
|
|
funcHash = Djb2A((PUCHAR)funcName);
|
|
HMODULE hModule = ApiWin->LoadLibraryA(moduleName);
|
|
|
|
memset(symbolCopy, 0, StrLenA(symbol));
|
|
|
|
if (hModule)
|
|
return GetSymbolAddress(hModule, funcHash);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char* PrepareEntryName(char* targetFuncName)
|
|
{
|
|
#if defined(__x86_64__) || defined(_WIN64)
|
|
return targetFuncName;
|
|
#else
|
|
int targetLength = StrLenA(targetFuncName);
|
|
char* entryName = (char*)MemAllocLocal(targetLength + 2);
|
|
if (!entryName)
|
|
return NULL;
|
|
|
|
entryName[0] = '_';
|
|
memcpy(entryName + 1, targetFuncName, targetLength + 1);
|
|
return entryName;
|
|
#endif
|
|
}
|
|
|
|
void FreeFunctionName(char* targetFuncName)
|
|
{
|
|
#if !defined(__x86_64__) && !defined(_WIN64)
|
|
MemFreeLocal((LPVOID*) & targetFuncName, StrLenA(targetFuncName));
|
|
#endif
|
|
}
|
|
|
|
bool AllocateSections(unsigned char* coffFile, COF_HEADER* pHeader, PCHAR* mapSections)
|
|
{
|
|
for (int i = 0; i < pHeader->NumberOfSections; i++) {
|
|
COF_SECTION* pSection = (COF_SECTION*)(coffFile + sizeof(COF_HEADER) + (sizeof(COF_SECTION) * i));
|
|
mapSections[i] = (char*)ApiWin->VirtualAlloc(NULL, pSection->SizeOfRawData, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
|
|
if (!mapSections[i] && pSection->SizeOfRawData)
|
|
return FALSE;
|
|
|
|
if (pSection->PointerToRawData)
|
|
memcpy(mapSections[i], coffFile + pSection->PointerToRawData, pSection->SizeOfRawData);
|
|
else
|
|
memset(mapSections[i], 0, pSection->SizeOfRawData);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CleanupSections(PCHAR* mapSections, int maxSections)
|
|
{
|
|
for (int i = 0; i < maxSections; i++) {
|
|
if (mapSections[i]) {
|
|
ApiWin->VirtualFree(mapSections[i], 0, MEM_RELEASE);
|
|
mapSections[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ProcessRelocations(unsigned char* coffFile, COF_HEADER* pHeader, PCHAR* mapSections, COF_SYMBOL* pSymbolTable, LPVOID* mapFunctions)
|
|
{
|
|
bool status = TRUE;
|
|
int mapFunctionsSize = 0;
|
|
char* procSymbol = NULL;
|
|
char procSymbolShort[9] = { 0 };
|
|
|
|
for (int sectionIndex = 0; sectionIndex < pHeader->NumberOfSections; sectionIndex++) {
|
|
COF_SECTION* pSection = (COF_SECTION*)(coffFile + sizeof(COF_HEADER) + (sizeof(COF_SECTION) * sectionIndex));
|
|
COF_RELOCATION* pRelocTable = (COF_RELOCATION*)(coffFile + pSection->PointerToRelocations);
|
|
|
|
for (int relocIndex = 0; relocIndex < pSection->NumberOfRelocations; relocIndex++) {
|
|
COF_SYMBOL pSymbol = pSymbolTable[pRelocTable->SymbolTableIndex];
|
|
if (pRelocTable->SymbolTableIndex >= pHeader->NumberOfSymbols) {
|
|
BeaconOutput(BOF_ERROR_PARSE, NULL, 0);
|
|
return FALSE;
|
|
}
|
|
|
|
int offset = 0;
|
|
void* procAddress = NULL;
|
|
#ifdef _WIN64
|
|
unsigned long long bigOffset = 0;
|
|
#endif
|
|
|
|
if (pSymbol.Name.dwName[0] == 0) {
|
|
procSymbol = ((char*)(pSymbolTable + pHeader->NumberOfSymbols)) + pSymbol.Name.dwName[1];
|
|
}
|
|
else {
|
|
if (pSymbol.Name.cName[7] != 0) {
|
|
my_strncpy_s(procSymbolShort, sizeof(procSymbolShort), pSymbol.Name.cName, sizeof(pSymbol.Name.cName));
|
|
procSymbol = procSymbolShort;
|
|
}
|
|
else {
|
|
procSymbol = pSymbol.Name.cName;
|
|
}
|
|
}
|
|
|
|
if (pSymbol.SectionNumber > 0) {
|
|
procAddress = mapSections[pSymbol.SectionNumber - 1];
|
|
procAddress = (void*)((char*)procAddress + pSymbol.Value);
|
|
}
|
|
else if(pSymbol.Value == 0 && (pSymbol.StorageClass == IMAGE_SYM_CLASS_EXTERNAL || pSymbol.StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)) {
|
|
procAddress = FindProcBySymbol(procSymbol);
|
|
if (procAddress == NULL && pSymbolTable[pRelocTable->SymbolTableIndex].SectionNumber == 0) {
|
|
BeaconOutput(BOF_ERROR_SYMBOL, procSymbol, StrLenA(procSymbol));
|
|
status = FALSE;
|
|
}
|
|
else {
|
|
mapFunctions[mapFunctionsSize] = procAddress;
|
|
procAddress = &mapFunctions[mapFunctionsSize];
|
|
mapFunctionsSize++;
|
|
}
|
|
}
|
|
else {
|
|
BeaconOutput(BOF_ERROR_SYMBOL, "Undefined symbol", 17);
|
|
status = FALSE;
|
|
}
|
|
|
|
if (status != FALSE) {
|
|
#ifdef _WIN64
|
|
if (pRelocTable->Type == IMAGE_REL_AMD64_ADDR64) // Type == 1 - 64-bit VA of the relocation target
|
|
{
|
|
memcpy(&bigOffset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(unsigned long long));
|
|
bigOffset += (unsigned long long) procAddress;
|
|
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &bigOffset, sizeof(unsigned long long));
|
|
}
|
|
else if (pRelocTable->Type == IMAGE_REL_AMD64_ADDR32NB) // Type == 3 relocation code
|
|
{
|
|
memcpy(&offset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(int));
|
|
if (((char*)(mapSections[pSymbol.SectionNumber - 1] + offset) - (char*)(mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4)) > 0xffffffff) {
|
|
return FALSE;
|
|
}
|
|
offset = ((char*)(mapSections[pSymbol.SectionNumber - 1] + offset) - (char*)(mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4));
|
|
offset += pSymbolTable[pRelocTable->SymbolTableIndex].Value;
|
|
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &offset, sizeof(int));
|
|
}
|
|
// Type == 4,5,6,7,8,9 relocation code (make global variables)
|
|
else if (pRelocTable->Type == IMAGE_REL_AMD64_REL32 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_1 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_2 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_3 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_4 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_5)
|
|
{
|
|
offset = 0;
|
|
int typeIndex = pRelocTable->Type - 4;
|
|
|
|
memcpy(&offset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(int));
|
|
if (llabs((long long)procAddress - (long long)(mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4 + typeIndex)) > UINT_MAX) {
|
|
return FALSE;
|
|
}
|
|
offset += ((size_t)procAddress - ((size_t)mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4 + typeIndex));
|
|
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &offset, sizeof(int));
|
|
}
|
|
#else
|
|
if (pRelocTable->Type == IMAGE_REL_I386_DIR32)
|
|
{
|
|
offset = 0;
|
|
memcpy(&offset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(int));
|
|
offset = (unsigned int)procAddress + offset;
|
|
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &offset, sizeof(unsigned int));
|
|
}
|
|
else if (pRelocTable->Type == IMAGE_REL_I386_REL32)
|
|
{
|
|
offset = 0;
|
|
memcpy(&offset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(int));
|
|
offset = (unsigned int)procAddress - (unsigned int)(mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4);
|
|
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &offset, sizeof(unsigned int));
|
|
}
|
|
#endif
|
|
}
|
|
pRelocTable = (COF_RELOCATION*)((char*)pRelocTable + sizeof(COF_RELOCATION));
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
void ExecuteProc(char* entryFuncName, unsigned char* args, int argsSize, COF_SYMBOL* pSymbolTable, COF_HEADER* pHeader, PCHAR* mapSections)
|
|
{
|
|
for (int i = 0; i < pHeader->NumberOfSymbols; i++) {
|
|
if (StrCmpA(pSymbolTable[i].Name.cName, entryFuncName) == 0) {
|
|
void(*proc)(char*, unsigned long) = (void(*)(char*, unsigned long)) (mapSections[pSymbolTable[i].SectionNumber - 1] + pSymbolTable[i].Value);
|
|
proc((char*)args, argsSize);
|
|
return;
|
|
}
|
|
}
|
|
BeaconOutput(BOF_ERROR_ENTRY, NULL, 0);
|
|
}
|
|
|
|
Packer* ObjectExecute(ULONG taskId, char* targetFuncName, unsigned char* coffFile, unsigned int cofFileSize, unsigned char* args, int argsSize)
|
|
{
|
|
COF_HEADER* pHeader = NULL;
|
|
COF_SYMBOL* pSymbolTable = NULL;
|
|
PCHAR entryFuncName = NULL;
|
|
LPVOID* mapFunctions = NULL;
|
|
BOOL result = FALSE;
|
|
PCHAR mapSections[MAX_SECTIONS] = { 0 };
|
|
|
|
InitBofOutputData();
|
|
bofTaskId = taskId;
|
|
|
|
if (!coffFile || !targetFuncName) {
|
|
goto RET;
|
|
}
|
|
|
|
pHeader = (COF_HEADER*)coffFile;
|
|
pSymbolTable = (COF_SYMBOL*)(coffFile + pHeader->PointerToSymbolTable);
|
|
|
|
entryFuncName = PrepareEntryName(targetFuncName);
|
|
if (!entryFuncName) {
|
|
BeaconOutput(BOF_ERROR_ENTRY, NULL, 0);
|
|
goto RET;
|
|
}
|
|
|
|
result = AllocateSections(coffFile, pHeader, mapSections);
|
|
if (!result) {
|
|
BeaconOutput(BOF_ERROR_ALLOC, NULL, 0);
|
|
goto RET;
|
|
}
|
|
|
|
mapFunctions = (LPVOID*) ApiWin->VirtualAlloc(NULL, MAP_FUNCTIONS_SIZE, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
|
|
if (!mapFunctions) {
|
|
BeaconOutput(BOF_ERROR_ALLOC, NULL, 0);
|
|
goto RET;
|
|
}
|
|
|
|
result = ProcessRelocations(coffFile, pHeader, mapSections, pSymbolTable, mapFunctions);
|
|
if (!result) {
|
|
|
|
goto RET;
|
|
}
|
|
|
|
ExecuteProc(entryFuncName, args, argsSize, pSymbolTable, pHeader, mapSections);
|
|
|
|
RET:
|
|
if (mapFunctions) {
|
|
ApiWin->VirtualFree(mapFunctions, 0, MEM_RELEASE);
|
|
mapFunctions = NULL;
|
|
}
|
|
|
|
FreeFunctionName(entryFuncName);
|
|
CleanupSections(mapSections, MAX_SECTIONS);
|
|
|
|
bofTaskId = 0;
|
|
|
|
return bofOutputPacker;
|
|
} |