
Analyzing Golang Malware With Ghidra
- 330 installs
- 27.3k repo stars
- Updated August 2, 2026
- mukul975/anthropic-cybersecurity-skills
Analyzing Golang Malware with Ghidra is an agent skill that structures Go binary reverse-engineering reports with recovered functions, C2 indicators, and remediation recommendations.
About
Analyzing Golang Malware with Ghidra is a security-focused agent skill for builders and analysts who encounter unknown Go executables in incidents, vendor drops, or compromised environments. It standardizes how you capture sample metadata, recover categorized functions despite stripping or garble obfuscation, map module dependencies, and tabulate command-and-control indicators. The output follows a fixed report skeleton so you can hand findings to blocking, detection, and monitoring work without reinventing sections each time. It assumes comfort with Ghidra and offensive-security context; it is not a substitute for legal authorization or a full SOC playbook. Solo indie builders might use it rarely—mainly when investigating a compromised dependency, a suspicious CLI distributed in your ecosystem, or learning malware analysis—but the primary audience is security-minded operators shipping or operating software who must document Go-specific binary behavior credibly.
- Report template for SHA-256, Go version, arch, stripped, and garble obfuscation flags
- Function recovery buckets: main, networking, crypto, os/exec, and third-party modules
- C2 infrastructure table for URLs, IPs, and domains extracted from the sample
- Dependency module mapping and actionable blocklist plus YARA guidance
- Oriented to amd64, arm64, and 386 Go malware artifacts
Analyzing Golang Malware With Ghidra by the numbers
- 330 all-time installs (skills.sh)
- +23 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #603 of 2,203 Security skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill analyzing-golang-malware-with-ghidraAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 330 |
|---|---|
| repo stars | ★ 27.3k |
| Security audit | 1 / 3 scanners passed |
| Last updated | August 2, 2026 |
| Repository | mukul975/anthropic-cybersecurity-skills ↗ |
What it does
Reverse-engineer suspicious Go binaries in Ghidra and document C2 indicators, dependencies, and defensive recommendations.
Who is it for?
Security-literate developers or small teams triaging Go malware samples in Ghidra during incident response or supply-chain review.
Skip if: Beginners seeking automatic one-click remediation, or founders who only need routine dependency CVE scanning without reverse engineering.
When should I use this skill?
You are reverse-engineering a Go malware or suspicious Go binary in Ghidra and need a standardized analysis and C2 reporting format.
What you get
You produce a completed Go malware analysis report with indicator tables and prioritized recommendations to block C2, draft YARA, and watch for similar build artifacts.
- Go malware analysis report with sample metadata
- C2 and dependency indicator tables
- Blocking, YARA, and monitoring recommendations
By the numbers
- 5 function recovery categories in the report template (main, networking, crypto, os/exec, third-party)
Files
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
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
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
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 referencesGo 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
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]#!/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)}")
#!/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()
Related skills
How it compares
Use for Ghidra-centric Go malware documentation—not for generic SAST scanners or application penetration-test checklists.
FAQ
Who is analyzing-golang-malware-with-ghidra for?
Operators and security-curious developers who analyze Go executables in Ghidra and need a repeatable report format for C2 and function recovery.
When should I use analyzing-golang-malware-with-ghidra?
During ship/security reviews of suspicious binaries, after a supply-chain scare, or in operate/incident workflows when documenting Go malware for blocking and detection.
Is analyzing-golang-malware-with-ghidra safe to install?
The skill describes analysis of potentially malicious samples; only run in isolated lab environments and review the Security Audits panel on this Prism page before install.