0x00 基本信息
首先通过exeinfo确定该文件是一个exe vc++编译 有标准的winMain函数
可以在xp下跑,直接使用SysTracer.exe 查看一下行为:
这里可以看到,样本运行后,将会在启动目录下新建一个文件,然后在appdata目录下释放一个AaccroR3d2.exe.exe文件。
经过hash查询,可以知道appdata目录下释放的这个AaccroR3d2.exe.exe实际上就是原始的样本。
并且查看原始样本的运行目录,可以发现样本已经被删除,所以我们可以知道,样本运行后,会删除自身,然后将自身重命名并移动到%appdata%目录下。同时在启动目录下创建一个新文件。
尝试在win7下运行,可以知道创建的文件是一个快捷方式,指向在%appdata%路径下释放的文件
0x01 样本分析
IDA信息
IDA里面基本信息如下,可以看到样本的.text段很小,只有3000的大小,左边窗口的FunctionName也很少,并且最后还有一个自定义的DATA段,所以可以猜测样本的主要功能并不在.text段,而是在加密的DATA段中。
DATA段数据如下:
定位关键代码
winMain函数的结构很简单,几乎看不到恶意行为,但是其中调用了sub_401000函数,sub_401000函数一共800多行,并且有大量计算操作,所以我打算用调试器过来看看。
首先尝试直接winMain的起始地址00402DA0下断点跑过来
然后程序就跑飞了
然后终止
这就是说明,程序是没有跑到winMain函数的,这种有两种情况
1是winMain函数之前有反调试
2是样本的真实代码在winMain之前跑完了
两种情况都是修改了样本的CRT。
为了验证到底是哪种情况,我们可以结合SysTracer一起分析
我们首先用SysTracer加载od:
然后通过od加载exe,程序默认停在入口点
然后在WinMain设置断点并且清空SysTracer的当前日志
然后F9运行,可以发现od依旧没有断在winMain,但是SysTracer已经捕获到了之前的恶意行为。
所以可以说明该样本的关键代码在WinMain之前,根本就没有执行WinMain。
所以我们在start函数中看看程序到底是哪儿跳走的。
start函数如下:
从start函数f8单步往下走,发现在00402F9E处有一个 call initterm函数,F8过了之后程序od就陷入了运行状态。
_initterm函数目前可以不用知晓这里的原理,因为涉及到CRT的一些处理。
我们直接F7进入到initterm函数,是调用的系统的_initterm函数
然后F7往下,过来了之后是系统空间
不用管这里面到底做了什么操作,直接一直按住F8 往下走,直到回到用户空间
程序最后通过一个retn 返回到了用户的地址空间
回来的地址是0041B82D (这里注意存一个快照,后面的代码IDA里面看不到,可能要调试多次)
我们在IDA里面可以看到该地址就是我们最开始分析的DATA段中
所以程序在之前的initterm中应该是执行了解密操作解密了DATA段的数据,然后跳入过来执行。
DATA段代码分析
样本首先会通过GetProcAddress获取SHGetFolderPath进行调用,以获取用户系统目录
成功获取到%appdata%目录
同样的操作,通过GetModuleFileName获取到程序当前的运行路径
然后通过lstrcmpiW比较一下当前运行的路径和指定的是否相同
如果不同则会通过MoveFile函数将文件移动到%appdata%目录下并重命名
移动之后,则会在启动菜单下创建该文件的快捷方式
然后调用CreateProcess函数创建一个新进程,启动的新进程就是释放在%appdata%目录下的AccroRd2.exe.exe
因为这里有对路径的判断,我们可以直接重新加载%appdata%目录下的AccroRd2.exe.exe看看会发生什么
还是通过之前的方法,让程序跑到比较文件这儿,这里可以看je跳转已经实现。
直接跳转到最后ret出当前函数:
所以这部分的代码功能就是将自身移动到%appdata%目录下并重命名,增加开始菜单的快捷方式。
我们看retn出去之后的代码。
retn回来的代码带有混淆了,od无法正常识别。
这种代码调的时候,多多注意EAX和堆栈
F8单步往下走,有很多jmp 和call
比如遇到这样的call 我们想知道GetProcAddress获取的是哪个API的地址,但是这里我们并不能直接鼠标往上滑去找push的参数。滑动鼠标这里的代码将会变成这样,无法找到call edi这行代码了。
从上面的图我们可以看到call edi的hex数据是FF D7
而下面这张图中,FF D7 已经识别错误,跟其他数据连起来,变成一个地址了。
所以这种混淆的代码,我们就往下走,call完之后多注意eax的值。
一直往下走,程序调用了CreateProcess函数
这里有两个关键参数,ModuleFileName和CommandLine
两个参数的值都是当前的这个程序路径。说明该程序会创新一个新的进程,新进程的参数就是当前程序的路径。
往下走,程序会分配两次内存
然后通过RltMoveMemory填充
填充后如下:
接着通过0041b752函数解密出一个PE文件
多次通过writeprocessmemory 改写进程内存
可以看到UPX0 UPX1的提示信息
这里的操作应该是解密数据
最后解密完成了之后会执行解密的代码并通过ExitProcess退出当前的程序
我们将这片内存dump出来。
exeinfo查壳可以看到是upx加壳的,和我们之前在内存中看到的一致
直接通过upx -d 进行脱壳
脱壳成功
dump PE分析
解密出来的PE入口如下
第一个函数sub_40392d没有什么实际意义
第二个函数sub_40c3c5是一个解密函数,内容如下:
第三个函数sub_40AC20也不用管 这种函数 可以F8直接过 有时间也可以调一下看下具体解密的内容
第四个函数sub_40A7AE会解密出通信的C2:prefetch.no-ip.biz:3360
然后就可以根据这个C2去网上查询该C2的相关信息 定位下家族什么的,需要注意这里要注意一下样本的时间和这个C2的有效时间。
然后程序在第五个函数sub_40A3CE创建了一个名为AxEXpdAb的互斥体
如果互斥体存在,说明程序已经存在,则退出进程
创建互斥体之后,程序通过设置
\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\注册表键值将自己设置为开机自启动
设置代理
恢复干净快照之后可以看到行为
程序会不停对我们在调试时候看到的C2地址发起dns请求。
请求的dns是prefetch.no-ip.biz
在奇安信的平台上查询可以看到该域名被打上了VBKrypt的标签
通过powershell在本地计算出hash后,在vt查询该文件hash可以知道该文件约为13年到15年之间上传