Hiding behind the library line — Go malware development
当我在研究著名的 Flare-On CTF 的一道逆向工程挑战时,我突然想到了向原生库注入代码的想法。通常情况下,对用 Go 编写的应用程序进行逆向工程分析时,分析师们往往会忽略内置库。这是因为 Go 是一种静态链接的编程语言,这意味着它会直接将所有库的代码包含在二进制文件中。所以,没有必要查看这些库,对吧?
好吧,我想并非如此。
我现在正在一家咖啡馆,让我们开始一个快速的支线任务,在这个项目上花费几个小时。
那么,让我们编写一些没有实际用途的示例代码。
package main
import (
"fmt"
"net/http"
"time"
)
funcmain() {
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := client.Get("https://www.google.com")
if err != nil {
fmt.Println("Error making request:", err)
return
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
如果我们对其进行反编译,我们可以看到反编译版本以及它是如何对应原始源代码的。
我最初尝试通过修补其中一个函数的内部代码直接将汇编代码注入到可执行文件中。然而,这需要大量工作,所以我决定将其推迟到后续计划中。
相反,为什么不编译我们自己的 Go 版本并直接在那里注入代码呢?
完整说明可以在这里找到:[https://go.dev/doc/install/source](https://go.dev/doc/install/source).
简而言之,克隆仓库,导航到src/
目录,然后执行以下两个命令:
GOOS=windows GOARCH=amd64 ./bootstrap.bash
./all.bash
首先,我想将代码注入到 client.Get() 函数中。
修改代码后,使用 ./all.bash
重新构建项目,然后使用 bin/go
中的二进制文件来编译你的示例代码。
GOOS=windows GOARCH=amd64 ./golang_src/go/bin/go build
但是在执行时这种方法并不奏效。
反编译后,似乎我修改了错误的 Get 函数。如下所示,它与我们在原始代码仓库中看到的代码不匹配。
相反,让我们从反编译版本回溯,找到函数的位置。这次让我们选择 fmt.Println。
查看代码,我们发现它实际上调用的是 fmt.Fprintln。
在源代码中找到这个函数,它位于 src/fmt/print.go 下。看起来很相似。
现在只需添加你的代码就很简单了,首先通过创建文件来进行完整性检查。
很好,我们成功创建了一个文件。
这需要在 print.go 中导入额外的库 os/exec,但我们可以直接使用 os 库进行文件创建和代码执行,因为它已经被导入并且有两个有用的函数:os.Create() 用于创建文件,os.StartProcess() 用于执行任何 PowerShell/exe 文件。
作为示例,我编写了一段简短的代码,用于在磁盘上释放另一个可执行文件并执行它。
原文始发于微信公众号(securitainment):隐藏在原生库代码背后 — Go 恶意软件开发
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论