Communitygithub.com

使用Ghidra分析Golang恶意软件

通过解析Go构建信息,在Ghidra中逆向分析Go编译的恶意软件。

使用Ghidra分析Golang恶意软件 是什么?

该技能提供了一套在Ghidra中逆向分析Go编译恶意软件的结构化方法。Go语言因其交叉编译能力、静态链接(生成独立二进制文件)以及逆向工程复杂性而受到恶意软件作者的青睐。Go二进制文件包含运行时、标准库和所有依赖项的静态链接,导致文件体积庞大(通常5-15MB)并包含数千个函数。Ghidra在处理Go特有的字符串格式(非空终止)、被剥离的函数名和goroutine并发模式时存在困难。该技能利用GoResolver等工具,通过控制流图相似性自动去混淆并恢复被剥离或混淆的Go二进制文件中的函数名。它支持Ghidra 11.0+(JDK 17+)、GoResolver插件、Go逆向工程工具包(go-re.tk)等平台。工作流程包括:初始二进制分析(提取Go构建信息、pclntab、函数名、依赖项和可疑字符串)、Ghidra分析脚本(定位pclntab、修复Go字符串引用、分类函数),以及验证标准(提取Go版本、识别依赖项、枚举主要包函数)。该技能通过解析pclntab结构和模组数据,显著提升了Ghidra对Go恶意软件的分析能力。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/analyzing-golang-malware-with-ghidra

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

使用Ghidra分析Golang恶意软件 是做什么的?

概述

Go(Golang)因其交叉编译能力、产生独立二进制文件的静态链接特性以及给逆向工程带来的复杂性,已成为恶意软件作者的热门语言。Go二进制文件包含整个运行时、标准库和所有依赖项的静态链接,导致二进制文件体积庞大(通常5-15MB)并包含数千个函数。Ghidra在处理Go特有的字符串格式(非空终止)、剥离的函数名和goroutine并发模式时存在困难。GoResolver(Volexity,2025)等专业工具利用控制流图相似性自动去混淆并恢复被剥离或混淆的Go二进制文件中的函数名。

使用时机

  • 当调查需要使用Ghidra分析Golang恶意软件的安全事件时
  • 当为此领域构建检测规则或威胁狩猎查询时
  • 当SOC分析师需要针对此类分析的结构化流程时
  • 当验证相关攻击技术的安全监控覆盖范围时

前提条件

  • Ghidra 11.0+,配备JDK 17+
  • GoResolver插件(用于函数名恢复)
  • Go Reverse Engineering Tool Kit (go-re.tk)
  • Python 3.9+(用于辅助脚本)
  • 理解Go运行时内部机制(goroutines、channels、interfaces)
  • 熟悉Go二进制结构(pclntab、moduledata、itab)

关键概念

Go二进制结构

Go二进制文件在pclntab(PC行表)结构中嵌入了丰富的元数据,该结构将程序计数器映射到函数名、源文件和行号。即使是被剥离的二进制文件也会保留这些元数据。moduledata结构包含指向类型信息、itab(接口表)和pclntab本身的指针。Go字符串存储为指针-长度对,而不是以空字符结尾的C字符串。

剥离二进制文件中的函数恢复

尽管符号表被剥离,Go二进制文件仍在pclntab中保留了函数名。然而,像garble这样的混淆工具会将函数重命名为随机字符串。GoResolver通过计算混淆函数的控制流图签名,并将其与已知Go标准库和第三方包函数的数据库进行匹配来解决此问题。

Crate/依赖项提取

Go的依赖管理在二进制文件中嵌入了模块路径和版本字符串。提取这些信息可以揭示恶意软件的第三方依赖项(HTTP库、加密包、C2框架),从而在不进行完整逆向工程的情况下洞察其能力。

工作流程

步骤1:初始二进制分析

#!/usr/bin/env python3
"""用于恶意软件分析的Go二进制元数据分析。"""
import struct
import sys
import re


def find_go_build_info(data):
    """从二进制文件中提取Go构建信息。"""
    # Go buildinfo magic: \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])

步骤2:Ghidra分析脚本

# Ghidra脚本(在Ghidra的脚本管理器中运行)
# 保存为AnalyzeGoBinary.py到Ghidra脚本目录

# @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()

验证标准

  • 从二进制文件中提取Go版本和构建信息
  • 定位并解析pclntab以恢复函数名
  • 识别第三方依赖项,揭示恶意软件能力
  • 枚举主包函数以进行针对性分析
  • 分类网络、加密和OS执行函数
  • Ghidra分析正确标记Go运行时结构

参考文献

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

abusing-dpapi-for-credential-access

Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys) online or offline using SharpDPAPI, SharpChrome, Mimikatz, or Impacket

abusing-shadow-credentials-for-privesc

Take over Active Directory accounts by writing attacker-controlled public keys to msDS-KeyCredentialLink (Shadow Credentials) with pyWhisker, Whisker, or Certipy, then authenticate via PKINIT to recover the target

achieving-cmmc-level-2-compliance

>-

acquiring-disk-image-with-dd-and-dcfldd

Create forensically sound bit-for-bit disk images with dd or dcfldd on a Linux forensic workstation, preserving evidence integrity through hash verification (MD5/SHA) during acquisition. Use when imaging a suspect drive, USB device, or memory card for investigation, preserving volatile disk evidence during incident response, or producing a verified copy for legal or law-enforcement proceedings before any destructive analysis.

analyzing-active-directory-acl-abuse

Detect dangerous ACL misconfigurations in Active Directory using ldap3

analyzing-android-malware-with-apktool

Perform static analysis of Android APK malware using apktool for resource decompilation, jadx for Java source recovery, and androguard for manifest inspection, dangerous permission-combination detection, and identification of obfuscated code, dynamic code loading, and reflection-based API calls. Use to statically triage a suspicious APK without executing it or to build mobile malware detection rules.

analyzing-api-gateway-access-logs

Parses API Gateway access logs (AWS API Gateway, Kong, Nginx) to detect

analyzing-apt-group-with-mitre-navigator

Query ATT&CK data with attackcti, mitreattack-python, and stix2, then build MITRE ATT&CK Navigator layers and multi-layer heatmap overlays mapping one or more APT groups

analyzing-azure-activity-logs-for-threats

Queries Azure Monitor activity logs and sign-in logs via azure-monitor-query

analyzing-bootkit-and-rootkit-samples

Analyzes bootkit and advanced rootkit malware infecting the Master

analyzing-browser-forensics-with-hindsight

Parse Chromium-based browser databases with Hindsight to extract and correlate browsing history, downloads, cookies, cached content, autofill data, saved passwords, and extensions from Chrome, Edge, Brave, Opera, and Vivaldi into a unified timeline (XLSX, JSON, or SQLite output). Use during incident response, insider-threat investigations, or criminal cases when you need to reconstruct a user

analyzing-campaign-attribution-evidence

Systematically evaluate cyber-campaign evidence to attribute an operation to a threat actor, using the Diamond Model and Analysis of Competing Hypotheses (ACH) to weigh infrastructure overlaps, TTP consistency, malware code similarity, and timing/language artifacts into confidence-weighted attribution assessments. Use when an incident investigation needs a defensible attribution confidence level.

analyzing-certificate-transparency-for-phishing

Monitor Certificate Transparency logs using crt.sh and Certstream to

analyzing-cloud-storage-access-patterns

Detect abnormal access in AWS S3, GCS, and Azure Blob Storage by analyzing CloudTrail Data Events, GCS audit logs, and Azure Storage Analytics for after-hours bulk downloads, new-IP access, and API-call spikes (e.g. GetObject) via statistical baselines and time-series anomaly detection. Use when investigating suspected cloud data exfiltration or building related detection rules.

analyzing-cobalt-strike-beacon-configuration

Extract and analyze Cobalt Strike beacon configuration from PE files

analyzing-cobaltstrike-malleable-c2-profiles

Parse and analyze Cobalt Strike Malleable C2 profiles with dissect.cobaltstrike (profiles and beacon-payload configs) and pyMalleableC2 (AST parsing) to extract HTTP/DNS transforms, URIs, headers, sleep/jitter, and injection behavior, then generate network detection signatures. Use when reverse-engineering a captured malleable profile or building detections against Cobalt Strike Beacon traffic.

analyzing-command-and-control-communication

Analyzes malware C2 communication over HTTP, HTTPS, DNS, and custom

analyzing-cyber-kill-chain

Analyzes intrusion activity against the Lockheed Martin Cyber Kill Chain

analyzing-disk-image-with-autopsy

Perform comprehensive forensic analysis of raw (dd), E01, or AFF disk images with Autopsy and The Sleuth Kit, recovering deleted files, examining metadata and embedded artifacts, keyword searching, and building investigation timelines with visual reports. Use for structured analysis of a forensic disk image or when stakeholders need visual reports from evidence.

analyzing-dns-logs-for-exfiltration

Analyzes DNS query logs to detect data exfiltration via DNS tunneling,

相关技能