首页
论坛
课程
招聘
[原创]某型勒索软件分析
2020-10-30 16:17 3510

[原创]某型勒索软件分析

2020-10-30 16:17
3510

某型勒索软件分析(一):软件架构动态分析








(之前一直从事逆向工程工作,对二进制安全的了解不多,写的不好或者研究的不够深入希望各位大佬见谅。)



背景:样本来源、威胁未知;使用工具为ollydbg、idapro;



分析过程:



step1



静态架构分析,主要用于分析代码的逻辑结构,将样本同时载入idapro和ollydbg,跟入oep,进入功能主函数。

  1. 其功能主函数为sub_403060;

  2. 功能主函数地址004035C8处调用函数00401470,通过ldr获取kernel32.dll;

  3. 功能主函数地址004035D8处调用函数00401890,传入kernel32模块句柄,解析dll导出表,获取LoadLibraryA函数;

  4. 功能主函数地址0040363A调用函数00401890,传入kernel32模块句柄,解析dll导出表,GetCurrentProcess函数;

  5. 功能主函数地址0040369E调用函数00401890,传入kernel32模块句柄,解析dll导出表,VirtualAllocExNuma函数;

  6. 功能主函数地址004037AB调用函数0040F3D0;

  7. 函数0040F3D0通过之前获取的LoadLibraryA与GetCurrentProcess载入需要的函数,并以挂起的形式创建子进程,同时通过WriteProcessMemory将二进制数据写入创建的子进程(后期分析发现该步骤用于重组子进程PE,且LoadLibraryA与GetCurrentProcess获取的函数地址用于修复子进程导入表,该步骤参基于Windows加载dll时会将dll放入相同的内存镜像地址);

  8. 地址0040BB57通过GetThreadContext获取CONTEXT,并通过0040C082地址处SetThreadContext修改CONTEXT的eax为新的oep,此处可查询函数RtlUserThreadStart参数信息,其第一个参数eax为用户主线程的入口点,也就是oep;

  9. ResumThread后启动子进程;



主函数详情:


获取线程上下文:

设置线程上下文

获取线程上下文(高亮处为线程上下文,eax为004127C7)

设置线程上下文(高亮处为线程上下文,eax为0040FBA0)







step2



通过step1,已经对该程序的功能架构和防护模式有了大体的了解:以主进程的作用更多的是做为一层壳,在通过WriteProcessMemory和SetThreadContext等操作重组了子进程之后就会退出,而具体的任务就会交给子进程。因此,我们只需要在子进程进行附加调试就可以了,在进行附加调试的时候,需要注意两个问题:

  1. 不要使用win10作为调试环境,否则样本的一些功能似乎无法正常实现;

  2. 附加调试应该选在ResumThread执行之前,但如果此时主进程处于调试状态,子进程无法调试,应该是子进程继承了调试属性,将主进程执行ResumThread的地址修改成int3就行了,此时子进程的名称为ntdll(step1提过主进程修改了子进程模块);


附加调试后,线程信息如下(eax为0040FBA0,验证step1的猜想):


单步执行,跟踪到程序在下图地址读取临时文件夹内容,并判断是否为“ended”,因为之前调试过,所以的电脑该文件内容为“ended”,如下图所示:



f9运行,程序界面启动,此时我们确定其为勒索病毒,如下图:







step3



此时我们删除临时文件夹中保存“ended”字节的文字,step2中,我们确定该“ended”标志用于判断文件是否已经被勒索病毒加密,并重新附加调试该程序。由于总所周知的原因,勒索病毒主要通过加解密文件勒索被控制计算机,因此这次我们只需要在文件读写API下断点即可。




其中如图所示的部门,猜测应该为白名单文件类型,病毒感染可执行文件的意义不大:


继续跟踪,我们发现程序有重新启动了一次子进程,如下图所示:




此时我们跟踪查看临时文件夹,发先文件写入了一串数字,猜测是控制过程或者是中间密钥,如下图所示:



继续附加调试子进程,此时程序开始进行文件读写操作,和我们之前猜测的类似,程序开始遍历驱动器和文件夹。


遍历驱动器:



遍历文件夹:




在加密文件之后,程序运行了一条shellcode删除卷影副本,如下图所示:






总结


由于动态调试主要用于分析程序的功能和架构,在step3中,我们已经定位到了算法的代码,后面的分析就留到dump镜像之后再做静态还原分析,由于时间的原因,我还没有做,后续抽时间更新。


文件链接如下:其中test_int.exe在NtResumeThread调用地址处下断点,使用该程序进行动态调试。


链接: https://pan.baidu.com/s/1PHhzBXjfLzTSTlkNkoXSgQ 提取码: jqyz 复制这段内容后打开百度网盘手机App,操作更方便哦






某型勒索软件分析(二):软件算法调试分析


(本来想到此打住的,没想到被版主催更了,那我索性就写完后面代码分析的过程吧。)



step4



接回动态框架分析部分的总结,要想做代码算法逻辑分析,就需要对内存镜像做dump分析。其过程如下所示:

  1. 使用od附加调试;

  2. 在内存中修改段section头信息,为了方便我们将内存偏移和大小覆盖到文件偏移和大小(这么做的目的是因为子进程的主模块被修改位ntdll);

  3. 使用ollydump脱壳工具拷贝镜像至文件当中;

如下图我将“CODE”段的内存地址和大小覆盖到文件地址和大小:


修改imagebase、oep、大小、复选框不勾选,点击脱壳即可:







step5




在dump内存镜像之后,使用ida打开,并使用od调试定位算法地址,在readfile和writefile处,我们下断点调试,发现读写文件的缓存区地址均为0041A370,我们在此处下内存写入断点,如下图所示:


此处代码在ida中无法通过f5进行反编译,因此我们根据自己的理解进行阅读,代码如下:


0040EA35    8BFB            mov edi,ebx
0040EA37    81FF FF010000   cmp edi,0x1FF
0040EA3D    76 05           jbe short 0040EA44
0040EA3F    E8 E44DFFFF     call 00403828
0040EA44    803C7D 1D484100>cmp byte ptr ds:[edi*2+0x41481D],0x0
0040EA4C    74 4C           je short 0040EA9A
0040EA4E    81FB FF010000   cmp ebx,0x1FF
0040EA54    76 05           jbe short 0040EA5B
0040EA56    E8 CD4DFFFF     call 00403828
0040EA5B    33D2            xor edx,edx
0040EA5D    8A97 C8664200   mov dl,byte ptr ds:[edi+0x4266C8]
0040EA63    8B45 F4         mov eax,dword ptr ss:[ebp-0xC]
0040EA66    48              dec eax
0040EA67    3D 4FC30000     cmp eax,0xC34F
0040EA6C    76 05           jbe short 0040EA73
0040EA6E    E8 B54DFFFF     call 00403828
0040EA73    40              inc eax
0040EA74    0FB680 6FA34100 movzx eax,byte ptr ds:[eax+0x41A36F]
0040EA7B    E8 20DFFFFF     call 0040C9A0
0040EA80    8B55 F4         mov edx,dword ptr ss:[ebp-0xC]
0040EA83    4A              dec edx
0040EA84    81FA 4FC30000   cmp edx,0xC34F
0040EA8A    76 05           jbe short 0040EA91
0040EA8C    E8 974DFFFF     call 00403828
0040EA91    42              inc edx
0040EA92    8882 6FA34100   mov byte ptr ds:[edx+0x41A36F],al
0040EA98    EB 4A           jmp short 0040EAE4
0040EA9A    81FB FF010000   cmp ebx,0x1FF
0040EAA0    76 05           jbe short 0040EAA7
0040EAA2    E8 814DFFFF     call 00403828
0040EAA7    33D2            xor edx,edx
0040EAA9    8A97 C8664200   mov dl,byte ptr ds:[edi+0x4266C8]
0040EAAF    8B45 F4         mov eax,dword ptr ss:[ebp-0xC]
0040EAB2    48              dec eax
0040EAB3    3D 4FC30000     cmp eax,0xC34F
0040EAB8    76 05           jbe short 0040EABF
0040EABA    E8 694DFFFF     call 00403828
0040EABF    40              inc eax
0040EAC0    0FB680 6FA34100 movzx eax,byte ptr ds:[eax+0x41A36F]
0040EAC7    E8 E8DEFFFF     call 0040C9B4
0040EACC    8B55 F4         mov edx,dword ptr ss:[ebp-0xC]
0040EACF    4A              dec edx
0040EAD0    81FA 4FC30000   cmp edx,0xC34F
0040EAD6    76 05           jbe short 0040EADD
0040EAD8    E8 4B4DFFFF     call 00403828
0040EADD    42              inc edx
0040EADE    8882 6FA34100   mov byte ptr ds:[edx+0x41A36F],al
0040EAE4    43              inc ebx
0040EAE5    81FB FF000000   cmp ebx,0xFF
0040EAEB    7E 02           jle short 0040EAEF
0040EAED    33DB            xor ebx,ebx
0040EAEF    FF45 F4         inc dword ptr ss:[ebp-0xC]
0040EAF2    4E              dec esi
0040EAF3  ^ 0F85 3CFFFFFF   jnz 0040EA35


此段代码是一个大循环,在0040EAE5和0040EAED之间控制了ebx的大小,因此函数00403828不可能被调用,函数0040C9B4返回al和dl之和,因此整个循环大体伪代码如下:


//RawByte为文件内容,length为长度
int i = 0;
int index = 0;
do
{
RawByte[i] = RawByte[i] + string4266C4[index + 4];
i++; index++;
if (index>0xFF)index = 0;
} while (i < length);


跟踪到这一步,我们发现此时代码中调用了4266c8开始的变量,我们对其下内存写断点,继续调试,在两个位置生成了断点


位置一:



此处代码为一个循环,而且比较简单,就是将地址004148BC处的内容拷贝0x200个至地址4266c8;



位置二:



此处代码如下:


0040E9D4    BF CC6A4200     mov edi,0x426ACC
0040E9D9    BB 00010000     mov ebx,0x100
0040E9DE    BE C8664200     mov esi,0x4266C8
0040E9E3    33C0            xor eax,eax
0040E9E5    8A07            mov al,byte ptr ds:[edi]
0040E9E7    05 00010000     add eax,0x100
0040E9EC    3D FF010000     cmp eax,0x1FF
0040E9F1    76 05           jbe short 0040E9F8
0040E9F3    E8 304EFFFF     call 00403828
0040E9F8    33D2            xor edx,edx
0040E9FA    8A90 C8664200   mov dl,byte ptr ds:[eax+0x4266C8]
0040EA00    33C0            xor eax,eax
0040EA02    8A06            mov al,byte ptr ds:[esi]
0040EA04    E8 97DFFFFF     call 0040C9A0
0040EA09    8806            mov byte ptr ds:[esi],al
0040EA0B    46              inc esi
0040EA0C    4B              dec ebx
0040EA0D  ^ 75 D4           jnz short 0040E9E3
0040EA0F    47              inc edi
0040EA10    FF4D F4         dec dword ptr ss:[ebp-0xC]
0040EA13  ^ 75 C4           jnz short 0040E9D9


此处代码为一个双重循环,也比较简单,内层循环逻辑大概是取地址426ACC处首字节,加上0x100,作为索引index,4266C8+index赋值给寄存器dl,esi指针赋值给寄存器al,调用函数040C9B4(之前我们分析过,该函数返回al与dl之和),外曾循环次数为ebp-c。



step6



在上一次的分析当中,我们已经跟踪到了加密文件的算法函数,其关键算法种子大概为4266C8处的0x200个字节。其中,要生成该种子,我们需要两个变量,分别为426ACC和004148BC。



我们先分析426ACC,内存写断点调试,我们发现其通过调用函数00402864和函数00402E40获取变量值,如下图所示:



使用ida反编译这两个函数,如下图所示:



此处我们可以确定变量426ACC通过时间生成。




继续分析变量004148BC,同样内存写断点调试,我们发现程序无法中断,根据前方的分析,此处的缓存区较大,猜测可能仅初始化一次。因此我重新附加调试,程序中断位置如下图所示:



使用ida对该处地址反编译,如下图所示:



通过阅读代码,大体上也可以分析出程序通过时间生成004148BC处的字节串。





总结




动态分析可以得出发现程序通过时间生成种子,对文件内容进行加密,程序同时还会同时生成一段种子写在文件末尾用于还原的凭证,这一段我没有做分析,感兴趣的小伙伴可以尝试分析,当然也可以尝试重写算法。



文件末尾凭证如下图所示:




idb文件地址:链接: https://pan.baidu.com/s/1MkcuWNkBgHWT-8E7z5SE8g 提取码: s65h 复制这段内容后打开百度网盘手机App,操作更方便哦




(最后打个小广告,小弟最近准备找工作,希望有看到的大哥高抬贵手捞一把,pc端逆向/反外挂/反病毒都可)




【看雪培训】《Adroid高级研修班》2022年夏季班招生中!

最后于 2020-11-3 15:49 被zhuhelin1997编辑 ,原因: 主题编辑有误
收藏
点赞0
打赏
分享
最新回复 (1)
雪    币: 9139
活跃值: 活跃值 (34442)
能力值: (RANK:105 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2020-11-2 10:23
2
0
由于篇幅不长,建议第2节以跟帖形式发此帖,版主会跟据文章详细程度和质量来设精华优秀。
游客
登录 | 注册 方可回帖
返回