壳版本:VMProtect.Ultimate.2.12.3

样本:notepad.exe

目的:IAT修复

作者:MrWrong

标题:探讨VMP 2.12.3 导入表修复

只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

由于仅是对VMP壳的导入表加密进行较为肤浅地探讨,所以对样本notepad的加VMP壳时,资源保护并未选择,也并未对OEP进行偷取或对其VM(虚拟化)。

一般加密壳都是将对调用导入表中系统函数的FF25型、FF15型、MOV reg, [iat_addr]型指令转换成call addr_in_shell_section(目标地址在壳区段的call)。这些call所做的工作是通过加壳时保存的数据信息,“绕着弯儿”执行原指令。VMP也不例外,只是它不拘一格,形式多变,难以修复。

修复导入表是实现脱壳文件可跨平台运行的关键,大致过程如下:

1、OD加载并执行到OEP后,保存环境。

2、在代码段搜索call addr_in_vmp_section,直到搜索完整个待修复区域,跳到4。

3、修复找到的位置,回到1。

4、上UIF。

5、上ImportREC。

6、上LoadPE删除VMP0和VMP1两个区段,并重建PE。

过程3是关键:

在找到的位置新建eip并记录此地址为S,F7(步入)跟踪执行直到如下指令对出现:

push dword ptr[esp+param1]

retn param2

在"retn param2"处停下,并记录:

A=[esp];

B=[esp+param1+8];

C=[esp+4];

D=param2-param1;

此后分几种情况分析:

第一种情况: FF25(call dword ptr[iataddr])的变形

如果A是一个系统函数地址,并有(D==4)&&(B==(S+6)||B==(S+5))为真

则此E8的call是变形自FF25形式的call。

此时修复为:

*(byte*)(B-6)=0x90;

*(byte*)(B-5)=0xE8;

*(dword*)(B-4)=A-B;

第二种情况 FF15(jmp dword ptr[iataddr])的变形

如果A是一个系统函数地址,并有(D==8)&&(B==(S+6)||B==(S+5))为真

则此E8的call是变形自FF15形式的jmp dword prt[iataddr]。

此时修复为:

*(byte*)(B-6)=0x90;

*(byte*)(B-5)=0xE9;

*(dword*)(B-4)=A-B;

第三种情况 mov e??, dword ptr[iataddr]的变形

A不是一个系统函数地址,并有(D==4)&&(A==(S+6)||A==(S+5))为真

则此时有一下几种情况需要判断,这是由于被变形前字节数的原因。

因为 "mov eax, dword ptr[iataddr]"是5个字节(A1+iataddress)

而其他的都是六字节,如:

mov ebx, dword ptr[iataddr] (8B1D+iataddress)

mov ecx, dword ptr[iataddr] (8B0D+iataddress)

mov edx, dword ptr[iataddr] (8B15+iataddress)

mov esi, dword ptr[iataddr] (8B35+iataddress)

mov edi, dword ptr[iataddr] (8B3D+iataddress)

确定为第三种情况后,则先记录下"call addr_in_shell_section"处的寄存器环境,

在"retn param2"处对各个寄存器进行对比,哪个更改了,要修复的目标函数地址就在哪个寄存器里。

5字节的情况直接修复成:mov eax, iataddress

6字节的情况修复成: mov e??, iataddress + (nop)

目前由于本实例只看到6字节的情况,所以本条规则还不完全,暂定于此。

另外一个值得重视的情形是:

mov ebx, dword ptr[iataddr] (8B1D+iataddress)

mov ecx, dword ptr[iataddr] (8B0D+iataddress)

mov edx, dword ptr[iataddr] (8B15+iataddress)

mov esi, dword ptr[iataddr] (8B35+iataddress)

mov edi, dword ptr[iataddr] (8B3D+iataddress)

这5种6字节情况都有可能被修改成

push e??

call addr_in_shell_section

指令对的形式。

这中情况下,对比寄存器是否改变的方式就会有不足之处:因为call  addr_in_shell_section里面的代码会在"retn param2"之前已经将push e??的值从堆栈中取出并赋给了e??,而之前保存的寄存器环境是在call addr_in_shell_section指令处。这会导致对比e??的环境也发生了改变,而e??并不是我们所要寻找的目标。

这种情况可以在对比寄存器的时候,若发现有两个寄存器值不相同,则去取push e??这条指令,把e??排除。

我相信这些壳方面的技术早早地已经掌握在大牛们的手里了,只是最近壳的人气日衰,很少有人发表相关技术。可能还有诸多情况,鄙人水平有限,错误在所难免,修复的脚本在别的系统跑起来好像会存在一点点问题,好在自己的win7 64位系统是跑过了。仅是抛个砖,不足之处还请诸位大侠赐教。

最后特别感谢好朋友KeyKernel的帮助。独学而无友,则孤陋而寡闻。

怎么上传附件啊我擦

http://files.cnblogs.com/MrWrong/vmp2.12.3_iat_fix.zip

探讨VMP 2.12.3 导入表修复的更多相关文章

  1. VMProtect修复导入表的插件

    壳版本:VMProtect.Ultimate.2.12.3 样本:TKLobby.exe 目的:IAT修复 作者:MrWrong 标题:VMProtect修复导入表的插件 只是感兴趣,没有其他目的.失 ...

  2. C/C++ 手工实现IAT导入表注入劫持

    DLL注入有多种方式,今天介绍的这一种注入方式是通过修改导入表,增加一项导入DLL以及导入函数,我们知道当程序在被运行起来之前,其导入表中的导入DLL与导入函数会被递归读取加载到目标空间中,我们向导入 ...

  3. 利用PE数据目录的导入表获取函数名及其地址

    PE文件是以64字节的DOS文件头开始的(IMAGE_DOS_HEADER),接着是一段小DOS程序,然后是248字节的 NT文件头(IMAGE_NT_HEADERS),NT的文件头位置由IMAGE_ ...

  4. IDA分析脱壳后丢失导入表的PE

    1. 问题 一些程序经过脱壳后(如用OD的dump插件),一些导入表信息丢失了,导致拖入IDA后看不到API的信息(如右图所示,第一个红圈处实际是GetCurrentProcessId),给分析造成极 ...

  5. PE知识复习之PE的绑定导入表

    PE知识复习之PE的绑定导入表 一丶简介 根据前几讲,我们已经熟悉了导入表结构.但是如果大家尝试过打印导入表的结构. INT IAT的时候. 会出现问题. PE在加载前 INT IAT表都指向一个名称 ...

  6. Oracle导出表数据与导入表数据dmp,以及导入导出时候常见错误

    使用DOS 操作界面导出表数据,导入表数据(需要在数据库所在的服务器上边执行) exp UserName/Password@192.168.0.141/orcl   file=d:\xtables.d ...

  7. impdp导入表不创建segments

    一.文档说明 1.0 需求:需要将生产环境PICC用户导出,在测试环境中docker 测试数据库导入,只需要表结构: 2.0 思路:根据开发人员提供的需求,数据库源端aix 11.2.0.4, 目标端 ...

  8. C/C++ 导入表与IAT内存修正

    本章教程中,使用的工具是上次制作的PE结构解析器,如果还不会使用请先看前一篇文章中对该工具的介绍,本章节内容主要复习导入表结构的基础知识点,并通过前面编写的一些小案例,实现对内存的转储与导入表的脱壳修 ...

  9. 手动添加导入表修改EXE功能

    目标: 改动PE导入表,手工给HelloWorld增加一个功能,就是启动的时候写入一条开机启动项,C:\cmd0000000000000000000000000000.exe 实现方法: 直接在注册相 ...

随机推荐

  1. C语言中for循环的使用

    for循环的作用: 注意:要主要满足条件一和二后是先执行语句,后再执行条件三. 简单重复的输出 for(int i=0:i<10;i++){ printf("对一句话简单重复输出输出1 ...

  2. HDOJ 2200 Eddy's AC难题(数学组合概率题)

    Problem Description Eddy是个ACMer,他不仅喜欢做ACM题,而且对于Ranklist中每个人的ac数量也有一定的研究,他在无聊时经常在纸上把Ranklist上每个人的ac题目 ...

  3. java中的Package语句和import语句

    在实际项目中会有成百上千个类,我们把近似的类放在同一个包里面,比如把实体类放在实体类包里面   package 为解决类的 命名冲突问题而引入的机制. package语句作为Java源文件的第一条语句 ...

  4. requirejs2读书笔记

    If you want to do require() calls in the HTML page, then it is best to not use data-main. data-main ...

  5. JS~js里实现队列与堆栈

    在面向对象的程序设计里,一般都提供了实现队列(queue)和堆栈(stack)的方法,而对于JS来说,我们可以实现数组的相关操作,来实现队列和堆栈的功能,看下面的相关介绍. 一 看一下它们的性质,这种 ...

  6. SKNode类

    继承自 UIResponder:NSObject 符合 NSCodingNSCopyingNSObject(NSObject) 框架  /System/Library/Frameworks/Sprit ...

  7. HDU1247 Hat’s Words 【trie树】

    Hat's Words Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tota ...

  8. Creating a Swap Partition

    Creating a Swap Partition 1.   Use  fdisk /dev/vda  to open your disk in fdisk. (Use gdisk if you ar ...

  9. Linq使用GroupBy筛选数据

    StringBuilder sb = new StringBuilder(); List<IGrouping<string, modle>> listRepeat = mode ...

  10. char * 和 void *

    POSIX.1 将 read函数的原型做了修改,经典的定义为 int read(int filedes, char *buf, unsigned nbytes); 修改为 ssize_t read(i ...