Skip to content

Add Go c-archive output format#2290

Open
ph0neh0me wants to merge 1 commit into
BishopFox:masterfrom
ph0neh0me:feature/go-archive-output
Open

Add Go c-archive output format#2290
ph0neh0me wants to merge 1 commit into
BishopFox:masterfrom
ph0neh0me:feature/go-archive-output

Conversation

@ph0neh0me

Copy link
Copy Markdown

Summary

Closes #2289

Adds archive as a generation output format for Go c-archives. The new format builds Sliver as a Go c-archive and packages the generated .a, generated cgo export header, and rendered main.h into a .zip.

This format requires CGO because Go c-archive output depends on -buildmode=c-archive; the implementation mirrors the existing shared-library compiler setup where possible.

Motivation

Sliver already supports Go shared library output for compatible targets. This adds a closely related archive output for users who need to link the generated implant archive into their own native wrapper or loader workflow.

Implementation

  • Adds GO_ARCHIVE to the client protobuf output format enum.
  • Wires archive through the CLI, generate forms, profiles, RPC generation path, server builder, and external builder metadata.
  • Adds SliverArchive beside the existing shared-library generation path.
  • Reuses the existing shared-library export rendering by setting config.IsSharedLib = true.
  • Builds with Go -buildmode=c-archive.
  • Packages the generated .a, generated .h, and rendered main.h into a .zip.

Tests

  • Added unit coverage for the new output format display name.
  • Added unit coverage for archive ZIP packaging to verify .a, generated .h, and main.h are included.
NewUnitTests
  • Ran focused package tests for client generate and server generate archive behavior.
  • Ran compile-only checks for touched server packages.

Manual Validation

Generated a Windows AMD64 archive with:

generate --format archive --mtls localhost

As expected, a ZIP archive is emitted containing the archive and header files:

OutputProof

Created a minimal wrapper for native linking validation:

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

DWORD WINAPI WorkerThread(LPVOID lpParam)
{
    StartW();
    return 0;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hinstDLL);

        HANDLE hThread = CreateThread(NULL, 0, WorkerThread, NULL, 0, NULL);
        if (hThread != NULL) {
            CloseHandle(hThread);
        }
    }
    return TRUE;
}

Linked the archive into a DLL:

x86_64-w64-mingw32-g++ -std=c++11 -Wall -I. -shared -o beacon.dll wrapper.cpp ARCHITECTURAL_YOKE.a

Created a minimal loader to validate symbol resolution and invocation:

#include <windows.h>
#include <stdio.h>

int main() {
    HMODULE h = LoadLibraryA("beacon.dll");
    if (!h) {
        printf("LoadLibrary failed: %lu\n", GetLastError());
        return 1;
    }

    FARPROC p = GetProcAddress(h, "StartW");
    printf("LoadLibrary OK, StartW=%p\n", p);

    FreeLibrary(h);
    return 0;
}

Created a simple application to test calls:

#include <windows.h>
#include <stdio.h>

typedef void (*StartWFn)(void);

int main() {
    HMODULE h = LoadLibraryA("beacon.dll");
    if (!h) {
        printf("LoadLibrary failed: %lu\n", GetLastError());
        return 1;
    }

    StartWFn StartW = (StartWFn)GetProcAddress(h, "StartW");
    if (!StartW) {
        printf("GetProcAddress failed: %lu\n", GetLastError());
        return 1;
    }

    printf("Calling StartW...\n");
    StartW();

    printf("StartW returned\n");
    FreeLibrary(h);
    return 0;
}

Validated the generated artifact end-to-end in a local test environment:

SliverCallerProof

Server-side validation:

SliverKaliProof

@ph0neh0me
ph0neh0me requested a review from a team as a code owner July 18, 2026 12:15
@ph0neh0me
ph0neh0me requested a review from bf-brock July 18, 2026 12:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Go c-archive output format

1 participant