/*
 * whoami_bof.c -- Practical BOF that queries the current user and token
 * Step 08: Demonstrates proper DLL import conventions, error handling,
 *          and real Windows API usage in a BOF.
 *
 * Opens the process token, retrieves TokenUser information, and
 * looks up the account SID to display DOMAIN\username and PID.
 *
 * Compile (do NOT link):
 *   MinGW:  x86_64-w64-mingw32-gcc -c whoami_bof.c -o whoami_bof.o
 *   MSVC:   cl.exe /c /GS- whoami_bof.c /Fo whoami_bof.obj
 *
 * Run with COFFLoader:
 *   COFFLoader.exe go whoami_bof.o
 */

#include <windows.h>
#include "beacon.h"

/* ================================================================
 * DLL import declarations using LIBRARY$Function convention
 *
 * The compiler generates __imp_LIBRARY$Function symbols.
 * COFFLoader splits on '$', calls LoadLibraryA then GetProcAddress.
 * ================================================================ */
DECLSPEC_IMPORT BOOL    WINAPI ADVAPI32$OpenProcessToken(HANDLE, DWORD, PHANDLE);
DECLSPEC_IMPORT BOOL    WINAPI ADVAPI32$GetTokenInformation(HANDLE, TOKEN_INFORMATION_CLASS,
                                                             LPVOID, DWORD, PDWORD);
DECLSPEC_IMPORT BOOL    WINAPI ADVAPI32$LookupAccountSidA(LPCSTR, PSID, LPSTR, LPDWORD,
                                                           LPSTR, LPDWORD, PSID_NAME_USE);
DECLSPEC_IMPORT HANDLE  WINAPI KERNEL32$GetCurrentProcess(void);
DECLSPEC_IMPORT BOOL    WINAPI KERNEL32$CloseHandle(HANDLE);
DECLSPEC_IMPORT DWORD   WINAPI KERNEL32$GetCurrentProcessId(void);
DECLSPEC_IMPORT DWORD   WINAPI KERNEL32$GetLastError(void);

void go(char* args, int len) {
    HANDLE hToken = NULL;
    DWORD  pid = KERNEL32$GetCurrentProcessId();

    BeaconPrintf(CALLBACK_OUTPUT, "[*] PID: %d\n", pid);

    /* Open our process token */
    if (!ADVAPI32$OpenProcessToken(
            KERNEL32$GetCurrentProcess(),
            TOKEN_QUERY,
            &hToken))
    {
        BeaconPrintf(CALLBACK_ERROR, "[!] OpenProcessToken failed: %d\n",
                     KERNEL32$GetLastError());
        return;
    }

    /* Get the token user information */
    BYTE tokenInfo[256];
    DWORD returnLength = 0;

    if (!ADVAPI32$GetTokenInformation(
            hToken, TokenUser, tokenInfo, sizeof(tokenInfo), &returnLength))
    {
        BeaconPrintf(CALLBACK_ERROR, "[!] GetTokenInformation failed: %d\n",
                     KERNEL32$GetLastError());
        KERNEL32$CloseHandle(hToken);
        return;
    }

    /* Look up the account name from the SID */
    TOKEN_USER* pUser = (TOKEN_USER*)tokenInfo;
    char username[128] = {0};
    char domain[128]   = {0};
    DWORD userLen   = sizeof(username);
    DWORD domainLen = sizeof(domain);
    SID_NAME_USE sidType;

    if (ADVAPI32$LookupAccountSidA(
            NULL, pUser->User.Sid,
            username, &userLen,
            domain, &domainLen,
            &sidType))
    {
        BeaconPrintf(CALLBACK_OUTPUT, "[+] User: %s\\%s\n", domain, username);
    }
    else {
        BeaconPrintf(CALLBACK_ERROR, "[!] LookupAccountSid failed: %d\n",
                     KERNEL32$GetLastError());
    }

    KERNEL32$CloseHandle(hToken);
}
