• 探讨VMP 2.12.3 导入表修复


    壳版本: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的帮助。独学而无友,则孤陋而寡闻。

    怎么上传附件啊我擦

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

  • 相关阅读:
    python 函数
    谷歌浏览器安装POSTMAN
    Django提示Unknown database处理方法
    Django 连接Mysql异常处理
    Django输入 中文参数保存异常解决方法
    vscode过滤pyc文件
    Jenkins启动和停止服务
    执行robot framework 的测试用例 命令行pybot使用方式
    Jenkins定时任务
    Jenkins构建Python项目失败
  • 原文地址:https://www.cnblogs.com/MrWrong/p/3640369.html
Copyright © 2020-2023  润新知