要么全力以赴,要么干脆放弃:分析 Golang
ztj100 2025-07-23 19:25 23 浏览 0 评论
GO BIG OR GO HOME (AND OTHER TERRIBLE GO PUNS) TIPS FOR ANALYZING GOLANG MALWARE
免责声明:本博客文章仅用于教育和研究目的。提供的所有技术和代码示例旨在帮助防御者理解攻击手法并提高安全态势。请勿使用此信息访问或干扰您不拥有或没有明确测试权限的系统。未经授权的使用可能违反法律和道德准则。作者对因应用所讨论概念而导致的任何误用或损害不承担任何责任。
几天前,Dr. Josh Stroschein 邀请我在他的 YouTube 频道 上讨论 Golang 恶意软件。为了趁热打铁,我决定将直播内容整理成这篇博客。以下是直播讨论的精华总结。如果你不想阅读文章,可以直接观看直播 回放 。那么,让我们开始吧。
Go(或 Golang)在过去几年中不仅受到开发者的青睐,也越来越受到寻求灵活性和可移植性的恶意软件作者的关注。作为逆向工程师和恶意软件分析师,这意味着我们需要更熟悉 Go 二进制文件,了解它们的结构,并知道它们与用 C、C++ 或 Delphi 编写的传统恶意软件有何不同。
什么是 Go,为什么它重要?
Go 是 Google 开发的一种静态类型、编译型编程语言。它设计简单、编译快速且高效。Go 的一些优点包括:
从开发者的角度来看,它高效且实用。从恶意软件分析师的角度来看,它带来了一些有趣的挑战。
为什么使用 Go 编写恶意软件?
Go 提供了几个对恶意软件作者有吸引力的优势:
分析 Go 恶意软件的常见陷阱
1. 大文件体积
即使是一个简单的 Go 程序,编译后的二进制文件也可能达到几十 MB。这是由于 Go 运行时和标准库的静态链接。对于分析师来说,这意味着需要筛选更多代码,因为通常无法立即确定恶意代码的起始和结束位置。
2. 大量合法代码
Go 的标准库非常广泛,恶意软件通常使用常见的包,如 net
、 os
、 crypto
和 io
。二进制文件中的大部分代码可能是良性的。挑战在于在大量合法功能中识别出小部分自定义或恶意逻辑。这就像在针堆里找针。
3. 混淆(Garble 等)
Go 恶意软件越来越多地使用混淆工具,如 Garble ,它会剥离或随机化符号名称、重新排序包,并破坏常见的静态分析工作流程。这些技术并不一定使恶意软件更复杂,但确实增加了逆向工程的难度。
其他常见的混淆技术可能包括:
让我们分析一个非常基础的 Go 二进制文件。最好的方法是我们自己编写代码。
分析一个基础的 Go 程序
Go 代码相当直接且易于编写。以下是最基础的 Go 应用程序,打印我们最喜欢的 "Hello World"(在这里是 "Hello Earth")字符串:
使用 go build
命令编译后,二进制文件相当大(2MB+)。由于 Go 将大量库代码打包到每个编译后的可执行文件中,即使这个简单的 Hello World 二进制文件也相当大。
让我们在 IDA 中打开它,这是我最喜欢的 Golang 反汇编工具。较新版本的 IDA(我认为是 8+ 版本)能够很好地识别 Go 标准库代码。IDA 将这些库分组在 "文件夹" 中,如下面的截图所示:
每个文件夹代表一个库。例如," internal
"、" runtime
" 和 " math
" 都是导入到这个 Go 程序中的库。IDA 能够识别这些库和函数并适当地命名它们。如果你的反汇编工具不是为 Golang 设计的,你会看到这些函数的一堆通用名称,这使得分析 Go 二进制文件更加困难。一个工具( GoReSim )可以帮助识别这些函数,然后可以将该工具的输出重新导入到一些反汇编工具中,如 Ghidra。
在未混淆的 Golang 二进制文件中,程序的主要功能通常位于 main.main
或 main_main
函数中,IDA 已经为我们识别了这一点:
提示:每当我分析 Go 二进制文件时,我总是首先寻找 main_main
或其他包含 " main_*
" 名称的函数。
在 main_main
中,我们可以看到我们的 Hello World
代码。你可能会在下面的代码中发现 "Hello Earth!" 字符串:
这个 "Hello Earth!" 字符串还包含一堆其他垃圾。这些也是二进制文件中的字符串。分析 Golang 代码时的一个挑战是,字符串不像 C 程序那样以 null 结尾。每个字符串实际上是一个结构,包含字符串本身和一个表示字符串长度的整数。我提供了一些糟糕的伪代码来可视化这一点:
struct string (
value = "Hello Earth!"
length = 12
)
在这种情况下,IDA 不知道 "Hello Earth!" 是与 "152587…" 等字符串分开的。这是分析 Golang 时需要考虑的一点。
好了,Hello World 应用程序很酷,但让我们更进一步。许多用 Go 编写的恶意软件二进制文件会被混淆。 Garble 就是这样一个混淆器。Garble... 嗯... 混淆了 Go 二进制文件的元数据。它通过在编译时剥离符号、函数名称、模块和构建信息以及其他元数据来实现这一点。
如果我们在 IDA 中打开同一个 Hello World 二进制文件,但在编译时进行了 "Garbled" 处理,它看起来大不相同:
我们所有漂亮的 Golang 函数名称都被替换为丑陋的通用 IDA 函数名称(" sub_xxxxxx
")。那么我们现在如何找到我们的主函数代码呢?我们找不到——Golang 赢了。是时候收拾东西回家了。
不,开个玩笑。我们只需要更努力一点。我发现 Golang 需要几个关键库才能正常运行,其中之一是 " runtime
" 库,它包含大量 Go 的运行时代码。通常,runtime 库名称不会被混淆,就像我这个用 Garble 编译的二进制文件中的情况一样( 注意:我认为 Garble 也可以从 "runtime" 中剥离模块名称,但我没有测试过。无论如何,"runtime" 模块名称通常不会被混淆 )。这意味着我们可以在代码中找到对 runtime 函数的交叉引用,并追踪回程序的主函数!让我们试试看。
如果我们在 IDA 的函数列表中搜索 "runtime",我们会得到以下结果:
一个常见的 runtime 函数是 runtime_unlockOSThread
。我们可以双击这个函数并选择 CTRL+X 来查看它的交叉引用。查看所有交叉引用的函数会引导你到一个看起来像这样的代码块:
当你发现包含大量 "runtime" 函数的功能时,你可能接近程序的主代码位置。在这种情况下,我们的主代码就在不远处的 sub_49A9E0
。你可能会想:"Kyle,你怎么这么聪明,这么快就找到了?"。好吧,除了智力之外,这主要是因为在代码中进行了大量搜索。没有什么疯狂的技巧。
这是我们在 sub_49A9E0 处的主代码:
提示:Garble 和其他混淆器不仅可以混淆函数名称,还可以混淆字符串。我使用了默认的 Garble 设置来处理这个二进制文件。然而,分析方法是一样的。
额外资源
一些关于 Golang 的额外资源,我觉得非常有帮助:
关键要点
Go 语言编写的恶意软件越来越普遍,并且可能会持续存在。虽然它带来了一些独特的挑战,但许多逆向工程的基本原则仍然适用。你只需要调整你的方法和工具。
逆向分析 Go 恶意软件的 5 个技巧
1. 从 main.main
(main_main
) 开始 - 这几乎总是 Go 二进制文件的入口点,可以为你提供进入其余逻辑的切入点2. 使用正确的工具 - IDA、带有 GoReSym
的 Ghidra(其他反汇编器可能也有效,但我没有测试过),以及名为 UnGarbler 的反混淆工具3. 忽略噪音 - 跳过大部分标准库代码,除非它直接参与恶意行为 4. 寻找关键 API - 即使经过混淆,像 " net.Dial
"、"os/exec
" 或 "http.Get
" 这样的模式也能帮助缩小可疑区域的范围5. 结合静态和动态分析 - 特别是对于混淆的二进制文件,动态跟踪或调试可能是理解实际行为的最快方法。Ivan Kwiatkowski 在这个 视频 中提供了一些关于调试 Go 语言的实用技巧
相关推荐
- Linux集群自动化监控系统Zabbix集群搭建到实战
-
自动化监控系统...
- systemd是什么如何使用_systemd/system
-
systemd是什么如何使用简介Systemd是一个在现代Linux发行版中广泛使用的系统和服务管理器。它负责启动系统并管理系统中运行的服务和进程。使用管理服务systemd可以用来启动、停止、...
- Linux服务器日常巡检脚本分享_linux服务器监控脚本
-
Linux系统日常巡检脚本,巡检内容包含了,磁盘,...
- 7,MySQL管理员用户管理_mysql 管理员用户
-
一、首次设置密码1.初始化时设置(推荐)mysqld--initialize--user=mysql--datadir=/data/3306/data--basedir=/usr/local...
- Python数据库编程教程:第 1 章 数据库基础与 Python 连接入门
-
1.1数据库的核心概念在开始Python数据库编程之前,我们需要先理解几个核心概念。数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,它就像一个电子化的文件柜,能让我们高效...
- Linux自定义开机自启动服务脚本_linux添加开机自启动脚本
-
设置WGCloud开机自动启动服务init.d目录下新建脚本在/etc/rc.d/init.d新建启动脚本wgcloudstart.sh,内容如下...
- linux系统启动流程和服务管理,带你进去系统的世界
-
Linux启动流程Rhel6启动过程:开机自检bios-->MBR引导-->GRUB菜单-->加载内核-->init进程初始化Rhel7启动过程:开机自检BIOS-->M...
- CentOS7系统如何修改主机名_centos更改主机名称
-
请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习1.前言本文将讲解CentOS7系统如何修改主机名。...
- 前端工程师需要熟悉的Linux服务器(SSH 终端操作)指令
-
在Linux服务器管理中,SSH(SecureShell)是远程操作的核心工具。以下是SSH终端操作的常用命令和技巧,涵盖连接、文件操作、系统管理等场景:一、SSH连接服务器1.基本连接...
- Linux开机自启服务完全指南:3步搞定系统服务管理器配置
-
为什么需要配置开机自启?想象一下:电商服务器重启后,MySQL和Nginx没自动启动,整个网站瘫痪!这就是为什么开机自启是Linux运维的必备技能。自启服务能确保核心程序在系统启动时自动运行,避免人工...
- Kubernetes 高可用(HA)集群部署指南
-
Kubernetes高可用(HA)集群部署指南本指南涵盖从概念理解、架构选择,到kubeadm高可用部署、生产优化、监控备份和运维的全流程,适用于希望搭建稳定、生产级Kubernetes集群...
- Linux项目开发,你必须了解Systemd服务!
-
1.Systemd简介...
- Linux系统systemd服务管理工具使用技巧
-
简介:在Linux系统里,systemd就像是所有进程的“源头”,它可是系统中PID值为1的进程哟。systemd其实是一堆工具的组合,它的作用可不止是启动操作系统这么简单,像后台服务...
- Linux下NetworkManager和network的和平共处
-
简介我们在使用CentoOS系统时偶尔会遇到配置都正确但network启动不了的问题,这问题经常是由NetworkManager引起的,关闭NetworkManage并取消开机启动network就能正...
你 发表评论:
欢迎- 一周热门
-
-
MySQL中这14个小玩意,让人眼前一亮!
-
旗舰机新标杆 OPPO Find X2系列正式发布 售价5499元起
-
面试官:使用int类型做加减操作,是线程安全吗
-
C++编程知识:ToString()字符串转换你用正确了吗?
-
【Spring Boot】WebSocket 的 6 种集成方式
-
PyTorch 深度学习实战(26):多目标强化学习Multi-Objective RL
-
Linux下NetworkManager和network的和平共处
-
Kubernetes 高可用(HA)集群部署指南
-
linux系统启动流程和服务管理,带你进去系统的世界
-
7,MySQL管理员用户管理_mysql 管理员用户
-
- 最近发表
-
- Linux集群自动化监控系统Zabbix集群搭建到实战
- systemd是什么如何使用_systemd/system
- Linux服务器日常巡检脚本分享_linux服务器监控脚本
- 7,MySQL管理员用户管理_mysql 管理员用户
- Python数据库编程教程:第 1 章 数据库基础与 Python 连接入门
- Linux自定义开机自启动服务脚本_linux添加开机自启动脚本
- linux系统启动流程和服务管理,带你进去系统的世界
- CentOS7系统如何修改主机名_centos更改主机名称
- 前端工程师需要熟悉的Linux服务器(SSH 终端操作)指令
- Linux开机自启服务完全指南:3步搞定系统服务管理器配置
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)