原文首发做:奇安信攻防社区
https://forum.butian.net/share/3701
好久没写文章了,简单写篇样本分析的文章记录下前几天分析的一个样本,这个样本还是比较经典的,做了些反分析的手段,也使用了一些比较流行免杀对抗技术,能够免杀一些杀软;这篇文章我们主要看这个loader怎么做的,以及如何正常分析这样的样本和快速拿到c2;同时也分享一些奇奇怪怪的知识:如何提取样本特征做威胁狩猎以及对样本对抗的一些思考和想法;
0x01 前言
好久没写文章了,简单写篇样本分析的文章记录下前几天分析的一个样本,这个样本还是比较经典的,做了些反分析的手段,也使用了一些比较流行免杀对抗技术,能够免杀一些杀软;这篇文章我们主要看这个loader怎么做的,以及如何正常分析这样的样本和快速拿到c2;同时也分享一些奇奇怪怪的知识:如何提取样本特征做威胁狩猎以及对样本对抗的一些思考和想法;
样本是一次演习活动别人分享出来的,通过微步可以下载;
下载地址
0x02 基本信息
样本信息:
name:汪涵-上海交大硕士-应聘系统安全岗20240722转换pdf.exe md5:aeae584563bb8bf0961bd99aaeb41cf0
0x03 分析
首先样本exe伪装pdf,加了各pdf的图标资源;
一、上火绒剑
这里直接上火绒剑,开启系统监控,然后运行样本,粗略的看下样本的行为
这里我们直接把样本丢到虚拟机并双击运行:
没有发现外联行为,进程起来之后,1秒不到很快就自动挂了,行为主要都是一些文件读取和注册标读取操作;
行为列表的最后,我们发现两个可疑的操作,文件读取和注册表读取
第一个动作时读取桌面文件目录,第二个动作时读了一个特殊的注册表(似乎和虚拟机有关,键里面有wmware);
这里第二个特征比较有辨识度,我们尝试google下:
简答看下第二个帖子:这个帖子总结了一些常见反虚拟化操作,根据帖子中下面描述,攻击者可以通过检查特定注册表值来判断当前运行环境是否是在虚拟机Vmware和VirtualBox,其中我们看到 上面的HKEY_CLASSES_ROOT\Applications\VMwareHostOpen.exe
可以用来检测对当前环境是否是Vmware:
该动作的堆栈调用情况,这里记录下,之后调试分析的时候会用到:
二、上IDA
直接定位调用的堆栈处,调用函数的RVA:0xfa97,可以看到这个函数就是两个注册表OPEN操作,第一个就是我们刚刚分析的可能是用来检测当前运行环境是否在Vmware虚拟机中的:
通过RVA:0xfa97的函数回溯,找到调用链:
这里我们反着,从底层向上一个个来看下这些函数;
1、sub_14000DDA0
如下图,这个函数里面我们简单看,对一些条件做了判断,然后最后满足某种条件,就会调用CreateThread新建线程执行StartAddress处的逻辑;大致是有四个条件,其中一个就是我们刚刚分析的对注册表 虚拟机项的判断;
这里我简单看下另外三个条件函数是在做什么:
sub_14000F974
代码实现如下:
通过SHGetFolderPathW获取桌面路径(第二个参数CSIDL 0X11),然后通过FindFirstFileW和FindNextFileW遍历目录下的文件;遍历的时候没有其他逻辑只是一个计数,最后判断数量是否大于10个,来返回;比较明显的通过桌面文件数量来对抗虚拟机和沙箱;
sub_14000FB54
代码逻辑如下:
通过SHGetKnewFolderPath
获取指定文件路径;其中&rfid
参数含义及解释,我们可以知道这里是通过guid来获取文件路径,和上面的CSIDL异曲同工;
该参数的值:
从而windows SDK里面的knownfolders.h
(或者参考:https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid),找内置的这个值对应文件夹路径是 《最近》目录;
然后通过FindFirstFileW和FindNextFileW遍历《最近使用》目录下的文件;遍历的时候没有其他逻辑只是一个计数,最后判断数量是否大于10个,来返回;比较明显的通过《最近使用》文件夹下的文件数量来对抗虚拟机和沙箱;
sub_14000FC7B
这个不用多说,用来检测系统上装没装微信,(这个注册表是微信安装目录的键值对所在):
同时这里我们也分析下,下面的创建线程要执行的代码是干什么的:
如下,弹窗报错,然后结束,这里应该就是检测到虚拟机就调用这个来伪装结束:
2、sub_14000D8A3
这个函数上来的逻辑比较清晰,从资源段拿到了数据;
然后数据存在的情况下,调用了一堆函数处理;
我们先来看sub_140011220
这个函数,根据图中文字分析,我们可以大致推测出,这个应该是个memorycopy操作,参数1是目的地址,参数2是源地址,参数3是copy的字节数;
这样我们就能简单看出,此处的逻辑是:把对应资源段提出来的内容的前0x90个字节赋值给v23,然后调用上面分析的反虚拟化函数处理v23,然后开辟一个空间,空间大小是资源大小-0xb0,把资源段的0xb0偏移开始位置的内容复制到开辟的空间里面v12;
接着,根据反虚拟化函数sub_14000dda0
的结果调用函数对提取出来的资源段0x0b偏移核心内容v12进行处理,这里有一个细节就是决定两个处理逻辑的是资源段里面的某个值,所以这里大概率是攻击者可以配置修改;
上图中的处理,跟进函数细节,你会发现一堆看不懂的逻辑运算以及操作;这里我们用常规思维 一些细节去猜就行了,然后动态调试的时候来证实下我们的猜想即可;
从逻辑上看,这里从资源段拿了一堆数据,现在是对这堆数据操作,是不是大概率是有可能是解密操作; 从函数参数和实现上看,传入的第四个参数是128,这里我们对数据要敏感,128是aes加密的最小单元,如下图,我们看到de42偏移的这个函数逻辑里面,有模128取余操作,是不是和aes里面的填充或者解分组(ecb)啥的是不是有有可能有关系;
所以这里大概率是解密操作;我们不做详细分析了;
接着还有一堆逻辑,我们简单分为几块,如下图,第一块是简单看,看不出来逻辑的一些项,尝试看下函数实现,也没有相关明显发现;
第二块,这里是通过GetAdaptersInfo(xp之前使用)来获取网络适配器的信息,AdapterName就是适配器的guid,这个值加了个值然后赋值给v19了,v18变量记录的是获取到的网络相关信息结构体IP_ADAPTER_INFO
的大小;
接着往下的逻辑,我们看到上面获取到的两个值v18、v19,作为第二和第三个参数都传入了函数 sub_14000E71F
;
函数sub_14000E71F
的实现如下:通过v19(guid)作为随机种子,获取伪随机值;v18是返回的数组大小,返回数组每个元素都是通过v19异或第一个参数(第一个参数是前面资源段解密后的内容数组,这里按个取数组值)然后再异或伪随机(种子是guid)获得的值;最后返回该字节数组;这里看上去是一个特定环境的解密,依赖于获取到的网络设备的guid信息(后面动态调试的时候会发现其实不然,这里只是虚晃一枪);
上面返回的数组,在sub_14000D8A3
里面也是直接作为返回值,返回了,如下图:
最后一部分逻辑,如下图,两个函数:
sub_14000e778
这个函数实现如下:
这个函数先是通过K32GetModuleInformation这个函数获取到ntdll的基址,然后遍历区块表,找到.text节,然后从文件系统中获取C:WindowsSystem32ntdll.dll文件的映射值,用这个text节的值覆盖进程中text节的值;非常经典的反监测;很多杀软都会通过在r3层hook一些关键api(一般都是inlinehook,在原始api调用的地方来个jmp),对一些关键api的调用进行监控,这里为了绕过这种类型的监控,选择将r3层的ntdll给重置,从而unhook掉杀软做的inlinehook;
待动态分析确认:sub_14000E71F 里面第三个参数是多少,srand的参数是这个;目前静态看是adaptername里面的第一个字节 111;
3、sub_14000A4CC
函数伪代码实现如下:
可以看到前面的逻辑里面都是调用sub_1400d7ed
这个函数,该函数传入的参数是一个winapi的名称;
该函数的实现如下:
上图,可以看到上来就是眼熟的0x3c和0x88,从某个基址找pe头找导出表;然后就是根据函数名称表,函数地址表,函数序号表,获取到传入参数名称的函数地址,这里返回的是进程空间的绝对地址;
这里的基址是v2,v2是从sub_140018F10
这里来的,所以这里我们看下这个函数,如下图,可以看到就是peb拿ldr,再拿InMemoryOrderModuleList,再拿基址那套,获取当前进程内存加载顺序的内存加载模块列表,这里跳过了第一个模块,因为第一个模块是自己;
所以sub_14000d7ed
这个函数其实就是get_apiaddressbyname
;
再回过来看sub_14000A4CC
,注释之后,如下图,我们可以分析出来,这里就是一个利用纤程实现的shellcodeloader,还算是比较少见的,shellcode就是从上面分析的sub1400d8a3
来的,结合刚刚sub_14000d8a3
分析的逻辑,是从资源段取出来了一段数据,进行了一堆操作,最后还原出的shellcode;
4、sub_14000A2FC
该函数伪代码逻辑如下,如果sub_14000a4cc
没有报错或者出问题,这里显示创建了一个互斥变量,防止多实例,然后就是afx ui的一堆函数和逻辑,这里我们暂时不做关注;
三、上dbg
1、找到函数调用点
上面我们分析的这些代码,静态分析是没有直接的主函数调用的,但我们能看到的是,调用地址是在rdata段有对应记录的;这里我们先给sub_1400a2fc
一个断点,从堆栈返回调用链
断点如下,(dbg里面的基址:0x7FF7C3D80000,这里正确的分析顺序一般先是用dbg打开样本,拿到基址之后,再去ida分析,ida分析rebase下基址,两边基址对齐,看起来方便点)
断下来的时候堆栈如下,
找到调用点,7FF7C3F393C9
, 减基址得到偏移为:1B93c9
回到IDA,我们看下这个地址在哪,如下两图,winmain里面动态获取地址转指针调用的,afx相关编程(这里笔者对这个也不是很熟悉,不知道是编译器生成就是这里调用用户代码,还是攻击者这里是通过篡改编译器生成的代码造成,但是不管怎么样,是这里调用过去的)
2、过反虚拟机代码
断点打在dda0
偏移处(上面分析的反虚拟化函数地址,最好是打在调用该函数处,因为进来之后,你还要管堆栈)
调试,断住,然后把rip置为return的值来跳过对vm的检测;
3、获取shellcode
获取网卡的guid,但是这里只了第一个字节{
,加0x313131
,得到0x3131ac
,所以后面随机种子其实都是这个,由这个随机种子生成的随机数,就是密钥(严格意义上说是第二个密钥,由于异或解密;上面资源段拿出来后还有一个aes解密);
资源段拿出来第一次解密前:
第二次解密前:
第二次解密后,此时就是最后的shellcode;
dump下shellcode,继续调试;
这里我们这篇文章不对该攻击者shellcode做剖解分析;有机会之后再写个文章分析;(对shellcode分析是非常有必要的,有时候我们可以通过shellcode定位攻击者,不管是攻击者自己研发的远控,或者是通用远控;从其中使用的技术,我们都可以提取特征,这个特征可以是一种新型的shellcode写法,也可以是一种通用远控的新型配置,可以抽象的理解为攻击者的指纹)
4、获取c2
不对shellcode做详细分析,这里我们直接使用快速分析的方法,可以直接跑,然后上procmon监控下进程动作,注意这里把断点都清了,里面可能会有反调试操作,如下是该进程的加载的模块;我们都知道shellcode肯定是要外联的,不管你里面做了多少花里胡哨的操作,通过加载的模块,可以大致看出,外联使用的是winInet实现的和cobaltstrike类似;
接下来就直接上断点,wininet里面的关键函数:
InternetConnect HttpOpenRequest HttpSendRequest
然后拿到外联详情:
InternetConnect 这里可以直接看到目的域名是:static.aliyuncs.com.dsa.dnsv1.com
,目的端口443;
HttpOpenRequest 里面看到,这里是get请求,请求资源是:/link/Members/C90RDRN279YK.js
从HttpSendRequest这里,我们可以看到请求头相关信息,如下和下图,其中我们可以看到此时http请求内容里面的请求头中,hos置值为了:static.aliyuncs.com
;其中cookie里面的SESSIONID_P9041TWNDWNT53JA4LTXGEJNZNE3
字段疑似为相关心跳源数据;
Accept: image/*, application/json, text/html
Accept-Language: pt-br
Accept-Encoding: compress, *
Cookie: SESSIONID_P9041TWNDWNT53JA4LTXGEJNZNE3=BLJAEAGAHACNDJOJEDMEACFDJKJCCMNBMCEPHJLEIOHBPMACFOMELJNHLENBNOIEINLEBKFLFFNHBMCIJEMEFEGHJPHGGHHFOFGAFBMGJHBKFPOJKECMOOAPAFLDLCICOGCAANAOPELMOIBMCJJGCGFAMCBEKCJOBIBDGNMAPBKFNPPMPFHPEIPOHMFLIGBGMICLDONFGIKJGKKAMHEPJKLFBGFKFADNLLEHNOKFOLMCEMKLMLKBBDGEPHEMBDMLBHIDMMEN
Host: static.aliyuncs.com
再有就是这里用了域名前置的技术:
前置域名使用的是:
static.aliyuncs.com.dsa.dnsv1.com
后置域名使用的:static.aliyuncs.com
如下是后置域名的访问量,看上去像是阿里的正规网址,其实不然,全网google、百度、搜狗、都找不到其存在的痕迹;
对域前置的对抗技术,可以参见笔者blog中的另一篇关于对于样本分析的文章
0x04 思考:
这里笔者想借助这个样本的分析,表达对于几个问题的思考
一、制作样本和样本分析的对抗
1、从样本制作的角度(攻击者):
想要对抗样本分析,很多时候是有一个短板效应的;好比这样一个问题:制造样本的时候,是否可以为了对抗分析,有什么对抗手段就都上,这样就可以层层对抗,别人更不好分析了
这个问题笔者之前的看法是,给分析者的分析阻力越大,对抗越足,这样的样本就越好;但是其实不然这个问题是有一个前提的,前提是你给的这些阻力,每个阻力之间是叠加了,并且这些阻力的力度至少是相当的,就好比一个人向着浪拍来的方向游泳,他的前方有很多层浪,他在没有穿过第一个浪的时候其实他并不知道第二个浪的样貌;当时样本对抗技术并不是这样的,样本对抗过程中,很多时候你的这些对抗技术就是一个浪,而浪也有高点和低点,而你使用的技术的对抗强度就是这个浪不同位置的高度,此时这个人想要穿过这个浪,并不需要从最高点穿越,可以直接找个最低点穿越(如果你对密码学有过了解的话,这里可以理解为后向安全性,样本中的对抗技术之间大多数并不具备前后的位置性质,更不具备后向安全性);并且有的时候,做的越多,破绽就越多;好比一句老话说的,言多必失;
你可以使用多种对抗技术,但是不要良莠不齐,最终搞成吕布骑马这种操作;所以笔者认为所有的红队,但凡你需要上样本的,最好是都能深入的学习和了解样本的免杀和对抗技术,你可以不会实现,但是你要明白你用的东西他的效果,以及他对抗的点在哪,如果只会用一些所谓的免杀工具,就非常容易搞吕布骑狗的操作;
2、从样本分析(防守者)的角度:
样本分析其实和数据分析类似,就是一个穿针引线的过程;一个**“好的”**样本(这里指有较完善的免杀和反分析手段的样本),不会轻易的让分析者,找到所谓的短板;如:笔者之前看某个apt样本,利用编译器做一些文章,将恶意代码嵌入编译器生成的代码,从而实现对抗;如果分析方法不对,很有可能就会找不到入口;所以笔者认为一个优秀样本分析工程师,需要对数据以及代码有很强的敏感度,以及胆大心细推敲,找到样本中的短板,将整个样本连根拔起;
二、相同的操作为什么要变着花样做
分析的时候我们会发现上面的样本里面,sub_14000dda0
同样一个获取路径的操作,使用了不同方法去获取,甚至使用的都是一些远古系统里面使用的方法,后面的系统因为要向前兼容,所以相关方法还是可以生效;从分析的角度看,这里之所以要这么做主要是为了对抗一些杀软和沙箱,杀软、沙箱一般会对一些敏感行为、函数进行监测,但是这些监测点可能并不全,攻击者可以使用一些偏门、冷门的方法去绕过这个监测,从而使样本免于被查杀;最简单的例子就是比如杀软监控的memcpy函数,我们可以使用RtlCopyMemory来绕过检测;
0x05 狩猎
一直以来狩猎都是一个防守方的热点话题,从样本的维度看,样本是可以为狩猎提供非常丰富的素材,样本中所有使用的对抗手段,都象征着这个攻击者的特征,虽然每个对抗手段有可能是通用的,被各个攻击者都使用,但是对于这些对抗手段的组合以及一些特有的编程习惯和技术搭配却是独一无二的;例如上面这个样本我们可以拿到的特征是:
1、通过检查注册表
HKCUSoftwareTencentbugreportWechatWindows
来判断微信安装情况,反虚拟话 2、通过检查“最近”、“桌面”目录下的文件项数目来判断是否为真实环境 3、通过检查注册表HKCRApplicationsVMwareHostOpen
和HKLMSOFTWAREOracleVirtualBox Guest Additions
来判断当前环境是否为Vmware或VirtualBox虚拟机环境, 4、绕过r3层杀软对ntdll的监控,是通过卸载该进程ntdll里面inlinehook,还原ntdll text段内容; 5、创建互斥变量风格:类似guid格式{xxxxxxxx-xxxx-xxxxxx-xxxx-xxxxxxxxxxxx}
,第三部分占位6位,这里可能是攻击者自拟的某种标识符 6、通过比较古老和久远的第系统版本方法获取相关路径:SHGetFolderPathW方法和SHGetKnewFolderPath方法;(xp之前的系统使用) 7、利用随机数生成依赖随机种子,使用固定随机种子,控制随机数,从而在样本中动态获取密钥; 8、随机种子的获取的时候做了一些花里胡哨操作,获取网卡guid,但是没有使用,只使用了里面第一个字符{
,这里大概率攻击者在其实现的其他样本中还有一堆其他的花里胡哨操作来获取{
; 9、资源段存储shellcode,双层解密,aes 异或 10、监测到虚拟机退出,使用的结束方法是弹messagebox,内容是:“错误” 11、MFC编程,动态调用函数(这里笔者不是很确定,这里貌似是篡改了mfc编程,编译器生成的代码) 12、样本回连c2使用域前置技术,并且做了一个非常有意思的前置域和后置域的关联,看上去比较像;前置:static.aliyuncs.com.dsa.dnsv1.com
,后置:static.aliyuncs.com
13、远控心跳 url:/link/Members/C90RDRN279YK.js 14、远控元数据使用cookies里面的特殊形式的session字段承载;
还是那句话,其中的某个特征可能是很多人都用的,但是下一次如果再次出现相同的组合搭配大概率就是同一个攻击者或者同一伙攻击组织;并且里面有些项其实是富有比较特殊的“个人特征”,比如mute变量的命名,再比如利用guid首字符生成随机数,这些操作都是具备非常强的攻击者专有特征;进一步我们分析shellcode同样也可以拿到一批特征,比如shellcode里面的apicall特征码怎么计算的等,这种都是比较特殊的“个人特征”;如果我们手上有一些端侧数据,比如360安全卫士上云的数据,我们就可以去落地做一些狩猎动作;又或是我们具有很多客户,客户被打请求协助分析,我们利用这些特征可以帮助客户做一些溯源的工作,对攻击定性,对攻击者定性等;对攻击者进行深入挖掘,每个事件从都提取部分攻击者信息,最后组成一个全方面的塑形;
笔者才疏学浅,若文中存在错误观点,欢迎斧正。
参考:
样本对抗-反虚拟机
一次域前置样本分析