用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/killvxk/cybersecurity-skills-zh --skill analyzing-golang-malware-with-ghidra命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| 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}()")
offset, version
,
():
pclntab_offset :
[]
functions = []
func_pattern = re.(
,
)
func_pattern.finditer(data):
name = .group().decode(, errors=)
(name) > (name) < :
functions.append(name)
((functions))
():
strings = []
ascii_pattern = re.()
ascii_pattern.finditer(data):
s = .group().decode()
interesting = [
, , , , ,
, , , , ,
, , , , ,
, , , , ,
, , , ,
]
(kw s.lower() kw interesting):
strings.append(s)
strings
():
deps = []
dep_pattern = re.(
)
dep_pattern.finditer(data):
dep = .group().decode(, errors=)
deps.append(dep)
unique_deps = ((deps))
unique_deps
():
(filepath, ) f:
data = f.read()
()
()
( * )
find_go_build_info(data)
pclntab_offset, go_version = find_pclntab(data)
functions = extract_function_names(data, pclntab_offset)
()
categories = {
: [], : [], : [],
: [], : [], : [],
}
f functions:
f f.lower():
categories[].append(f)
f:
categories[].append(f)
f f:
categories[].append(f)
f f:
categories[].append(f)
f.startswith():
categories[].append(f)
f f:
categories[].append(f)
cat, funcs categories.items():
funcs:
()
fn funcs[:]:
()
deps = extract_dependencies(data)
()
dep deps[:]:
()
sus_strings = extract_go_strings(data)
()
s sus_strings[:]:
()
__name__ == :
(sys.argv) < :
()
sys.exit()
analyze_go_binary(sys.argv[])
# 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, , ,
ghidra.program.model.symbol.SourceType.ANALYSIS
)
()
symbol_table = program.getSymbolTable()
func_count =
symbol symbol_table.getAllSymbols():
name = symbol.getName()
( name
(pkg name pkg
[, , , , ])):
func_count +=
()
analyze_go_binary_ghidra()