现在的技术更新换代真是快哦,好多壳都还没有脱成功,就出现VM了.本来还不打算接触VM的,  但是被某某鄙视不动手的懒人,所以今天就动手给他瞧瞧.不过话说回来,我确实有点懒,因为我把大部分时间都花在泡MM,游戏,跟发呆上(我经常发呆冥想自己中了大奖,有个美女跟我搭讪什么的),做今天这样的事情完全是凭心血来潮.
 
看了些讨论虚拟机的帖子,“每个虚拟机都有自己的CONTEXT”,“会在伪指令中修改EIP”
我纳闷了好久,按我目前的理解,我就知道有一个SetThreadContext可以修改CONTEXT结构,但是用OD打开VM过的程序,楞是没看到呀??

入口参数:
00401166 > $  68 514E4000   push    00404E51                        //压入PCODE首地址
0040116B   .- E9 4F3A0000   jmp     00404BBF

VM初始化:
00404BBF    9C              pushfd                                    //压入32位的EFLAGS
00404BC0    60              pushad                                   //压入eax,ecx,edx,ebx,esp,ebp,esi,edi
00404BC1    68 00000000     push    0                                //我把他看作压入一个DWORD变量
00404BC6    8B7424 28       mov     esi, dword ptr [esp+28]          //[esp+28]=00404E51            
00404BCA    BF 00404000     mov     edi, 00404000                    //edi=CONTEXT结构 
00404BCF    FC              cld
00404BD0    89F3            mov     ebx, esi
00404BD2    033424          add     esi, dword ptr [esp]            

00000000(变量) |
edi            |
esi            | ⌒
ebp            | 堆
esp            | 栈
ebx            | ↓
edx            |
ecx            |
eax            |
flags          |
00404e51       |

 mov     edi, 00404000 
对比了一些帖子,我也敢说00404000指向CONTEXT结构,刚开始的时候我觉得这个地址就是VMP区段的开头,没什么特别的。
CTRL+G到00404000看看:
00404000    F5                cmc
00404001    808B 1C99DCE8 E2  or      byte ptr [ebx+E8DC991C], 0E2
00404008    94                xchg    eax, esp
00404009    3386 C61FD899     xor     eax, dword ptr [esi+99D81FC6]
0040400F    8136 24CFFA5B     xor     dword ptr [esi], 5BFACF24
00404015    7E 68             jle     short 0040407F
00404017    48                dec     eax
00404018    2B8C14 DDA08B9B   sub     ecx, dword ptr [esp+edx+9B8BA0DD]
0040401F    6E                outs    dx, byte ptr es:[edi]
00404020    F605 6B6A8A6E 80  test    byte ptr [6E8A6A6B], 80
00404027    3246 52           xor     al, byte ptr [esi+52]
0040402A    4D                dec     ebp
0040402B    55                push    ebp
0040402C    55                push    ebp
0040402D    1D 94803BB9       sbb     eax, B93B8094
00404032    5D                pop     ebp
00404033    F693 7570A7FE     not     byte ptr [ebx+FEA77075]
00404039    F5                cmc
0040403A    04 4E             add     al, 4E
0040403C    2130              and     dword ptr [eax], esi
0040403E    8C2459            mov     word ptr [ecx+ebx*2], fs 
00404041    0F23C1            mov     dr0, ecx                          //这里看起来想一个伪指令的开始呢
00404044    E9 8C0B0000       jmp     00404BD5

那么00404000--00404041之间的就是CONTEXT结构,才41h大小呀??远远比一个完整的CONTEXT结构要小很多呢!!
现在按我的理解这个CONTEXT结构指向的是一个内存地址,不是真实的寄存器。既然是内存的一块,要么是作者定义的一个对象,要么是申请的一块内存,
这里更象前者。那这样看来,论坛里讨论虚拟机帖子里给出的那些CONTEXT结构中的EAX,EDX,EIP,EFLAGS都不是真实的寄存器,只是一个变量,一个符号而已!?

接下来我也来到了VM指令解释器:
VM指令解释器:
00404BD5    8A0E            mov     cl, byte ptr [esi]
00404BD7    00D9            add     cl, bl
00404BD9    FEC1            inc     cl
00404BDB    F6D1            not     cl
00404BDD    80E9 47         sub     cl, 47                          //对esi做一系列变换
00404BE0    C0C1 07         rol     cl, 7
00404BE3    46              inc     esi                             //esi++
00404BE4    80F1 C5         xor     cl, 0C5
00404BE7    80E9 CD         sub     cl, 0CD
00404BEA    C0C1 05         rol     cl, 5
00404BED    00CB            add     bl, cl
00404BEF    0FB6C1          movzx   eax, cl                        //eax在这里作为指针
00404BF2    8D1485 48424000 lea     edx, dword ptr [eax*4+404248]  //00404248就是那张大的表的起始地址
00404BF9    FF22            jmp     dword ptr [edx]                //jmp VM_Op_Code

ESI指向PCODE,地址位于VMP区段,这些PCODE是怎么来的呢?有没有什么规律?我现在也不清楚,但是对比了一下程序,我至少知道了它不是从原始程序中来的,
是作者自己安排的。原来的代码还好好的在那躺着呢!(刚开始的时候我认为虚拟机是把原始代指令化后保存在文件中,执行的时候再把这些指令还原,并跑到“虚拟机”中执行指令)
----“上面就是VM的主循环.”

~!#¥%¥%
前面突然停电了,来电后我用VMP再一次VM了程序,原来的就被覆盖掉了,真不好意思,下面的是新的程序,所以地址跟某些代码有些变化,但大致结构还是差不多的。VMP我还不大会用,每次加的程序运行总会弹出个非法对话框。
接下来这段代码执行了很多次了,就是把堆栈顶端的数据弹到[EDI+EAX*4]这个地址中去。今天我突然觉得这段代码应该是设置CONTEXT结构的,原来我以为这里也是一个伪指令。
00404076    AC              lods    byte ptr [esi]
00404077    00D8            add     al, bl
00404079    34 F9           xor     al, 0F9
0040407B    2C 70           sub     al, 70
0040407D    C0C0 05         rol     al, 5
00404080    2C 0C           sub     al, 0C
00404082    C0C0 06         rol     al, 6
00404085    00C3            add     bl, al
00404087    8F0487          pop     dword ptr [edi+eax*4]
0040408A  ^ E9 87FFFFFF     jmp     00404016
EDI指向CONTEXT结构的呢,eax做为指针。代码把0,edi,esi,ebp---eflags弹到了CONTEXT结构这个地址,这样就设置了一个CONTEXT结构。例如把EAX弹到了XXXX这个地址,就可以把这个地址看成是EAX,应该是这样吧。

接下来应该是执行伪指令了吧????我见大虾们都给它们起了一个很好听的名字.
004045B5    58              pop     eax                              
004045B6  ^ E9 5BFAFFFF     jmp     00404016
把这里命名为p_popeax怎么样???
004042E3    AC              lods    byte ptr [esi]
004042E4    00D8            add     al, bl
004042E6    34 F9           xor     al, 0F9
004042E8    2C 70           sub     al, 70
004042EA    C0C0 05         rol     al, 5
004042ED    2C 0C           sub     al, 0C
004042EF    C0C0 06         rol     al, 6
004042F2    00C3            add     bl, al
004042F4    FF3487          push    dword ptr [edi+eax*4]
004042F7  ^ E9 1AFDFFFF     jmp     00404016

00404228    AD              lods    dword ptr [esi]
00404229    01D8            add     eax, ebx
0040422B    05 972C1742     add     eax, 42172C97
00404230    35 C476D6BE     xor     eax, BED676C4
00404235    05 43E5412D     add     eax, 2D41E543
0040423A    C1C0 10         rol     eax, 10
0040423D    01C3            add     ebx, eax
0040423F    50              push    eax
00404240  ^ E9 D1FDFFFF     jmp     00404016

跟到这里就懒的跟下去拉。。。。如果说上面的都是伪指令,却没有看到修改EIP的,我只看到了VM解释器里的inc esi(有些是lods byte ptr [esi]).
意思是说我只看到程序在跑自己的PCODE,跑完了就到原始的程序接着跑,当然我可没有跟到原始程序,我心疼我的F7跟F8。

目前我对虚拟机的理解就到这里了,也不知道对不对。
前些天我问了一个外星人:
“我觉得VM过的程序只是多了一个VMP区段,把这个区段删掉,再修复PE头里的section,sizeofimage,不就可以了吗?”
“还要修复VM!”
“什么是修复VM呀?”
“就是还原成80X86指令!”
听到这样的答复我立即跑了,太深奥了嘛~!
今天我又拿程序出来对比了下,发现除了多出这个VMP区段以外,还有有一处不一样:

原始程序的:
00401166 >/$  E8 1EFFFFFF   call    00401089
0040116B  |.  6A 00         push    0                                ; /ExitCode = 0
0040116D  \.  E8 5A000000   call    <jmp.&kernel32.ExitProcess>      ; \ExitProcess
00401172   $- FF25 48204000 jmp     dword ptr [<&user32.BeginPaint>] ;  user32.BeginPaint

VM过的:
00401166 > $  68 514E4000   push    00404E51                        //压入PCODE首地址
0040116B   .- E9 4F3A0000   jmp     00404BBF

我这里只有一处不一样,我不知道VM过的程序是否有多处,我把原始程序的二进制代码替换掉VM过的,保存后不要VMP区段也可以运行。难道这样就是修复VM??
如果是的话那可就麻烦大了,如何得知原来的代码是什么呢,CTRL+B搜索不到,疑惑中。。。。。

总结一下今天的理解:
①:VM里有自己的context结构,按我的理解我没有把这个结构与真实的context结构联系起来
②:pcode是作者自己定义的,目前我还没有发现这些pcode跟伪指令有什么联系
③:程序在跑自己的pcode,似乎什么都没有做!
                                                                                                      2008-2-29 下午 1:32:06
                                                                                                                      小娃崽