VM分析初探

来源:互联网 发布:mysql数据库无法写入 编辑:程序博客网 时间:2024/05/21 10:23
------------------------------------------------------ 
mov ecx,[da3c0c]  //通过基址取得虚函数地址 
mov edx,[ecx] 
push 3 
push 0 
call [edx+3c0] [49cca0] //开始调用被VM保护的虚函数 
 
------------------------------------------------------ 
 
49cca0:jmp 1116c8a  //当我们调用DLL里面的函数时都有这一步跳转这里很正常 
 
------------------------------------------------------ 
 
1116c8a:push ED21C7FA //用来计算数据存放地址的常数 
push ecx  //63A3800 
push edx  //B96EFC 
push ebx  //143 
push eax  //0 
push esi  //B 
pushfd 
push ebp  //12FD68 
push edi  //3F 
 
          //这些push保存了虚拟代码执行前的所有堆栈和EFLAG 
          //因为虚拟代码要做大量的堆栈及寄存器操作所以他先把 
          //原始环境先保存好等到虚拟代码执行完毕后再恢复寄存 
          //器和堆栈 这些代码也正预示着真正的VM已经开始了 
jmp 1127783 
 
------------------------------------------------------ 
 
1127783:mov eax,0  //寄存器赋值 
mov edi,fs:[18] //许多人也许对FS寄存器比较陌生这里我们附上一点说明 
                //FS寄存器指向当前活动线程的TEB结构(线程结构) 
                //偏移  说明 
                //000  指向SEH链指针 
                //004  线程堆栈顶部 
                //008  线程堆栈底部 
                //00C  SubSystemTib 
                //010  FiberData 
                //014  ArbitraryUserPointer 
                //018  FS段寄存器在内存中的镜像地址 
                //020  进程PID 
                //024  线程ID 
                //02C  指向线程局部存储指针 
                //030  PEB结构地址(进程结构) 
                //034  上个错误号 
                //关于TEB更多的资料大家可以去网上查找作为知识的拓展 
 
mov edi,[edi+8] 
mov [edi],eax  //上面从FS获得的地址原来是要向其中写入数据 
mov esi,[esp+20] //。。这个堆栈地址什么用途呢。。看下数值大家就开朗了 
                //[12fd34]=ED21C7FA 呵呵正是上面VM刚开始的时候压入的 
                //地址计算常量,之所以说他是计算地址用的常量到了后面 
                //才会得到验证 
rol esi,9 
add esi,BD81ACE6 
add esi,eax  //ED21C7FA这个数据到这里就利用完了,我们不管他是怎么计算的 
            //反正他是通过一堆运算最后存在ESI中了。 
lodsd eax    //lodsd这个指令是用来进行数据传送的,而且是双字传送 
 
 
              //我们通过罗云彬的一个字符串拷贝的小例子就可以理解他的功能及原理: 
              //entry: 
              //cld  //即告诉程序地址指针si,di向前移动 
              //  mov esi,offset source //将数据来源地址传给ESI 
              //  mov edi,offset dest //将数据拷贝目标地址传给EDI 
              //  mov cx,LENGTHOF source //计数器用来决定读取的次数 
              //StartRepeat: 
              //  lodsb //读取数据至EAX 
              //  stosb //保存EAX内的数据至目标地址 
              //  loop StartRepeat //循环至计数器CX规定的次数 
              //通过上面这个小例子我们就可以看出lodsd这个命令执行并不是 
              //孤立的 它需要事先给ESI 和 EDI赋值以确定到底要从哪里读取 
              //数据,并要写入到哪里。所以这句代码上面的所有对于寄存器 
              //ESI和EDI的操作是我们最为关心的 这就是为什么我将上面的 
              //1116c8a:push ED21C7FA 这一句注解成:用来计算数据存放地址的常数 
              //虽然这么简单的一句代码却需要ESI和EAX来配合,并且经过运算后 
              //会同时改变EAX和ESI的数值,EAX的数值变化是因为LODSD的数据拷贝 
              //而ESI则是系统自动改变的,这时他是数据地址指针,这点很重要 
 
 
add eax,[edi] 
add eax,181C25BC 
push eax //eax=113b71f 这一句和下面的ret配合精妙绝伦,我希望大家自己来理解 
        //这画龙点睛一笔 希望大家不要忽视这里 一定要把它看懂 
ret  //在这个小函数体内实际功能是2个,一个是给EAX和ESI EDI赋值,另外一个就是计算出 
    //CALL返回后要返回到哪里去,这3个赋值功能要到下面才可以知道是用来做什么的 
 
------------------------------------------------------ 
//如果上一个函数你理解的够深刻的话,那下面这个我们很快就能发现这个函数的功能 
//其实也是分2个部分,数据处理部分和返回地址(也就是跳转到下一指令的地址)计算部分 
 
113b71f:movzx eax,byte ptr[esi+4]  
pop [edi+eax*4]  //[3002c] 这里是将堆栈数据弹入地址3002c中 运算后 
                //[3002c]=3F 
lodsd eax 9F26D59B 
add esi,1 
add eax,[edi] 
add eax,31ECE184 
push eax //eax=113b71f 
ret 
 
------------------------------------------------------ 
 
分析过程至此结束,这只是VM的一小部分但是确实十分重要的一步,下面是总结: 
我们先来说下VM的大概流程: 
例如:add eax,1 
这一句的VM实现方法:push eax (将eax内的数据入栈)--》pop [寄存器映射地址] (将压入堆栈的寄存器
数值弹出到虚拟的EAX中) 
这并没有结束,后续步骤由于跟本章所讲内容无关所以不在这里给出。 
 
我们看到这样的处理步骤跟我们上面所分析的过程是一样的,其实上面的2个小函数实现的功能就是 
push edi  //3F 
pop [3002c] 
 
也就是将EDI的数值放入虚拟寄存器EDI的过程,所以3002c对应的也就是寄存器EDI 
 
VM本质上就是简单事情复杂做,一个寄存器操作要使用堆栈做中转存入虚拟寄存器,攻虚拟代码运行使
用,所以往往是大段代码分析完后只是一句简单的指令,所以许多人都把破解VM叫做体力劳动是有原因
的。 
 
本文结束,但是上面短短几段代码中的诸多玄妙希望大家都能一一掌握,分析中有的地方数据跨度很大需
要上下对比反复琢磨。我也会故意漏掉一些细节,当做给大家的课后作业,不自己动手分析是不能最终完
全理解这部分内容的,虽然我已经加了许多注视和讲解。 
刚刚接触VM,如果分析过程中有错误和偏差还希望路过的高手能给予指正。