Golang Assist脚本解析

 go教练   2019-06-21 15:59   132 人阅读  0 条评论

在网上有一篇著名的go语言逆向解析博文,安全客中也有人提供了翻译,链接参见前言部分。该作者对golang的编译原理有着较深的理解,同时其提供了golang_loader_assist.py脚本用于还原符号信息,这对逆向而言真是再好也不为过了。但是这个脚本无法恢复Windows下编译的go程序,因为这个脚本中最重要的部分,是找到go语言程序中一个非常重要的段,叫做.gopclntab,在这个段中保存了函数的实际名称,而在Windows下编译的程序中则不存在这个段。

在这个脚本中最终的部分如下图所示:

 微信截图_20190621094804.png

首先通过get_segm_by_name('.gopclntab')来定位到.gopclntab段的首地址。然后寻找偏移量是8的地方,根据程序字长来创建指针,再接下来一个字长则给出了.gopclntab段的大小,这样我们就能开始逐个处理每条数据,对每条数据而言,其中都包含了一个函数指针和一个函数名字符串偏移量,循环处理这些数据就能对所有的函数名进行还原,得到带符号信息的函数名称。

 微信截图_20190621094812.png

在实际使用这个脚本进行测试的过程中,需要注意的是,由于ida7.0对sdk和api的大量更新和重新,在idapython中的创建字符串函数MakeStr出错,主要原因是函数的重复定义,参看前言中看雪论坛的相关讨论,修改方式如上图所示。

自己将最关键的部分代码进行了分析和抽取,脚本如上,这段代码可直接在ida中运行,用以定位函数名偏移量和修改函数名,但是注意最后这个地方函数名修改会有点问题,原因是函数名中除了下划线不能出现其他字符,但是当我们运行完毕后,很多函数名是存在特殊符号的,需要自己过滤。

gopclntab = get_segm_by_name('.gopclntab')if gopclntab is not None: base = gopclntab.startEA + 8 # 计算函数名个数 count = Dword(base) # 基地址 base += 8 for i in xrange(0, 2 * count, 2): # 创建函数指针 MakeQword(base + 8*i) functionAddr = Qword(base + 8*i) # 创建函数名字符串偏移量(相对于gopclntab基地址而言) MakeQword(base + 8*i + 8) offset = Qword(base + 8*i + 8) offset = Dword(offset + gopclntab.startEA + 8) # 函数名字符串偏移量(文件偏移量FOA) functionName = offset + gopclntab.startEA name = GetString(functionName) # 创建字符串 MakeStr(functionName, functionName + len(name)) # 修改函数名(ida禁止函数名出现特殊符号,需过滤后才能达到100%效果,我这里没有过滤) MakeName(functionAddr, name)

运行结果如下图所示:

 微信截图_20190621094825.png

通过分析go语言特有的.gopclntab段,我们可以恢复调试符号信息,只有该段中保存的信息均可以进行恢复,恢复率达到98%以上。

IDAGolangHelper脚本

刚刚讨论完了GolangAssist,效果是非常不错的,而作为GolangAssist的升级版本,IDAGolangHelper做的则更加完善,该脚本的作者在2016年底的zeronights会议中展示了他的成果,有兴趣的同学可以参看他的PPT,其实整个脚本的思路和上面一样,同样是通过.gopclntab这个段所保存的符号信息来获取函数信息,如下图所示。

 微信截图_20190621094838.png

除此之外,作者进一步分析了go语言的版本问题,通过2种方式来确定当前程序的go语言版本,一是通过特征字符串的来进行查找,二是通过分析go中特有的结构体类型,由于不同版本之间有结构体会产生变化,作者提出了这种思路来确定版本信息。

 微信截图_20190621094853.png

而通过实际分析证明,第一种方法,即特征字符串的方式来查找版本还是会更高效,更准确些,相比而言,第二种方法由于版本之间的差异不多,则会导致歧义。下图是使用效果,当我们载入该脚本后,第二种方式只能判断是go1.8或1.9或1.10,但是特征字符串则较好的确定是go1.9版本。在重命名函数后,再搜索main字符串,就能定位到main包中的所有函数了。

 微信截图_20190621094902.png

其他方法

当然无符号问题解决的方法还有很多,比如著名符号执行引擎angr中就使用了基于函数语义识别库函数,也有人对源码进行了分析。函数语义就是分析函数的功能和执行的操作,包括寄存器、内存、堆栈和对其他函数的调用流,作为人去分析函数的时,也是类似的,所以感觉这里也可以用机器学习的方法来进一步提高分析效率。

当然学术界也有对这方面的研究,比如二进制代码函数相似度匹配技术研究这篇论文,通过函数的序言部分的特征,提出了二阶段函数匹配方法TPM,在识别出相似函数后,找到其调用关系和决策规则,然后递归的识别不同版本的函数,据论文所述,识别准确率平均高于diaphora和patchdiff方法,也是值得借鉴的。

以上就是今天给大家介绍的Golang Assist脚本解析,如果你还想了解更多关于golang的知识技巧,可以继续关注我们http://www.fastgolang.com

本文地址:http://fastgolang.com/82.html
版权声明:本文为原创文章,版权归 go教练 所有,欢迎分享本文,转载请保留出处!

 发表评论


表情

还没有留言,还不快点抢沙发?