欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

手把手教你如何专业地逆向GO二进制程序

来源:本站整理 作者:佚名 时间:2017-03-15 TAG: 我要投稿

GO二进制程序很不可思议,至少今天一切从它讲起。当深入研究一些名为Rex的Linux恶意软件时,我意识到比起我想要的,我可能需要先理解更多的东西。就在前一周,我一直在逆向用go语言编写的Linux Lady,由于它不是一个剥离过的二进制文件,所以这很容易。显然,二进制文件是相当大的,也有许多我并不在乎的多余方法,虽然我真的只是不明白为什么。老实说,我还没有深入到Golang代码,也没有真正在Go中写很多代码,所以从表面意义上来看,这些信息有部分可能是错误的; 因为这只是我在逆向一些ELF格式Go二进制程序的经验!如果你不想读整篇文章或者只想滚动到底部去获得一个完整报告的链接,那么只需点这里。
为了解释我的案例,我要使用一个非常简单的“Hello,World!”的例子并且我还参考了Rex恶意软件。代码和Make文件非常简单;
Hello.go
package main
import "fmt"
func main() {
    fmt.Println("Hello, World!")
}
Makefile
all:
GOOS=linux GOARCH=386 go build -o hello-stripped -ldflags "-s" hello.go
GOOS=linux GOARCH=386 go build -o hello-normal hello.go
因为我在OSX机器上做这些工作,显然需要上面的GOOS和GOARCH变量来正确地交叉编译。第一行还添加了ldflags剥离二进制文件的选项。这样我们可以用剥离和不剥离的两种方式来分析相同的可执行文件。之后复制这些文件,运行make,然后在反汇编器中打开你所选择的文件,对于这个博客,我打算使用IDA Pro。如果我们在IDA Pro中打开未剥离过的二进制文件,我们可以看到如下;

那么,我们的5行代码已经转化成2058个函数。越过所有运行时执行的代码,我们在main()函数上也没有什么有趣的事发生。如果进一步深究,发现其实我们感兴趣的代码实际是在main_main里面;

这样很好,因为我真的不想看过多的代码。加载的字符串看起来也有点奇怪,虽然IDA似乎已经很好地识别了必要的字节。我们可以很容易地看到加载字符串实际上是一组三个mov指令;
String load(字符串加载)
mov     ebx, offset aHelloWorld ; "Hello, World!"
mov     [esp+3Ch+var_14], ebx ; 把字符串放到该位置上
mov     [esp+3Ch+var_10], 0Dh ; 字符串长度
这并不是完全颠覆性的,虽然我其实不假思索的说我以前就已经看到过这样的事情。我们也需要继续注意它,因为之后这将继续处理。引起我注意的另一个代码是runtime_morestack_context的调用;
morestack_context
loc_80490CB:
call    runtime_morestack_noctxt
jmp     main_main
这种风格的代码块似乎总是在函数的结尾,它似乎总是循环回到同一个函数的顶部。这可以通过查看对此函数的交叉引用来验证。好了,现在我们知道IDA Pro可以处理未剥离的二进制文件,让我们加载相同的代码,但是这次是剥离的版本。

我们随即看到了一些结果,好吧,让我们姑且把它们称为“差异”。这里有1329个函数定义,现在通过查看导航工具栏看到一些未定义的代码。幸运的是,IDA仍然能够找到我们想寻找的字符串加载,然而这个函数现在似乎不太好处理。

我们现在没有更多的函数名称了,然而,函数名称似乎保留在二进制特定的节里,如果我们给main.main做一个字符串搜索(这将呈现在前面屏幕截图的main_main函数,因为IDA遇到并识别了一个“ . ”);
.gopclntab
.gopclntab:0813E174 db 6Dh; m
.gopclntab:0813E175 db 61h; a
.gopclntab:0813E176 db 69h; i
.gopclntab:0813E177 db 6Eh; n
.gopclntab:0813E178 db 2Eh; .
.gopclntab:0813E179 db 6Dh; m
.gopclntab:0813E17A db 61h; a
.gopclntab:0813E17B db 69h; i
.gopclntab:0813E17C db 6Eh; n
好了,这里看起来有些遗留的东西需要去研究。在深入挖掘谷歌搜索结果后进入gopclntab和关于这的推特-一个友好的逆向朋友George (Egor?)Zaytsev给我看了他的IDA Pro的脚本重命名函数并添加类型信息。浏览了这些之后,很容易理解这个部分的格式,所以我在一些功能上复制了他的脚本。基本代码如下所示,非常简单,我们看.gopclntab段并跳过前8个字节。然后我们创建一个指针(Qword或Dword,根据二进制是否是64位)。第一组数据实际上给出了.gopclntab表的大小,所以我们知道离进入这个结构有多远。现在我们可以开始处理其余的数据,这些数据出现在(函数)name_offset 后面的function_offset。当我们创建指向这些偏移的指针,并告诉IDA创建字符串,我们只需要确保我们不会传递给MakeString任何损坏的字符,因此我们使用该clean_function_name函数去除任何不好的地方。
renamer.py
def create_pointer(addr, force_size=None):
    if force_size is not 4 and (idaapi.get_inf_structure().is_64bit() or force_size is 8):
        MakeQword(addr)
return Qword(addr), 8
    else:

[1] [2] [3] [4] [5] [6]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载