burrowers/garble
GitHub: burrowers/garble
一款通过包装 Go 工具链实现代码混淆的工具,用于在构建阶段生成难以逆向分析的 Go 二进制文件。
Stars: 5480 | Forks: 355
# garble
```
go install mvdan.cc/garble@latest # or @master
```
通过包装 Go 工具链来混淆 Go 代码。需要 Go 1.26 或更高版本。
```
garble build [build flags] [packages]
```
该工具还支持 `garble test` 以使用混淆后的代码运行测试,
`garble run` 用于混淆并执行简单程序,
`garble reverse` 用于反混淆诸如堆栈跟踪之类的文本,
以及 `garble bug` 用于提交预填好的 Bug 报告。
运行 `garble -h` 以查看所有可用的命令和参数标志。
### 目的
生成一个与常规构建运行效果相同,但包含尽可能少的原始源代码信息的二进制文件。
该工具旨在:
* 与 `cmd/go` 结合使用,以支持模块和构建缓存
* 在给定相同初始源代码的情况下,具有确定性和可重现性
* 在给定原始源代码的情况下可逆,以反混淆 panic 堆栈跟踪
### 机制
该工具通过包装对 Go 编译器和链接器的调用来改变 Go 构建,以实现:
* 用简短的 base64 哈希值替换标识符和包路径
* 用简短的 base64 哈希化文件名替换位置信息
* 删除所有[构建](https://go.dev/pkg/runtime/#Version)、[模块](https://go.dev/pkg/runtime/debug/#ReadBuildInfo)和调试信息
* 如果指定了 `-literals` 标志,则[混淆字面量](#literal-obfuscation)
* 如果指定了 `-tiny` 标志,则删除[额外信息](#tiny-mode)
默认情况下,该工具会混淆所有正在构建的包。
你可以通过 `GOGARBLE` 手动指定要混淆的包,
它是一个以逗号分隔的、与包路径前缀匹配的 glob 模式列表。
此格式借用于 `GOPRIVATE`;请参阅 `go help private`。
请注意,诸如 `garble build` 之类的命令将使用在你的 `$PATH` 中找到的 `go` 版本。要使用不同版本的 Go,你可以[使用 `GOTOOLCHAIN`](https://go.dev/doc/toolchain)。
### 使用场景
一个常见的问题是,为什么 Go 这种编译型语言需要代码混淆器。
Go 二进制文件包含了大量关于原始源代码的惊人信息;
即使剥离了调试信息和符号表,为了跟踪、反射和调试,
许多名称和位置依然会被保留。
Go 的某些使用场景需要与最终用户共享 Go 二进制文件。
如果二进制文件的源代码是私有的或需要购买的,
对其进行混淆有助于阻止逆向工程。
一个类似的使用场景是源代码为私有或需要购买的 Go 库。
由于 Go 库不能以二进制形式导入,而且 Go 插件[有其自身的缺点](https://github.com/golang/go/issues/19282),
共享混淆后的源代码便成了一种选择。
参见 [#369](https://github.com/burrowers/garble/issues/369)。
混淆也可以帮助处理与许可完全无关的方面。
例如,`-tiny` 标志可以使二进制文件缩小 15%,
类似于 [Android 中的常见做法](https://developer.android.com/build/shrink-code#obfuscate)以减小应用程序大小。
混淆还帮助一些开源开发者解决了杀毒软件错误地将 Go 二进制文件视为恶意软件的问题。
### 字面量混淆
使用 `-literals` 标志会导致诸如字符串之类的字面量表达式被更复杂的表达式替换,并在运行时解析为相同的值。
通过 `-ldflags=-X` 注入的字符串字面量也会被此标志替换。
此功能是选择性的(opt-in),因为根据输入代码的不同,它可能会导致运行变慢。
常量表达式中使用的字面量无法被混淆,因为它们在编译时已被解析。例如,这包括作为 `const` 声明一部分的任何表达式。
请注意,只要有足够的精力,此过程是可以被逆向的;
参见 [#984](https://github.com/burrowers/garble/issues/984)。
### Tiny 模式
使用 `-tiny` 标志,Go 二进制文件中将被剥离更多信息。
位置信息将被完全删除,而不是被混淆。
用于打印 panic、致命错误以及跟踪/调试信息的运行时代码将被删除。
在链接阶段,许多符号名也会从二进制文件段中被省略。
总而言之,这可以使二进制文件缩小约 15%。
使用此标志后,将永远不会打印任何 panic 或致命的运行时错误,但它们依然可以像往常一样通过 `recover` 在内部进行处理。
请注意,此标志会使调试崩溃变得更加困难,因为发生 panic 时会直接退出整个程序而不会打印堆栈跟踪,而且源代码位置和许多名称都已被删除。
同样地,`garble reverse` 在这种模式下通常也没有用处。
### 控制流混淆
参见:[CONTROLFLOW.md](docs/CONTROLFLOW.md)
### 速度
`garble build` 耗时大约应为 `go build` 的两倍,因为它需要完成两次构建。第一次是原始构建,以便能够加载和类型检查输入代码;然后是混淆构建。
Garble 每次混淆一个包,这与 Go 每次编译一个包的方式相对应。这使得 Garble 能够完全支持 Go 的构建缓存;增量的 `garble build` 调用应仅重新构建和重新混淆已修改的代码。
请注意,第一次调用 `garble build` 可能会比较慢,
因为它必须首次混淆每个包。这类似于清除了 `GOCACHE`(通过 `go clean -cache`)并从头开始运行 `go build`。
Garble 也利用自己的缓存来复用工作,类似于 Go 的 `GOCACHE`。
它默认使用用户缓存目录下的一个子目录,
例如 `~/.cache/garble`,并且可以通过设置 `GARBLE_CACHE` 将其放置在其他位置。
### 确定性与种子
与 Go 一样,garble 构建在本质上是确定且可重现的。
这带来了显著的好处,例如缓存构建以及能够使用 `garble reverse` 来反混淆堆栈跟踪。
默认情况下,garble 将以独特的方式混淆每个包,
当其构建输入发生变化时,这种独特方式也会随之改变:garble 的版本、Go 的版本、包的源代码,或任何构建参数(如 GOOS 或 -tags)。
这是一个合理的默认设置,因为猜测这些输入非常困难。
你可以使用 `-seed` 标志来提供你自己的混淆随机种子。
复用相同的种子有助于生成相同的代码混淆,
这有助于调试或重现问题。
定期轮换种子从长远来看也有助于防范逆向工程,
否则,人们可以通过观察 Go 标准库的混淆方式变化,来猜测在一系列构建中 Go 或 garble 版本何时发生了更改。
要确保每次构建始终使用不同的种子,请使用 `-seed=random`。
请注意,使用自定义种子时应格外小心:
如果构建中使用的 `-seed` 值丢失,`garble reverse` 将无法工作。
### 注意事项
其中大多数问题都可以随着时间的推移和努力得到改善。本节旨在记录该工具目前的不足之处。
* 导出的方法目前永远不会被混淆,因为接口可能会需要它们。这方面的工作仍在进行中;参见 [#3](https://github.com/burrowers/garble/issues/3)。
* 除了通过 `GOGARBLE` 选择要混淆的包模式外,
没有受支持的方法来排除对选定文件或包的混淆。
通常情况下,用户想要这样做是为了绕过某个 Bug;请改为提交该 Bug。
* Go 程序[被初始化](https://go.dev/ref/spec#Program_initialization)时一次初始化一个包,
其中被导入的包总是会在其导入者之前被初始化,
在其他情况下,它们会按照其导入路径的词法顺序进行初始化。
由于 garble 混淆了导入路径,这种词法顺序可能会任意改变。
* 当前不支持 Go 插件;参见 [#87](https://github.com/burrowers/garble/issues/87)。
* Garble 需要 `git` 来修补链接器。一旦 go-gitdiff 支持[非严格补丁](https://github.com/bluekeyes/go-gitdiff/issues/30),就可以避免这种情况。
* 诸如 [`runtime.GOROOT`](https://pkg.go.dev/runtime#GOROOT) 和 [`runtime/debug.ReadBuildInfo`](https://pkg.go.dev/runtime/debug#ReadBuildInfo) 之类的 API 将无法在混淆后的二进制文件中工作。例如,这可能会影响[加载时区](https://github.com/golang/go/issues/51473#issuecomment-2490564684)。
### 贡献
我们欢迎新的贡献者。如果你想做出贡献,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 作为起点。
标签:EVTX分析, Golang, Go工具链, Go语言, URL提取, 二进制安全, 代码加密, 代码混淆, 信息消除, 反编译, 威胁情报, 安全编程, 开发者工具, 日志审计, 标识符加密, 混淆器, 源码保护, 确定构建, 程序破解, 编译器包装, 跨平台编译, 软件加固, 逆向工程防护, 链接器, 静态分析防御