吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4595|回复: 6
收起左侧

[转贴] 【转帖】利用Ghidra分析恶意软件Emotet

[复制链接]
默小白 发表于 2019-4-28 14:22

转自:https://xz.aliyun.com/t/4931

原文地址:https://medium.com/@0xd0cf11e/analyzing-emotet-with-ghidra-part-1-4da71a5c8d69
https://medium.com/@0xd0cf11e/analyzing-emotet-with-ghidra-part-2-9efbea374b14

在本文中,我们将为读者演示如何使用Ghidra来分析恶意软件Emotet的最新样本。

需要说明的是,我们的分析工作是在脱壳后的二进制文件的基础上完成的。由于这里主要是为读者展示如何使用Ghidra的python脚本管理器来对字符串和API调用进行解密,所以,具体的脱壳过程,就不再这里介绍了。

概述

什么是Ghidra?

  • Ghidra是一个开源的逆向工程工具套件,关于它的详细介绍,请参阅https://ghidra-sre.org/。

为何选择Emotet?

  • Emotet是一种流行的银行木马恶意软件。该木马的生命力非常强,其感染机制还在不断进化。当前,已经有一些关于该恶意软件的分析文章,感兴趣的读者请访问https://www.google.com/search?q=emotet。

为什么使用Ghidra分析Emotet?

  • 为啥?还不是因为IDA Pro许可证太贵,哥又不想放弃自己的恶意软件分析师职业生涯。
  • 当然,使用免费版IDA v7.0也是一个不错的选择,但是这样的话,就无法使用IDA Python了。在试用一段时间IDA自家脚本语言IDC之后,我发现Python才是我的最爱。而Emotet不仅支持Python,还提供了许多现成的分析脚本

使用Ghidra分析Emotet

在使用Ghidra时,首先要创建相应的项目。按照屏幕上的提示,我创建了一个名为“Emotet”的项目。要想将待分析的文件添加到项目中,只需键入I或选择File -> Import File菜单项。

img

导入Emotet的二进制文件

导入Emotet的二进制文件后,Ghidra将显示该文件的各种属性。之后,双击文件名,就会在CodeBrowser中打开该文件。在这里,CodeBrowser是一个反汇编工具。

img

CodeBrowser中的Emotet视图

在符号树下(通常显示在左侧;如果没有打开的话,可以通过window->symbol tree来打开它),通过过滤“entry”,就可以找到该二进制文件的入口点。

img

Emotet的入口点

在Listing窗口下面,我们可以看到编译后的代码,而右边显示的是反编译后的代码。由于之前已经对这些二进制文件进行了分析,因此,图中某些子例程调用和偏移量已经被我重命名了。当我们想要对偏移量进行重命名的时候,请右键单击相应的偏移量,然后,选择“Edit Label”(或键入L)即可。

Emotet的函数调用

Emotet不仅对自身的字符串进行了加密,同时,还将自身的API调用名称存储为哈希值形式。因此,静态查看该文件的内容的话,理解起来非常困难。

为了深入了解Emotet的payload,通常需要借助Olldbg、Wingdb或其他调试器来分析所有的函数,以弄清楚其内部运作机制。而本文的目标,就是如何利用Ghidra让这个过程更轻松一些。

下面,我们将展示如何利用Emotet弄清楚两个函数的运行机制。其中,第一个函数是一个简单的xor例程,用于解密字符串。表面上看,这个函数非常复杂(因为在函数中使用了移位运算符),直到在Ollydbg中运行一遍后,我才明白它到底是干什么的……第二个函数用于查找API名称与哈希值之间的对应关系(具体在后文中介绍)。当然,如果您觉得我说的还不够清楚的很,只要在Ollydbg中运行一下相应的代码,就能很好的理解了。

然后,我们将介绍Ghidra的脚本管理器,并展示如何通过python脚本来解密字符串并解析二进制文件中用到的API调用。

字符串是如何加密的?

在这个二进制文件中,我们发现许多地方都引用了0x00401b70处的一个函数调用。实际上,这个调用是用来解密字符串的,因此,不妨将其重命名为decode_strings。要查找对该函数的引用,请右键单击该函数,然后选择References -> Show References to即可。

img

对decode_strings函数的引用

img

对decode_strings函数的调用

函数decode_strings有两个参数,分别位于ECX和EDX中。其中,ECX中存放的是加密字符串的偏移量,而EDX存放的则是xor密钥。另外,解密后的字符串将存放到在堆中分配的内存中,其地址将存放到EAX中。

(注意:我已将字符串“ecx = offset \n edx = key”添加为该函数的可重复注释(repeatable comment)。具体操作方法为,右键单击地址,然后选择Comments -> Set Repeatable Comment,或键入;即可)

位于该偏移量处的第一个dword与进行异或操作后,就会得到字符串的长度。之后,根据前面得到的字符串长度,对后面相应数量的dword进行异或处理。

现在,我们将为读者介绍最为激动人心的部分——使用Ghidra通过python脚本自动完成上述操作。

使用Python完成自动解密

img

脚本管理器图标

在Ghidra的顶部的工具栏中,我们可以看到如图所示的图标。点击该图标,就会打开脚本管理器。此外,我们也可以通过Window -> Script Manager来打开它。

img

脚本管理器

打开脚本管理器后,我们会看到许多使用Java或Python语言编写的脚本,这些都是软件自带的。此外,脚本管理器还提供了许多python脚本示例。所以,要想学习如何编写python脚本,我们可以通过.py过滤相应的脚本。通过Python Interpreter,我们还可以使用Jython与Ghidra的Java API进行交互。至于Java API的文档,可以在Ghidra安装目录下的docs文件夹中的压缩文件中找到。

img

新建脚本图标

要新建python脚本,可以点击上图所示的图标;或者,我们也可以选择Python,然后输入为脚本指定的名称即可。

img

示例脚本test.py

此外,建议大家阅读帮助文档(请访问Help -> Contents)中“Script Development”一节的内容,那里详细介绍了创建新脚本时生成的各种元数据标记。

我已将脚本上传到我的github repo中,访问地址为https://github.com/0xd0cf11e/ghidra/blob/master/ghidra_emotet_decode_strings.py。

img

解密后的字符串以注释的形式显示

该脚本的思路就是,在将偏移量保存到ECX的指令旁边,以注释的形式显示解密后的字符串。

img

二进制文件中修补的字节。

然后,修补二进制中的字节。

img

首先,找出引用decode_strings函数的所有代码。

img

为此,需要遍历所有引用,并找出操作码指令MOV ECX和MOV EDX。实际上,这些指令并不总是位于函数调用之前。所以,为了查找这些操作码,我最多遍历100条指令。

完成上述操作后,执行xor例程,修补相应的字节,并在相应位置写入注释。

上面,我们介绍了如何使用Ghidra来静态分析恶意软件Emotet。我们知道,Emotet通过简单的xor函数对其字符串进行了加密处理。由于在整个文件中都使用了xor例程,手动解密非常繁琐,所以,我们为大家介绍了如何使用Ghidra的脚本管理器编写python脚本,以自动解码字符串。

接下来,我们将为大家演示如何利用类似的方法,来将Emotet中编码为哈希值解析为API名称。

Emotet是如何解析API地址的?

对于这款恶意软件的二进制文件来说,它并没有对API名称字符串进行加密。相反,它将API名称存储为哈希值,以加大安全人员的分析难度。

这些哈希值数组存储在堆栈中,然后,在函数0x401230中通过指针来引用这些哈希值。所以,我们已将函数0x401230函数标记为decodeAPINames。

img

保存在堆栈中的哈希值

img

传递给函数的其他参数

首先,在调用decodeAPINames之前需要获取DLL的句柄。为此,该恶意软件通过PEB枚举来查找kernel32.dll和ntdll.dll的句柄。而其余的DLL,则通过LoadLibraryW(DLL名称由xor例程进行了编码)进行加载。

该函数使用这个句柄来读取DLL的导出地址表。同时,它会计算表中的每个API名称的哈希值,并与压入堆栈的哈希值进行比较。如果匹配,则将相应的API地址将保存为文件内部偏移量。

注意,堆栈中并非所有哈希值都是有用的。相反,许多哈希值都是用来滥竽充数的,所以,乍一看该文件的API地址列表硕大无比,实际上,这只是迷惑安全分析人员的假象。

使用Python将哈希值解析为函数名称

这里有一个通过哈希值解析函数名称的脚本,下载地址为:  https://github.com/0xd0cf11e/ghidra/blob/master/ghidra_emotet_decode_hash.py

当然,还有许多其他方法也可以解决这个问题。这里使用的方法一方面需要用户进行参与,同时,还需要将API名称列表保存到一个文件中。正是因为这个过程有些繁琐,因此,我才编写了一个简单的脚本,让它来替我们完成这些准备工作。

img

来自Kernel32的部分API名称

首先,我编写了一个脚本,用来将DLL的所有导出函数都保存到一个文件中。

然后,用这个脚本来处理ntdll.dll、kernel32.dll、advapi32.dll、shell32.dll、crypt32.dll、urlmon.dll、userenv.dll、wininet.dll和wtsapi.dll。

接下来是找到所有引用decodeAPINames的偏移量。在这个过程中,我在脚本管理器中无意中发现了Ghidra提供的Java脚本ShowCCallScripts.java。根据该脚本名的提示,我将光标放在decodeAPINames函数中,然后运行了该脚本,结果如下所示:

img

运行ShowCCallScripts.java后,控制台的输出结果

运行该脚本时,需要注意哪个引用的偏移量处的函数解析哪个DLL的API名称的。
例如,0x4079c0处的函数解析crypt32.dll API名称。为什么这么说呢?因为我发现,当调用decode_strings时,其名称是由0x407afa处的函数进行解析的(详见前文)。然后,会在偏移量0x407b3a处调用decodeAPINames。

img

输入引用decodeAPINames的偏移量。

脚本运行时,会要求输入相应的偏移量。例如上图中,我们输入的是407b3a。

img

crypt32.list文件,其中含有crypt32.dll导出函数名称列表。

接下来,它会提示输入文件名,这里,我们输入的是用来保存crypt32.dll导出函数名称的文件。

在控制台中,我们看到解析了哪些API名称。就crypt32.dll来说,只有一个API名称解析了出来,即CryptDecodeObjectEx,尽管有39个(十六进制为0x27)哈希值被压入堆栈。

img

控制台输出结果

之后,该脚本会使用API名称来标记偏移量。

img

创建CryptDecodeObjectEx标签。

下面是处理kernel32.dll的结果:

img

kernel32的API名称

希望本文能够对读者有所启发,如果您已经找到了更好的方法来解析哈希值,或发现了与Ghidra有关的有趣的技术,欢迎与我们一起分享。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
bbn + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

A-new 发表于 2019-4-28 16:37
直接写为ida脚本不更好
Oyasimi 发表于 2019-4-28 18:37
Vulpine 发表于 2019-4-28 21:15
zxkj13 发表于 2019-4-28 21:40
注册码:THFD-WHEY-LYQB-JQYV
92013 发表于 2019-5-3 18:36
非常感谢OAO
genliese 发表于 2019-12-26 18:31
大佬,强!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-24 18:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表