二进制逆向工程师_利用Ghidra逆向分析Go二进制程序(下篇)

eea6dcf55ca1549734fc87aa42f25c22.gif

(接上文)

6e5889519ec7d4a34725b2481c3b03ec.png

动态分配字符串结构

在第一种情况下,字符串结构是在运行时创建的,为此,需要使用一系列汇编指令在字符串操作之前设置相应的结构。由于指令集的不同,不同的架构之间的结构也是不同的。让我们通过几个案例,来展示我们的脚本(find_dynamic_strings.py)寻找的指令序列。

x86架构下字符串结构的动态分配

首先,我们先来看看“Hello Hacktivity”这个例子。340a02a408496cbfdc8e8ffbc779f4ea.png

图20 hello_go中字符串结构的动态分配情况

5ad96125bcc60aea4bf45097760b115c.png

图21 hello_go中未定义的“hello, hacktivity”字符串

运行脚本后,代码是这样的:1cd3eb2d46bb82fde0b86bdedf44fd35.png

图22 执行find_dynamic_strings.py后,hello_go中动态分配的字符串结构

可以看到,该字符串已经被定义:

b8bfce82d015223eda21473e1f30e9b5.png

图23 hello_go中已经定义了“hello hacktivity”字符串

同时,字符串“hacktivity”也可以在Ghidra的Defined Strings视图中找到。

0f68f94eb500aac11978c4c781c45f12.png

图24 通过"hacktivity"过滤在hello_go中已定义的字符串

实验证明,我们的脚本能够在32位和64位x86二进制文件中寻找以下指令序列:

b4b33eb175d9fc66b1d9dd75d660d01f.png

图25 eCh0raix字符串结构的动态分配

d4598639e9d45dcafb176e7c04395e7a.png

图26 hello_go中动态分配的字符串结构

ARM架构下字符串的动态分配

对于32位ARM架构,我们将以eCh0raix勒索软件样本为例来说明字符串的恢复方法。

841b5b4f077c8f79be57842babc7faea.png

图27 eCh0raix中字符串结构的动态分配

4e394a37444a1af7b368b271c5cd1f3d.png

图28 eCh0raix中指向字符串地址的指针

4fe75559ebed7978d27d9e6c94462114.png

图29 eCh0raix中未定义的字符串

执行脚本后,代码将变成下面的样子:

b03bcb3482e44b970a2335aac01809d9.png

图30 执行find_dynamic_strings.py后,eCh0raix中动态分配字符串结构

我们可以看到,指针已经被重新命名,并定义了字符串:

9f26722fa899e1f957afee912bb23cbd.png

图31 执行find_dynamic_strings.py后,eCh0raix中指向字符串地址的指针

7e27a0ab85414c0c63ccb880d97cf27f.png

图32 执行find_dynamic_strings.py后,eCh0raix中定义的字符串

该脚本在32位ARM二进制文件中查找可以下指令序列:

074e5c2d5102cd985d98e9793f4b7eef.png

对于64位ARM架构,我们将通过一个Kaiji样本来演示字符串的恢复方法。在这里,代码使用了两个指令序列,但是只在一个序列中发生了变化:

2574864c8e1cdc1251b18bddecd010d8.png

图33 Kaiji中字符串结构的动态分配

执行脚本后,代码将变为:

abed554fcf435d9ffb099ae29519bce3.png

图34 执行find_dynamic_strings.py后,Kaiji中字符串结构的动态分配情况

我们可以看到,这些字符串已经被定义:

b95229a15734b0fc9f8294f3f90f0aa5.png

图35 执行find_dynamic_strings.py后,Kaiji中定义的字符串

该脚本能够在64位ARM二进制文件中找到以下指令序列:

00f575e436786c159f98851371291ce9.png

如您所见,该脚本可以恢复动态分配的字符串结构。这非常有助于逆向工程师阅读汇编代码,或在Ghidra中的Defined String视图中寻找可疑的字符串。

这种方法所面临的挑战

这种方法最大的缺点是,每种架构(甚至同一架构内的不同解决方案)都需要在脚本中添加一个新的分支。而且,规避这些预定义的指令集是很容易的。在下面的例子中,对于Kaiji 64位ARM恶意软件样本来说,由于字符串的长度被移到了一个寄存器中,而脚本却没有预料到这一点,因此会漏掉这个字符串。

1690a2a1c04c5d52d5e882bf05b28829.png

图36 Kaiji以不寻常的方式动态分配字符串结构

f7d1531af987e0f4088defb7975a02ba.png

图37 Kaiji中一个未定义的字符串

6e5889519ec7d4a34725b2481c3b03ec.png

静态分配字符串结构

在接下来的这个案例中,我们的脚本(find_static_strings.py)用于查找静态分配的字符串结构。这意味着字符串指针后面是字符串长度。

这就是x86 eCh0raix勒索软件样本中找到的字符串指针及其长度:

d2f63dc7e5f873e4c936e444477a7041.png

图38 eCh0raix中静态分配的字符串结构

在上图中,字符串指针后面是字符串长度值,然而,Ghidra无法区分地址和整数数据类型,但是代码中直接引用的第一个指针除外。

07f58fccad0d5537238da0bab404dd99.png

图39 eCh0raix中的字符串指针

未定义的字符串可以通过字符串地址找到:

411af1de3473e9492b27c41ccf41fd1a.png

图40 eCh0raix中未定义的字符串

执行该脚本后,将定义字符串地址、字符串长度值和字符串本身:

d028ce79f389a10caf38308eea925743.png

图41 执行find_static_strings.py后,eCh0raix中静态分配的字符串结构

d84148f17e46891f1dd4a734d8f6889c.png

图42 执行find_static_strings.py后,eCh0raix中定义的字符串 

6e5889519ec7d4a34725b2481c3b03ec.png

挑战:消除误报和字符串遗漏

我们希望消除误报,为此,我们需要:

· 限制字符串的长度

· 搜索可打印字符

· 在二进制文件的数据段进行搜索

很明显,由于这些限制,字符串很容易成为漏网之鱼。如果你使用这个脚本,请随意试验:不停改变这些值,以找到最佳设置。其中,以下代码用于限制长度和字符集:

ae1fde1e175db4c6718d3592e66b24cb.png

图43 find_static_strings.py.

c9f186160edb6d67a0fed0447fd7a59c.png

图44 find_static_strings.py

字符串恢复所面临的进一步挑战

Ghidra的自动分析可能会错误地识别某些数据类型。如果发生这种情况,我们的脚本将无法在该特定位置创建正确的数据。为了解决这个问题,必须先删除不正确的数据类型,然后才能创建新的数据类型。

例如,先我们来看看eCh0riax勒索软件中静态分配的字符串结构。

59d449a7aca0d52d06f32503d0c0c110.png

图45 eCh0raix中静态分配的字符串结构

在这里,地址的识别是正确的,但是,字符串长度值(应该是整数数据类型)被错误地识别为未定义的值。

在我们的脚本中,以下几行代码用于删除不正确的数据类型:

3e92aeaad95d5154b6c2d632d8c7f0f3.png

图46 find_static_strings.py

执行该脚本后,不仅所有的数据类型都被正确识别出来了,而且所有字符串也被定义了:

144b629ff7c6c637794ac1ccccc44544.png

图47 执行find_static_strings.py后,eCh0raix中字符串结构的静态分配情况

另一个问题来自于这样一个事实:在Go二进制文件中,字符串将被串联并存储到一个大的字符串blob中。在某些情况下,Ghidra会将整个blob定义为单个字符串。这些可以通过大量的offcut引用来识别。Offcut引用是对已定义字符串的某些部分的引用,不是对字符串起始地址的引用——注意,它是对字符串内部的某个位置的引用。

下面的内容来自ARM Kaiji样本:

625271f766bbcf54f0148ee94ad852fe.png

图48 Ghidra错误定义的字符串

f8b4c3a0a2cf781657c203b1872c6302.png

图49 Kaiji对错误定义的字符串的offcut引用

要找到错误定义的字符串,可以使用Ghidra中的Defined Strings窗口,按照offcut引用数对字符串进行排序。在执行字符串恢复脚本之前,可以手动取消对具有大量offcut引用的大型字符串的定义。这样,脚本就可以成功地创建正确的字符串数据类型。

9f7e03a58b88e8f98ee310d03351435f.png

图50 Kaiji中定义的字符串

一旦通过手动方式或通过我们的脚本成功定义了一个字符串,它就能够在Ghidra的列表视图中正确的显示出来,从而帮助逆向工程师顺利阅读汇编代码。但是,Ghidra中的反编译器视图无法正确处理固定长度的字符串,并且,无论字符串的长度如何,它都会显示所有内容,直到找到空字符为止。幸运的是,这个问题将在Ghidra(9.2)的下一个版本中得到解决。

下面,我们以eCh0raix样本为例来说明这个软件问题:

c039d16ac2edf2e5cf5a53617def0fdb.png

图51 eCh0raix显示在Listing视图中的已定义字符串

8eb5c593a2b1d759321c0f1fceaaa586.png

图52 eCh0raix显示在Decompile视图中的已定义字符串

6e5889519ec7d4a34725b2481c3b03ec.png

小结

本文重点探讨了逆向分析Go二进制文件时所面临的两个难题的解决方法,以帮助逆向工程师使用Ghidra对使用Go编写的恶意软件进行静态分析。具体来说,我们首先讨论了如何恢复剥离型Go二进制文件中的函数名,并提出了几种在Ghidra中定义字符串的解决方案。我们创建的脚本和本文中的例子所使用的文件都是公开的,大家可以通过下面的链接找到它们。

实际上,这只是在Go二进制程序的逆向之旅中迈出的一小步。接下来,我们计划深入研究Go函数的调用约定和类型系统。

在Go二进制代码中,参数和返回值是通过栈而不是寄存器传递给函数的,而Ghidra目前很难正确检测到这些内容。因此,帮助Ghidra支持Go的调用约定将有助于逆向工程师理解所分析的函数的用途。

另一个有趣的话题是Go二进制文件中的类型。正如我们从被调查的文件中提取函数名称所显示的那样,Go二进制文件也存储有关所用类型的信息。恢复这些类型对逆向工程有很大的帮助。在下面的例子中,我们恢复了一个eCh0raix勒索软件样本中的main.Info结构体。这个结构体能够告诉我们,恶意软件希望从C2服务器得到哪些信息。

cd69e059d370d88902484d288d0e92e8.png

图53 eCh0raix中的main.info结构体

bccd7b2b434169231569ddc4657ba825.png

图54 eCh0raix中的main.info字段

5e746dbeb8af57d4a22aee06782d01a4.png

图55 eCh0raix中的main.info结构体

正如你所看到的,从逆向工程的角度来看,在Go二进制代码中还有很多有趣的地方有待考察,对此感兴趣的读者,请关注我们的下一篇文章。

保存本文中所用脚本和其他材料的Github仓库的地址如下所示:

· https://github.com/getCUJO/ThreatIntel/tree/master/Scripts/Ghidra

· https://github.com/getCUJO/ThreatIntel/tree/master/Research_materials/Golang_reversing

本文所使用的相关文件:

File name   SHA-256

[1]     hello.c     ab84ee5bcc6507d870fdbb6597bed13f858bbe322dc566522723fd8669a6d073

[2]     hello.go     2f6f6b83179a239c5ed63cccf5082d0336b9a86ed93dcf0e03634c8e1ba8389b

[3]     hello_c     efe3a095cea591fe9f36b6dd8f67bd8e043c92678f479582f61aabf5428e4fc4

[4]     hello_c_strip     95bca2d8795243af30c3c00922240d85385ee2c6e161d242ec37fa986b423726

[5]     hello_go     4d18f9824fe6c1ce28f93af6d12bdb290633905a34678009505d216bf744ecb3

[6]     hello_go_strip     45a338dfddf59b3fd229ddd5822bc44e0d4a036f570b7eaa8a32958222af2be2

[7]     hello_go.exe     5ab9ab9ca2abf03199516285b4fc81e2884342211bf0b88b7684f87e61538c4d

[8]     hello_go_strip.exe     ca487812de31a5b74b3e43f399cb58d6bd6d8c422a4009788f22ed4bd4fd936c

[9]     eCh0raix – x86     154dea7cace3d58c0ceccb5a3b8d7e0347674a0e76daffa9fa53578c036d9357

[10]    eCh0raix – ARM     3d7ebe73319a3435293838296fbb86c2e920fd0ccc9169285cc2c4d7fa3f120d

[11]    Kaiji – x86_64     f4a64ab3ffc0b4a94fd07a55565f24915b7a1aaec58454df5e47d8f8a2eec22a

[12]    Kaiji – ARM     3e68118ad46b9eb64063b259fca5f6682c5c2cb18fd9a4e7d97969226b2e6fb4

6e5889519ec7d4a34725b2481c3b03ec.png

参考资料

· https://rednaga.io/2016/09/21/reversing_go_binaries_like_a_pro/

· https://2016.zeronights.ru/wp-content/uploads/2016/12/GO_Zaytsev.pdf

· https://carvesystems.com/news/reverse-engineering-go-binaries-using-radare-2-and-python/

· https://www.pnfsoftware.com/blog/analyzing-golang-executables/

· https://github.com/strazzere/golang_loader_assist/blob/master/Bsides-GO-Forth-And-Reverse.pdf

· https://github.com/radareorg/r2con2020/blob/master/day2/r2_Gophers-· AnalysisOfGoBinariesWithRadare2.pdf

6e5889519ec7d4a34725b2481c3b03ec.png

相关工具

IDA Pro

· https://github.com/sibears/IDAGolangHelper

· https://github.com/strazzere/golang_loader_assist

radare2/Cutter

· https://github.com/f0rki/r2-go-helpers

· https://github.com/JacobPimental/r2-gohelper/blob/master/golang_helper.py

· https://github.com/CarveSystems/gostringsr2

Binary Ninja

· https://github.com/f0rki/bn-goloader 

Ghidra

· https://github.com/felberj/gotools

· https://github.com/ghidraninja/ghidra_scripts/blob/master/golang_renamer.py

参考及来源:https://cujo.com/reverse-engineering-go-binaries-with-ghidra

6afad88a17672f5529466ba179575b8b.png

99edd2cece4997f16108fd1835f2816c.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/365720.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工艺路线和工序有差别吗_你知道吗?市政道路排水工程的主要工序施工工艺是什么...

易筑教育给排水课程火热招生中!张老师微信号:yizhujiaoyu999市政道排工程施工遵循的基本顺序是:先地下,后地上;先深后浅。按照这个顺序,正常的施工顺序为基础处理、排水管道(涵)施工(雨、污水)、道路基层(常…

如何:从Spring 4.0快速入门以构建简单的REST-Like API(演练)

如何:从Spring 4.0快速入门以构建简单的REST-Like API(演练) 关于使用Spring MVC创建Web API的另一篇教程。 不太复杂。 只是一个演练。 生成的应用程序将提供简单的API,将Mongo作为其持久性,并将通过Spring Security进…

01-Web客户端与服务器详解

1、CS与BS 软件使用方式上两种划分  C/S架构 Client/ServerPC客户端、服务器架构 特点:   在服务器当中就主要是一个数据库,把所有的业务逻辑以及界面都交给客户端完成 优点:   较为安全,用户界面丰富,用户体验好…

axi ps读写pl_PL读写DDR:Datamover能干什么

最近发现工程项目中一直在用AXI-DMA。这玩意儿搬数据倒是没问题,就是用axi-lite配置起来非常反人类。。。简单的办法其实是用datamover ip核。这个ip核能干嘛呢。准备写个文章解析一下。由于好多feature没用过,所以仅仅看文档可能理解有误,欢…

在10分钟内在新Mac中设置Java开发环境(更新)

这只是一个小的更新文章,它引用了2个较旧的条目( a , b ),我将它们合并为一个步骤,就像一步操作,并确保所有功能都在最新的MacOSX 10.9 Mavericks下工作 。 我主要针对的是初次尝试设置其环境的…

linux path 与 classpath 区别

linux path 与 classpath 区别 一、OS依据path中的路径信息来寻找可执行指令; 例如: cat /etc/profile 我们就可以在任意目录执行hadoop / hdfs / yarn / java 等相关命令了 export HADOOP_HOME/opt/hadoop/hadoop-2.6.0 export JAVA_HOME/home/jdk1.8.0…

开启9008端口进入深刷模式

除了前文所述,使用深刷线,还可以用命令开启9008端口,进入深刷模式。 adb reboot edl fastboot oem edl 这个在小米4c上测试ok 下面这个可能用于其他手机。 fastboot reboot emergency http://www.znsjw.net/nd.jsp?id19 小米绕BL锁9008工程…

hashmap为什么用红黑树_要看HashMap源码,先来看看它的设计思想

HashMap 是日常开发中,用的最多的集合类之一,也是面试中经常被问到的 Java 类之一。同时,HashMap 在实现方式上面又有十分典型的范例。不管是从哪一方面来看,学习 HashMap 都可以说是有利无害的。分析 HashMap 的源码的文章在网上…

实现CA和证书申请

文字说明 1 在CA上执行,建立CA cd /etc/pki/CA touch index.txt echo 0F > serial (umask 077;openssl genrsa -out private/cakey.pem 2048) openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 3650 填写多项内容:国家&#xff…

端口如何支持非localhost访问_新特性解读 | MySQL 8.0.19 支持 DNS SRV

转载自公众号:玩转MySQL作者:洪斌MySQL Router 是 InnoDB Cluster 架构的访问入口,在架构部署上,官方给出的建议是 router 与应用端绑定部署,避免 router 单点问题。之前还有客户咨询,能否 router 不与应用…

记录奥运-当今五大Java记录框架之间的竞赛

开发人员:Takipi会告诉您何时新代码在生产中中断– Log4J vs SLF4J简单vs Logback vs Java Util日志记录vs LOG4J2 日志记录实际上是每个服务器端应用程序中古老而固有的部分。 这是应用程序以持久且可读的方式输出实时状态的主要方法。 某些应用程序每天可能仅记录…

移动端实现元素拖拽效果插件_基于自然流布局的可视化拖拽搭建平台设计方案...

LowCode 是高效、高性能的拖拽式低代码开发平台. 也是笔者最近一直在研究的方向, 对于可视化搭建平台的实现方案笔者之前写过很多文章, 这里带大家探索一个新方向——基于自然流布局的可视化搭建平台.在我们之前实现的 h5-dooring 搭建平台中, 我们采用了网格布局的方式来实现拖…

07-数据类型

【转】07-数据类型 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 详细参考链接:http://www.runoob.com/mysql/mysql-data-types.html mysql常用数据类型概括&#x…

yii::$app-mongodb 查询纪录数_老詹总决赛有多强?12项数据领先乔丹科比,已握10项数据纪录...

勒布朗詹姆贡献了38分16个篮板和10个助攻的狂暴三双数据,并率领湖人淘汰了掘金,这使得他迈进了职业生涯第10次总决赛舞台。我们都知道,詹姆斯几乎统治着NBA季后赛大部分数据纪录,事实上,他在总决赛同样如此。根据《sta…

前端共享桌面_2020 前端学习路线总结,哎呦,不错哦!

2020 前端学习路线总结在 GitHub 看到一个很不错的前端学习路线图(roadmap),从前端基础到前端工程化,再到跨端,都有知识点的覆盖,非常推荐阅读。图下面是我翻译的一个文字版,可以先看图再看文字…

Confluence 6 高级性能诊断

请在你的系统服务请求中包括下面所有的信息,如果可能的话,你也可以在请求中包括你认为最有可能出现的问题。这样的话,可以避免我们进一步对你系统的问题进行询问。 系统信息 Confluence 服务器 你系统信息的屏幕截图 Confluences Administrat…

RequireJS使用注意地方

使用RequireJS做异步模块加载,有几点值得注意的地方: 1.模块定义两种写法 1. 存在依赖的函数式定义 如果模块存在依赖:则第一个参数是依赖的名称数组;第二个参数是函数,在模块的所有依赖加载完毕后,该函…

WildFly上具有AngularJS的Java EE 7和Java WebSocket API(JSR 356)

这篇博客文章描述了用于WebSocket协议的Java API(JSR 356) (这是Java EE 7平台的四个最新JSR之一),并提供了部署在WildFly 8上并可以在OpenShift上在线获得的具体应用程序。 [FR]版本的法语( HTML或PDF &a…

日期加减加1天_2小时整理了13个时间日期函数,动图演示简单易学,收藏备用吧...

Hello,大家好,今天跟大家整理汇总了13个工作中经常用到的日期与时间函数的使用方法,学会它们几乎可以解决所有工作中遇到的,关于日期与时间提取与转换的问题。话不多说,让我们直接开始吧一、了解时间与日期的本质工作中…

点云数据显示_vispy 显示 kitti 点云数据

国内博客找了一圈,居然没有发现有用 vispy 做可视化的代码,这里做一个简单的示例,代码大部分来自官方。import numpy as np import vispy.scene from vispy.scene import visuals import sys# Make a canvas and add simple view canvas vis…