【文章标题】: TTProtect 1.06DEMO主程序VM浅析
【文章作者】: cxhcxh
【软件名称】: TTProtect 1.06DEMO
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  
  1.闲来无事,就下了个TTProtect 1.6 DEMO的主程序玩玩,打发打发时间,据几位大牛说这壳很厉害,在此就以学习的态度来研究研究他的虚拟机.
  
  
  2.个人感觉TTP的VM和VMP的VM非常像,如果研究过VMP的VM,再来看TTP的话就会比较轻松,TTP是堆栈机,所有的运算都通过堆栈来传递参数,而且是用的自身栈,也有自己的
  CHECK_STACK_OVERFLOW,废话少说,看看他是怎么进入虚拟机的
  
  
  027EA7DC    68 A17703B2     push    B20377A1                       ;keydate
  027EA7E1  ^ E9 C21BDFFF     jmp     025DC3A8                       ;VMINIT
  025DC3A8  ^\E9 A11669FF     jmp     01C6DA4E
  01C6DA4E    9C              pushfd                                 ;保存寄存器
  01C6DA4F    60              pushad                                 ;保存寄存器
  01C6DA50    53              push    ebx                            ;开始计算key
  01C6DA51    53              push    ebx
  01C6DA52    52              push    edx
  01C6DA53    0F8B 21683000   jpo     01F7427A
  01C6DA59    0F8A 1B683000   jpe     01F7427A
  01F7427A    9C              pushfd
  01F7427B    E8 01000000     call    01F74281
  01F74281   /E9 27760B00     jmp     0202B8AD
  0202B8AD    5B              pop     ebx                              
  0202B8AE    81C3 ADB96F4E   add     ebx, 4E6FB9AD
  0202B8B4    8BD3            mov     edx, ebx                         ; key =ebx=5066FC2D
  0202B8B6  ^ E9 7945EFFF     jmp     01F1FE34
  01F1FE34    81C2 00000000   add     edx, 0
  01F1FE3A    899424 0C000000 mov     dword ptr [esp+C], edx           ;保存key
  01F1FE41    9D              popfd
  01F1FE42    5A              pop     edx
  01F1FE43    5B              pop     ebx
  01F1FE44    E9 415C1F00     jmp     02115A8A
  02115A8A    8BB424 28000000 mov     esi, dword ptr [esp+28]          ;取keydata
  02115A91    FC              cld
  02115A92    8BEC            mov     ebp, esp                         ;保存真实栈
  02115A94    E8 03000000     call    02115A9C
  02115A9C    66:9C           pushfw
  02115A9E    818424 02000000>add     dword ptr [esp+2], 6251A3
  02115AA9    66:9D           popfw
  02115AAB    C3              retn
  0273AC3C    81EC 00020000   sub     esp, 200                         ;分配VMCONTEXT空间
  0273AC42    8BFC            mov     edi, esp                         ;edi指向VMCONTEXT
  0273AC44  ^ E9 618290FF     jmp     02042EAA
  02042EAA    8BDE            mov     ebx, esi        
  02042EAC    51              push    ecx
  02042EAD    50              push    eax
  02042EAE    9C              pushfd
  02042EAF    E8 01000000     call    02042EB5
  02042EB5   /E9 86927600     jmp     027AC140
  027AC140    59              pop     ecx                              ; 02042EB4
  027AC141    81C1 79CD624E   add     ecx, 4E62CD79
  027AC147    8BC1            mov     eax, ecx                         ;ecx=5066FC2D
  027AC149    81C0 00000000   add     eax, 0
  027AC14F  ^ E9 3B43A1FF     jmp     021C048F
  021C048F    9D              popfd
  021C0490    03F0            add     esi, eax                          ;ESI指向VMDATA
  021C0492    58              pop     eax
  021C0493    68 9AB9F5C7     push    C7F5B99A
  021C0498    55              push    ebp
  021C0499    E8 02000000     call    021C04A0
  021C049E    B6 19           mov     dh, 19
  021C04A0    5D              pop     ebp                              ; 021C049E
  021C04A1    9C              pushfd
  021C04A2    89AC24 08000000 mov     dword ptr [esp+8], ebp
  021C04A9    818424 08000000>add     dword ptr [esp+8], 42B1FE
  021C04B4    81C5 4F654300   add     ebp, 43654F
  021C04BA    9D              popfd
  021C04BB    55              push    ebp
  021C04BC    C3              retn
  025F69ED    5D              pop     ebp                              ; 0012FDB4
  025F69EE    C3              retn
  025EB69C    59              pop     ecx                              ; 0012FDBC
  025EB69D  ^\E9 5149F4FF     jmp     <FetchCode>
  

  TTP以PUSH IMM32/jmp VMINIT对进入虚拟机,并把寄存器和key按顺序入栈
  /*
  key
  edi
  esi
  ebp
  esp
  ebx
  edx
  ecx
  eax
  eflag
  keydata
  */
  

  其中eax,ecx,edx作为虚拟机的寄存器用于运算
  edi指向VMCONTEXT
  ESI指向VMDATA
  EBP指向真实堆栈
  EBX作为key参与运算
  

  
  3.下面看一下VM的主要流程
  
  0252FFF3 >  AC              lods    byte ptr [esi]                   ;取VMDATA
  0252FFF4    FEC8            dec     al                               ;计算
  0252FFF6  ^ 0F80 A87BFAFF   jo      024D7BA4
  0252FFFC  ^ 0F81 A27BFAFF   jno     024D7BA4
  024D7BA4    C0C0 EE         rol     al, 0EE                          ;计算
  024D7BA7    FEC8            dec     al                               ;计算
  024D7BA9    E8 02000000     call    024D7BB0
  024D7BAE  ^ 76 8D           jbe     short 024D7B3D
  024D7BB0    9C              pushfd
  024D7BB1    818424 04000000>add     dword ptr [esp+4], 3B4DDA
  024D7BBC    9D              popfd
  024D7BBD    C3              retn
  0288C988    C0C0 78         rol     al, 78                           ;计算
  0288C98B    FEC8            dec     al                               ;计算
  0288C98D  ^ 0F83 C34554FF   jnb     01DD0F56
  0288C993  ^ 0F82 BD4554FF   jb      01DD0F56
  01DD0F56    80F0 17         xor     al, 17                           ;计算
  01DD0F59    C0C8 40         ror     al, 40                           ;计算
  01DD0F5C    E9 39788700     jmp     0264879A
  0264879A    FEC8            dec     al                               ;计算
  0264879C    2AD8            sub     bl, al                           ;更新key
  0264879E    32D8            xor     bl, al                           ;更新key
  026487A0    0FB6C0          movzx   eax, al                          ;计算
  026487A3    E9 52971800     jmp     027D1EFA
  027D1EFA    C1C0 02         rol     eax, 2                           ;计算
  027D1EFD    53              push    ebx                              ;保存key
  027D1EFE  ^ 0F8C 157DF4FF   jl      02719C19
  027D1F04  ^ 0F8D 0F7DF4FF   jge     02719C19
  02719C19    9C              pushfd
  02719C1A    E8 03000000     call    02719C22
  02719C1F    3BC0            cmp     eax, eax
  02719C21    EF              out     dx, eax
  02719C22    5B              pop     ebx
  02719C23    81C3 0E60F54D   add     ebx, 4DF5600E               ;ebx=5066FC2D
  02719C29    53              push    ebx
  02719C2A  ^ E9 2A4561FF     jmp     01D2E159
  01D2E159    018424 00000000 add     dword ptr [esp], eax
  01D2E160    818424 00000000>add     dword ptr [esp], B1D5B90E
  01D2E16B    5B              pop     ebx
  01D2E16C    E8 04000000     call    01D2E175
  01D2E171    90              nop
  01D2E172    90              nop
  01D2E173    90              nop
  01D2E174    90              nop
  01D2E175    9C              pushfd
  01D2E176    818424 04000000>add     dword ptr [esp+4], 10D892
  01D2E181    9D              popfd
  01D2E182    C3              retn
  01E3BA03    8B03            mov     eax, dword ptr [ebx]          ;取加密的DISPATCH_CODE
  01E3BA05    9D              popfd
  01E3BA06    5B              pop     ebx
  01E3BA07    57              push    edi
  01E3BA08    56              push    esi
  01E3BA09  ^ E9 B328FFFF     jmp     01E2E2C1
  01E2E2C1    9C              pushfd
  01E2E2C2    E8 03000000     call    01E2E2CA
  01E2E2C7    90              nop
  01E2E2C8    90              nop
  01E2E2C9    90              nop
  01E2E2CA    5F              pop     edi
  01E2E2CB    81C7 6619844E   add     edi, 4E841966
  01E2E2D1    0F8D D4471E00   jge     02012AAB
  01E2E2D7    0F8C CE471E00   jl      02012AAB
  02012AAB    8BF7            mov     esi, edi                     
  02012AAD    81C6 00000000   add     esi, 0
  02012AB3    9D              popfd
  02012AB4  ^ E9 4264D3FF     jmp     01D48EFB
  01D48EFB    03C6            add     eax, esi                     ;解密
  01D48EFD    5E              pop     esi
  01D48EFE    5F              pop     edi
  01D48EFF    E9 D1B41F00     jmp     01F443D5
  01F443D5   /FFE0            jmp     eax                          ;执行DISPATCH_CODE
  
  从内存中提取初所有加密的地址,写个代码得到所有的DISPATCH_CODE
  
  // TTPdecode.cpp : Defines the entry point for the console application.
  //
  
  #include "stdafx.h"
  #include <stdio.h>
  #include <Windows.h>
  DWORD dispatch[]={
            0xB1A71E26, 0xB2158CEE, 0xB1BB174B, 0xB1DB6D49, 0xB1C2C790, 0xB19011B6, 0xB1C3E920, 0xB1EC03C6, 0xB17EA2D4, 0xB15F06F1, 
      0xB209056F, 0xB178E836, 0xB1D1E146, 0xB1BB174B, 0xB17565A2, 0xB21AB0C1, 0xB1E26E56, 0xB1ED32A3, 0xB1C2C790, 0xB1A8CAAC, 
      0xB1B53F83, 0xB1B38C6B, 0xB20D81E2, 0xB15FDE21, 0xB1C2ECCF, 0xB20DD142, 0xB19D327D, 0xB1FBEC69, 0xB1BB174B, 0xB209056F, 
      0xB1AD0DB5, 0xB1E1E460, 0xB17EA2D4, 0xB17565A2, 0xB21AB0C1, 0xB1C2ECCF, 0xB209056F, 0xB1FD9013, 0xB1A8CAAC, 0xB1E1E460, 
      0xB19234F7, 0xB1DB6D49, 0xB1FB49D7, 0xB19011B6, 0xB2158CEE, 0xB1E62E64, 0xB15FDE21, 0xB1E32A0C, 0xB1B38C6B, 0xB16C9090, 
      0xB21AB0C1, 0xB1C76138, 0xB16B87DD, 0xB1CA1F2E, 0xB1C2C790, 0xB1FBEC69, 0xB17565A2, 0xB1F27DB1, 0xB1E62E64, 0xB20DD142, 
      0xB19DE8E6, 0xB1E62E64, 0xB20D81E2, 0xB19011B6, 0xB1BB174B, 0xB1FB49D7, 0xB1DA5A3D, 0xB17AF4E4, 0xB1F5E06F, 0xB19234F7, 
      0xB1AD0DB5, 0xB19DE8E6, 0xB1D1E146, 0xB1C2C790, 0xB1DB6D49, 0xB1AD0DB5, 0xB1E62E64, 0xB16C9090, 0xB1FBEC69, 0xB1F6BC35, 
      0xB1F7FF6E, 0xB1C2ECCF, 0xB1E32A0C, 0xB20D81E2, 0xB17EA2D4, 0xB1E32A0C, 0xB15FDE21, 0xB1F6BC35, 0xB1E26E56, 0xB17EA2D4, 
      0xB15FDE21, 0xB1C3E920, 0xB178E836, 0xB1E62E64, 0xB1DB6D49, 0xB15FDE21, 0xB1DB6D49, 0xB1DA5A3D, 0xB1AD0DB5, 0xB1A8CAAC, 
      0xB1EC03C6, 0xB20DD142, 0xB16C9090, 0xB1A8CAAC, 0xB19DE8E6, 0xB16C9090, 0xB17AF4E4, 0xB178E836, 0xB1D1E146, 0xB1D9BBB9, 
      0xB1C2ECCF, 0xB16B87DD, 0xB1ACEA6D, 0xB19234F7, 0xB1614C85, 0xB1C3E920, 0xB1A71E26, 0xB1C2ECCF, 0xB1CA1F2E, 0xB1E1E460, 
      0xB1D97554, 0xB1B53F83, 0xB1E32A0C, 0xB1AC9F66, 0xB1F27DB1, 0xB1B53F83, 0xB1BD681D, 0xB1C3E920, 0xB22AB7CA, 0xB19DE8E6, 
      0xB1FBEC69, 0xB1C3E920, 0xB15FDE21, 0xB1A71E26, 0xB1A8CAAC, 0xB20DD142, 0xB1B38C6B, 0xB22AB7CA, 0xB1C2ECCF, 0xB1E62E64, 
      0xB1F27DB1, 0xB1C3E920, 0xB1F6BC35, 0xB1E32A0C, 0xB1E1E460, 0xB1BBE22C, 0xB16B87DD, 0xB1ACEA6D, 0xB1B53F83, 0xB1FB49D7, 
      0xB1AD0DB5, 0xB19D327D, 0xB1BD681D, 0xB1E1E460, 0xB1BBE22C, 0xB1B53F83, 0xB17EA2D4, 0xB1BEB0C5, 0xB1D9BBB9, 0xB1BB174B, 
      0xB1E26E56, 0xB1EB1FB2, 0xB15FDE21, 0xB1AC9F66, 0xB1EB1FB2, 0xB19D327D, 0xB22AB7CA, 0xB1F27DB1, 0xB16C9090, 0xB1F5E06F, 
      0xB1E26E56, 0xB15F06F1, 0xB1F5E06F, 0xB1C3E920, 0xB17AF4E4, 0xB1F7FF6E, 0xB1BD681D, 0xB1D97554, 0xB1F7FF6E, 0xB19011B6, 
      0xB1FD9013, 0xB1B38C6B, 0xB1F27DB1, 0xB19D327D, 0xB17AF4E4, 0xB1B38C6B, 0xB19011B6, 0xB1A71E26, 0xB17EA2D4, 0xB1C2ECCF, 
      0xB16B87DD, 0xB1A71E26, 0xB1EC03C6, 0xB1AC9F66, 0xB1BB174B, 0xB19011B6, 0xB1EB1FB2, 0xB1F27DB1, 0xB1D97554, 0xB1FBEC69, 
      0xB18DF2E6, 0xB1ED32A3, 0xB17EA2D4, 0xB1AC9F66, 0xB1F6E0A1, 0xB1E26E56, 0xB1FBEC69, 0xB1F7FF6E, 0xB1614C85, 0xB209056F, 
      0xB1C2C790, 0xB1F6E0A1, 0xB1EC03C6, 0xB1A71E26, 0xB1DA5A3D, 0xB17EA2D4, 0xB1BBE22C, 0xB1D9BBB9, 0xB1C2ECCF, 0xB20DD142, 
      0xB19D327D, 0xB1DB6D49, 0xB19234F7, 0xB17AF4E4, 0xB1F27DB1, 0xB1FB49D7, 0xB1F27DB1, 0xB1B38C6B, 0xB16B87DD, 0xB20D81E2, 
      0xB1C2ECCF, 0xB1F5E06F, 0xB178E836, 0xB1E26E56, 0xB1ACEA6D, 0xB1F5E06F, 0xB18DF2E6, 0xB1AC9F66, 0xB15F06F1, 0xB19011B6, 
      0xB1CA1F2E, 0xB1DB6D49, 0xB178E836, 0xB1ACEA6D, 0xB1EB1FB2, 0xB1C76138, 0xB19DE8E6, 0xB22AB7CA, 0xB209056F, 0xB1D9BBB9, 
                  0xB1C3E920, 0xB1A8CAAC, 0xB1D1E146, 0xB17EA2D4, 0xB1B53F83, 0xB1ED32A3
  };
  
  
  int main(int argc, char* argv[])
  {
    FILE *fp;
    int k=0;
    DWORD record=0;
    fp = fopen("dispatch.txt","w");
      
    for (int i=0;i<256;i++)
    {
      dispatch[i]+=0x506EFC2D;                          //解密所有的DISPATCH_CODE
      fprintf(fp,"%02x   %08x\n",i,dispatch[i]);
    }
    fclose(fp);
  
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  //进行分类
    fp = fopen("fix.txt","w");
     
    for (i=0;i<256;i++)
    {
      if (dispatch[i])
      {
        k++;
        record=dispatch[i];
  
        for (int j=0;j<256;j++)
        {  
          if (dispatch[j]==record)
          {
                                          fprintf(fp,"%02x   %08x\n",j,dispatch[j]);
            dispatch[j]=0;
          }
        }
        
      }
  
    }
    fprintf(fp,"total:%d",k);
    fclose(fp);
  
    return 0;
  }
  
  一共得到256条DIPATCH_NUMBER,总共56条DISPATCH_CODE


  其中很多DISPATCH_CODE中都会检查堆栈,即CHECK_STACK_OVERFLOW如果EBP大于EDI+100的时候,就会引起堆栈的重新分配
  
  0274CD6F    8D97 00010000   lea     edx, dword ptr [edi+100]
  0274CD75    3BD5            cmp     edx, ebp                        ;是否越界
  0274CD77  ^ 0F8C 7632DEFF   jl      <FetchCode>
  0274CD7D    8DA5 00FEFFFF   lea     esp, dword ptr [ebp-200]        ;重新分配
  0274CD83    C7C1 80000000   mov     ecx, 80
  0274CD89    68 508561F7     push    F7618550
  0274CD8E    53              push    ebx


  列举几条来看下,具体见附件,整理的有点乱
  
  0270019C    AD              lods    dword ptr [esi]            ;取VMDATA DWORD
  0270019D    03C3            add     eax, ebx                   ;下面是一系列的运算
  0270019F    81E8 633B97F2   sub     eax, F2973B63
  027001A5    F7D0            not     eax
  027001A7   /E9 A0661C00     jmp     028C684C
  028C684C    F7D8            neg     eax
  028C684E    81F0 260DE2BF   xor     eax, BFE20D26
  028C6854    2BC3            sub     eax, ebx
  028C6856    81E8 5676C0DF   sub     eax, DFC07656
  028C685C    F7D0            not     eax
  028C685E  ^ E9 F1BA53FF     jmp     01E02354
  01E02354    03D8            add     ebx, eax                    ;更新KEY
  01E02356    33D8            xor     ebx, eax                    ;更新KEY
  01E02358    81ED 04000000   sub     ebp, 4
  01E0235E    8985 00000000   mov     dword ptr [ebp], eax        ;保存结果
  01E02364    E9 12B16B00     jmp     024BD47B
  024BD47B   /E9 732B0700     jmp     <FetchCode>
  
  这条其实就是PUSH IMM32
  
  
  01C848B2    8B85 00000000   mov     eax, dword ptr [ebp]
  01C848B8    81C5 04000000   add     ebp, 4
  01C848BE    0F85 9E87A100   jnz     0269D062
  01C848C4    0F84 9887A100   je      0269D062
  0269D062    66:8B8D 0000000>mov     cx, word ptr [ebp]
  0269D069    81C5 02000000   add     ebp, 2
  0269D06F    66:8908         mov     word ptr [eax], cx
  0269D072  ^ E9 5187A4FF     jmp     020E57C8
  020E57C8   /E9 26A84400     jmp     <FetchCode>
  
  这条就是MOV [ADDR],IMM16
  

  其他的具体见附件
  我看了所有的DISPATCH_CODE,发现TTP的VM还是比较干净的,既没有FAKE CALL,也没有JCC和垃圾代码,有的只是两种变形后的JMP,一种是je/jne,jo/jno等等的成对出现,再就是
  形如call /pop reg/add [esp+2],imm/ret的形式,
  可能是DEMO的原因,我没有正式版,不知道正式版是什么样,可能正式版比这个要复杂。
  可以写程序恢复,注意寄存器的关系和堆栈的变化,恢复起来应该不难,只是工作量有点大。
  
  附件是整理的DISPATCH_CODE,生成的IDB较大,就不上传了,论坛上有主程序,可以对照这看,还有就是TTP的虚拟机地址是动态生成的,地址可能不一样,但代码是一样的。

上传的附件 TTPVM.rar