بنقرة واحدة
analyzing-golang-malware-with-ghidra
使用 Ghidra 及专用脚本对 Go 编译的恶意软件进行逆向工程,包括函数恢复、字符串提取和去符号表 Go 二进制文件的类型重建。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
使用 Ghidra 及专用脚本对 Go 编译的恶意软件进行逆向工程,包括函数恢复、字符串提取和去符号表 Go 二进制文件的类型重建。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
通过分析 Zeek dns.log 中的高熵子域名查询、超量查询量、超长查询长度以及异常 DNS 记录类型,检测 DNS 隧道和数据外泄中的隐蔽通道通信。适用于:当需要狩猎基于 DNS 的 C2 或数据外泄通道、调查异常 DNS 查询模式、或响应涉及 DNS 隧道工具(iodine、dnscat2、DNSExfiltrator)的威胁情报时使用。
实施 Google 的 BeyondCorp 零信任访问模型,通过 IAP、Access Context Manager 和 Chrome Enterprise Premium,消除网络边界的隐式信任,强制执行基于身份的访问控制,实现无 VPN 的安全应用访问。适用于将传统 VPN 替换为零信任架构、部署 Identity-Aware Proxy、配置设备信任策略、或为远程办公实施上下文感知访问控制时使用。
在授权的安全评估过程中,使用 Burp Suite 的扫描器、Intruder 和 Repeater 工具识别和验证跨站脚本(XSS)漏洞。适用于 Web 应用渗透测试中检测反射型、存储型和 DOM 型 XSS,验证自动化扫描器报告的 XSS 发现,以及评估 CSP 和 XSS 过滤器的有效性时使用。
攻击活动溯源归因分析涉及系统性地评估证据,以确定哪个威胁行为者或组织对某次网络行动负责。本技能涵盖使用 Diamond Model 和 ACH(竞争假设分析)收集并加权溯源归因指标、分析基础设施重叠、TTP 一致性、恶意软件代码相似性、操作时序模式和语言痕迹,以构建置信度加权的溯源归因评估。
从 PE 文件和内存转储中提取并分析 Cobalt Strike beacon 配置,以识别 C2 基础设施、Malleable C2 配置文件和攻击者操作惯例。
MITRE ATT&CK 是基于真实世界观察的全球可访问的对手战术、技术和过程(TTP)知识库。本技能涵盖系统性地将威胁行为者行为映射到 ATT&CK 框架、使用 ATT&CK Navigator 构建技术覆盖热力图、识别检测差距,以及生成将观察到的 IOC 关联到 Enterprise、Mobile 和 ICS 矩阵中特定对手技术的可执行情报报告。
| name | analyzing-golang-malware-with-ghidra |
| description | 使用 Ghidra 及专用脚本对 Go 编译的恶意软件进行逆向工程,包括函数恢复、字符串提取和去符号表 Go 二进制文件的类型重建。 |
| 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 |
Go(Golang)因其跨平台编译能力、生成自包含二进制文件的静态链接以及逆向工程的复杂性,成为恶意软件作者的热门语言。Go 二进制文件包含整个运行时、标准库和所有依赖项的静态链接,产生大型二进制文件(通常 5-15MB),包含数千个函数。Ghidra 在处理 Go 特有的字符串格式(非空终止符)、去符号的函数名和 goroutine 并发模式时存在困难。Volexity 开发的 GoResolver 等专用工具使用控制流图相似性在去符号或混淆的 Go 二进制文件中自动去混淆并恢复函数名。
Go 二进制文件在 pclntab(PC 行表)结构中嵌入了丰富的元数据,将程序计数器映射到函数名、源文件和行号。即使去符号表的二进制文件也保留此元数据。moduledata 结构包含指向类型信息、itab(接口表)和 pclntab 本身的指针。Go 字符串以指针-长度对的形式存储,而非以空字符结尾的 C 字符串。
尽管去除了符号表,Go 二进制文件仍在 pclntab 中保留函数名。然而,garble 等混淆工具会将函数重命名为随机字符串。GoResolver 通过计算混淆函数的控制流图签名,并与已知 Go 标准库和第三方包函数的数据库进行匹配来解决此问题。
Go 的依赖管理将模块路径和版本字符串嵌入二进制文件。提取这些信息可揭示恶意软件的第三方依赖(HTTP 库、加密包、C2 框架),在不进行完整逆向工程的情况下了解其能力。
#!/usr/bin/env python3
"""分析 Go 二进制文件元数据用于恶意软件分析。"""
import struct
import sys
import re
def find_go_build_info(data):
"""从二进制文件提取 Go 构建信息。"""
# Go buildinfo 魔数:\xff Go buildinf:
magic = b'\xff Go buildinf:'
offset = data.find(magic)
if offset == -1:
return None
print(f"[+] Go 构建信息位于偏移 0x{offset:x}")
# 提取附近的 Go 版本字符串
go_version = re.search(rb'go\d+\.\d+(?:\.\d+)?', data[offset:offset+256])
if go_version:
print(f" Go 版本:{go_version.group().decode()}")
return offset
def find_pclntab(data):
"""定位 pclntab(PC 行表)结构。"""
# pclntab 魔数字节随 Go 版本而变化
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 位于 0x{offset:x}({version})")
return offset, version
return None, None
def extract_function_names(data, pclntab_offset):
"""从 pclntab 提取函数名。"""
if pclntab_offset is None:
return []
functions = []
# 函数名字符串遵循特定模式
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):
"""提取 Go 风格字符串(指针+长度对)。"""
# Go 字符串不以空字符结尾;提取可读序列
strings = []
ascii_pattern = re.compile(rb'[\x20-\x7e]{10,}')
for match in ascii_pattern.finditer(data):
s = match.group().decode('ascii')
# 过滤出有趣的恶意软件字符串
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):
"""从二进制文件提取 Go 模块依赖项。"""
deps = []
# 模块路径遵循模式: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):
"""对 Go 恶意软件二进制文件进行完整分析。"""
with open(filepath, 'rb') as f:
data = f.read()
print(f"[+] 正在分析 Go 二进制文件:{filepath}")
print(f" 文件大小:{len(data):,} 字节")
print("=" * 60)
# 构建信息
find_go_build_info(data)
# pclntab
pclntab_offset, go_version = find_pclntab(data)
# 函数
functions = extract_function_names(data, pclntab_offset)
print(f"\n[+] 恢复了 {len(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)} 个函数):")
for fn in funcs[:10]:
print(f" {fn}")
# 依赖项
deps = extract_dependencies(data)
print(f"\n[+] 依赖项({len(deps)} 个):")
for dep in deps[:20]:
print(f" {dep}")
# 可疑字符串
sus_strings = extract_go_strings(data)
print(f"\n[+] 可疑字符串({len(sus_strings)} 个):")
for s in sus_strings[:20]:
print(f" {s}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"用法:{sys.argv[0]} <go_binary>")
sys.exit(1)
analyze_go_binary(sys.argv[1])
# Ghidra 脚本(在 Ghidra 的脚本管理器中运行)
# 保存为 AnalyzeGoBinary.py 到 Ghidra scripts 目录
# @category MalwareAnalysis
# @description 分析 Go 二进制结构并恢复元数据
def analyze_go_binary_ghidra():
"""用于 Go 二进制分析的 Ghidra 脚本。"""
from ghidra.program.model.mem import MemoryAccessException
program = getCurrentProgram()
memory = program.getMemory()
listing = program.getListing()
print("[+] Go 二进制分析脚本")
print(f" 程序:{program.getName()}")
# 查找 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 位于 {addr}")
# 创建标签
program.getSymbolTable().createLabel(
addr, "go_pclntab", None,
ghidra.program.model.symbol.SourceType.ANALYSIS
)
break
# 修复 Go 字符串定义
# Go 字符串是 ptr+len,不是空终止
print("[+] 正在修复 Go 字符串引用...")
# 搜索包含包路径的函数名
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"[+] 找到 {func_count} 个 Go 函数符号")
# 执行
analyze_go_binary_ghidra()