analyzing-golang-malware-with-ghidra skill (Anthropic-Cybersecurity-Skills)

From Public Agent Wiki

What it does. Reverse engineer Go-compiled malware in Ghidra by parsing Go buildinfo Part of mukul975/Anthropic-Cybersecurity-Skills (817 security skills) (mukul975/Anthropic-Cybersecurity-Skills).

Upstream mukul975/Anthropic-Cybersecurity-Skills
Skill file skills/analyzing-golang-malware-with-ghidra/SKILL.md
License Apache-2.0 (skill folder LICENSE)
Author mukul975
Fetched 2026-09-10

Install

  • npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill analyzing-golang-malware-with-ghidra, or copy the skill folder into ~/.claude/skills/analyzing-golang-malware-with-ghidra/.
  • Raw file: curl -sL https://raw.githubusercontent.com/mukul975/Anthropic-Cybersecurity-Skills/HEAD/skills/analyzing-golang-malware-with-ghidra/SKILL.md

SKILL.md (verbatim)

name: analyzing-golang-malware-with-ghidra
description: Reverse engineer Go-compiled malware in Ghidra by parsing Go buildinfo
  and pclntab structures, recovering stripped/obfuscated function names (e.g. via
  GoResolver), and extracting embedded module/dependency strings and types from Go
  binaries. Use when analyzing a Go-language malware sample, deobfuscating a garble-packed
  Go binary, or recovering function names and third-party dependencies from a stripped
  Go executable.
domain: cybersecurity
subdomain: malware-analysis
tags:
- golang
- ghidra
- reverse-engineering
- malware-analysis
- binary-analysis
- go-malware
- disassembly
version: '1.0'
author: mahipal
license: Apache-2.0
nist_csf:
- DE.AE-02
- RS.AN-03
- ID.RA-01
- DE.CM-01
mitre_attack:
- T1027
- T1620
- T1140
- T1059

Analyzing Golang Malware with Ghidra

Overview

Go (Golang) has become a popular language for malware authors due to its cross-compilation capabilities, static linking that produces self-contained binaries, and the complexity it introduces for reverse engineering. Go binaries contain the entire runtime, standard library, and all dependencies statically linked, resulting in large binaries (often 5-15MB) with thousands of functions. Ghidra struggles with Go-specific string formats (non-null-terminated), stripped function names, and goroutine concurrency patterns. Specialized tools like GoResolver (Volexity, 2025) use control-flow graph similarity to automatically deobfuscate and recover function names in stripped or obfuscated Go binaries.

When to Use

  • When investigating security incidents that require analyzing golang malware with ghidra
  • When building detection rules or threat hunting queries for this domain
  • When SOC analysts need structured procedures for this analysis type
  • When validating security monitoring coverage for related attack techniques

Prerequisites

  • Ghidra 11.0+ with JDK 17+
  • GoResolver plugin (for function name recovery)
  • Go Reverse Engineering Tool Kit (go-re.tk)
  • Python 3.9+ for helper scripts
  • Understanding of Go runtime internals (goroutines, channels, interfaces)
  • Familiarity with Go binary structure (pclntab, moduledata, itab)

Key Concepts

Go Binary Structure

Go binaries embed rich metadata in the pclntab (PC Line Table) structure, which maps program counters to function names, source files, and line numbers. Even stripped binaries retain this metadata. The moduledata structure contains pointers to type information, itabs (interface tables), and the pclntab itself. Go strings are stored as a pointer-length pair rather than null-terminated C strings.

Function Recovery in Stripped Binaries

Despite stripping symbol tables, Go binaries retain function names within the pclntab. However, obfuscation tools like garble rename functions to random strings. GoResolver addresses this by computing control-flow graph signatures of obfuscated functions and matching them against a database of known Go standard library and third-party package functions.

Crate/Dependency Extraction

Go's dependency management embeds module paths and version strings in the binary. Extracting these reveals the malware's third-party dependencies (HTTP libraries, encryption packages, C2 frameworks), which provides insight into capabilities without full reverse engineering.

Workflow

Step 1: Initial Binary Analysis

#!/usr/bin/env python3
"""Analyze Go binary metadata for malware analysis."""
import struct
import sys
import re


def find_go_build_info(data):
    """Extract Go build information from binary."""
    # Go buildinfo magic: \xff Go buildinf:
    magic = b'\xff Go buildinf:'
    offset = data.find(magic)
    if offset == -1:
        return None

    print(f"[+] Go build info at offset 0x{offset:x}")

    # Extract Go version string nearby
    go_version = re.search(rb'go\d+\.\d+(?:\.\d+)?', data[offset:offset+256])
    if go_version:
        print(f"  Go Version: {go_version.group().decode()}")

    return offset


def find_pclntab(data):
    """Locate the pclntab (PC Line Table) structure."""
    # pclntab magic bytes vary by Go version
    magics = {
        b'\xfb\xff\xff\xff\x00\x00': "Go 1.2-1.15",
        b'\xfa\xff\xff\xff\x00\x00': "Go 1.16-1.17",
        b'\xf1\xff\xff\xff\x00\x00': "Go 1.18-1.19",
        b'\xf0\xff\xff\xff\x00\x00': "Go 1.20+",
    }

    for magic, version in magics.items():
        offset = data.find(magic)
        if offset != -1:
            print(f"[+] pclntab found at 0x{offset:x} ({version})")
            return offset, version

    return None, None


def extract_function_names(data, pclntab_offset):
    """Extract function names from pclntab."""
    if pclntab_offset is None:
        return []

    functions = []
    # Function name strings follow specific patterns
    func_pattern = re.compile(
        rb'(?:main|runtime|fmt|net|os|crypto|encoding|io|sync|'
        rb'syscall|reflect|strings|bytes|path|time|math|sort|'
        rb'github\.com|golang\.org)[/\.][\w/.]+',
    )

    for match in func_pattern.finditer(data):
        name = match.group().decode('utf-8', errors='replace')
        if len(name) > 4 and len(name) < 200:
            functions.append(name)

    return sorted(set(functions))


def extract_go_strings(data):
    """Extract Go-style strings (pointer+length pairs)."""
    # Go strings are not null-terminated; extract readable sequences
    strings = []
    ascii_pattern = re.compile(rb'[\x20-\x7e]{10,}')

    for match in ascii_pattern.finditer(data):
        s = match.group().decode('ascii')
        # Filter for interesting malware strings
        interesting = [
            'http', 'https', 'tcp', 'udp', 'dns',
            'cmd', 'shell', 'exec', 'upload', 'download',
            'encrypt', 'decrypt', 'key', 'token', 'password',
            'c2', 'beacon', 'agent', 'implant', 'bot',
            'mutex', 'persist', 'registry', 'scheduled',
        ]
        if any(kw in s.lower() for kw in interesting):
            strings.append(s)

    return strings


def extract_dependencies(data):
    """Extract Go module dependencies from binary."""
    deps = []
    # Module paths follow pattern: github.com/user/repo
    dep_pattern = re.compile(
        rb'((?:github\.com|gitlab\.com|golang\.org|gopkg\.in|'
        rb'go\.etcd\.io|google\.golang\.org)/[^\x00\s]{5,80})'
    )

    for match in dep_pattern.finditer(data):
        dep = match.group().decode('utf-8', errors='replace')
        deps.append(dep)

    unique_deps = sorted(set(deps))
    return unique_deps


def analyze_go_binary(filepath):
    """Full analysis of Go malware binary."""
    with open(filepath, 'rb') as f:
        data = f.read()

    print(f"[+] Analyzing Go binary: {filepath}")
    print(f"  File size: {len(data):,} bytes")
    print("=" * 60)

    # Build info
    find_go_build_info(data)

    # pclntab
    pclntab_offset, go_version = find_pclntab(data)

    # Functions
    functions = extract_function_names(data, pclntab_offset)
    print(f"\n[+] Recovered {len(functions)} function names")

    # Categorize functions
    categories = {
        "network": [], "crypto": [], "os_exec": [],
        "file_io": [], "main": [], "third_party": [],
    }
    for f in functions:
        if 'net/' in f or 'http' in f.lower():
            categories["network"].append(f)
        elif 'crypto' in f:
            categories["crypto"].append(f)
        elif 'os/exec' in f or 'syscall' in f:
            categories["os_exec"].append(f)
        elif 'os.' in f or 'io/' in f:
            categories["file_io"].append(f)
        elif f.startswith('main.'):
            categories["main"].append(f)
        elif 'github.com' in f or 'golang.org' in f:
            categories["third_party"].append(f)

    for cat, funcs in categories.items():
        if funcs:
            print(f"\n  [{cat}] ({len(funcs)} functions):")
            for fn in funcs[:10]:
                print(f"    {fn}")

    # Dependencies
    deps = extract_dependencies(data)
    print(f"\n[+] Dependencies ({len(deps)}):")
    for dep in deps[:20]:
        print(f"    {dep}")

    # Suspicious strings
    sus_strings = extract_go_strings(data)
    print(f"\n[+] Suspicious strings ({len(sus_strings)}):")
    for s in sus_strings[:20]:
        print(f"    {s}")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <go_binary>")
        sys.exit(1)
    analyze_go_binary(sys.argv[1])

Step 2: Ghidra Analysis Script

# Ghidra script (run within Ghidra's script manager)
# Save as AnalyzeGoBinary.py in Ghidra scripts directory

# @category MalwareAnalysis
# @description Analyze Go binary structure and recover metadata

def analyze_go_binary_ghidra():
    """Ghidra script for Go binary analysis."""
    from ghidra.program.model.mem import MemoryAccessException

    program = getCurrentProgram()
    memory = program.getMemory()
    listing = program.getListing()

    print("[+] Go Binary Analysis Script")
    print(f"  Program: {program.getName()}")

    # Find pclntab
    pclntab_magics = [
        bytes([0xf0, 0xff, 0xff, 0xff]),  # Go 1.20+
        bytes([0xf1, 0xff, 0xff, 0xff]),  # Go 1.18-1.19
        bytes([0xfa, 0xff, 0xff, 0xff]),  # Go 1.16-1.17
        bytes([0xfb, 0xff, 0xff, 0xff]),  # Go 1.2-1.15
    ]

    for magic in pclntab_magics:
        addr = memory.findBytes(
            program.getMinAddress(), magic, None, True, None
        )
        if addr:
            print(f"[+] pclntab found at {addr}")
            # Create label
            program.getSymbolTable().createLabel(
                addr, "go_pclntab", None,
                ghidra.program.model.symbol.SourceType.ANALYSIS
            )
            break

    # Fix Go string definitions
    # Go strings are ptr+len, not null terminated
    print("[+] Fixing Go string references...")

    # Search for function names containing package paths
    symbol_table = program.getSymbolTable()
    func_count = 0
    for symbol in symbol_table.getAllSymbols(True):
        name = symbol.getName()
        if ('.' in name and
            any(pkg in name for pkg in
                ['main.', 'runtime.', 'net.', 'crypto.', 'os.'])):
            func_count += 1

    print(f"[+] Found {func_count} Go function symbols")


# Execute
analyze_go_binary_ghidra()

Validation Criteria

  • Go version and build information extracted from binary
  • pclntab located and parsed for function name recovery
  • Third-party dependencies identified revealing malware capabilities
  • Main package functions enumerated for targeted analysis
  • Network, crypto, and OS exec functions categorized
  • Ghidra analysis correctly labels Go runtime structures

References

Other files in this skill

assets/template.md (verbatim)

Go Malware Analysis Report

Sample Information

Field Value
SHA-256
File Size
Go Version
Architecture amd64 / arm64 / 386
Stripped Yes / No
Obfuscated Yes (garble) / No

Recovered Functions

Category Count Key Functions
main
networking
crypto
os/exec
third-party

Dependencies

Module Purpose

C2 Infrastructure

Indicator Type Value
URL / IP / Domain

Recommendations

  1. Block identified C2 infrastructure
  2. Create YARA rule for unique Go function signatures
  3. Monitor for similar Go binary compilation artifacts

references/api-reference.md (verbatim)

API Reference: Go Malware Analysis with Ghidra

Ghidra Go Analysis Setup

GoResolver Script (Volexity)

# Install GoResolver for stripped Go binary function recovery
git clone https://github.com/volexity/GoResolver
# Run against Ghidra project
analyzeHeadless /ghidra_projects MyProject -process go_malware.exe \
  -postScript GoResolver.java

Ghidra Built-in Go Support (10.3+)

File > Import > Select Go binary
Analysis > Auto Analyze (includes GolangAnalyzer)
Window > Function Tags > Filter "go."

Go Binary Characteristics

Build Info Magic

Offset in .go.buildinfo section: "\xff Go buildinf:"

gopclntab Magic Bytes

Go Version Magic
1.2-1.15 FB FF FF FF 00 00
1.16-1.17 FA FF FF FF 00 00
1.18-1.19 F0 FF FF FF 00 00
1.20+ F1 FF FF FF 00 00

String Format

Go strings are length-prefixed (not null-terminated):

struct GoString {
    char *ptr;      // pointer to string data
    int64 length;   // string length
};

Go-Specific Ghidra Scripts

GoReSym (Mandiant)

GoReSym -t -d -p /path/to/binary
# -t: Recover type information
# -d: Dump function metadata
# -p: Print package listing

redress (Go Reverse Engineering)

redress -src binary.exe           # Reconstruct source tree
redress -pkg binary.exe           # List packages
redress -type binary.exe          # Type information
redress -string binary.exe        # Go string extraction
redress -interface binary.exe     # Interface types

Go Obfuscation Tools

Tool Technique Detection
garble Function name hashing, literal obfuscation Hash-like symbols, missing debug info
gobfuscate Package/function renaming Random 8-char names
go-strip Symbol table removal Missing gopclntab entries

Common Go Malware Families

Family Type Notable Packages
Sliver C2 implant protobuf, grpc, mtls
Merlin C2 agent http2, jose, websocket
Sunlogin/Cobalt RAT screenshot, clipboard, keylog
BianLian Ransomware crypto/aes, filepath.Walk
Royal Ransomware goroutine-based parallel encryption

Key Ghidra Analysis Steps

1. Search > For Strings > "go1." (version identification)
2. Search > For Bytes > FB FF FF FF (gopclntab)
3. Symbol Table > Filter "main." (entry points)
4. Navigation > Go To "runtime.main" (program start)
5. Decompiler > Check goroutine spawns (runtime.newproc)
6. Data Types > Apply GoString struct to string references

references/standards.md (verbatim)

Go Binary Analysis Standards

Go Binary Structure

Component Description Location
pclntab PC-to-function mapping table .gopclntab or .text
moduledata Runtime metadata structure .noptrdata
itab Interface method tables .rodata
buildinfo Go version and module info .go.buildinfo
typelinks Type descriptor table .rodata

pclntab Magic Bytes by Go Version

Magic Go Version
0xFBFFFFFF 1.2 - 1.15
0xFAFFFFFF 1.16 - 1.17
0xF1FFFFFF 1.18 - 1.19
0xF0FFFFFF 1.20+

Common Go Malware Families

  • Sliver C2 implant
  • Geacon (Go Cobalt Strike beacon)
  • GoBruteforcer
  • Kaiji botnet
  • Chaos botnet (Go-based)

References

references/workflows.md (verbatim)

Go Malware Analysis Workflows

Workflow 1: Stripped Binary Recovery

[Stripped Go Binary] --> [Find pclntab] --> [Recover Function Names]
                                                    |
                                                    v
                                           [Apply GoResolver] --> [Deobfuscate Names]
                                                                        |
                                                                        v
                                                               [Categorize Functions]

Workflow 2: Full Ghidra Analysis

[Go Binary] --> [Import to Ghidra] --> [Run Go Analysis Scripts]
                                              |
                                              v
                                    [Fix String References]
                                              |
                                              v
                                    [Identify main Package]
                                              |
                                              v
                                    [Analyze C2/Network Logic]

Workflow 3: Dependency-Based Capability Assessment

[Go Binary] --> [Extract Module Info] --> [List Dependencies]
                                                |
                                                v
                                       [Map to Capabilities]
                                                |
                                                v
                                       [Prioritize Analysis]

Back to mukul975/Anthropic-Cybersecurity-Skills (817 security skills) or Agent skills.