_ _ (_) | | __ ____ __ _ _ _ _ __ ___ _ __ _ __ ___ | |_ \ \ / /\ \/ /| || | | || '_ ` _ \ | '_ \ | '_ \ / _ \| __| \ V / > < | || |_| || | | | | || |_) |_ | | | || __/| |_ \_/ /_/\_\| | \__,_||_| |_| |_|| .__/(_)|_| |_| \___| \__| _/ | | | |__/ |_| /---------------------------------------------------------------------------------------\ |>...................[ 隐形解密技术病毒的分析与对抗 ]...............<| |>......................[ by nEINEI/vxjump.net ]......................<| |>......................[ 2009-11-27 ]......................<| \>...................... [ neineit_at_gmail.com ] ....................IAT | | | .-------> "Sleep" | | | |-------> "ExitProcess" | | | |------... | | | | | | |->Kernel32.dll(FirstThunk) | | | | | |->user32.dll(FirstThunk) | | |... | | | |--------> ... | | |--------> "DrawRect" | | .--------> "GetDC" | +_________________________________________________+ | | | section n | +-------------------------------------------------+ 感染后: PE Header-------. | V +-------------------------------------------------+ .---|--------------< IAT rva | | |_________________________________________________| | | section... | | |-------------------------------------------------| | | | | | ori IAT | | | .-------> "Sleep" | | | |-------> "ExitProcess" | | | |------... | | | | | | | .------>|->Kernel32.dll(FirstThunk) | | | | | | | | .------>|->user32.dll(FirstThunk) | | | | |... | | | | .---. |--------> ... | | | | |--------> "DrawRect" | | | | .--------> "GetDC" | | +_____|___________________________________________+ | | | | | | | section n | | | | | .---|-->new IAT >------------. | | | | | V | | advapi32.dll(FirstThunk) | | | | | "random api 1"<-----|--->"CryptDeriveKey" | | | | | "random api n"<-----|--->"CryptDecrypt" | | | |-------------------------------------------------+ | virus body | +-------------------------------------------------+ 这样一个解密器基本需求就建立起来了,它可以像普通应用程序那样解密virus body,并且对IAT中的函数进行patch,可以躲过一般的静态扫描,但这样还远远不够,Win32/Leon 还在继续伪装解密器。 [0x03].反AVs检测技术 3.1.anti-Heuristic 由于在程序执行过程中,解密器的调用API的序列固定,所以Win32/Leon 尝试随机的插入一些API调用放到解密器的代码之中,这里kaze提出了一个“safe api”的概念,但这里 的“safe api”不是MS概念中的安全API,而是指“可随机构造API函数的输入参数值,然后调用它,除了返回错误码外,不影响程序运行的API”.例如 CloseHandle这个函数,我这样调用 call random ; eax 存放随机值0 ~ 2^32-1 mov ecx,eax puhs ecx call CloseHandle; eax 中会存入一个返回值(错误码) 可以99.9999%的肯定,这样的语句加入程序中,除了得到一个错误码外,不会影响任何事情,所以kaze的想法就是在解密器的代码中,随机的位置,插入随机的这样的“safe api”,这是 Win32/Leon对抗启发式检测的主要思路。 3.2.获得safe api 1)选择我们的要找的api所以在模块,比如kernel32.dll user32.dll advapi32.dll gdi32.dll 中导出的函数 2)对于每一个api,我们并不知道它有多少个参数,所以在堆栈中压入20个参数,看有多少个dword被pop出来,这个数字就是函数的参数。 3)调用api多次,并且每次随机选择不同的参数进行调用 4)如果没有异常抛出,也没有崩溃,那么这个api就是一个safe api kaze 编写了一个工具,自动的跑出了这些结果,在os(winxp sp1 sp2 / win2k) 中取这些结果api的交集。下面列出一部分这样的safe api。 kernel32.dll 参数个数:名称 1 ; AddAtomA 1 ; AddAtomW 3 ; AddConsoleAliasA 3 ; AddConsoleAliasW 0 ; AllocConsole 3 ; AllocateUserPhysicalPages 0 ; AreFileApisANSI 2 ; AssignProcessToJobObject 1 ; CloseHandle 0 ; CloseProfileUserMapping 1 ; CmdBatNotification ... ws2_32.dll 参数个数:名称 0 ; WSACancelBlockingCall 0 ; WSACleanup 1 ; WSACloseEvent 7 ; WSAConnect 0 ; WSACreateEvent 3 ; WSADuplicateSocketA 3 ; WSADuplicateSocketW 2 ; WSAEnumNameSpaceProvidersA .... user32.dll 参数个数:名称 2 ; ActivateKeyboardLayout 4 ; AlignRects 1 ; AllowSetForegroundWindow 3 ; AnimateWindow 0 ; AnyPopup 1 ; ArrangeIconicWindows 3 ; AttachThreadInput 0 ; DestroyCaret 1 ; DestroyCursor 1 ; DestroyIcon 1 ; DestroyMenu ... 以上这些api在win2k和winxp下进行调用基本都是安全的,但在vista下如果传入错误参数,会有5~10%的函数抛出异常,因为Win32/Leon主要是xp/2000平台,在这方面也就没有继续 筛选。 3.3."碎片化"解密器 为了获得更好的混淆效果,Win32/Leon将解密器分成若个chunk代码块,每一个chunk块包含一个API的调用,这些块随机的写入宿主程序的不同位置,首块位于宿主程序的EOP处, 宿主程序被改写的这些代码或数据保存在virusbody中,在virus退出时,重新写回宿主程序,然后再jump到宿主程序入口OEP,继续执行宿主程序。当然选择这些位置时要格外的小心, 避免宿主程序被破坏,还包括重要的PE结构也不能破坏(IAT, EAT, ressources, tls ...),感染后的一个文件可能情况如下: PE header -----------. | V +-------------------------------------------------+ | EOP-----|------. |_________________________________________________| | | section 1(code) | | | +-------+ +------+<--------|------. | |api #2 |<----------------- |api #1| | | +-------+ +------+ OEP<===|======\ |--------|----------------------------------------| | | | section 1(code/data/reloc...) | | | | | | | .---------------------->+-------+ | | | +--------+ |api #3 | | | .----|----|api #n |<--------------. +-------+ | | | | +--------+ | | | |jmp OEP | | \------/ | | | | | | | |-------------------------------------------------| | | | section n | | | |-------------------------------------------------| | | | | | | | +-------+ +-------+ +-------+ +--------+ | | | | |save #1| |save #2| |save #3| |save #n | | | | | +-------+ +-------+ +-------+ +--------+ | | | | | | .--->| virus body |======/ +-------------------------------------------------+ 为了防止启发式检测,chunk块之间的调用要加入混淆,假设AVs不知道一个API调用的参数个数(基于不会仿真所有api的假设),那么在执行chunk #k块向chunk #k+1块调用时, 将采用如下的方式: chunk #k ---> CloseHandle 带1个参数 chunk #k+1 ---> lstrcmp 带2个参数 chunk #k chunk #k+1 +-------------------------------------+ .---->+-------------------------------+ | | | | | | push fake_address1 | | | push fake_address1 | | push fake_address2 | | | push fake_address2 | | | | | push fake_address3 | | * push chunk#k+1_address * -----|-------. |* push chunk#k+2_address *... | | | | | | push random() | | push random() | | call CloseHandle() | | push random() | | ret | | call lstrcmp() | +-------------------------------------+ | ret | +-------------------------------+ 这样,因为AVs在chunk #k中不知道参数的个数,导致无法分析出chunk #k+1情况下的函数调用(当然这些对具有完备的sandbox功能的AVs是无效的,对付的是中等品质的仿真器),基 于以上的种种处理,Win32/Leon将具备一定anti-emultor功能。但对抗AVs特征检测方面还比较薄弱,针对这一点,主要使用多态方式。 [0x04].反AVs特征检测技术 4.1.解密器多态处理 对抗特征检测最有效的方式就是对解密器进行多态伪装,但Win32/Leon多态的目的不同于以往病毒的多态引擎,因为要求代码多态后也要使解密器看起来像普通的应用程序调用, Win32/Leon没有使用标准的多态引擎,因为那会使代码看起来怪怪的,还会有些少见的opcode出现,这些对于高级别AVs仿真器很有可能会报毒”suspicious“。kaze在多态方面使用规则化 的多态引擎思路。 4.2.”规则化“的多态引擎(Kpasm) kpasm是一个更像编译器的工具,只不过它按照规则产生一个多态代码的工具。而它的规则编写则更像是高级语言,有点像C语言,执行过程如下: .-------. rule_kpasm.txt------>| kpasm | ----------->poly_kpasm.asm----. .-------. |---> virus.exe virus.asm----. 产生的混淆代码可能如下: mov reg,data <== > mov reg,0 , add reg,data 规则会列出这样的一组描述,而引擎针对的处理则是个复杂的产生过程,比如会使用随机寄存器,jumps,loops,mem read ,mem wirte 等操作手段操作。 因为规则就是对产生指令的描述,所以同样要避免产生僻指令,及过多的使用stc ,clc 这样的指令。Win32/Leon 使用的规则如下: *标准操作: mov, add, sub, lea, cmp, jmp, push, pop, etc. *API 调用: junk api *jumps : 产生Predicate *junk :少量的junk loops Win32/Leon 使用的多态并不多,而且也只是为了对付特征检测而加入的。但要保证的是,当产生两个类似的解密器时,要产生完全不同的代码,当然这需要一个平衡,多态过多 容易引起仿真器的报警,太少则无法绕过特征检测。 kpasm 的规则语法也很简介,依据自己的思路就可以产生任意一个等效指令,部分规则描述如下: //----------------------- **** mov regx,xxx **** --------------------------------// mov_reg_cst(reg:registre,cst:entier) { 1: { mov_reg_cst(reg,cst-[freemem0]); // 等效 mov reg,cst-[mem] ; add reg,[mem] junk(); add_reg_mem(reg,freemem0); } 1: { mov_reg_cst(reg,cst+[freemem0]); // 等效 mov reg,cst+[mem]; sub reg,[mem] junk(); sub_reg_mem(reg,freemem0); } 1: { mov_reg_mem(reg,freemem0); // 等效 mov reg,[mem]; add reg,cst-[mem] junk(); add_reg_cst(reg,cst-[freemem0]); } 1: { mov_reg_mem(reg,freemem0); // 等效 mov reg,[mem] ; sub reg,[mem]-cst junk(); sub_reg_cst(reg,[freemem0]-cst); } 1: { mov_reg_cst(reg,cst-1); // 等效 mov reg,cst-1 ; inc reg junk(); inc_reg(reg); } 4: DEFAUT // 不经过任何变换 { write8(0xB8|reg); write32(cst); } } //------------------------ **** cmp [xxx],yyy ****--------------------------------// cmp_mem_cst(mem:adresse,cst:entier) { 1: { mov_reg_mem(freereg0,mem); // 等效 mov tmp_Reg , mem ; cmp tmp_reg , cst cmp_reg_cst(freereg0,cst); } 4: DEFAUT { // 不经过任何变换 write16(0x3D81); write32(mem); write32(cst); } } // ---------------------------------------------------------------------------------// 其余的规则于此类似不再赘述,Win32/Leon的一部分多态的代码如下: 6A EC push -14 FF35 18880001 push dword ptr ds:[1008818] 8BD8 mov ebx,eax FF68 94 jmp far fword ptr ds:[eax-6C] 14 00 adc al,0 01BE 40B13801 add dword ptr ds:[esi+138B140] 8B0D 2F280301 mov ecx,dword ptr ds:[103282F] 2BF1 sub esi,ecx 43 inc ebx B8 D2110301 mov eax,KAZENO~1.010311D2 8998 CD150000 mov dword ptr ds:[eax+15CD],eb 8935 AB270301 mov dword ptr ds:[10327AB],esi FF35 AB270301 push dword ptr ds:[10327AB] 68 00008000 push 800000 FF35 1B280301 push dword ptr ds:[103281B] A1 8B270301 mov eax,dword ptr ds:[103278B] 05 8DB2F7FF add eax,FFF7B28D BF 351B0301 mov edi,KAZENO~1.01031B35 8BB7 520D0000 mov esi,dword ptr ds:[edi+D52] A3 2F270301 mov dword ptr ds:[103272F],eax 对函数调用的一个混淆如下: 68 2F600001 push KAZENO~1.0100602F -------------> stack中压入下一个chunk块的地址 FF35 EB270301 push dword ptr ds:[10327EB] @1 C705 2B270301 653594>mov dword ptr ds:[103272B],5E943565 BB FF38AD3E mov ebx,3EAD38FF BD 86AFDCE6 mov ebp,E6DCAF86 FF35 2B270301 push dword ptr ds:[103272B] @2 FF35 03280301 push dword ptr ds:[1032803] @3 68 E1F5FE63 push 63FEF5E1 @4 BD 87280301 mov ebp,KAZENO~1.01032887 8B5D 08 mov ebx,dword ptr ss:[ebp+8] 41 inc ecx 891D 9B270301 mov dword ptr ds:[103279B],ebx FF35 9B270301 push dword ptr ds:[103279B] @5 FF35 F3270301 push dword ptr ds:[10327F3] @6 FF15 04110001 call dword ptr ds:[<&KERNEL32.CompareStringW>] 8B3D 0F280301 mov edi,dword ptr ds:[103280F] C3 retn 可以看到在一个函数的参数之间,有随机的寄存器,内存读写,而且整体代码看起来是合法的调用,参数都是随机产生的,所以感染一个宿主程序两次,即便是同样的调用 CompareStringW的代码块,也很难出现连续3个字节以上相同的特征,所以重复的几率是微乎其微的。 4.3.继续强化 通过重定位方式可以继续对解密器的代码进行混淆,当然,这样要求宿主程序也要有.reloc节,或者再新添加一个.reloc节,一般来说有.reloc节的PE文件占整体的~5%。这一技术 最早描述在29a#5 tcp写的Encryptation through relocs 中,Win32/Leon中思路和那篇类似,也就是利用重定位节中的数据再次对病毒代码进行解密,而这个解密是windows帮我们做 的,在此不再赘述。 通过以上种种对抗方式使得Win32/Leon是一个难于检测的感染式病毒,能对其准确报出病毒名称的也只有avp,a-squared,Sophos等...。kaze在将病毒发给AVs三周后,sophos 能对 感染后的文件保持在~80%的检出率,而其他的都低于20%。6个月后,sophos达到~95%,avp ~15%,sophos利用的是解密器的若干个有效的特征码,所以针对Win32/Leon产生的特征码文件 也很大。其他AVs检出率不高,有可能是传播不广的原因。 [0x05].检测分析 首先我们知道,对于隐形解密技术,一定要加入一个IID到宿主程序,这样有可能会产生两个同名DLL的IID,这在标准编译器编译出来的程序中是极为少见的(我不确定是否 是能通过配置编译选项,作出那个效果来),对检测来说,这是很重要的一点,可以配合其它的检测信息来确定是否是隐形解密类病毒感染的。下面将从3方面入手进行检测。 5.1.代码段扫描 我们知道,即便宿主没有导入advapi32,也会由病毒添加了一个advapi32 IID到PE结构中,其里面的API名称是由cryptAPI系列和随机的用于混淆的特征检的其它api组成,而这 些api并不会所有的,都在宿主程序中被调用,而正常程序的导入表的api都是由编译器自行生成的,都是源代码中一定调用的,这样我们可以通过扫描代码段来发现这样的差异。 同样对整个节进行扫描,注意,我们扫描整个节数据,仅当我们忽略对寄存器调用这种情况的分析时,会发现,被其感染后的宿主程序会有如下明显的特征序列,所以该方式也可 以作为检测依据,当然,仅当被感染的宿主程序使用如下结构的调用方式: mov Rx , 0x7xxxxxx ;0x7xxxxxx => CreateProcessA address call Rx ;=> call CreateProcessA // ------------------------------------------------------------------------------------------------------------- api call -> off:0x00000913:CryptDecrypt api call -> off:0x00002a8a:CryptHashData api call -> off:0x000046e8:CryptAcquireContextA api call -> off:0x0000544e:CryptCreateHash api call -> off:0x000059dd:CryptDeriveKey api call -> off:0x00000913:CryptDecrypt api call -> off:0x00002a8a:CryptHashData api call -> off:0x000046e8:CryptAcquireContextA api call -> off:0x0000544e:CryptCreateHash api call -> off:0x000059dd:CryptDeriveKey api call -> off:0x00000913:CryptDecrypt api call -> off:0x00002a8a:CryptHashData api call -> off:0x000046e8:CryptAcquireContextA api call -> off:0x0000544e:CryptCreateHash api call -> off:0x000059dd:CryptDeriveKey api call -> off:0x00000913:CryptDecrypt api call -> off:0x00002a8a:CryptHashData api call -> off:0x000046e8:CryptAcquireContextA api call -> off:0x0000544e:CryptCreateHash // ------------------------------------------------------------------------------------------------------------- 注意APIs前面的地址数据值,都是间距很大的跨越,这是”碎片化“解密器的结果。 .... 5.2.动态代码分析 在bytehero team内部的动态代码分析环境(Win32/Leon的anti-emultor对bdv无效)中分析,会发现如下调用方式: 0x90000052(0x02E3F91C)--->0x01006B22 CreateFileW -->@ safe api 0x90000C87(0x02E3F91C)--->0x010052EE CryptAcquireContextA --># decryptor code 0x90000038(0x02E3F91C)--->0x01001CFC CompareStringW -->@ safe api 0x90000C8A(0x02E3F91C)--->0x01006054 CryptCreateHash --># decryptor code 0x90000C9F(0x02E3F91C)--->0x01003690 CryptHashData --># decryptor code 0x90000038(0x02E3F91C)--->0x010058CF CompareStringW -->@ safe api 0x90000C8C(0x02E3F91C)--->0x010065E3 CryptDeriveKey --># decryptor code 0x90000C8B(0x02E3F91C)--->0x01001519 CryptDecrypt --># decryptor code 0x90000247(0x02E3F91C)--->0x01018E7D LocalAlloc 0x90000247(0x02E3F91C)--->0x01018E7D LocalAlloc 0x90000247(0x02E3F91C)--->0x01018E7D LocalAlloc 0x90000247(0x02E3F91C)--->0x01018E7D LocalAlloc 0x90000051(0x02E3F91C)--->0x01030B80 CreateFileMappingW 0x90000241(0x02E3F91C)--->0x01030B29 LoadLibraryA 0x90000241(0x02E3F91C)--->0x01030B29 LoadLibraryA 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000241(0x02E3F91C)--->0x01030B29 LoadLibraryA 0x90000052(0x02E3F91C)--->0x01030B80 CreateFileW 0x90000052(0x02E3F91C)--->0x01030B80 CreateFileW 0x90000197(0x02E3F91C)--->0x01030B29 GetProcAddress 0x90000241(0x02E3F91C)--->0x01030B29 LoadLibraryA 0x90000051(0x02E3F91C)--->0x01030B80 CreateFileMappingW 0x90000051(0x02E3F91C)--->0x01030B80 CreateFileMappingW 0x90000197(0x02E3F91C)--->0x01030B29 GetProcAddress 0x90000038(0x02E3F91C)--->0x01030B80 CompareStringW 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x900001D1(0x02E3F91C)--->0x01018FDC GetTickCount 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x900000D0(0x02E3F91C)--->0x01030B29 FindFirstFileA 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000592(0x02E3F91C)--->0x01030B29 MessageBoxA -->@ payload 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x90000371(0x02E3F91C)--->0x01030B29 VirtualProtect 0x90000031(0x02E3F91C)--->0x01030B80 CloseHandle 0x9000006C(0x02E3F91C)--->0x010315AC CreateThread 0x90000175(0x02E3F91C)--->0x01006AF7 GetModuleHandleA ... //转向宿主程序调用 这样配合前面提到过的被感染程序IID方面的信息,就可以检测出当前程序是否被感染Win32/Leon了。 5.3.静态代码分析 由于Win32/Leon的payload仅是个msgbox,如果在动态环境中在执行GetModuleHandleA前还不能完全确认其感染,此时动态可转调静态分析,静态分析开头的部分情况如下: 0x0 : 0x1006b63 call[0] - > __p__fmode 0x1 : 0x1006b71 call[0] - > __p__commode 0x2 : 0x1006b8b call[1] - > sub_1006d10 0x4 : 0x1006b9d call[0] - > __setusermatherr 0x5 : 0x1006ba4 call[1] - > sub_1006cfe 0x6 : 0x1006d08 call[1] - > _controlfp 0x8 : 0x1006bb3 call[0] - > _initterm 0x9 : 0x1006bd6 call[0] - > __getmainargs 0xa : 0x1006be9 call[0] - > _initterm 0xb : 0x1006c28 call[0] - > GetStartupInfoA 0xc : 0x1006c4f call[1] - > sub_1002801 0xd : 0x1002809 call[1] - > GetCommandLineW 0xe : 0x1002818 call[1] - > GetSystemMetrics 0xf : 0x100281f call[1] - > GetProcAddress 0x10 : 0x1002838 call[2] - > sub_1001b4a 0x11 : 0x1001b75 call[2] - > CharNextW 0x13 : 0x1002844 call[2] - > sub_10041ca 0x14 : 0x10041d5 call[2] - > RegisterWindowMessageW 0x15 : 0x10041fe call[2] - > GetDC 0x16 : 0x100420f call[3] - > sub_1003d57 0x17 : 0x1003d5b call[4] - > sub_1003cf2 0x18 : 0x1003d15 call[4] - > LoadStringW 0x19 : 0x1003d2d call[4] - > LocalFree 0x1a : 0x1003d40 call[4] - > LocalAlloc 0x1b : 0x1003d5b call[4] - > sub_1003cf2 0x1c : 0x1003d70 call[4] - > LocalAlloc 0x1d : 0x1003d81 call[4] - > LocalSize 0x1e : 0x1003d9c call[4] - > LoadStringW 0x1f : 0x1003dbb call[4] - > lstrcpynW 0x20 : 0x1003e04 call[4] - > MessageBoxW 0x21 : 0x1003e3f call[5] - > sub_1003c15 0x22 : 0x1003c28 call[5] - > CharUpperW 0x24 : 0x1003e5d call[4] - > GetSystemMenu 0x25 : 0x1003e73 call[4] - > LoadAcceleratorsW ... 可以看到,这是一个标准VC++编写的程序开头,同时出现了在病毒程序中一般不会出现的,窗口类,字体,图形类API,可以肯定GetModuleHandleA前开头的代码可能是宿主程序 被加壳后的代码,或是被病毒感染后的结果。 总结一下检测的依据: 1)被感染程序出现同名advapi.dll的IID,同时导入了cryptapi。再通过壳特征库,排除壳的可能。 2)代码段扫描,发现crypt API固定序列,advapi.dll导入函数不是完全被调用。 3) 动态代码分析下,出现crypt AIP固定序列,在调用CryptDecrypt解密结束后,存在大的跨段跳转。 4) 动态代码分析下,出现查找当前目录文件,依据条件感染文件,执行payload,此时动态分析可以确定病毒,停止分析。 5)跳向宿主程序,静态分析出现病毒少见的API调用(窗口类,字体,图形类API)情况,该项依据被感染的宿主程序而定,是补充条件。 这样再配合被感染程序自身的文件特性,就可综合的得出被Win32/Leon感染的结论了。 [0x06].其他 Win32/Leon 使用的隐形解密技术是对AVs有效的一个反击,而且它的规则化引擎也非常有趣,但对反病毒研究人员来说,强大的动态代码分析能力,仍然是对抗这类复杂病毒的 最有效武器。 附参考文献: [1] kaze. 《Stealth api-based decryptor》