逆向学习1-[脱壳技术]/篇1

壳是包裹在程序外的一层代码,通常先于程序执行,达到防止源程序不被非法修改或反编译的目的

壳的分类

壳分为压缩壳和加密壳

压缩壳

压缩壳主要是帮助减少PE文件(Windows下的文件格式)大小,隐藏PE文件内部的代码和资源

常见的压缩壳有:Upx、ASpack、PECompat

加密壳

加密壳应用有多种防止代码逆向分析的技术 ,用该壳的PE文件会比原文件大很多,有时恶意程序也用加密壳来降低杀毒软件的扫描

常见的加密壳有:ASProtector、Armadillo、EXECryptor、Themida、VMProtect

壳加载过程

1. 保存入口参数

壳初始化时会保存各寄存器的值,运行结束后由恢复这些值,最后返回原程序执行

通常用 pushad / popadpushfd / popfd 指令对来保存和恢复现场环境

2.获取所需函数API

先要大概知道什么是输入表,简单来说它是壳程序与DLL文件(动态链接库)交流的中枢

一般壳的输入表中只有 GetProcAddressGetModuleHandle 和 LoadLibrary 这几个 API 函数,若需要调用DLL文件中的其他API函数代码,需要通过 

  1. LoadLibraryA(W) 或 LoadLibraryExA(W) 将 DLL 文件映射到内存中,就可以
  2. 调用 GetModuleHandleA(W) 函数获得 DLL 模块句柄,一旦 DLL 模块被加载,就可以
  3. 调用 GetProcAddress 函数获取输入函数的地址

3.解密各区块数据

壳一般会按区块加密以保护源程序,源程序执行时又按区块解密,以让程序正常运行

4.跳转回原程序入口

壳一般会构造自己的输入表(IAT),所以跳回前会先回复之前PE文件的输入表,处理好重定向项(主要是 DLL 文件),之后会将控制权移交原程序执行。

脱壳方法

1、单步跟踪法

我们完整运行脱壳程序,跳过循环恢复代码的片段,边调试边观察,确保程序不会略过EOP,让软件实现自动脱壳

要点:

  • 跟踪过程是不修改任何代码
  • 使用F7[单步步入]、F8[单步步过]、F4[直接执行到指定位置]等功能完整的进行自脱壳的过程
  • 大循环用f4跳过,尽量实现向下jmp
  • 函数载入不远处的call一般选择f7步入
  • 一般如果jmp到很远的地址,那极有可能就是跳到原程序入口(EOP)

示例

程序2:easyre.exe   提取码:cscj

加壳软件:upx加壳工具

这里使用的是x32进行调试的,建议还是使用OD调试,否则程序入口代码前还会有很多其他的代码

进去x32调试要加载ntdll,一直f8后到达壳程序,pushad就是一个壳程序开始的标志

这个壳一直f8,遇到循环选择下一个地址f4直接跳过即可

但到下面这个循环(415861)时,不能直接选择415867进行f4,否则程序会直接显示输出input the flag的字符串,程序无法再向下调试。跳过415861的方法之一就是在如图两个地址上下断点,直接f9运行,就会直接停到415867的位置

 我们就能继续往下运行,popad就是要脱壳完成的标志

看到有一个跳转到很远的地方,应该就是OEP了

跳转过去就是没加壳程序刚进入的程序入口

 

2、ESP定律法

原理是运用程序中的堆栈平衡来实现。

大多壳开始会使用pushad来保存寄存器,在pushad保存好寄存器后,对esp下硬件断点,之后直接f9运行,就会到达最后的popad,硬件断点就会触发。就我的理解是:也就是一开始(pushad)栈指针指向一个位置,但最后(popad)esp还是会回到一开始栈指针指向的地方,所以开始给esp的地址下断点,最后还是会恢复到这个地址,恢复到这个地址时,硬件断点就会触发。

硬件断点与软件断点的区别:

硬件断点由调试寄存器的值来控制,它是看地址来下断点和判断与触发断点的,而软件断点是看指令根据指令来下断点和判断断点来触发的

要点:

  • 程序开始pushad/pushfd
  • 在pushad/pushfd压栈后设置ESP硬件断点
  • F9运行
  • 删除断点后即可分析

示例

还是用上一个程序做演示

这里使用x32dbg作为调试器,使用吾爱破解的时候没有找到下ESP断点的地方

使用x32dbg时,程序刚载入是这样的

直接按F9,就会跳到pushad的地方,先F8一下执行pushad保存寄存器

然后在右边显示寄存器框里的黑色区域右键——>设置硬件断点于ESP,然后F9运行

然后就运行到了popad的后面了,之后就单步几下就跳到原程序入口了

3、一步到达OEP法

找到离OEP或大jmp近的popad,下int3断点,然后直接运行到断点处实现脱壳

要点

  • ctrl+f查找popad
  • ctrl+l跳到下一匹配处,选择确认正确的popad位置,下断点运行到该处
  • 只适用于极少数壳

示例

继续使用之前的程序例子

程序开始ctrl+f,查找,然后ctrl+l,会搜到多个popad,向下看是否有大jmp或OEP

 正确的popad,后面有大jmp

4、 内存镜像法

暂没有找到合适的实例程序资源,但先记录一下,经检测这个方法一般用于ASPack壳加密

原理

在程序自解压或解密时会先访问程序资源段,自动脱壳后转回程序代码段,所以我们现在程序资源段下一个断点,运行完后又在代码段下一个断点运行

要点

  • 菜单的选项—>调试选项—>异常—>勾选所有的忽略异常
  • alt+m打开内存镜像,找到程序的第一个.rsrc,F2下断点,shift+f9运行到断点
  • alt+m在第一个.rsrc上面的.text地址F2下断点,然后shift+f9

5、最后一次异常法

原理

程序自解压或自解密过程可能会触发很多异常,最后一次异常是很接近自动脱壳完成的地方,所以我们可以想办法给最后一个异常处下断点

要点

  • Ollydbg 选项—>调试异常—>异常,将所有✔消掉,ctrl+f2重新加载程序
  • 开始程序是一个跳转,按shift+f9,直到程序运行,要记录按shift+f9的次数m
  • ctrl+f2重新加载程序,按m-1次shift+f9,OD右下角的框里会看到"SE句柄",ctrl+g,输入SE句柄前的地址
  • 在地址上按f2下断点,shift+f9来到断点,f8跟踪

6、SFX法

Ollydbg自带的OEP寻找功能,找到后直接停在OEP处

要点

  • OD异常选项卡都打上勾
  • 同一框内的SFX选项卡选择 "字节模式跟踪实际入口 (速度非常慢)"
  • 重新加载程序(如果跳出是否 "压缩代码?" 选择 "否", OD 直接到达 OEP)

Dump及IAT重建

在脱壳找到OEP后,我们需要将程序dump出来,并重建IAT

示例

还是用之前的easyre.exe程序

我们到达大jmp处后跳转到OEP地址0040DE05,然后右键->用OllyDump脱壳调试进程(LoadPE也可dump出来)

 有一个框,查看入口点地址是否正确,取消勾选重建输入表

点击脱壳,保存为一个新程序,我们这里命名为dump1.exe

点击程序无法正常运行,如果OEP找对,放到IDA确实可以正常反编译,那么就是IAT出现了问题,需要重建IAT

这里使用ImportREC工具来修复输入表

打开 ImportREC 工具,选择一个正在运行的程序,即上面在调试中的 easyre.exe,所以Ollydbg dump后不要关闭这个进程。因为这个工具需要入口点,0040DE05,基址为400000,那么在下方的OEP处输入0000DE05,然后点击自动搜索

 点击确定后,点击获取导入表

然后点击修复转储,选择刚刚dump出来的dump1.exe程序,可能会报一个问题,但不用管,当前目录下会有一个dump_.exe程序,运行正常

手动查找IAT并使用ImportREC重建

示例

依然用easyre.exe

依然调试到OEP处,右键-查找-所有模块间的调用

随意双击一个程序的函数(非系统函数),来到函数调用处,右键,点击跟随,进入函数,再右键,数据窗口中跟随-内存地址(如果没有显示内存地址,那么可能程序函数选错了,重选一下就行),到左下方的框中,如果全是16进制就右键,长型-地址

在框中向上找IAT表的起始位置,选中所有,从IAT起始到IAT结束,这里是0040F000开始,下方显示块大小为0x14c

 结束位置

 打开 ImportREC ,选择进程,并在下面三个框中输入对应已知的的上面三个信息,分别是OEP、IAT起始位置以及IAT的块大小

 然后点击获取导入表,在导入表函数框中右键,高级命令,选择代码区段

 跳出一个框,点击完整转储,保存dump出的程序,这里命名dump.exe

之后点击修复转储,选择上面dump出来的dump.exe文件,就会显示保存了一个dump_.exe文件,运行正常

DLL文件脱壳

DLL 文件脱壳 - CTF Wiki (ctf-wiki.org)

参考链接:

https://ctf-wiki.org/reverse/windows

逆向脱壳-压缩壳脱壳单步跟踪方法_GTZ_Crow的博客-CSDN博客

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值