npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
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
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md2.5 KB
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.javaGhidra 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 listingredress (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 typesGo 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 referencesstandards.md0.9 KB
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
workflows.md1.6 KB
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]Scripts 2
agent.py8.9 KB
#!/usr/bin/env python3
"""Go malware analysis agent for Ghidra-assisted reverse engineering.
Analyzes Go binaries to extract function names, strings, build metadata,
package information, and detects common Go malware characteristics.
"""
import os
import sys
import json
import hashlib
import re
import math
from collections import Counter
def compute_hash(filepath):
"""Compute SHA-256 hash of file."""
sha256 = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""):
sha256.update(chunk)
return sha256.hexdigest()
def shannon_entropy(data):
"""Calculate Shannon entropy."""
if not data:
return 0.0
freq = Counter(data)
length = len(data)
return -sum((c / length) * math.log2(c / length) for c in freq.values())
def detect_go_binary(filepath):
"""Detect if a binary is compiled with Go and extract version info."""
with open(filepath, "rb") as f:
data = f.read()
indicators = {
"is_go_binary": False,
"go_version": None,
"go_buildinfo": False,
"gopclntab_found": False,
}
# Go build info magic
buildinfo_magic = b"\xff Go buildinf:"
offset = data.find(buildinfo_magic)
if offset != -1:
indicators["is_go_binary"] = True
indicators["go_buildinfo"] = True
# Go version string
version_pattern = rb"go(\d+\.\d+(?:\.\d+)?)"
matches = re.findall(version_pattern, data)
if matches:
indicators["is_go_binary"] = True
versions = sorted(set(m.decode() for m in matches))
indicators["go_version"] = versions[-1] if versions else None
# gopclntab (Go PC line table) magic bytes
gopclntab_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"\xf0\xff\xff\xff\x00\x00", # Go 1.18+
b"\xf1\xff\xff\xff\x00\x00", # Go 1.20+
]
for magic in gopclntab_magics:
if magic in data:
indicators["gopclntab_found"] = True
indicators["is_go_binary"] = True
break
# Runtime strings
go_strings = [b"runtime.main", b"runtime.goexit", b"runtime.gopanic",
b"runtime.newproc", b"GOROOT", b"GOPATH"]
found_runtime = sum(1 for s in go_strings if s in data)
if found_runtime >= 2:
indicators["is_go_binary"] = True
indicators["runtime_strings_found"] = found_runtime
return indicators
def extract_go_strings(filepath, min_length=6):
"""Extract Go-style strings (length-prefixed, not null-terminated)."""
with open(filepath, "rb") as f:
data = f.read()
# Standard ASCII string extraction
ascii_pattern = re.compile(rb"[\x20-\x7e]{%d,}" % min_length)
strings = [m.group().decode("ascii", errors="replace") for m in ascii_pattern.finditer(data)]
return strings
def extract_go_packages(strings_list):
"""Identify Go packages from extracted strings."""
packages = set()
pkg_pattern = re.compile(r"^([a-zA-Z0-9_]+(?:/[a-zA-Z0-9_.-]+)+)\.")
for s in strings_list:
match = pkg_pattern.match(s)
if match:
packages.add(match.group(1))
# Also look for known Go import paths
for s in strings_list:
if s.startswith("github.com/") or s.startswith("golang.org/"):
parts = s.split("/")
if len(parts) >= 3:
packages.add("/".join(parts[:3]))
return sorted(packages)
SUSPICIOUS_GO_PACKAGES = {
"github.com/kbinani/screenshot": "Screen capture capability",
"github.com/atotto/clipboard": "Clipboard access",
"github.com/go-vgo/robotgo": "Desktop automation / keylogging",
"github.com/miekg/dns": "Custom DNS resolution (C2/tunneling)",
"golang.org/x/crypto/ssh": "SSH client (lateral movement)",
"github.com/shirou/gopsutil": "System enumeration",
"github.com/mitchellh/go-ps": "Process listing",
"github.com/gobuffalo/packr": "Binary resource embedding",
"github.com/Ne0nd0g/merlin": "Merlin C2 agent",
"github.com/BishopFox/sliver": "Sliver C2 framework",
"github.com/traefik/yaegi": "Go interpreter (dynamic execution)",
}
def detect_suspicious_packages(packages):
"""Flag suspicious Go packages commonly used in malware."""
findings = []
for pkg in packages:
for sus_pkg, description in SUSPICIOUS_GO_PACKAGES.items():
if sus_pkg in pkg:
findings.append({"package": pkg, "concern": description})
return findings
def analyze_sections(filepath):
"""Analyze PE/ELF sections for Go binary characteristics."""
with open(filepath, "rb") as f:
magic = f.read(4)
f.seek(0)
data = f.read()
sections = []
if magic[:2] == b"MZ": # PE
try:
import pefile
pe = pefile.PE(data=data)
for section in pe.sections:
name = section.Name.rstrip(b"\x00").decode("ascii", errors="replace")
entropy = section.get_entropy()
sections.append({
"name": name, "virtual_size": section.Misc_VirtualSize,
"raw_size": section.SizeOfRawData, "entropy": round(entropy, 3),
})
pe.close()
except ImportError:
sections.append({"note": "pefile not installed"})
elif magic[:4] == b"\x7fELF":
try:
from elftools.elf.elffile import ELFFile
from io import BytesIO
elf = ELFFile(BytesIO(data))
for section in elf.iter_sections():
sec_data = section.data() if section.header.sh_size > 0 else b""
entropy = shannon_entropy(sec_data) if sec_data else 0
sections.append({
"name": section.name, "size": section.header.sh_size,
"entropy": round(entropy, 3), "type": section.header.sh_type,
})
except ImportError:
sections.append({"note": "pyelftools not installed"})
return sections
def detect_obfuscation(go_info, strings_list):
"""Detect Go binary obfuscation (garble, gobfuscate)."""
indicators = {"obfuscated": False, "techniques": []}
# Garble replaces function names with hashes
hash_names = sum(1 for s in strings_list if re.match(r"^[a-f0-9]{16,}$", s))
if hash_names > 20:
indicators["obfuscated"] = True
indicators["techniques"].append("Possible garble obfuscation (hash-like function names)")
# Missing gopclntab suggests stripping
if not go_info.get("gopclntab_found"):
indicators["techniques"].append("gopclntab not found - may be stripped or modified")
# Low runtime string count
if go_info.get("runtime_strings_found", 0) < 2:
indicators["obfuscated"] = True
indicators["techniques"].append("Low Go runtime string count - possible obfuscation")
return indicators
def generate_report(filepath):
"""Generate comprehensive Go malware analysis report."""
report = {
"file": filepath,
"sha256": compute_hash(filepath),
"size": os.path.getsize(filepath),
}
go_info = detect_go_binary(filepath)
report["go_detection"] = go_info
if not go_info["is_go_binary"]:
report["conclusion"] = "Not identified as a Go binary"
return report
strings_list = extract_go_strings(filepath)
report["total_strings"] = len(strings_list)
packages = extract_go_packages(strings_list)
report["packages"] = packages[:50]
suspicious = detect_suspicious_packages(packages)
report["suspicious_packages"] = suspicious
sections = analyze_sections(filepath)
report["sections"] = sections
obfuscation = detect_obfuscation(go_info, strings_list)
report["obfuscation"] = obfuscation
return report
if __name__ == "__main__":
print("=" * 60)
print("Go Malware Analysis Agent (Ghidra-assisted)")
print("Go binary detection, package extraction, obfuscation detection")
print("=" * 60)
target = sys.argv[1] if len(sys.argv) > 1 else None
if not target or not os.path.exists(target):
print("\n[DEMO] Usage: python agent.py <go_binary>")
sys.exit(0)
report = generate_report(target)
go = report.get("go_detection", {})
print(f"\n[*] File: {target}")
print(f"[*] SHA-256: {report['sha256']}")
print(f"[*] Go binary: {go.get('is_go_binary', False)}")
print(f"[*] Go version: {go.get('go_version', 'unknown')}")
print(f"[*] Strings: {report.get('total_strings', 0)}")
print("\n--- Packages ---")
for pkg in report.get("packages", [])[:15]:
print(f" {pkg}")
print("\n--- Suspicious Packages ---")
for s in report.get("suspicious_packages", []):
print(f" [!] {s['package']}: {s['concern']}")
print("\n--- Obfuscation ---")
obf = report.get("obfuscation", {})
print(f" Obfuscated: {obf.get('obfuscated', False)}")
for t in obf.get("techniques", []):
print(f" {t}")
print(f"\n{json.dumps(report, indent=2, default=str)}")
process.py4.6 KB
#!/usr/bin/env python3
"""
Go Malware Binary Analyzer
Extracts metadata, function names, dependencies, and suspicious
indicators from Go-compiled malware binaries.
Usage:
python process.py --file malware.exe --output report.json
"""
import argparse
import json
import re
import struct
import sys
from pathlib import Path
PCLNTAB_MAGICS = {
b'\xf0\xff\xff\xff': "Go 1.20+",
b'\xf1\xff\xff\xff': "Go 1.18-1.19",
b'\xfa\xff\xff\xff': "Go 1.16-1.17",
b'\xfb\xff\xff\xff': "Go 1.2-1.15",
}
def find_pclntab(data):
for magic, version in PCLNTAB_MAGICS.items():
offset = data.find(magic)
if offset != -1:
return offset, version
return None, None
def extract_go_version(data):
match = re.search(rb'go(\d+\.\d+(?:\.\d+)?)', data)
return match.group(1).decode() if match else "unknown"
def extract_functions(data):
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|gopkg\.in)[/\.][\w/.]+)'
)
functions = set()
for match in func_pattern.finditer(data):
name = match.group(1).decode('utf-8', errors='replace')
if 4 < len(name) < 200:
functions.add(name)
return sorted(functions)
def extract_dependencies(data):
dep_pattern = re.compile(
rb'((?:github\.com|gitlab\.com|golang\.org|gopkg\.in|'
rb'go\.etcd\.io|google\.golang\.org)/[\w./-]{5,80})'
)
deps = set()
for match in dep_pattern.finditer(data):
dep = match.group(1).decode('utf-8', errors='replace')
# Clean up trailing artifacts
dep = dep.rstrip('/.')
deps.add(dep)
return sorted(deps)
def extract_suspicious_strings(data):
interesting_patterns = [
rb'https?://[\w./:?&=-]+',
rb'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?::\d+)?',
rb'(?:cmd|powershell|bash|sh)(?:\.exe)?',
rb'(?:HKLM|HKCU)\\[^\x00]+',
rb'/etc/(?:passwd|shadow|crontab)',
]
results = {}
for pattern in interesting_patterns:
matches = re.findall(pattern, data)
if matches:
decoded = [m.decode('utf-8', errors='replace') for m in matches]
results[pattern.decode('utf-8', errors='replace')] = list(set(decoded))
return results
def categorize_functions(functions):
categories = {
"main_logic": [],
"networking": [],
"cryptography": [],
"os_execution": [],
"file_operations": [],
"third_party": [],
"runtime": [],
}
for func in functions:
fl = func.lower()
if func.startswith('main.'):
categories["main_logic"].append(func)
elif any(x in fl for x in ['net/', 'http', 'tcp', 'udp', 'dns']):
categories["networking"].append(func)
elif 'crypto' in fl:
categories["cryptography"].append(func)
elif any(x in fl for x in ['os/exec', 'syscall']):
categories["os_execution"].append(func)
elif any(x in fl for x in ['os.', 'io/', 'ioutil']):
categories["file_operations"].append(func)
elif any(x in fl for x in ['github.com', 'golang.org', 'gopkg.in']):
categories["third_party"].append(func)
elif func.startswith('runtime.'):
categories["runtime"].append(func)
return {k: v for k, v in categories.items() if v}
def analyze(filepath):
with open(filepath, 'rb') as f:
data = f.read()
report = {
"file": str(filepath),
"size": len(data),
"go_version": extract_go_version(data),
}
pclntab_offset, pclntab_version = find_pclntab(data)
report["pclntab"] = {
"offset": f"0x{pclntab_offset:x}" if pclntab_offset else None,
"version": pclntab_version,
}
functions = extract_functions(data)
report["total_functions"] = len(functions)
report["function_categories"] = categorize_functions(functions)
report["dependencies"] = extract_dependencies(data)
report["suspicious_strings"] = extract_suspicious_strings(data)
return report
def main():
parser = argparse.ArgumentParser(description="Go Malware Analyzer")
parser.add_argument("--file", required=True, help="Go binary to analyze")
parser.add_argument("--output", help="Output JSON report")
args = parser.parse_args()
report = analyze(args.file)
print(json.dumps(report, indent=2))
if args.output:
with open(args.output, 'w') as f:
json.dump(report, f, indent=2)
print(f"\n[+] Report saved to {args.output}")
if __name__ == "__main__":
main()