zjlsjz 发表于 2010-8-14 19:11

学习继续和谐VMP2.0X~

我们主要来看看IAT是如何修复的,首先看看修复的脚本.
   以下代码引用自Vmprotect 2.0x Unpacker脚本
首先看看视频里的那5个变量mov first,0044CA98
mov write,004B5B72
mov getapi,004B372E
mov begin,0012F7FC
mov end,0012FB98
first : 是OEP,在这个脚本里OEP就是代表一个出口,代表在VM里执行解码IAT的函数已经执行完了.
   write :004B5B72   8910             MOV DWORD PTR DS:,EDX
这个其实是VMP的一个数据输出指令,相当于汇编里的mov dword ptr ds:,reg32
   IAT是一组全局变量,而这个指令就是负责写入全局变量的.我们可以知道最终函数保存的地址,视频里下的写入断点就是为了快速地定位这条输出指令,这种方法在其它虚拟机里应该也是通用的.
   在VM里追踪数据,hook住数据的输入和输出指令是很常见的方法,以我个人的理解,这个和hook函数的思想是一样的.
   hook住这个指令后,可以得到些什么东西呢,答案就是函数的地址和key,在虚拟机里,数据的流动是很频繁的,那么如何确定是输出到IAT呢,就要靠下面的几个变量了.
   
   getapi :004B372E   36:8B00          MOV EAX,DWORD PTR SS:
这个又是什么东东呢,看到这个指令使用SS前缀想到了吧,没错,这个就是VMP里的堆栈输入指令,这里可以把它看成汇编的mov reg32,dword ptr ss:,这条指令用来读取局部变量.
   在我上次的扫盲贴里已经说过了,VMP使用了随机指令表,每次的handle和指令的关系都是不一样的,因此每次分析时都需要修正指令表,而在视频里并没有分析指令表,而是直接定位指令,定位这个指令
的过程非常有趣,我们来看一下定位的过程.
   通常的情况下,解码IAT都是在一个循环里进行的,"读取key-->解密-->填充IAT"这样的流程,通过内存断点,我们找到了循环的尾部填充部分,只要不是最后一个函数,那么就会在下一轮再次命中输出断
点的,视频里的run trace就是追踪了一个循环的过程.因为这个循环解密了一个函数,所以必定要通过输入指令来读取key,在追踪的数据中查找输入指令的特征码就可以定位到指令了.
   
   光hook住输入指令和输出指令还不够,这两个指令会很频繁地调用,因此还要去除垃圾数据,用什么方法来去除垃圾数据呢,就靠下面的那两个变量了.
   begin和end光看名字就知道是IAT数据的界限了,VM掉的函数应该是VMP对IAT进行二次加密的函数,这时真正的数据是通过堆栈来传递的,用的是局部变量的数组,如何准确地查找这个表估计就只有凭经
验了.
   好了,修正完这些变量后,我们来看看脚本是如何工作的,脚本前面的部分是用来获取当前环境各段的基址和大小,用处在后面可以看到.
   接下来断VirtualProtect跳过解码.sub end,4
bphws end,"w"
esto
bphwc
bphws first
add end,4
在指令表尾部下一个写入断点,跳过解码过程,直接到二次加密.loopfix:
eval "eax>{begin}&&eax<{end}"
bpcnd getapi, $RESULT                //筛选无效的数据,只要不是引用指令表的数据都跳过
esto
cmp eip,first                                 //停下来的地方是OEP,解码过程已经结束了
je exit
bc eip
sti
mov rapi,eax
gn eax                                       //获取地址所对应的函数名
mov dllname,$RESULT_1
mov apiname,$RESULT_2
bp write                                       //断输出指令,记录加密后的地址
esto
cmp eip,first
je exit
bc eip                                          //取消输出断点,因为其他的指令也会调用输出指令,这里不取消的话就有可能杯具了
mov addr,eax                           //记录IAT的地址
mov dword,rapi
sub dword,edx                        //整个脚本最重要的地方,先记下来吧
wrta logfile,addr
wrta logfile,","
wrta logfile,dword
wrta logfile,","
wrta logfile,dllname
wrta logfile,","
wrta logfile,apiname
wrta logfile,"\r\n"
jmp loopfix
好了,脚本到这里就完了,下面我们来看生成的LOG文件
LOG文件的开头这样的B               //段数,这里估计是用来确定IAT数据的起始
401000            //下面的都是基址和大小,估计是用来进行重定位,这里是带基址的 ,loader检查PE头??
4BAE0
44D000
1124
44F000
BD9
450000
1F2A
452000
10
453000
18
454000
5520
45A000
5400
460000
7190
468000
4DDBB
4B6000
5254
下面就是与IAT相关的数据了,这里举一个函数为例子,来理解戏法是怎么变的~
   和视频里一样,这里用的是456ED4,8ED28660,kernel32,GetModuleHandleA
456ED4是程序存放key的地址,8ED28660是脚本上面用sub计算出来的值,kernel32是DLL文件名,GetModuleHandleA是函数名.
   456ED4是需要重定位的,如果程序不是载入到00400000,那么就会出错,上面的那些数据估计就是用来对这个地址进行重定位了.

   其它都很好理解,关键就是8ED28660这个数值,要明白这个数值,首先要搞明白VMP的二次加密对函数地址做了些什么东西,和视频里一样,我们来看看关键的几条指令.00466171    BD 92E94300   MOV
EBP,delphi7?0043E992
00466180    8BAD 42850100   MOV EBP,DWORD PTR SS:
00462BE1    8DAD 6086D28E   LEA EBP,DWORD PTR SS:
关键就这三条指令,0043E992+18542=456ED4,就是存放key的地址,看到了吗"8ED28660"这个就是脚本保存的数值,VMP对IAT的二次加密就是减去一个随机数,因为这些代码是分散在程序里,因此脚本直接模
拟这个减法运算,计算出这个随机值.接下来就是对函数进行重定位了,这个就是loader的作用了,loader可以通过GetProcAddress获得当前函数的地址,而随机数8ED28660加上456ED4保存的EDAE3041就可以
得到dump时的函数地址,然后用地址差值来修正456ED4保存的数据就可以了,如果你开始不明白的话,参考一下经典的自定位.      call @f
      @@:
      pop reg32
      sub reg32,@b

yegeziz 发表于 2010-8-14 19:22

研究是好习惯

Zanker 发表于 2010-8-14 19:22

汗...
高手 啊....

qq460218711 发表于 2010-8-14 19:22

······我想UXP1···

ldw471427015 发表于 2010-8-14 19:22

看不懂.....

三月初七 发表于 2010-8-14 19:28

膜拜~

牛人、

zjlsjz 发表于 2010-8-14 19:32

转载的-.-

fnx5 发表于 2010-8-14 19:44

进来学习下

zxc7754480 发表于 2010-8-14 21:38

来学习一下~~

chinamail 发表于 2010-8-19 08:46

谢谢分享,,,我昨天刚刚看了那录象,这些还真是我不懂的
页: [1] 2
查看完整版本: 学习继续和谐VMP2.0X~