【文章标题】: 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的虚拟机地址是动态生成的,地址可能不一样,但代码是一样的。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!