/*
 * beacon_compatibility.c -- Beacon API stub implementations
 * Step 06: Provides the functions that BOFs call (BeaconPrintf, data
 *          parsing, etc.) and the InternalFunctions lookup table so
 *          the loader can resolve __imp_Beacon* symbols.
 *
 * These implementations are "standalone" stubs -- they print to the
 * console directly instead of routing output through a C2 channel.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "beacon_compatibility.h"

/* ================================================================
 * Global output buffer (unused in this step -- reserved for later)
 * ================================================================ */
char*  beacon_compatibility_output  = NULL;
int    beacon_compatibility_size    = 0;
int    beacon_compatibility_offset  = 0;

/* ================================================================
 * Data Parsing API -- real implementations
 *
 * The packed argument format has a 4-byte length prefix followed by
 * the raw data.  BeaconDataParse skips that prefix so subsequent
 * extract calls start at the actual payload.
 * ================================================================ */

/* Initialize the parser, skipping the 4-byte length prefix */
void BeaconDataParse(datap* parser, char* buffer, int size) {
    if (buffer == NULL) {
        parser->original = NULL;
        parser->buffer   = NULL;
        parser->length   = 0;
        parser->size     = 0;
        return;
    }
    parser->original = buffer;
    parser->buffer   = buffer + 4;  /* skip 4-byte length prefix */
    parser->length   = size - 4;
    parser->size     = size - 4;
}

/* Read a 4-byte big-endian integer and advance the cursor */
int BeaconDataInt(datap* parser) {
    if (parser->length < 4) return 0;
    int val = 0;
    memcpy(&val, parser->buffer, 4);
    parser->buffer += 4;
    parser->length -= 4;
    return val;
}

/* Read a 2-byte big-endian short and advance the cursor */
short BeaconDataShort(datap* parser) {
    if (parser->length < 2) return 0;
    short val = 0;
    memcpy(&val, parser->buffer, 2);
    parser->buffer += 2;
    parser->length -= 2;
    return val;
}

/* Return the number of bytes remaining */
int BeaconDataLength(datap* parser) {
    return parser->length;
}

/* Extract a length-prefixed blob: 4-byte length, then raw bytes */
char* BeaconDataExtract(datap* parser, int* size) {
    if (parser->length < 4) {
        if (size) *size = 0;
        return NULL;
    }
    int len = 0;
    memcpy(&len, parser->buffer, 4);
    parser->buffer += 4;
    parser->length -= 4;

    char* result = parser->buffer;
    if (size) *size = len;

    parser->buffer += len;
    parser->length -= len;
    return result;
}

/* ================================================================
 * Output API -- prints to console for standalone operation
 * ================================================================ */

/* BeaconPrintf: simple vprintf to stdout (no buffer routing yet) */
void BeaconPrintf(int type, char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

/* BeaconOutput: write raw bytes to stdout */
void BeaconOutput(int type, char* data, int len) {
    fwrite(data, 1, len, stdout);
}

/* ================================================================
 * Format Buffer API -- stubs that do nothing
 *
 * A full implementation would allocate a growable buffer and let
 * the BOF build output incrementally.  For step06 these are
 * no-ops since hello_bof.c does not use format buffers.
 * ================================================================ */

void BeaconFormatAlloc(formatp* format, int maxsz) {
    (void)format; (void)maxsz;
}

void BeaconFormatReset(formatp* format) {
    (void)format;
}

void BeaconFormatFree(formatp* format) {
    (void)format;
}

void BeaconFormatAppend(formatp* format, char* text, int len) {
    (void)format; (void)text; (void)len;
}

void BeaconFormatPrintf(formatp* format, char* fmt, ...) {
    (void)format; (void)fmt;
}

char* BeaconFormatToString(formatp* format, int* size) {
    (void)format;
    if (size) *size = 0;
    return NULL;
}

void BeaconFormatInt(formatp* format, int value) {
    (void)format; (void)value;
}

/* ================================================================
 * Token / Process API -- empty stubs
 *
 * These are C2-specific operations that do nothing in a standalone
 * loader.  They exist so symbol resolution does not fail.
 * ================================================================ */

void BeaconUseToken(HANDLE token) {
    (void)token;
}

void BeaconRevertToken(void) {
}

BOOL BeaconIsAdmin(void) {
    return FALSE;
}

void BeaconGetSpawnTo(BOOL x86, char* buffer, int length) {
    (void)x86; (void)buffer; (void)length;
}

BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken,
        STARTUPINFOA* si, PROCESS_INFORMATION* pi) {
    (void)x86; (void)ignoreToken; (void)si; (void)pi;
    return FALSE;
}

void BeaconInjectProcess(HANDLE hProc, int pid,
        char* payload, int p_len, int offset,
        char* arg, int a_len) {
    (void)hProc; (void)pid; (void)payload; (void)p_len;
    (void)offset; (void)arg; (void)a_len;
}

void BeaconInjectTemporaryProcess(PROCESS_INFORMATION* pi,
        char* payload, int p_len, int offset,
        char* arg, int a_len) {
    (void)pi; (void)payload; (void)p_len;
    (void)offset; (void)arg; (void)a_len;
}

void BeaconCleanupProcess(PROCESS_INFORMATION* pi) {
    (void)pi;
}

/* ================================================================
 * Utility
 * ================================================================ */

BOOL toWideChar(char* src, wchar_t* dst, int max) {
    return MultiByteToWideChar(CP_ACP, 0, src, -1, dst, max) > 0;
}

/* ================================================================
 * Output retrieval -- returns NULL in this step
 * ================================================================ */
char* BeaconGetOutputData(int* outsize) {
    if (outsize) *outsize = 0;
    return NULL;
}

/* ================================================================
 * InternalFunctions table
 *
 * Maps Beacon API symbol names to their function pointers.
 * The loader's process_symbol() searches this table when it
 * encounters an __imp_Beacon* or __imp_toWideChar symbol.
 *
 * Each row: { (unsigned char*)"FunctionName",
 *             (unsigned char*)function_pointer }
 * ================================================================ */
unsigned char* InternalFunctions[30][2] = {
    /* Data parsing */
    { (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 },

    /* Output */
    { (unsigned char*)"BeaconPrintf",      (unsigned char*)BeaconPrintf      },
    { (unsigned char*)"BeaconOutput",      (unsigned char*)BeaconOutput      },

    /* Format buffer */
    { (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     },

    /* Token / Process */
    { (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          },

    /* Utility */
    { (unsigned char*)"toWideChar",        (unsigned char*)toWideChar        },

    /* Output retrieval */
    { (unsigned char*)"BeaconGetOutputData", (unsigned char*)BeaconGetOutputData },

    /* Sentinel -- marks end of table */
    { NULL, NULL }
};
