快捷搜索:

您的位置:澳门新葡4473网站 > 热门贴子 > [转] 菜鸟手脱VMP,附上脱壳过程和自己写的脚本

[转] 菜鸟手脱VMP,附上脱壳过程和自己写的脚本

发布时间:2019-10-11 01:30编辑:热门贴子浏览(149)

    • 在分析/逆向 程序时,如果事先知道这类程序的一些特征,那将会是事半功倍的;
    • 分析/逆向 程序,和写程序不同,比喻的话:写程序像在作案,分析/逆向 程序就像是在破案,对破案来讲,重在假想和推理;

    转载:

    特征1:VC链接器版本

    工作需要要脱一个VMP壳,我是一个从来没接触过脱壳的人。瞬间那种心情遇到的人应该都知道!没办法硬着头皮找教程,7天看完了 《天草的壳的世界》尝试脱壳下面是我的脱壳过程希望大牛多多指正!
    1、准备工具,FEID(查壳工具)、DIE(查壳工具)、LordPE(dump工具)、ImpRec(IAT修复工具)、UIF(IAT修复工具)、CFF(文件优化工具)、OD(吾爱破解专版 调试工具)
    2、查壳 PEID
    图片 1 
    区段显示是vmp1,看来是VMP壳编写语言还是不能确定上DIE
    图片 2 
    显示编程语言是VC++的,VMP壳
    3、开OD准备脱壳、OD设置如下
    图片 3

    VS版本 链接器版本
    VS2017 14.12
    VS2015 14.0, 14.1
    VS2013 12.0
    VS2012 11.0
    VS2010 10.0
    VS2008 9.0
    VS2005 8.0
    VC2003 7.0, 7.1
    VC6/VB6/E语言 6.0
    VC5/BC++ 5.0
    Delphi 2.25
    VB5

    4.20

     图片 4

     

    图片 5 
    打开进程到入口看下
    图片 6 
    4、跑OEP
    啥也卡不懂,不过没关系知道是VMP壳就好办,直接CTRL+G  输入 VirtualProtect 下断 如下图(如果提示未知,先在内存窗口找到 kernel32.dll代码段 进去后在转到就到了)
    图片 7 
    F9跑起来,这是会段下
    图片 8 
    注意NewProtect 这项 等于 PAGE_READONLY 是停下,否则一直F9 按慢点别跑飞了
    图片 9 
    到0401000处看看,代码是否已经解码
    图片 10 
    已经解码, 搜索特征码 EB0B85F375078BC6C1E0100BF0
    图片 11 
    这是OEP第一个CALL的尾部,根据他找到OEP 
    图片 12 
    OEP 就是 00a6f7c8,不过这才是第一步 这时候DUMP 是没用的 因为VMP加密了IAT 我们需要还原他
    5、还原IAT
    随便找一个IAT调用函数跟一下,刚好OEP下面就有两个 FF25 型的IAT 调用,跟进去看下
    图片 13 
    还是啥都看不懂,不过没关系 既然是调用IAT函数,肯定会在某一时刻调到真实函数地址去的 继续跟下面把整个跟的流程贴上来
    图片 14 
    图片 15 
    图片 16 
    图片 17 
    图片 18 
    这是整个流程的实际执行的代码 ,现在分析下
    01059D91    53              push ebx                     保护环境
    01059D92    66:0FB6DB       movzx bx,bl          垃圾代码
    01059D96    66:BB 5D55      mov bx,0x555D   垃圾代码
    01059D9A    BB 5AC27200     mov ebx,0072C25A   这才是最终对EBX操作所以上面两条都是没用的代码
    00F3BBFF    8B9B 25697400   mov ebx,dword ptr ds:[ebx+0x746925]    计算地址
    01196B98    8D9B 5071F632   lea ebx,dword ptr ds:[ebx+0x32F67150]  计算地址
    00EA9FC2    871C24          xchg dword ptr ss:[esp],ebx   和栈顶交换,并还原EBX的原始值
    00F9FC9D    C2 0400         retn 0x4                  还原EBX 并返回函数
    这时候看下堆栈 栈顶出现真实函数的地址
    <ignore_js_op>图片 19 
    00F9FC9D    C2 0400         retn 0x4       分析下这条指令的执行流程,先EIP=栈顶的值 也就是真实函数地址,栈顶+4+4 懂汇编的人就会发现,栈顶+8的位置保存是当前CALL的返回地址 那执行了这条指令后返回地址不是没有了么?因为这个IAT调用 没加密前是 FF25型的 也就是 jmp [????????] 所以不需要返回地址 ,而调用这个IAT的时候 是有一个CALL的进CALL的时候就会PUSH返回地址到堆栈,所以这个IAT处理的很巧妙!执行完真实函数后直接就返回到调用IATCALL的下面继续执行了。
    看图片发现 这个CALL 下面有一条 RETN指令 看来这条 是VMP加上去的了,但是不要忽略了这条指令 因为这条指令很重要,VMP在获取 IAT地址的最后RETN的地址 会随机JMP到代码他添加的RETN 上,并不完全是在壳段 所以这个RETN 要留到最后处理。
    再找一个FF25 型的IAT调用看看
    图片 20 
    跟进去看下,下面是执行流程代码
    00FB7DC7    90              nop
    00FB7DC8    0FB7D6          movzx edx,si        垃圾代码
    00FB7DCB    66:0FBED1       movsx dx,cl       垃圾代码
    00FB7DCF    5A              pop edx                   出栈                
    00FB7DD0    871424          xchg dword ptr ss:[esp],edx           交换栈顶的值,还原 EDX原始值
    00FB7DD3    52              push edx                              保护环境
    00FB7DD4    66:0FBED1       movsx dx,cl     垃圾
    00FB7DD8    0FB7D6          movzx edx,si      垃圾
    00FB7DDB    BA B7757D00     mov edx,007D75B7     计算地址
    010DFDAD    8B92 3D036900   mov edx,dword ptr ds:[edx+0x69033D]    计算地址
    0102B837    8D92 B52FE512   lea edx,dword ptr ds:[edx+0x12E52FB5]     计算地址
    00EACB30    871424          xchg dword ptr ss:[esp],edx   函数真实地址给栈顶 并还原环境          
    0115D36E    C2 0400         retn 0x4 
    这个FF25 CALL 的第四行 有个POP  edx 而进这个CALL之前  有一个push edx ,可以看出 这个push edx 也是垃圾代码是 VMP自己添加上去的,看来VMP 会随机在上下 填充一个字节,在上面就是 PUSH 一个寄存器,在下面就是 retn
    找一个 FF15型的CALL看看
    图片 21 
    跟进去看下流程
    010B27B9    BE B34E6E0B     mov esi,0xB6E4EB3    垃圾代码
    00EFFC5B    5E              pop esi               出栈
    00EEB9B0    873424          xchg dword ptr ss:[esp],esi    交换栈顶的值,还原 ESI原始值
    00F437BB    56              push esi   保存环境
    00F8D827    BE 4B084800     mov esi,0048084B    计算地址
    00FA55B3    8BB6 C005B900   mov esi,dword ptr ds:[esi+0xB905C0]  计算地址
    010E8053    8DB6 3F68AD31   lea esi,dword ptr ds:[esi+0x31AD683F] 计算地址
    00F44191    873424          xchg dword ptr ss:[esp],esi   真实函数地址给栈顶,还原环境
    0057A761    C3              retn 
    第二行 pop esi  看来这个CALL 的push esi 是垃圾指令了,但是 发现这个 是retn 为什么不是,retn 04 呢?因为这个是 FF15 型调用,也就是 call [????????]  需要执行完后返回到call 下面继续执行
    再找一个FF15型调用看看
    图片 22 
    跟进去看下流程
    00E77D14    90              nop
    00E77D15    51              push ecx            保存环境              
    00E77D16    66:F7D1         not cx           垃圾代码
    00E77D19    8B4C24 04       mov ecx,dword ptr ss:[esp+0x4]    栈顶+4(调用CALL的返回地址)给ECX,
    00FB7CFF    8D49 01         lea ecx,dword ptr ds:[ecx+0x1]   取 返回地址+1的值 给ECX
    01013FB5    894C24 04       mov dword ptr ss:[esp+0x4],ecx  重新写入到返回处
    01013FB9    B9 A1598A00     mov ecx,008A59A1 计算地址
    010566B2    8B89 94C36C00   mov ecx,dword ptr ds:[ecx+0x6CC394] 计算地址
    00E95200    8D89 19378077   lea ecx,dword ptr ds:[ecx+0x77803719] 计算地址
    00FEA363    870C24          xchg dword ptr ss:[esp],ecx  真实函数地址给栈顶,还原环境       
    010ABADE    C3              retn
    这个 有点不一样啊,很简单 看调用CALL 的下面有一个 RETN啊,这要是正常返回 程序还不得跑飞啊,VMP巧妙的利用 4 5 6三行代码 就搞定了,这写壳的人真是脑洞大开啊!
    所有的IAT加密就这样完了吗??? NO  还有更脑洞大开的 往下看
    图片 23 
    跟进去看看
    0119D768    90              nop
    0106B2C9    872C24          xchg dword ptr ss:[esp],ebp           交换栈顶的值,还原栈顶
    00F3E26F    55              push ebp                              保存返回地址
    00F3E270    F7D5            not ebp                               垃圾代码
    00F3E272    50              push eax                              保存环境
    00F3E273    B8 D41D4300     mov eax,00431DD4  计算地址
    00F3E278    66:8BEB         mov bp,bx  垃圾代码
    00F3E27B    8B80 41F7BE00   mov eax,dword ptr ds:[eax+0xBEF741]  计算地址
    00F3E281    66:0F4FE8       cmovg bp,ax  垃圾代码
    00F3E285    66:8BE8         mov bp,ax   垃圾代码
    00F3E288    8D80 903F170C   lea eax,dword ptr ds:[eax+0xC173F90]  计算地址
    00F3E28E    0FB7E8          movzx ebp,ax 垃圾代码
    00F3E291    8BE8            mov ebp,eax     真实函数地址给 EBP
    00F3E293    58              pop eax   还原 寄存器
    011B5D71    C3              retn
    这是在干啥呢?? 咋把真实函数地址 给了 EBP呢? 看调用处的下面 有一个 call ebp 明白了吧 这是把   mov xx,[????????]  整成了一个CALL哦,再来看下堆栈 调用处pop  EBP , CALL内 第2行 有把栈顶的值还原了,然后把函数的返回地址重新PUSH进去,这里处理的很巧妙,所有 调用处的 pop ebp也是垃圾指令,这就完了???NO还有往下看
    图片 24 
    跟进去看下
    00E97E5D    90              nop
    00E97E5E    0FBFDB          movsx ebx,bx  垃圾代码
    010C1083    50              push eax                    保存环境     
    010C1084    8B4424 04       mov eax,dword ptr ss:[esp+0x4]      获取当前CALL的返回地址给EAX
    00E2EB3F    8D40 01         lea eax,dword ptr ds:[eax+0x1]   获取当前CALL返回地址+1给EAX
    00E2EB42    0F45DB          cmovne ebx,ebx    垃圾代码
    00E2EB45    66:0FB6DB       movzx bx,bl  垃圾代码
    00E2EB49    894424 04       mov dword ptr ss:[esp+0x4],eax  保存返回地址
    00E2EB4D    B8 012C4300     mov eax,00432C01 计算地址
    00E2EB52    66:0FBEDB       movsx bx,bl 垃圾代码
    00E2EB56    66:8BDF         mov bx,di 垃圾代码
    01170378    8B80 F58CC000   mov eax,dword ptr ds:[eax+0xC08CF5] 计算地址
    0117037E    0FB7DC          movzx ebx,sp 垃圾代码
    01170381    0F41DE          cmovno ebx,esi      垃圾代码
    01170384    F6D7            not bh 垃圾代码
    01170386    8D80 145A2C32   lea eax,dword ptr ds:[eax+0x322C5A14] 计算地址
    0117038C    B3 85           mov bl,0x85 垃圾代码
    0117038E    8ADE            mov bl,dh 垃圾代码
    01170390    8BD8            mov ebx,eax   真实函数地址给 EBX              
    01170392    0FBFC2          movsx eax,dx 垃圾代码
    01170395    C6C4 E2         mov ah,0xE2 垃圾代码
    01170398    0FC8            bswap eax             垃圾代码            
    0117039A    58              pop eax      还原环境                    
    0117039B    C3              retn
    认真看 了上面的部分,这里不难理解了吧, 4 5 8行处理调用处的 下面 retn 的,函数是获取 EBX的调用值的

     

    一共6种 IAT相关的处理,所以我是 一边写脚本一边骂写 VMP壳的人,要不要这么坑啊,我要的脱的程序特别大 跑一遍要 1个小时,我也不记得我跑了多少遍了!哎!说来都是泪,新手就是这样啊!不多说了下面贴上脚本!需要的自己去下!

     

    6、用UIf 修复IAT 
    7、用lodepe dump
    8、用imprec 修复IAT
    9、用cff 去掉壳段
    至此VMP脱壳完成!

     

     

     

     

     

     

     

     

     

     

     

    特征2:OEP

    a0) VB5:

    【VB5】的OEP平衡堆栈是 sub esp,0x54

    【VB5】的OEP第一个API调用是GetStartupInfoA

    【VB5】程序的IAT引用,都是FF15型的

    图片 25

    图片 26

    a1) VB6

    【VB6】的OEP平衡堆栈是 sub esp,0x4C

    【VB6】的OEP第一个API调用是GetStartupInfoA

    【VB6】程序的IAT引用,都是FF15型的

     图片 27

    图片 28

    b0) Delphi

    【Delphi】OEP上面是一个地址
    【Delphi】OEP处 有5个CALL
    【Delphi】OEP 5个CALL之后,全是0
    【Delphi】OEP处第一个CALL有GetModuleHandleA调用
    【Delphi】的IAT调用是 FF25形式的

    图片 29

    图片 30

    b1) BC++

    【BC++】 二进制特征:EB1066623A432B2B484F4F4B90
    【BC++】 OEP的第一个API调用是 GetModuleHandleA
    【BC++】 IAT调用是 FF25形式的

    图片 31

    c) VC6/E语言(通过分析,发现二者特征一致,可以判定E语言和VC6如出一辙)

    【VC6】的OEP平衡堆栈是 sub esp,0x58 或 sub esp,0x68或add esp, -0x5C

    【VC6】的OEP第一个API调用是GetVersion

    【VC6】程序的IAT引用,都是FF15型的

    图片 32

    d) VS2013

    【VS2013】开始处,call xxx; jmp xxx;
    【VS2013】的OEP平衡堆栈是sub esp, 0x44
    【VS2013】的OEP第一个API调用是GetStartupInfoW
    【VS2013】程序的IAT引用,都是FF15型的

    图片 33

    图片 34

    图片 35

     

    这些特征,会对分析程序起到一定的帮助作用,这里,并没有完全列出全部的主流程序,希望抛砖引玉吧;

    本文由澳门新葡4473网站发布于热门贴子,转载请注明出处:[转] 菜鸟手脱VMP,附上脱壳过程和自己写的脚本

    关键词: