吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8300|回复: 13
收起左侧

[转载] 隐形解密技术病毒的分析与对抗

 关闭 [复制链接]
Hmily 发表于 2010-3-24 11:40
使用论坛附件上传样本压缩包时必须使用压缩密码保护,压缩密码:52pojie,否则会导致论坛被杀毒软件等误报,论坛有权随时删除相关附件和帖子!
病毒分析分区附件样本、网址谨慎下载点击,可能对计算机产生破坏,仅供安全人员在法律允许范围内研究,禁止非法用途!
禁止求非法渗透测试、非法网络攻击、获取隐私等违法内容,即使对方是非法内容,也应向警方求助!

                            =|--bytehero team--|=

/=-----------------------------------------------------------------------=\

|=-------------=[     隐形解密技术病毒的分析与对抗        ]=-------------=|

|=-----------------------------------------------------------------------=|

|=---------------=[   by nEINEI/[bytehero]/091127        ]=--------------=|

|=---------------=[   nEINEI<neinei_at_bytehero_dot_com> ]=--------------=|

\=-----------------------------------------------------------------------=/


[目录]

[0x01].简介

[0x02].隐形解密技术

   2.1.为什么要使用隐形解密

   2.2.隐形解密的前提条件

   2.3.基于API的隐形解密器结构

   2.4.隐藏IAT

[0x03].AVs启发式检测技术

   3.1.anti-Heuristic

   3.2.获得"safe api"

   3.3."碎片化"解密器

[0x04].AVs特征检测技术

   4.1.解密器多态处理

   4.2."规则化"的多态引擎(Kpasm)

   4.3.继续强化

[0x05].Win32/Leon的检测与分析

   5.1.代码段扫描

   5.2.动态代码分析

   5.3.静态代码分析  

[0x06].其他


[0x01].简介  


        Win32/Leonby kaze)病毒中首次使用了对病毒解密器进行非传统多态方式的伪装技术,这是一种的新的反启发式检测的方式,也就是基于API的隐形解密,以此来做到强于EPO的效果,目前看,能对该病毒感染后的文件完全检测的AVs产品还很少,下面将对该技术进行分析,同时给出可行的检测方案。


[0x02].隐形解密技术


   2.1.为什么要使用隐形解密


    众所周之,加密、多态病毒是逃避特征检测的最好方案(木马加壳一类不属于我们讨论的技术范畴),但无论是加密病毒还是多态病毒,如果aver在不考虑进行完全修复而仅是最大限度的检测病毒的情况下,最有效的检测位置就是解密器的那部分代码(sanboxes除外),所以解密器是vxeraver的必争之地,进而vxer针对该位置进行混淆,早期代表性的病毒有whale,MtE,hps,Vulcano...和由此产生的大量的polymorphism引擎。


    所以,此后的一段时间polymorphism偏向于复杂化,以难以让AVs检测为目的,同时尽量让代码变换得难以理解。 但有一点要注意的就是,一个多态引擎无论写的多好,一旦aver有了针对它的检测方案,那么再使用这个引擎进行伪装就是很危险的了。Win32/Leon采用逆向思维的方式来考虑这个问题,让病毒程序的入口代码--解密器(仅指加密、多态类病毒)尽量做到普通化,大众化,像普通应用程序一样平淡无奇,迫使AVs仿真器退出检测,这也就是隐形解密技术的产生原因。


   2.2.隐形解密的前提条件


       win32/Leon使用隐形技术的两个前提假设条件是:


       1)当前的AVs仿真器都不仿真APIs,至少不会仿真所有的APIs.


       2)如果仿真器分析的代码看起来像普通的应用程序,并且再去调用那些没有被AVs仿真的APIs,那么仿真器很有可能会取消检测.


       这两个假设有些牵强,但作为桌面防毒产品,不大可能花费非常多的时间用于仿真方面的检测,所以这样的假设是有实现可能的.


       常见的病毒解密器要编写的复杂和难以让仿真器执行,Win32/Leon要建立一个看起来像普通程序的代码,是一个”无害的代码块“,仅使用普通的APIs调用,不使用xor常见的解密方式及特殊的opcode,因为很少有病毒利用APIs作为解密器,更多都是使用垃圾指令来填充。同时Win32/Leon 还考虑了,当仿真器退出后,基于API序列的检测还会继续扫描,进而继续隐藏API序列。      


   2.3.基于API的隐形解密器结构


    可以完全的肯定,利用现有的APIs能完成解密器的设计的工作,关键是选择哪些APIsWin32/Leon使用了标准的Microsoft CryptoAPI系列API,因为这很方便也是现成加解密的方案,同样还可以选择其它的APIs,这就需要耐心一点的寻找,kaze推荐的有BitBlt,因为BitBlt的最后一个参数dwRop,提供多种逻辑操作手段,比如


   BOOL BitBlt(

   HDC hdcDest, // handle to destination DC

   int nXDest,  // x-coord of destination upper-left corner

   int nYDest,  // y-coord of destination upper-left corner

   int nWidth,  // width of destination rectangle

   int nHeight, // height of destination rectangle

   HDC hdcSrc,  // handle to source DC

   int nXSrc,   // x-coordinate of source upper-left corner

   int nYSrc,   // y-coordinate of source upper-left corner

   DWORD dwRop  // raster operation code

);

   dwRop 可选择

   PATINVERT  会执行一个xor操作

   MERGECOPY  会执行一个AND操作


   而且这些指令的执行是在GPU上,而不是CPU上,算是个很好的anti-emultor。有关图形图像的APIs,会有很多的数据逻辑操,这些都可以成为备选目标。Win32/Leon使用如下方式:


   csp   dd ?

   hash  dd ?

   key   db 48 dup (?)

   hkey  dd ?


   call CryptAcquireContext, offset csp,0,0,PROV_RSA_FULL,CRYPT_VERIFY_CONTEXT

   call CryptCreateHash,     csp,CALG_MD5,0,0,offset hash

   call CryptHashData,       hash, offset key,4,0

   call CryptDeriveKey,      csp,CALG_RC4,hash,48,offset hkey

   call CryptDecrypt,        hkey,0,1,0,start_of_virus,size_of_virus,start_of_virus


   这样就可以利用cr4对称密钥算法来解密病毒体,同样Win32/Leon也内置了一个xor方案的解密,但很少用。Win32/Leon中主要是利用CryptoAPI系列构建解密器。


   2.4.隐藏IAT


        首先修改宿主程序的IAT


        1)扩展最后一个节,分配一个空白数据空间,拷贝宿主程序的IAT到这里。


        2)添加一个IID(image import descriptor)项到宿主程序,也就是解密时用到的APIs函数,CryptoAPI系类函数都在advapi32.dll中导出,所以无论宿主程序是否导入了advapi32.dll,都要新添加一个IID目录项,有两个DLL同名的IID项是不影响PE程序执行的。


        3)给上面添加的IIDFirstThunkOriginalFirstThunk,填入适当RVA,使其指向解密时能用用到的函数名称,CryptAcquireContext","CryptCreateHash"...


        这时再调用这些APIs解密时,就和普通的应用程序没有区别了,因为通常的病毒程序的做法是自己搜索这些API的地址。但由于添加的IID过于明显,为了防止AVs的特征检测,Win32/Leon使用了两个小技巧。


        * OriginalFirstThunk FirstThunk 指向的函数名称随机存放。

        * 考虑到,如果在advapi32.dll中仅导入CryptoAPI系列函数,那么启发式检测就可以轻松的发现这个异常,所以在导入函数时,在随机的导入一些其他的函数。


        一个修改后的宿主IAT将会是如下方式:


感染前:


      PE Header-----.

                    |  

                    V  

        +-------------------------------------------------+

    .---|----------------< IAT rva                        |

    |   |_________________________________________________|

    |   |                  section...                     |

    |   |-------------------------------------------------|

    |   |                                                 |

    .---|-->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

  push 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个参数,看有多少个dwordpop出来,这个数字就是函数的参数。


       3)调用api多次,并且每次随机选择不同的参数进行调用


       4)如果没有异常抛出,也没有崩溃,那么这个api就是一个safe api


      kaze 编写了一个工具,自动的跑出了这些结果,在oswinxp 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            

      ...


      以上这些apiwin2kwinxp下进行调用基本都是安全的,但在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()               |

|      push  CloseHandle()            |             |  push  random()               |

|      ret                            |             |  call  lstrcmp()              |

+-------------------------------------+             |  ret                          |

                                                    +-------------------------------+


      这样,因为AVschunk #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      


       规则会列出这样的一组描述,而引擎针对的处理则是个复杂的产生过程,比如会使用随机寄存器,jumpsloopsmem 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 regcst-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到宿主程序,这样有可能会产生两个同名DLLIID,这在标准编译器编译出来的程序中是极为少见的(我不确定是否是能通过配置编译选项,作出那个效果来),对检测来说,这是很重要的一点,可以配合其它的检测信息来确定是否是隐形解密类病毒感染的。下面将从3方面入手进行检测。


       5.1.代码段扫描      


       我们知道,即便宿主没有导入advapi32,也会由病毒添加了一个advapi32 IIDPE结构中,其里面的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/Leonanti-emultorbdv无效)中分析,会发现如下调用方式:


        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/Leonpayload仅是个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.dllIID,同时导入了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

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

冥河 发表于 2010-3-24 12:27
好东西。看不太懂。。支持一下
lsslsslss888 发表于 2010-5-4 22:10
tengxiong532 发表于 2010-5-4 22:28
miyuecao 发表于 2010-5-5 08:31
支持下 好东西~~~
心中的雪 发表于 2010-5-25 22:31
好文章,不错,论坛上就要多一些这种类型的 技术型文章
douforster 发表于 2010-5-28 12:29
有点意思,学习了。
sa16333 发表于 2010-5-29 06:09
半懂不懂的挺麻烦的
happyzcq911 发表于 2010-5-29 09:10
哎!現在水平還完全看不懂,悲哀!
fweiger 发表于 2010-12-21 16:02
好好好好好好好好好好好好
可惜看不懂
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 13:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表