首页
社区
课程
招聘
C#恶意样本分析技巧
2021-11-19 17:32 8816

C#恶意样本分析技巧

2021-11-19 17:32
8816

​ 日常样本分析中,我们会遇到各式各样的语言所编写的恶意样本。除了最基础的C/C++之外,使用C#、python、VBScript、Office宏、PowerShell来构造恶意代码也较为常见。

 

​ 为了让新入门者对各种类型样本的代码结构和分析流程都进行一次了解,我构思了如下系列文章《如何分析各种类型的恶意样本》来进行讲解,希望可以帮到大家。最开始发布在本人博客hskull

概述

  • C#是微软公司发布的一种由C和C++衍生出来的面向对象的编程语言、运行于.NET Framework和.NET Core(完全开源,跨平台)之上的高级程序设计语言。由于其相较于C/C++更为易于开发且同样强大,近年来越来越多的APT组织以及一些RAT工具都将C#做为主编程语言进行恶意样本的Downloader或者恶意样本本身来开发。
  • .NET/C#的反编译工具常见的有:.Net Reflector、ILSpy/dnSpy、JetBrains dotPeek、GrayWolf等。我常用的是ILSpy/dnSpy这两个工具,尤其dnSpy所具有的动态调试功能是分析样本的利器。
  • 另外.Net/C#相关的逆向分析工具还有很多,比如解混淆的de4Dot,这些工具在吾爱的工具包中都已经集成了,需要可以去吾爱进行下载并使用。

这里我将对一个典型的适合新手进行分析的C#远控样本进行分析,来对一些基础的C#分析技术点进行说明。

  • 样本信息如下:
描述 信息
MD5 BFA95399E5F9413A0EC9289FAA1DC801
  • 拿到样本后通过Exeinfo查看,样本是一个.net程序,使用dnspy进行分析

  • 样本执行流程大致如下:

详细分析

样本自身功能分析

  • 将样本拖入DnSpy开始进行分析(Dnspy运行需要.Net Framework环境的支持,不能运行请下载并安装后再运行Dnspy),拖入后会显示下图所示一些信息包括文件名以及版本等静态信息。另外要注意的是exe文件拖入Dnspy后在侧边栏中名称为黄色,而dll文件拖入后在侧边栏中名称为白色。

 

之后右键Go To Entry Point即可跳转到main函数,一般来说程序具有窗口(无论隐藏与否)时,main函数都是用来调用Application.Run()进行窗口的启动(学过SDK/MFS的同学应该不陌生,这就相当于启动了窗口的消息循环):

 

 

一般来说,恶意操作都会在隐藏窗口类中进行,我们只需向下寻找即可。向下分析后果然找到了内嵌ShellCode代码:

 

 

这里提一句,在Dnspy中也可以进行交叉引用的分析,只要选中函数名或变量名,然后右键Analyze即可打开对应窗口进行查看,很方便:

 

  • 上述的shellcode在样本中是加密存储的,样本执行时会对其进行两次解密,这里就要用到Dnspy动态调试的功能来对解密后的shellcode进行dump,点击上方的start,默认以C#代码进行调试(另外还有IL和VB两种查看方式),Dnspy调试快捷键和VS相同(F9、F10、F11),我们在调试时,会自动显示出Locals窗口,里面对当前所在命令空间的变量进行实时显示。Dnspy中所有能显示的窗口都在Debug选项下。

 

运行到解密完成后,观察 rawAssembly的值:

 

 

将其中数据拿出后,发现解密后的shellcode为一个PE格式的恶意代码:

 

 

通过Locals中右键rawAssenbly进行save操作,将shellcdoe保存到本地,留待稍后分析。

  • 这里解密后的操作时利用C#反射的技术进行shellcode调用,可以判断dump到的shellcode为一个dll,接口为dll的Main函数,传入参数如下所示,同样通过调试运行观察内存得到:

dump到的dll分析

  • 查看dump到的恶意shellcode,确实是个dll文件,Dnspy分析其名称为CoreFunctions.dll(重要),信息如下所示:
描述 信息
MD5 501FEB03129FF392F6FFB5AEEC900356
名称 CoreFunctions.dll
 

  • 对于C#dll的分析,首先我们可以考虑自己写一个Loader然后将Loader.exe和dll一起拖入dnspy,然后进行dll调试。

我用到了VS进行Loader的编写,这里有个要注意点是,在using dll时,用到的dll名称要和将dll拖入dnspy中反编译出的命名空间名称一致即为CoreFunctions,代码的编写很简单,只要将对应的Main函数调用并传入上述抓取到的参数即可:

1
CoreFunctions.Class1.Main("02bc3.resources", "5de4f.png", "JV6tiESFB", null);

切记:建议向我这样加上一个窗口和调用按钮,防止在编译exe时不小心加载了恶意dll。当然也可以不加,不过就需要时刻注意自己生成exe的方式为右键重新生成而不是直接Release。

 

  • 另外分享一个快速调试方式,经过前辈们分析底层函数发现一个关键函数:InvokeMethodFast(),此函数在运行dll之后会被调用,步入断点所在的代码,就可以直接进入dll进行调试。ps:这个方法可以一直运行下去,省了dump的麻烦,可谓非常厉害了

  • 此dll执行的操作流程大致如下,详细分析不在赘述:

获取样本完整路径->加载样本的资源("02bc3.resources")->遍历资源找到"5de4f.png"的数据->对数据进行处理并以"JV6tiESFB"作为Key来解密数据->得到新的恶意代码并执行

 

 

资源如图所示:

 

新恶意代码分析

  • 依旧将新的恶意代码dump然后分析,命名为ReZer0V2.exe信息如下:
描述 信息
MD5 B9C0837EED92228BFD8C55E2D40630D6
名称 ReZer0V2.exe
 

 

分析调用后会发现,其会从EntryPonit入口点开始运行代码,样本是一个C#的exe,可以直接进行调试分析,调试方法和最初样本一样。

 

这份恶意代码又加入了新的东西,那就是C#程序防止反编译常用到的混淆操作。由于有混淆不能正常调试,所以调试之前先使用de4dot进行解混淆操作(大部分情况下不能解出正确的函数名,只是使得代码更加易读一点)。de4dot用法是将C#程序拖到de4dot.exe上执行即可(版本选择正确),也可以cmd命令行执行,看你个人选择。

  • 此恶意程序完成了如下的操作:

创建互斥体"FWYvRWJ"防多开、睡眠主线程

 

 

查询指定文件:"C:\Users\Administrator\AppData\Roaming\wpohqL.exe"是否存在,不存在生成,完成对最开始样本的复制存储

 

 

之后调用函数smethod_6进行操作:

 

 

主要完成了如下操作:

 

向路径"C:\Users\Administrator\AppData\Local\Temp\"下生成了一个临时命名的临时文件,将资源中的XML数据进行替换之后填充临时文件,如图所示:

 

 

之后构造一个进程启动信息,然后启动进程 schtasks.exe,输入命令为:/Create /TN ”Updates\ wpohqL" /XML "C:\Users\Administrator\AppData\Local\Temp\%.tmp",创建一个计划任务,任务目的是在用户登录时启动程序:C:\Users\Administrator\AppData\Roaming\wpohqL.exe,完成对样本副本的持久化

 

最后程序流程执行到运行一个新的恶意程序

熟悉的C++程序分析

  • 这次dump到的恶意程序,是一个熟悉的C++程序,信息如下:
描述 信息
MD5 eb5e1c063fab1a1a0f93ab615b72b461
 

 

这个恶意程序就是做恶意操作的主要程序,有以下恶意行为:

 

通过动态获取API地址来进行功能的实现,程序内置hash后的API名称字符串,通过函数sub.004031E5获取

 

利用SetErrorMode()来进行反沙箱操作

 

 

调用advapi32.dll中的函数来计算出一个唯一hash,用于创建互斥体,图中一个为计算之前的,圈出来为计算之后的互斥体名称,检测多开

 

 

  • 程序有几个关键的call,分别用于完成不同的功能:

 

第一个call:

 

获取注册表信息,修改FirFox配置进行流量劫持:

 

"SOFTWARE\Mozilla\Mozilla Firefox"拼接为完整信息“SOFTWARE\Mozilla\Mozilla Firefox\53.0 (x 86 zh-C)\Main”,并向path环境变量中添加新的路径:"C:\Program Files\Mozilla Firefox"

 

 

检测nss3.dll是否存在,存在加载dll,动态获取API

 

 

获取的API有:

 

NSS_Init、NSS_Shutdown、PK11_GetInternalKeySlot、PK11_FreeSlot、PK11_Authenticate、PK11SDR_Decrypt、PK11_CheckUserPassword、SECITEM_FreeItem

 

之后大范围去将“\AppData\Roaming\Mozilla\Firefox"+下图所示的路径拼接:(图示为一部分)

 

 

然后利用nss.dll对Firefox配置进行一些列操作

 

第二个call:

 

释放隐藏的副本文件

 

 

用于在本地"\ AppData\ Roaming\ "创建一个新目录,并向其中存放样本副本,同时为目录和副本都设置隐藏属性,路径如下:

 

 

第三个call:

 

构造Socket套接字,建立TCP远程通信,上传获取到的所有本机信息,等待后续远控

 

获取信息:

 

 

建立连接:

 

 

 

C2信息如下:

 

URL:hxxp://broken6[.]cf/L8/fre.pnp

 

IP:104.27.145.219:80

IOCs

Md5:

 

BFA95399E5F9413A0EC9289FAA1DC801

 

501FEB03129FF392F6FFB5AEEC900356

 

B9C0837EED92228BFD8C55E2D40630D6

 

eb5e1c063fab1a1a0f93ab615b72b461

 

URL:

 

hxxp://broken6[.]cf/L8/fre.pnp

 

Domain:

 

broken6[.]cf

 

IP:

 

104.27.145.219:80


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2021-11-22 17:24 被hskull编辑 ,原因:
收藏
点赞3
打赏
分享
最新回复 (9)
雪    币: 1451
活跃值: (14614)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
SSH山水画 3 2021-11-19 19:15
2
0

调试.NET dll还有个骚操作

随便加载一个C#的exe(一般是安装器),右键选 与程序集合并。  然后选择待调试的dll,这时候dll的所有类、资源、引用都与exe合并到一起了

然后修改原exe的入口函数(右键编辑类)直接调用dll的入口函数。

最后Ctrl+Shift+S保存,再调试exe就是直接跑dll的代码了。

雪    币: 5377
活跃值: (2498)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chinasmu 2021-11-19 20:28
3
0
SSH山水画 调试.NET dll还有个骚操作随便加载一个C#的exe(一般是安装器),右键选 与程序集合并。  然后选择待调试的dll,这时候dll的所有类、资源、引用都与exe合并到一起了然后 ...
加壳的dll也可以这样搞吗
雪    币: 1451
活跃值: (14614)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
SSH山水画 3 2021-11-19 23:14
4
0
chinasmu 加壳的dll也可以这样搞吗
可以啊,不过你不去混淆怎么动态调呀,多折磨啊。
一般是先去混淆,然后再这样调。 
雪    币: 5377
活跃值: (2498)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chinasmu 2021-11-20 01:03
5
0
SSH山水画 可以啊,不过你不去混淆怎么动态调呀,多折磨啊。 一般是先去混淆,然后再这样调。
我自己测试了一个发现认不出dll的类,没法调用dll的方法
雪    币: 1451
活跃值: (14614)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
SSH山水画 3 2021-11-20 01:47
6
0
chinasmu 我自己测试了一个发现认不出dll的类,没法调用dll的方法[em_25]

类上面手动导入 using  他不会自动帮你补的

最后于 2021-11-20 01:48 被SSH山水画编辑 ,原因:
雪    币: 5377
活跃值: (2498)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chinasmu 2021-11-22 08:08
7
0
SSH山水画 chinasmu 我自己测试了一个发现认不出dll的类,没法调用dll的方法[em_25] 类上面手动导入 using& ...
神奇的就是这个,我导入using是正常的,方法体里引入就识别不出来
雪    币: 1451
活跃值: (14614)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
SSH山水画 3 2021-11-22 09:44
8
0
chinasmu 神奇的就是这个,我导入using是正常的,方法体里引入就识别不出来
是静态成员吗,创建对象了吗
雪    币: 5
活跃值: (208)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
hskull 2021-11-22 17:18
9
0
SSH山水画 调试.NET dll还有个骚操作随便加载一个C#的exe(一般是安装器),右键选 与程序集合并。  然后选择待调试的dll,这时候dll的所有类、资源、引用都与exe合并到一起了然后 ...
哦吼,知识点+1
游客
登录 | 注册 方可回帖
返回