analyzing-golang-malware-with-ghidra — Claude Code skill: Go malware
Walks an agent through Go binary analysis in Ghidra: buildinfo, pclntab, function names, dependencies. Useful when the sample is Go-compiled.
npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill analyzing-golang-malware-with-ghidra -a claude-codeWhat analyzing-golang-malware-with-ghidra does
The skill lays out a procedure for reverse engineering Go malware in Ghidra. Go binaries statically link the runtime, the standard library and every dependency, so you get multi-megabyte files with thousands of functions, and Ghidra handles that poorly on its own. The skill explains where the metadata sits and how to pull it out.
Inside are steps for parsing pclntab and moduledata, locating buildinfo by its magic bytes, and recovering function names from stripped builds. Garble-packed samples go through GoResolver, which computes control-flow graph signatures and matches them against a database of known functions. There is also a pass over embedded module paths and versions, so third-party packages tell you what the sample can do without a full reverse.
You need Ghidra 11.0+ with JDK 17+, the GoResolver plugin, the Go Reverse Engineering Tool Kit and Python 3.9+ for the helper scripts. Familiarity with Go runtime internals — goroutines, channels, interfaces — matters here, because the pclntab and itab steps assume it rather than teach it.
What it helps with
- recover function names from a stripped Go binary
- locate buildinfo and identify the Go version used to compile
- deobfuscate garble-packed functions via CFG signature matching
- list third-party dependencies and module versions
- separate Go pointer-length strings from C strings in Ghidra
Example prompts for the agent
- analyze this Go binary in Ghidra: find pclntab and pull out function names
- this sample is garble-packed — recover the names with GoResolver
- extract module paths and dependency versions from the binary
How to install analyzing-golang-malware-with-ghidra
1Skills CLI (Vercel)
npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill analyzing-golang-malware-with-ghidra -a claude-code2Manually: put the files in place
~/.claude/skills/analyzing-golang-malware-with-ghidra/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/analyzing-golang-malware-with-ghidra/
1Skills CLI (Vercel)
npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill analyzing-golang-malware-with-ghidra -a codex2Manually: put the files in place
.agents/skills/analyzing-golang-malware-with-ghidra/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill analyzing-golang-malware-with-ghidra -a cursor2Manually: put the files in place
.cursor/skills/analyzing-golang-malware-with-ghidra/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install mukul975/Anthropic-Cybersecurity-Skills analyzing-golang-malware-with-ghidra2Manually: put the files in place
.github/skills/analyzing-golang-malware-with-ghidra/SKILL.md1Skills CLI (Vercel)
npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill analyzing-golang-malware-with-ghidra -a gemini-cli2Platform CLI
gemini skills install https://github.com/mukul975/Anthropic-Cybersecurity-Skills --path skills/analyzing-golang-malware-with-ghidraManually: put the files in place
.devin/skills/analyzing-golang-malware-with-ghidra/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill analyzing-golang-malware-with-ghidra -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about analyzing-golang-malware-with-ghidra
How do I install analyzing-golang-malware-with-ghidra in Claude?
Run npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill analyzing-golang-malware-with-ghidra -a claude-code. The skill file then lands at ~/.claude/skills/analyzing-golang-malware-with-ghidra/SKILL.md.
What does analyzing-golang-malware-with-ghidra do?
It guides an agent through Go malware reverse engineering in Ghidra: parsing buildinfo and pclntab, recovering function names in stripped or obfuscated builds, and extracting embedded modules and types.
What do I need before using it?
Ghidra 11.0+ with JDK 17+, the GoResolver plugin for function name recovery, the Go Reverse Engineering Tool Kit, and Python 3.9+ for the helper scripts.
Source text
SKILL.md · Apache-2.0
---
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
```python
#!/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
```python
# 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
- [CUJO AI - Reverse Engineering Go Binaries with Ghidra](https://cujo.com/blog/reverse-engineering-go-binaries-with-ghidra/)
- [Volexity GoResolver](https://www.volexity.com/blog/2025/04/01/goresolver-using-control-flow-graph-similarity-to-deobfuscate-golang-binaries-automatically/)
- [Go Reverse Engineering Tool Kit](https://go-re.tk/about/)
- [SentinelOne AlphaGolang](https://www.sentinelone.com/labs/alphagolang-a-step-by-step-go-malware-reversing-methodology-for-ida-pro/)
- [Go Binary Reversing Notes](https://gist.github.com/0xdevalias/4e430914124c3fd2c51cb7ac2801acba)
© mahipal · Apache-2.0 · mukul975/Anthropic-Cybersecurity-Skills