RE实战 - 记一次恶意代码分析

感谢@dumpwafen师傅提供的样本
借此机会好好学习一下Windows下的一些CTF考察以外的逆向技巧、操作
深刻意识到CTF中的re只是冰山一角 修行还远远不够

借着师傅给的5个问题:

  • Q1: 这个恶意代码向磁盘释放了什么?
  • Q2: 这个恶意代码如何进行驻留?
  • Q3: 这个恶意代码如何盗取用户登陆凭证?
  • Q4: 这个恶意代码对窃取的证书做了什么处理?
  • Q5: 如何在你的测试环境下让这个恶意代码获得用户登陆凭证?

首先 最关键的一点!摒弃CTF养成的'坏习惯'(指拿到题目ExeinfoPE一查完就丢IDA。。。)

好吧还是先丢Exeinfo看看
image
看似跟一般的一样
但是 如果用CFF Explorer查看
image

image
可以发现这里出现了MZ PE两个(PE文件头的知识日后来补 这里先看个大概)
image
在Resource Editor下发现有端倪
image
可以看到这里出现了一个单独的TGAD 将这个文件导出
IDA查看
image
可以看见左边出现了很多 gina_x()类型的函数
image
大概是以不同的参数调用某个函数
先把TGAD放一边 看看主程序是怎么调用这个TGAD的
IDA打开恶意代码
main函数
image

GetModuleHandleA:

用法:HMODULE GetModuleHandleA( [in, optional] LPCSTR lpModuleName );
用于检索指定模块的模块句柄

GetModuleFileNameA:

用法: DWORD GetModuleFileNameA( [in, optional] HMODULE hModule, [out] LPSTR lpFilename, [in] DWORD nSize );
检索包含指定模块的文件的完全限定路径

进入sub_401080看看对得到的句柄作了什么操作
image

FindResourceA:

用法:HRSRC FindResourceA( [in, optional] HMODULE hModule, [in] LPCSTR lpName, [in] LPCSTR lpType );
确定指定模块中具有指定类型和名称的资源的位置
自然的查看lpName
image
这不就跟之前分析的TGAD中的对应上了吗?
Find过后后续进行Load Lock 同时注意到v5 = VirtualAlloc(0, dwSize, 0x1000u, 4u);

VirtualAlloc:

用法:LPVOID VirtualAlloc( [in, optional] LPVOID lpAddress, [in] SIZE_T dwSize, [in] DWORD flAllocationType, [in] DWORD flProtect );
保留、提交或更改调用进程的虚拟地址空间中页面区域的状态。 此函数分配的内存会自动初始化为零。

qmemcpy(v5, Buffer, dwSize);
Stream = fopen(FileName, Mode);
fwrite(Buffer, 1u, dwSize, Stream);
fclose(Stream);

这段进行了一次读写操作
image
注意到等价于fopen('msgina32.dll','wb')
所以Q1答案就是:
从TGAD中提取出msgina32.dll然后将其释放到硬盘上(这是因为virtualalloc是分配本地的内存)

后面又有一个sub_401299 跟进查看
image
暂且看不出在干什么

sub_401080分析完后进入main的下一个函数sub_401000
image

这里就涉及到知识盲区了 关于注册表的知识

RegCreateKeyExA

创建指定的注册表项。 如果该项已存在,函数将打开它。 请注意,键名称不区分大小写。
image
关于返回值
image

可以看到这里的subkey是
image
所以创建的注册表的子项就是SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon

RegSetValueExA

用法:image
返回值跟上一个一样

这里的valuename设置为
image

这样分析就可以得出:
恶意代码将自己添加到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GinaDLL
注意到winlogon
image
可以知道添加到这个winlogon下的注册表使得恶意代码在系统启动的时候会被加载 从而可能对用户的登陆凭证进行截取
因此Q2的答案就是:恶意代码将自己添加到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GinaDLL中使得恶意代码在系统启动的时候会被加载 从而可能对用户的登陆凭证进行截取

继续分析Q3 前面的分析知道恶意代码会在系统启动的时候被加载
主程序的作用就是将恶意代码释放到硬盘上并且写入注册表 那么拦截的事情应该由TGAD来做
再次IDA查看
image
image
注意到将\MSGina这个directory get后load了它下面的library
查看
image
发现可疑ShellShutdownDialog
image
而这里面的参数ProcName就是WlxActivateUserShell WlxDisconnectNotify这一串
重点查看与登陆相关WlxLoggedOnSAS
在用户登陆时 这个会被调用

result = GetProcAddress(hLibModule, lpProcName);
  if ( !result )
  {
    if ( !((unsigned int)lpProcName >> 16) )
      wsprintfA(v2, "%d", lpProcName);
    ExitProcess(0xFFFFFFFE);
  }

这里GetProcAddress
image
所以获得的是WlxLoggedOnSAS的真实地址
下面出现了wsprintfA
image
也就是说代码将WlxLoggedOnSAS相关的信息写入了v2[ ]
即当前这个dll会对登陆的数据进行拦截处理
也就是将 Windowslogondll->msgina.dll
变成了 Windowslogondll->msgina32.dll->msgina.dll

分析Q4 恶意代码窃取凭证后进行了什么处理?
继续分析到WlxLoggedOutSAS
image
这里调用了一个sub_10001570
同时参数传的也是用户登陆的核心数据
image
可以看到这里将用户的数据写入了msutil32.sys
这里学习一下va_start

va_start

image
实例

#include<stdarg.h>
#include<stdio.h>

int sum(int, ...);

int main(void)
{
   printf("10、20 和 30 的和 = %d\n",  sum(3, 10, 20, 30) );
   printf("4、20、25 和 30 的和 = %d\n",  sum(4, 4, 20, 25, 30) );

   return 0;
}

int sum(int num_args, ...)
{
   int val = 0;
   va_list ap;
   int i;

   va_start(ap, num_args);
   for(i = 0; i < num_args; i++)
   {
      val += va_arg(ap, int);
   }
   va_end(ap);

   return val;
}

由于这里sub_10001570后面传的也是可变长参数 所以要用va_start
所以恶意代码将时间戳、用户登录数据等都存在了msutil32.sys

Q5,要使恶意代码发挥功能 必须要运行后重启系统 然后注销登陆状态 再次登陆就能在对应文件目录下看到日志文件了

只是大致走了一遍分析流程 里面还有些细节要慢慢琢磨

posted @ 2023-11-12 08:51  N0zoM1z0  阅读(34)  评论(0编辑  收藏  举报