首页
社区
课程
招聘
[原创]Code Virtualizer 1.3.8.0 小窥。
发表于: 2010-11-20 00:08 29751

[原创]Code Virtualizer 1.3.8.0 小窥。

2010-11-20 00:08
29751

似乎分析cv的东西不多,还好找到了Ryosuke兄弟的一个详细的分析,非常强大的。


http://bbs.pediy.com/showthread.php?t=62447&highlight=Virtualizer



1.3.8.0这版和Ryosuke分析的那版没有太多变化,vm_context中多了一个字段,增加到了0x48,其他的变化都不大,个别dispatch函数有些变化。选择不同的加密强度测试看,似乎在代码混淆方面并没明显加强,也许测试代码少的原因,分析的不到位。当时看的时候有些地方还没看懂,还是动手自己琢磨一下,顺便记录下的笔记,这个分析只是婴儿奶粉,不能补钙,高手略过吧。



    先把Code Virtualizer的虚拟机简单说一下,这里把我们自己的程序运行空间叫做宿主吧。cv虚拟机的所有运算的操作都在宿主的堆栈中完成。



    cv自己的存放宿主程序的寄存器及解析例程的结构叫vm_context,所有操作的都是由一个叫vm_data数据块来驱动的。这里面的数据会指示cv的虚拟机如何取指令计算出新的数据。



    程序运行进入cv虚拟机后,edi的值始终不变,一直指向vm_context(在Ryosuke的里面叫VM_BLOCK都是一个意思)的首地址。



    从偏移0 ~ 0x1c 存放的是宿主的寄存器,但每次都会变,这个是按某种顺序的变化的。


    


    esi指向vm_data结构,每执行一个dispatch,esi不断的增加。


    


    eax的用处就是从esi中读取数据,进行运算,获得解析例程的dispatch号码。或者是vm_context的某个相对偏移地址(cv里面为了操作某个结构)


    


    ebx就是参与计算用的,和vm_data中的数据运算,用来获得有效的eax


    


    edx是个临时的变量,cv在宿主堆栈的运算中,常用edx做临时变量来存放数据


    


    ebp,esp 基本没有太大用处,参与一些混淆代码的计算。


    


   struct vm_context


   {


  DWORD  vm_off_00;     +0


  DWORD  vm_off_04;     +4


  DWORD  vm_off_08;     +8


  DWORD  vm_off_0c;     +0c


  DWORD  vm_off_10;     +10


  DWORD  vm_off_14;     +14


  DWORD  vm_off_18;     +18


  DWORD  vm_off_1c;     +1c


  DWORD  vm_off_20;


  DWORD  VM_off_24;


  DWORD  VM_ecx_value;


  DWORD  VM_off_2c;  


  DWORD  VM_busy_flag;


  DWORD  VM_off_34;


  DWORD  VM_off_38;


  DWORD  VM_off_3c;


  DWORD  VM_off_40;


  DWORD  VM_off_44;


  DWORD  VM_off_48;


  DWORD  vm_context_xxx1;


  DWORD  VM_dispatch_xxx2;


  DWORD  VM_dispatch_xxx3;


  ...


   }


    


  下面就测试这么一个例子:


 


  .data 


  t_buff  db 100 dup(090h) 


  t_txt   db "test",0


  t_title db "codevirtualizer",0


  .code



  START:  


  


  mov     eax,offset t_buff


  


  call    VirtualizerStart    


  mov     dword ptr[eax],01234567h  ; 既然小窥,先只测试这一条语句吧,对cv的分析可以在里加入不同的语句一点一点分析    


  call    VirtualizerEnd


  


  invoke  MessageBox,0,offset t_txt,offset t_title,0


  invoke  ExitProcess,0



  end START


  


  分别在Protection Options中选择这两种个加一次



          Virtual Opcodes Obfuscation :Low ,Highest  


          Virtual Machine Complexity  :Low ,Highest 


          Opcodes Mutation            :Low ,Highest 


          


  分析后可以发现再混淆方面差别并不是太大。          



  进入VM之前先保存程序最初的环境



  EAX 00403000  


  ECX 0013FFB0


  EDX 7C92E514  


  EBX 7FFDE000


  ESP 0013FFC0


  EBP 0013FFF0


  ESI 00000068


  EDI 0013B790


  EIP 004034EC CV_TES~3.004034EC


   


  EFL 00000246 (NO,NB,E,BE,NS,PE,GE,LE)


 


  


  软后先压入VM_DATA


  00407083     68 1A704000        push CV_TES~3.0040701A  -----VM_DATA


  00407088   ^ E9 5FC4FFFF        jmp CV_TES~3.004034EC



  VM_DATA 内容每次加壳后都变化


  0040701A  3F 1E E1 D0 F8 5F A0 8F B7 A4 5B 4A 72 E4 1B 0A  ?嵝鴂爮筏[Jr?.


  0040702A  32 2A D5 C4 5F D9 C0 9C 63 52 7A DE 21 10 38 21  2*漳_倮渃Rz?8!


  0040703A  DE CD F5 65 9A 89 11 74 22 9F 40 20 7A DD 43 EF  尥鮡殙t"烜 z軨


  0040704A  45 05 C3 7B DD 74 54 43 A9 25 6B BD 85 1A EF 01  E脅輙TC?k絽?


  0040705A  00 00 00 FB 59 04 FB 59 C7 93 6C CA 38 21 DE 3C  ...鸜鸜菗l?!?


  0040706A  AA AE 51 AF 1D 3F C0 1E 8C D0 2F 8D FB 5B A4 02  Q???屝/嶜[?


  0040707A  70 EB 14 72 E0 77 88 E6 B8 68 1A 70 40 00 E9 5F  p?r鄔堟竓p@.開


  0040708A  C4 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00  ?.............



  通过重定位获得自身数据及处理例程的偏移,设置重定位标志,如果是dll还要重新定位。



  004034EF     E8 00000000        call CV_TES~3.004034F4   ; 重定位自身


  004034F4     5F                 pop edi


  004034F5     81EF F4344000      sub edi,CV_TES~3.004034F4


  004034FB     8BC7               mov eax,edi


  004034FD     81C7 00324000      add edi,offset  ;定位edi为vm_context 


  00403503     3B47 2C            cmp eax,dword ptr ds:[edi+2C]


  


  


  00403556     AC              lods byte ptr ds:[esi]  ;此处进入虚拟机,知道遇到vm_exit,才退出。


  00403557     04 81           add al,81


  00403559     04 90           add al,90


  0040355B     00D8            add al,bl


  0040355D     2C 90           sub al,90


  0040355F     E9 080A0000     jmp CV_TES~3.00403F6C


   


  1.3.8版的vm_dispatch



  00403200 >00000000


  00403204  00000000


  00403208  00000000


  0040320C  00000000


  00403210  00000000


  00403214  00000000


  00403218  00000000


  0040321C  00000000  ----->eflag 标志


  00403220  00000000


  00403224  00000000


  00403228  00000000


  0040322C  00000000


  00403230  00000000  ----->是否是忙的标志


  00403234  00000000


  00403238  00000000


  0040323C  00000000


  00403240  00000000


  00403244  00000000


  00403248  00000000 ------->相比前版本增加的字段


  0040324C  0040469C  CV_TES~3.0040469C  --- > 解析例程


  00403250  00403843  CV_TES~3.00403843  --- > 解析例程


  00403254  00403B82  CV_TES~3.00403B82  --- > 解析例程


  00403258  00403FE9  CV_TES~3.00403FE9  --- > 解析例程


  0040325C  00403608  CV_TES~3.00403608  --- > 解析例程


  00403260  004037E2  CV_TES~3.004037E2  --- > 解析例程


  00403264  00403723  CV_TES~3.00403723  --- > 解析例程


  00403268  004069F1  CV_TES~3.004069F1  --- > 解析例程


  0040326C  00406241  CV_TES~3.00406241  --- > 解析例程


  00403270  004064F3  CV_TES~3.004064F3  --- > 解析例程


  00403274  00405C54  CV_TES~3.00405C54  --- > 解析例程


  ...


  



  先开始分析进入虚拟机情况第一次情况:



  EAX 0000003F


  ECX 00000001


  EDX 7C92E514 ntdll.KiFastSystemCallRet


  EBX 0040701A CV_TES~3.0040701A           -----> vm_data[0] 数据


  ESP 0013FF9C


  EBP 0013FFF0


  ESI 0040701B CV_TES~3.0040701B           -----> vm_data[n+1] 以后esi依次递增


  EDI 00403200 offset 


  EIP 00403557 CV_TES~3.00403557


 


  EFL 00000246 (NO,NB,E,BE,NS,PE,GE,LE)


 


//进入运算前,就从VM_DATA中读取的al->0x3f  


//其实运算的内容都是为了混淆变乱而已,为了做到自动的去除这些指令,还得分析清楚这些内容



//跟踪的时候,盯住al寄存器,ebx 及堆栈数据的的变化就可以。


//al   - 计算得知最后的解析例程的索引值


//ebx  - 参与中间计算的用途,用来计算al时,所需要的值,每次都变化



//下面的代码是为了计算一个dispatch的索引,跟踪一遍明白原来后,其他的情况都类似



00403556     AC                 lods byte ptr ds:[esi]  --- 读取VM_DATA 中的数据,此时al->0x3f


00403557     04 81              add al,81


00403559     04 90              add al,90


0040355B     00D8               add al,bl


0040355D     2C 90              sub al,90


0040355F    /E9 080A0000        jmp CV_TES~3.00403F6C



eax --> 0xDA


//--------------------------------------



// 00403F6C


00403F6C     53                 push ebx                       ; CV_TES~3.0040701A


00403F6D     B7 57              mov bh,57


00403F6F     80EF D6            sub bh,0D6


00403F72     28F8               sub al,bh


00403F74     E9 4A230000        jmp CV_TES~3.004062C3



eax -> 0x59


//--------------------------------------



//004062C3


004062C3     5B                 pop ebx                        ; CV_TES~3.0040701A


004062C4     68 C5250000        push 25C5


004062C9     891C24             mov dword ptr ss:[esp],ebx     ; 这里注意堆栈中记录了vm_data位置,也就是ebx的值 


004062CC     B7 D2              mov bh,0D2                     ; 修改了ebx值


004062CE   ^ E9 97E8FFFF        jmp CV_TES~3.00404B6A



eax-> 0x59


esp-4 -> 0x40701A (vm_data offset)


 


// 继续跟踪



00404B6A     30F8               xor al,bh


00404B6C     8B1C24             mov ebx,dword ptr ss:[esp]  ; --> 又把ebx恢复了


00404B6F     81C4 04000000      add esp,4                   ; 恢复堆栈了,不再用[esp]保留,ebx值了。


00404B75     52                 push edx                    ; 又把edx压入堆栈保存起来,开始折腾edx值了


00404B76   ^ E9 06FDFFFF        jmp CV_TES~3.00404881


eax-> 0x8B


edx-> 7C92E514



//--------------------------------------


//00404881



00404881     B6 30              mov dh,30


00404883     80EE 70            sub dh,70


00404886     80C6 34            add dh,34


00404889     80EE 98            sub dh,98


0040488C     F6D6               not dh


0040488E   ^ E9 E5F2FFFF        jmp CV_TES~3.00403B78


// eax 不变, 


// edx -> 7C92A314


//--------------------------------------



//00403B78


00403B78     80F6 52            xor dh,52


00403B7B     2C 34              sub al,34


00403B7D     E9 E5130000        jmp CV_TES~3.00404F67



// eax->0x57


// edx->7C92F114



//--------------------------------------


//00404F67


00404F67     28F0               sub al,dh


00404F69     51                 push ecx             ; ecx 又压入栈中折腾去了


00404F6A     E9 390D0000        jmp CV_TES~3.00405CA8



// eax->66


// edx 不变


// ecx->0x01


//--------------------------------------


00405CA8     B1 12              mov cl,12


00405CAA     C0E1 05            shl cl,5


00405CAD     E9 210B0000        jmp CV_TES~3.004067D3



// eax 不变


// edx 不变


// ecx->40


//--------------------------------------


//004067D3 



004067D3     80C1 F4            add cl,0F4


004067D6     00C8               add al,cl


004067D8     59                 pop ecx


004067D9     5A                 pop edx


004067DA   ^ E9 B8FFFFFF        jmp CV_TES~3.00406797



// 堆栈已经被恢复


// eax -> 0x9A


// edx -> 变为最初值 0x7C92E514


// ecx -> 变为最初值 0x00000001



//--------------------------------------


// 修改ebx值 



//00406797


00406797     80C3 4C            add bl,4C


0040679A     80C3 BE            add bl,0BE


0040679D     00C3               add bl,al


0040679F     80EB BE            sub bl,0BE


004067A2   ^ E9 E8FFFFFF        jmp CV_TES~3.0040678F



// eax -> 0x9A


// ebx -> 00407000



//--------------------------------------


// 0040678F


0040678F     51                 push ecx


00406790     B5 CC              mov ch,0CC


00406792   ^ E9 F2DEFFFF        jmp CV_TES~3.00404689



// eax -> 0x9A


// ebx -> 00407000


// ecx -> 0000CC01



//--------------------------------------


00404689


00404689     D0ED               shr ch,1


0040468B     80E5 95            and ch,95


0040468E     80F5 48            xor ch,48


00404691     28EB               sub bl,ch


00404693     59                 pop ecx      ; 恢复了ecx为0x00000001


00404694     0FB6C0             movzx eax,al ; eax -> 0x0000009A


00404697   ^\FF2487             jmp dword ptr ds:[edi+eax*4]  ; 调向了真正的解析例程中



// ebx -> 0x004070b4



dword ptr ds:[edi+eax*4]  相当于


ds:[00403468]=00403FFE (CV_TES~3.00403FFE)



403468 是vm_dispatch的数据范围,里面存放的时候00403FFE解析例程


到此时我们已经知道,这一路跟踪下来的代码仅为了计算一个eax的值,用来定位解析例程的索引。



但al从0x3F如何变成0x9A 的?只要查看这一路跟下了起变化的过程即可。



al = vm_data[0 ~ n] + 0x81 + 0x90 + bl - 0x90 - 0x81 ^ 0xD2  - 0x34 - 0xF1  + 0x34 


al = vm_data[0 ~ n] + bl ^ 0xD2 - 0xF1 


al = (0x3f + 0x1a ) ^ 0xD2 - 0xF1


al = 0x9A



所以固定的计算就是 


index = (al + bl ) ^ 0xD2 - 0xF1 ;


同时更新ebx的值,


bl = bl + al



还是用这个程序加壳生成另外一个时,会发现和前面过程中执行的指令一摸一样,仅是利用大量的jmp打乱原有的指令


而已,也就是说指令的运算及执行条数是固定的,然后用jmp来打乱。只有设置不同的加密等级时才变得不一样。



x0:                                x0:


  xxx1                               xxx1


  xxx2                               xxx2


  xxx3            混乱为           jmp x1


jmp x1         --------------->         


 


x1:                                x1:


  xxx4                               xxx3


  xxx5                             jmp x2


  xxx6


jmp x2                             x2:


...                                  xxx4


                                     xxx5


                                     xxx6 


                                     jmp x3


                                     ...


                                     


// 继续看处理例程,还是那套路子,不过这次计算的al是用来获得vm_context中要操作的一个寄存器的索引标志


// 简化后 al = al - bl - 0x2b - 0x38 



00403FFE     AC                 lods byte ptr ds:[esi] ;取vm_data 下一个数据


00403FFF     2C 36              sub al,36


00404001     E9 F81A0000        jmp CV_TES~3.00405AFE



00405AFE     28D8               sub al,bl


00405B00     52                 push edx


00405B01     66:53              push bx


00405B03   ^ E9 71F9FFFF        jmp CV_TES~3.00405479



00405479     B7 AB              mov bh,0AB


0040547B     88FE               mov dh,bh


0040547D     66:5B              pop bx


0040547F     C0EE 06            shr dh,6


00405482     FEC6               inc dh


00405484     80F6 35            xor dh,35


00405487     00F0               add al,dh


00405489     E9 0B190000        jmp CV_TES~3.00406D99



00406D99     5A                 pop edx                                  


00406D9A   ^ E9 9CD0FFFF        jmp CV_TES~3.00403E3B



00403E3B     51                 push ecx


00403E3C     B5 C2              mov ch,0C2


00403E3E     F6DD               neg ch


00403E40     FECD               dec ch


00403E42     F6D5               not ch


00403E44     E9 8C0E0000        jmp CV_TES~3.00404CD5



00404CD5     80E5 6A            and ch,6A


00404CD8   ^ E9 47F0FFFF        jmp CV_TES~3.00403D24



00403D24     F6D5               not ch


00403D26     80C5 6E            add ch,6E


00403D29     28E8               sub al,ch


00403D2B     8B0C24             mov ecx,dword ptr ss:[esp]


00403D2E     83C4 04            add esp,4


00403D31     53                 push ebx


00403D32     B7 A7              mov bh,0A7


00403D34     50                 push eax


00403D35     B4 B3              mov ah,0B3


00403D37     80C4 26            add ah,26


00403D3A     80EC 91            sub ah,91


00403D3D     E9 3F1F0000        jmp CV_TES~3.00405C81



00405C81     80C7 D1            add bh,0D1


00405C84     28E7               sub bh,ah



[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (23)
雪    币: 2134
活跃值: (14)
能力值: (RANK:170 )
在线值:
发帖
回帖
粉丝
2
感谢neineit 如此细致的分析
2010-11-20 00:58
0
雪    币: 80
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
精华...
标记学习...
2010-11-20 02:29
0
雪    币: 1519
活跃值: (4662)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
4
精华之作,学习
2010-11-20 07:56
0
雪    币: 56043
活跃值: (21220)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
5
谢谢neineit!置顶两天鼓励。
2010-11-20 08:07
0
雪    币: 397
活跃值: (402)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
6
多谢Aker版主和老大的鼓励。
2010-11-20 09:16
0
雪    币: 560
活跃值: (248)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
精彩收了
2010-11-20 10:18
0
雪    币: 78
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
楼主真是太给力了
2010-11-20 10:23
0
雪    币: 7115
活跃值: (639)
能力值: (RANK:1290 )
在线值:
发帖
回帖
粉丝
9
太给力了。。。 顶礼膜拜。。
2010-11-20 13:13
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
实在不知道那里给力了,所以唯有傻傻的顶一下
2010-11-20 15:38
0
雪    币: 251
活跃值: (77)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
11
紧随yingyue兄的脚步过来。继续傻傻的顶一下

借贵宝地发个消息。
79119478[MaTrix]
聊天吹牛的QQ群。喜欢侃大山的速度来参加~\(≧▽≦)/~啦啦啦。。。。
2010-11-20 16:15
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
12
现在越来越多的vm了,跟不上形势了
2010-11-20 23:17
0
雪    币: 1925
活跃值: (906)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
13
好东西,学习了
2010-11-21 14:30
0
雪    币: 6797
活跃值: (4450)
能力值: (RANK:600 )
在线值:
发帖
回帖
粉丝
14
good job, 收藏学习!
2010-11-21 17:42
0
雪    币: 248
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
我这菜的连鸟都不算的只能望着天书兴叹了...
2010-11-22 00:20
0
雪    币: 1126
活跃值: (156)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
16
我要完整工具代码和工具,呵呵。把RISC模式的搞一下吧。
2010-11-22 15:53
0
雪    币: 397
活跃值: (402)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
17
唉,RISC搞不定不行啊。D哥,你给我的CodeExpand还没搞定呢,这玩意太累人了。
2010-11-22 22:57
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
mark```
2010-11-23 09:41
0
雪    币: 347
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
感谢分享,学习
2010-11-23 10:51
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
学习中 。。。
阔别已久了咛
2010-11-23 17:59
0
雪    币: 148
活跃值: (140)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
神器..都已经出世了..坐等final版本
2010-11-24 22:52
0
雪    币: 75
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
真的是好东西,学习啦
2010-11-26 00:39
0
雪    币: 205
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
不错,希望以后更多CV的资料
2010-11-26 13:08
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
不错,学习了
2010-12-26 03:18
0
游客
登录 | 注册 方可回帖
返回