Day9:壳与脱壳(一)

壳、壳的加载过程、工具脱壳、手动脱壳流程、esp定律(基于Xdbg)

  • 先看ctf-wiki对壳的介绍:

    是在一些计算机软件里一段专门负责保护软件不被非法修改或反编译的程序。

    它们一般都是先于程序运行,拿到控制权,然后完成它们保护软件的任务。

  • 因此,加壳程序包含壳程序和原程序两个部分,且原程序在壳程序运行后才恢复到独立可执行的状态。因此,可以借助动态调试器在壳程序运行完后进行dump,从而获得独立可执行的原程序

  • 常见的壳有压缩壳和加密壳两种:

    压缩壳:upx、ASpack、PECompat等

    加密壳:VMProtect、Themida、ASProtector等

壳的加载过程

  • 壳和原程序在逻辑上基本没有关联,因此,壳程序在解析加壳后的二进制文件前,会先保存各寄存器的值,通常用pushad/puahfd实现
  • 解析完成后,是原程序的逻辑部分,此时,壳程序给出控制权,寄存器恢复到解析前的状态,通常用popad/popfd实现
  • 最后,程序跳到原程序入口点开始执行

工具脱壳

  • 直接使用工具脱壳的情况主要有两种:一种是无修改的、只使用加壳程序加壳;另一种是使用加壳程序加壳后修改了区块名的。前者可以直接使用加壳程序脱壳(如果具备脱壳功能的话),后者先修改区块名再使用加壳程序脱壳。

  • upx无修改加壳示例:

    拿到可执行文件,先到DIE查看,发现有壳。对壳的信息描述没有出现“modified”字眼,因此判断是无修改加壳,直接使用工具脱壳

    查看壳信息

    直接使用upx -d脱壳

    upx-d脱壳

    再次用DIE打开,发现没有识别出壳了

    脱壳后查看壳信息

  • upx修改区块名加壳示例:

    先到DIE查看壳信息,发现是upx modified

    查看壳信息

    点击“区块“下方的”>“查看区块信息,发现区块名有改动

    区块名改动

    010editor修改区块名

    修改区块名

    再次查看壳信息,变成无修改加壳了,直接工具脱壳

    再次查看壳信息

手动脱壳流程

  • 步骤:

    • 查壳:使用DIE、ExeinfoPE、PEiD等工具查壳
    • 寻找程序原入口点(OEP):通过各种方法找到壳代码结束、程序真正开始的地方
    • dump内存:借助插件从OEP开始dump出原程序
    • 输入表(IAT)重建:借助插件重建输入表
    • 关闭程序重定位:使用DIE等工具关闭程序重定位
  • 寻找OEP的方法有很多,而dump和IAT重建以及关闭重定位的方法基本固定。先用一个例子展示整体流程,再详细展开寻找OEP的方法。upx手动脱壳示例:

    • 查壳:显示是upx

      查壳

    • 寻找OEP:

      采用esp定律法(详见下文)找到push ebp开头的一段代码

      寻找OEP

    • dump内存:

      打开插件scylla,点击“转储”栏中的“转储”,会获得一个_dump后缀的exe文件

      dump

    • IAT重建:

      点击“IAT自动搜索”,会有弹窗问是否使用高级搜索结果,点“是”。这时候,VA和“大小”两个框会被填充。

      IAT自动搜索

      接下来点“获取导入”,上方的大框中会出现dll结尾的东西,需要把带红色X的取消勾选

      获取导入

      然后点击修复转储,选择刚刚dump出来的文件,会得到一个再加上_SCY的exe文件。

      此时程序大概率运行不了,会闪退。但是对于静态分析来说,到这一步已经足够了。

    • 关闭重定位:把得到的_dump_SCY.exe文件拖到DIE,点击“区块”栏的“>”,会弹出文件结构界面

      文件结构界面

      先取消勾选右上角的“只读”

      取消只读

      点击IMAGE_NT_HEADERS下的IMAGE_FILE_HEADER,在“标志”选项中勾选“RELOCS_STRIPPED”(图中未勾选)

      勾选RELOCS_STRIPPED

      再点击IMAGE_OPTIONAL_HEADERS,找到另一个标志(DllCharacteristics),取消勾选“DYNAMIC_BASE”(图中未取消)

      取消勾选DYNAMIC_BASE

      这样子,我们的程序就脱完壳并且可以正常运行了

    • PS:关于IAT重建这一步骤,为什么不能IAT自动搜索再转储一步到位?

      结合AI的解释,个人见解是IAT自动搜索的过程可能会运行程序,导致地址刷新,OEP失效,dump出来的程序不完整或者不对。因此,dump和IAT重建实际上是两个步骤,不过被集成到了一个界面。其实还有手动重建IAT的方法,这种情况下就确确实实需要先dump再导入重建的IAT了,因为在调试器中找到OEP后还要继续找IAT

寻找OEP的方法(一)

ESP定律

  • 前文,我们知道了壳程序解析时会有pushad\popad或者pushfd\popfd的操作。pushad时,随着通用寄存器值的入栈,esp的值会发生变化,又因为栈平衡的特性,最终esp的值会回到pushad后的这个值。因此,可以借助这一点,给pushad后的esp值下硬件访问断点,popad后就会触发断点,中断调试,进而实现跳过整个壳解析过程。当然,中断处还不是OEP,一般在中断处后会有一个跨度明显的jmp,甚至jmp后还有一个跳转表jmp才会到达真正的OEP

  • 具体操作如下:

    • xdbg打开,F9到程序所在内存区域

      xdbg打开

    • 可以看到EIP所在就是pushad

      pushad

    • F8步过,esp更新

      esp更新

    • 在右下角栈窗口设上硬件访问断点

      设置硬件访问断点

    • 点击工具栏“视图”下方的“->”,程序会执行过popad。可以看到下方不远处有个大跳

      popad

    • F8到大跳处F7步入,有跳转表继续F7步入,可以看到开辟栈帧操作,这里就是OEP了,在此处直接使用scylla dump出程序

      OEP

单步跟踪法

作者

SydzI

发布于

2025-07-29

更新于

2025-10-03

许可协议

评论