恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录

GandCrab2.0 脱壳笔记分析记录

有人在2018年的时候就分析过了恶意样本分析,相关资料可以查看参考部分。由于里边有很多可以学习和总结的脱壳技术,因此重新分析这个样本,这篇文章暂时不做加密和勒索实际功能分析,如果要看分析样本形成勒索的过程以及相关分析报告,可以直接跳到参考部分,这篇文章主要关注的是脱壳相关的一些技术细节的分析,由于文章是我个人的一些分析和总结,因此会有一些不足,比较趋向于像我这样刚接触恶意软件分析,由于很多样本在分析前需要脱壳之后才能看到核心功能,因此这里重点关注脱壳过程,主要内容如下

  • 解密并dump出shellCode

  • 解密并dump出PE1

  • 解密并dump出encrpt.dll

解密并dump出shellCode

使用IDA打开病毒母体,来到入口函数,经过分析后程序会解密出资源文件的内容

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第1张图片
调用VirtualProtect函数修改shell_code的属性为可读写,这里的VirtualPtotect函数是通过动态获取的函数指针

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第2张图片

之后调用函数sub_401014shell_code解密并调用

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第3张图片
为了能进一步分析shell_code,需要在动态调试阶段dump下来,因此这里使用x32dbg调试母体病毒,在程序调用shell_code的时候,单步进入后dump下来,如下是来到执行调用shell_code的位置

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第4张图片

此时选择单步进入,来到shell_code的入口处,如下

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第5张图片

此时将内存dump下,步骤为在内存窗口点击右键-->选择 在内存布局中转到

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第6张图片
之后跳转到内存布局,之后选中对应的内存位置一般使用这个方式跳转到内存布局文件,默认会选择指定的内存,然后右键保存为文件,之后命名为shell_code.bin,如下

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第7张图片

使用ida分析shell_code的功能。

ShellCode功能分析

现在主要对shellcode的功能分析,这部分主要会完成如下功能

  • 解密PE1文件
  • 动态填充encrypt.dll文件
  • 反射调用encrypt.dll

解密并dump出PE1

在执行解密PE1这个文件之前,需要弄清楚几个问题

  • [ebp-0A0h]保存的内容是什么
  • 动态获取kernel32.dll函数是如何保存的
  • 解密的PE1文件什么时候选择dump

初始化数据和导入APIs

[ebp-0A0h]保存的内容是什么

在动态调试阶段注意如下指令

mov     eax, [ebp-8Ch]
mov     ecx, [ebp-3Ch]
lea     eax, [ecx+eax-38h]
mov     [ebp-8], eax
mov     eax, [ebp-8]
mov     [ebp-0A0h], eax ;这里赋值给[ebp-0xA0]

动态调试阶段内内存内容如下

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第8张图片

根据内存中的内容可以知道,这里保存的是一个PE文件,不过是被加密了在后面会执行解密,在执行解密前,程序动态保存了kernel32.dll GetProcAddress函数在栈上使用。如下

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第9张图片

通过这个手段,分别将需要的函数保存在了当前的栈上,主要获取的函数包括

 mov dword ptr ss:[ebp-38],eax  ;VirtualProtect 
 mov dword ptr ss:[ebp-48],eax  ;VirutalAlloc
 mov dword ptr ss:[ebp-24],eax  ;VirutalProtect
 mov dword ptr ss:[ebp-5c],eax  ;VirutalFree
 mov dword ptr ss:[ebp-44],eax  ;GetVersionExA
 mov dword ptr ss:[ebp-38],eax  ;TerminateProcess

这些字符串在dump出的shell_code中静态分析显示如下

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第10张图片

查看字符串内容

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第11张图片

由此可以知道这个主要是为了避免杀毒软件所查杀,因此在解密shellc_code并运行后,动态阶段解密后导入。

继续往下来到如下指令

push    dword ptr [ebp-44h] ; ptr_GetVersionExA
push    100000h
push    dword ptr [ebp-0A8h] ; buff_1
call    sub_4497

这里的[ebp-0x0A8]实际指向的是新的一个程序块,这部分的内容还没有被修复

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第12张图片

dump下这个文件命名为stage2.bin

在这里插入图片描述
拖入ida分析后保存,这部分的节区等信息没有被填充,如下

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第13张图片

这部分也是需要在后面的修复中使用的。

动态获取kernel32.dll函数是如何保存的

根据上面的分析shell_code在运行阶段动态导入了需要使用的API保存在栈上。

解密的PE1文件什么时候选择dump

在前面的准备阶段完成后开始调用VirtualAlloc分配一块内存
恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第14张图片

将返回的内存指针保存在了[ebp-0x10],这里命名内存块为new_pe1_buff,然后调用sub_4170函数执行解密

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第15张图片

执行解密前的new_pe1_buff的内存内容

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第16张图片

解密后

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第17张图片

此时将内存的数据保存解密后的内存为PE1.exe,这样就能获取解密后的PE1数据了。

下面的过程主要是分析内存修复PE文件的过程

往下继续分析,在解密PE1文件后,接着调用VirtualProtect函数修改了[ebp-0xA8]内存属性为0x40,对照了MSDN的文档后知道,修改为可读写属性,如下

#参考https://docs.microsoft.com/zh-cn/windows/win32/memory/memory-protection-constants
PAGE_EXECUTE_READWRITE
0x40

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第18张图片

修改完属性后就将[ebp-0xA8]的数据清空,目的是接下来就会对这个内存重新导入新的数据块 call sub_435D函数实际是调用了memset函数,如下

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第19张图片

在这里插入图片描述
在清空前的[ebp-0xA8]内存

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第20张图片

执行后清空掉这块内存,目的是后续重组一个PE文件

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第21张图片

重组一个PE文件,需要的数据包括

  • [ebp-0x10]
  • [ebp-0x90]

开始组装新的PE文件,调用sub_3EE函数复制头部信息,内容保存在[ebp-0xA8]

push    dword ptr [eax+14h];指向section->PointerToRawData
push    dword ptr [ebp-34h];指向了 new_pe1_dos_header
push    dword ptr [ebp-90h];这里指向的[ebp-0xA8]
call    sub_43EE

这里的[eax+0x14]是.text节区在文件内的大小映射到[ebp-0xA8]内。如下是动态调试时参数

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第22张图片

之后完成后就将[ebp-0x10]的节区按照文件大小映射到内存中,执行前
恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第23张图片

执行复制函数后,

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第24张图片

这里就将复制完了第一部分内容,后面还要继续复制节区数据和IAT修复。

复制section

在复制完header部分后后面,接着开始修复节区和IAT表。首先获取节区大小

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第25张图片

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第26张图片

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第27张图片
根据[ebp-0xB0]当做节区索引,如果小于当前的节区表大小,则跳入复制节区表

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第28张图片

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第29张图片

读取下一个节区

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第30张图片

重复复制完成后,开始修复IAT表

修复IAT

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第31张图片

设置完成导入表和导出表后,执行读取符号

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第32张图片

这里将[ebp-0x90]命名为payload.dll

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第33张图片

修复完成所有的函数后,最后跳转执行PE1.exe,来到最后跳转位置

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第34张图片

这个过程其实不用去过分关注,因为程序的核心程序并不在后面的节区复制和修复IAT过程,我们dump出的PE1.exe已经可以用作静态分析和动态调试了,经过分析后发现在解密完成PE1.exe之后的操作属于扰乱分析的一个手段实际程序会跳转到PE1.exe内执行解密encrypt.dll,这个在后面的动态调试PE1.exe中可以得到证明,分析的好处就是对内存加载PE以及修复PE的过程有了更熟悉了一些。

解密并dump出encrpt.dll

根据前面的分析可以知道,shell_code的主要功能是解密出PE1程序然后执行,释放的PE1并没有被写入到本地,这样就可以减少被查杀的概率,直接是无文件方式执行,同样的encrypt.dll也不会被写入到本地中,而是解密后反射运行,如下是dump的过程。

首先程序先解密出encrypt.dll程序

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第35张图片

之后获取dll内的ReflectLoader函数

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第36张图片

利用反射调用的方式执行encrypt.dll,关于反射调用可以看stephenfewer开源的项目,和一般的利用注射器(进程注入dll)方式利用VirtualAlloc,WriteProcessMemory,CreateRemoteThread,LoadLibrary等当时的注入不同,注射器方式需要写入dll到本地然后利用LoadLibrary函数加载dll触发dll内的DllMain会被执行,反射调用会在当前运行的进程加载dll然后执行。

在获取到ReflectiveLoader之后调用VirtualProtect函数修改encrypt.dll的属性为可执行

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第37张图片

这里就完成了PE1的核心功能

  • 解密encrypt.dll
  • 调用encrypt.dll内的导出符号ReflectiveLoader函数然后执行encyrpt.dll

接下来就是核心encrypt.dll的分析,在分析之前需要dump出这个dll文件。这一步我在分析和调试的时候走了很多弯路,例如一直调试母体病毒,分析shell_code的解密功能,包括解密出了PE1之后的程序,不过在多次调试和分析中,对这种内存解密和加载PE文件的方式也熟悉了不少。

dump核心的encrypt.dll可以建立在第二阶段获取的PE1.exe这个文件内,直接使用x32dbg调试PE1.exe文件,在分析PE1.exe时可以知道,程序要执行encrypt.dll前会调用VirtualProtect函数修改内存属性,由此可以知道此事的encrypt.dll是解密完成了,因此我们直接在调试的PE1.exeVirtualProtect函数上设置断点,需要注意的是这个函数会被调用两次,因此我们只需要在第一次命中断点后选择dump下来即可,设置断点的选择在如下位置方便获取到参数

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第38张图片

设置好断点后运行程序,在第一次断下来后查看内存,如下

恶意样本脱壳-GandCrab2.0 脱壳笔记分析记录_第39张图片

此时选择dump下来保存,即可获取到了核心的encrypt.dll

总结

首先程序会解密出shellCode来解密出第一阶段的PE1程序,PE1负责解密出encrypt.dll,之后通过反射调用的方式来运行恶意行为。从这个过程中可以看出这个过程是一个无文件方式,相比较于注射器来完成的进程注入方式,反射调用更加隐蔽。

一些常用的脱壳点可以在脱壳阶段使用:

关键内存Api断点

如果是进程注入的方式会选择在VirtualProtect,WriteProcessMemeory VirtualAlloc函数设置断点分别获取解密的PE文件,这种脱壳方式可以称为关键内存Api断点;例如上面的脱壳过程,可以设置断点在VirtualProtect,VirtualAlloc上,程序运行后分别关注每个次断点内存中的内存,然后每次都dump下来,然后做分析即可,可以不用去关心实际的一些解密过程。

ESP定律

如果是压缩壳类的,可以考虑ESP定律手段,这个资料比较多,也容易上手,这个我会在分析两个压缩壳的样本。

参考

来源

基本分析

详细分析1

详细分析2

你可能感兴趣的:(病毒分析)