壳的作用:

  • 加密:ASProtect、Armadillo(穿山甲)、EXECryptor、Themida、VMProtect
  • 压缩:ASPack(win32)、UPX、PECompact

    OEP:Original Entry Point

  • 原始程序入口点

    壳的装载过程

  • 获取壳自己所需要使用的API地址

  • 解压、解密原程序的各个区块
  • 进行必要重定位
  • 跳转到OEP,交还控制权

    压缩引擎

  • aPLib

  • JCALG1
  • LZMA

    简单脱壳1

  • 单步走,跳到OEP时没有正确分析为代码:右键->分析->分析代码

  • 接着用脱壳插件OllyDump,

image.png

  • 把壳删除,减少空间。使用LoadPE,和OD的M地址对应,点击section,右键wipe,save->ok->rebuild pe

简单脱壳2:根据堆栈平衡原理寻找OEP(tuts4you-lena15 UnPackMe_EZIP1.0.exe)

  • OD载入程序,发现很多跳转,如果跟随进去长得都像OEP的形式,但是要注意M窗口代码段的地址

image.png

  • 发现这个跳转在壳的代码段

image.png

  • 根据堆栈平衡原理寻找OEP,关注ESP的值,跳转到壳的代码后,单步运行,只要ESP的值改变(第一次变化就动手),就在它对应的内存处下硬件断点

image.png
image.png
image.png

  • F9运行,断下到 jmp ax,这通常是跳转到OEP的特征,这里eax=e4271B0,在主程序的代码段,寻找正确

image.png
image.png

  • 删除硬件断点(在查看的地方删除),在OEP处右键使用OllyDump,保存
    • image.png

image.png

  • 使用LordPE(PETools)修复,把壳的section删除后体积变大了,因为原壳是压缩壳

image.png
image.png

  • 分析壳的压缩过程(在jmp eax向上分析)

    简单脱壳3:根据堆栈平衡原理寻找OEP(UnPackMe_eXPressor1.3.0.1Pk.exe)

  • eXPressor 1.3.0 -> CGSoftLabs壳
  • OD打开,M窗口查看section分布,发现壳和原程序代码段混在一起,当OEP在401000~46A000时说明找到了,离开了壳的区域。

image.png

  • 单步执行,当esp改变时在对应内存区域下硬件断点,F9执行,断在OEP处

image.png

  • ollyDump转储,脱壳成功(因为选择了重建输入表,新程序中增加了.idata段)

image.png
image.png

简单脱壳4:根据堆栈平衡原理寻找OEP(UnPackMe_eXPressor1.3.0.1Pk.exe)

  • MEW 11 1.2 -> NorthFox/HCC壳(压缩壳)
  • 方法一:堆栈平衡
  • 方法二(MEW系列通用)
    • 起始在entrypoint先jmp

image.png

  • 在jmp到的地址向下寻找到retn,下断点,F9运行。断下后F7到OEP。

image.png

  • ollydump重建导入表,转存

脱壳5:代码段下断点寻找OEP(UnPackMe_NoNamePacker.d.out.exe)

  • PEID查壳,未找到信息

image.png

  • 程序具备反调试(win API),单步跟踪找到或者右键查找所有模块名称

image.png

  • 在API函数处下断点,F9运行

image.png

  • 在API地址处按ALT+F9到了调用它的程序领域中的下一条指令,查看这里eax的值,这是

isDebugPresent函数的返回值,在这个je处控制跳转(1or1=1,0or0=0),改成jmp去掉调试器检测。
image.pngimage.png

  • 接着开始寻找OEP,在.text段下断点,运行

image.png

  • 断下的位置仍不在.text段,只是访问到了代码段

image.png

  • 跳过loopd后,继续在.text处下断点,断到新的位置,发现还是对代码段的访问

image.png

  • 多次观察循环,找到循环末端,反复下断,找到.text内的地址。Crtl+F8(自动步过)跟踪执行,F12暂停,遇到循环手动略过。直到遇到一个持续循环,F4走到retn后,在再M窗口的.text出下断点,F9运行,断在了OEP。

image.png
image.png

  • ollydump转存,.Prt节可以删掉

重建输入表

  • 输入表:IAT(import address table)
    • 记录应用程序需要调用的API函数在动态链接库里的具体地址,由windows加载器加载可执行程序的时候填充
    • 如何填充
      • IMAGE_IMPORT_DESCRIPTOR -> INT -> IMAGE_IMPORT_BY_NAME
  • IAT是如何被填充和工作的(举例)

    • 调用Messagebox函数

      image.png
      image.png
      image.png

  • 打开M窗口,双击PE头,关注imagebase(基址:0x400000)和import address table(IAT的RVA:0x402050)

image.png
image.png

  • 查看IAT地址处(crtl+g跳到0x402050),使用analysethis插件分析该地址处汇编
    • 有两个输入表,一个给kernel32,一个给user32

image.png

  • 0x402098为IMAGE_IMPORT_DESCRIPTOR中的第0项OriginalFirstThunk的偏移地址,再找到INT,进而找到API name

image.png
image.png
image.png

  • 回到IMAGE_IMPORT_DESCRIPTOR(0x402050)处,第五项为FirstThunk,指向IAT的偏移地址。跳到0x40200c,是dll中API加载的地址。最后将上面得到的名字和该地址挂钩。

image.png
image.png
image.png

HOOK API

  • 壳模拟加载器加载原程序,因此加壳后的IAT是壳用hook API技术替换后的地址(间接调用)

image.png

FSG压缩壳和ImportREC工具(修复IAT)的使用

  • FSG压缩壳入口点典型形式:xchg

image.png
image.png

  • 复杂:F8单步,遇到向上的跳转直接F4跳过
  • 新方式(自解压): 选项->调试选项 ->SFX->字节方式跟随真正入口,重新载入程序,停在OEP。 image.png
  • FSG壳会对IAT进行破坏,使用OllyDump时先不用重建导入表
  • 使用importREC修复IAT(RVA中填充的一定是包含数据区所有内容,不能只有名字),size要覆盖这一块所有内容,大点没关系

image.png
image.png
image.png
image.png

  • 点击获取输入表,发现很多Invalid,点击显示无效函数(FSG壳捣鬼,加载器加载时会报错,地址不合法
  • )。把不合法的都删掉,点击修复转存文件。

image.png
image.png

  • 成功脱壳并能正确执行,因为修复了很多空白的地方,脱壳后体积增大

image.pngimage.png
image.png

UPX和WinUpack压缩壳的使用和脱法

  • UPX
    • 使用文件为,查壳

image.png

  • 堆栈平衡脱壳,ollydump,不重建IAT
  • ImportREC修复
    • WinUpack
  • 堆栈平衡脱壳,ollydump,不重建IAT
  • ImportREC修复

常见的恶意代码加壳特征

  • 程序中导入函数很少,导入函数仅有LoadLibrary和GetProcAddress时,应该引起特别注意
  • 当时用OllyDbg打开程序时,会有程序可能被加壳的警告
  • 程序的节名中包含某款加壳器的标识
  • 程序拥有不正常的节大小,例如.text节的原始数据大小为0,但虚拟大小非零

常见壳

  • 压缩壳
    • UPX
    • ASPack
    • PECompact
    • FSG
  • 加密壳
    • Themida
    • ASProtect:压缩、加密、反跟踪代码、反-反汇编代码、CRC校验和花指令等
    • VMProtect:难破解,影响速度

内存dump

  • 如果不能自动脱壳,则另一种较好的策略是使用ProcDump工具从内存中转储不在进行调试的进程。ProcDump是微软提供的一个工具,用来转储一个Windows进程的内容。设计他的目的是与调试器一起工作,但是它本身不是调试器。ProcDump的最大优点是在不停止进程或者调试进程的情况下,转储进程中的内存。这对转储那些使用了反调试机制的壳来说,非常有价值。甚至当不能调试一个可执行文件时,仍可以使用ProcDump工具转储正在运行可执行文件的脱壳内容。这个过程并不能完全恢复可执行文件,但那时他能让我们在代码上使用Strings工具并做一些分析。


穿山甲双进程壳

  • OD进程附加功能

预备知识

  • PUSHAD:压栈,代表程序入口点
  • POPAD:出栈,代表程序出口点

查找OEP的方法总结

1、单步跟踪法

  • OD载入,点“不分析代码”
  • 单步执行(只向下),向上的F4跳过(注意nop,有nop在下一行F4)
  • 如果刚载入程序在附近就有一个CALL(近CALL),F7跟进去(否则程序会跑飞)
  • 跟踪的 时候如果运行到某个CALL程序运行不停下,就在这个CALL中F7进入
  • 有大跳转(大跨段):jmp、je、retn等说明很快会到OEP(附近可能有popad)
  • !注意!:如果无法向下跟踪时,可以在附近找没有实现的大跳转,右键->跟随,F2下断,Shitf+F9运行停止在“跟随”的位置,再取消断点,继续F8单步跟踪

    2、ESP定律法

  • F8,观察ESP是否改变(红色)【也就是说选择的ESP是关键句之后的第一个ESP值】

    • 关键句:PUSHAD、POPAD等
  • 在esp对应地址的数据窗口下硬件断点
  • F9运行来到跳转处(-> 删除硬件断点),F8到达程序OEP

    3、内存镜像法(Alt+M)

  • OD:选项->调试选项->异常,选择忽略全部,Ctrl+F2重载下程序

  • Alt+M打开内存镜像,找到程序的第一个.rsrc,按F2下断点,按Shift+F9运行到断点
  • Alt+M打开内存镜像,找到程序的第一个.rsrc上面的.text(.code:delphi),按F2下断点,按Shift+F9运行到断点,直接到OEP

    4、一步到达OEP(UPX,ASPACK)

  • Crtl+F输入:popad

  • Crtl+L:查找下一个popad,找到最合适的,下断点按下F2,F9运行到此处(开头是PUSHAD的情况)
  • 来到大跳转处,按下F8,到达OEP

    5、最后一次异常法(适用加密壳)

  • OD:选项->调试选项->异常,选择不忽略异常(勾都取消),Ctrl+F2重载下程序

  • 一开始就是一个跳转,按Shit+F9,知道程序持续运行,计算这中间异常暂停的次数,记为m
  • Crtl+F2重载程序,按Shift+F9(按m-1次)
  • 在OD堆栈窗口看到有一个“SE句柄“,这时候按Ctrl+G,输入SE句柄前的地址
  • 按F2在这个地址处下断点,Shift+F9运行到该断点
  • 去掉断点,F8向下执行
  • 到达程序OEP

    6、模拟跟踪法(自解压?)

  • F9之后能直接执行,说明没有SEH暗桩,如果运行后中断或报错,说明存在SEH暗桩。该方法要在没有暗桩的情况下使用。

  • Alt+M打开内存镜像,找到(包含=SFX,imports,relocations)的段
  • 如果这个段的地址为0054B000,在命令行输入tc eip<0054B000,回车,正在跟踪ing...

    7、“SFX”法

  • 设置OD,忽略所有异常(都打上勾)

  • 切换到SFX选项卡,选择“字节模式跟踪实际入口(速度非常慢)“,确定。
  • 重载程序(如果弹框“是否压缩代码“,选择“否”),OD直接到达OEP

手脱UPX

  • 单步
  • esp定律:硬件断点(别忘了删除)
  • 基本都可以

手脱ASPack和变形(检查是未知壳)

  • 单步(进入有近call,F7)
  • esp定律
  • 变形:多次使用脱壳方法(壳外面套着壳)

手脱PECompact

PECompact 1.xx

  • 单步
    • !注意!:如果无法向下跟踪时(F4跑飞) ,可以在附近找没有实现的大跳转,右键->跟随,在跟随到的位置F2下断,Shitf+F9运行停止在“跟随”的位置,再取消断点,继续F8单步跟踪(大跳转可能有多个,多次重复这个操作)
  • ESP定律
  • 模拟跟踪法

    PECompact 2.xx-3.xx(跳过壳的加密)

    image.png

  • 选择忽略所有异常(勾都打上)

  • 下断点:BP VirtualFree。运行,中断后取消断点,Alt+F9运行
  • Ctrl+F,查找“push 8000特征码,在这个段的retn处下断点,F9运行
  • F8单步,遇到远j**m**p跳转到OEP,发现是原位置,但是解密完成!!

image.png

手脱nspack(北斗)和PEncrypt1

nspack <3.3

  • ESP定律
  • 巧方法(适用于北斗3.3以前的)

    • 北斗主程序是VC++编写的,入口处能看到GetVersion获取版本
    • 载入OD,command输入“at GetVersion”(添加监视表达式)
    • 运行,程序断下后,在这一段的段尾“retn”,F2下断点
    • 运行,中断,F8返回,返回到的位置向上拉一点就是OEP

      PEncrypt1

  • 最后一次异常

手脱Yoda’s Crypter(加密壳,重点是修复)

  • 方法一:内存镜像法
  • 修复IAT
    • shift选中无效指针,在importREC中右键跟踪等级2
    • 也可以手动找(反汇编能看到)
  • 方法二:
    • 先忽略除了内存访问外的所有异常
    • F9运行
    • 找到右下角SE句柄对应的地址,下断点
    • shift+F9运行中断,取消断点
    • 单步执行,注意寄存器变化,会包含OEP

手脱tElock(加密壳,重点是修复)

  • 最后一次异常

image.png

  • 模拟跟踪法
    • 先结合最后一次异常法
  • 内存镜像法
  • 修复
    • 存在大量无效指针
    • 右键跟踪等级三会卡死
    • 在OD外部再打开一个加壳程序,ImportREC选中,在ImportREC中一部分一部分的修复(麻烦)
    • 还无效的手动识别(反汇编能看到)

手脱PETIE

  • ESP定律
    • 关键句:pushfw pushad
    • 对应:popfw popad

手脱FSG2.0

  • 特点:xchg
    • 定位后下硬件断点,防止壳检测到

image.png

  • 手动查找IAT
    • 找到IAT的RVA和size
      • 通过call API找到IAT表,向上找到IAT开头的位置就是RVA(再往上都是0,区块分界)
      • size就是找到下面全零的地址减去开始的(或者直接在importrec里size输入1000,再把垃圾指针删掉)

ESP定律(堆栈平衡原理)

  • pushad:把所有寄存器压栈
  • popad:寄存器出栈
  • 下断点就是找恢复堆栈平衡的时候
  • 适用范围:压缩壳更适用

内存断点法

  • 因为.text段在.data段之前被壳解码
  • 可以一次或多次在.data下内存断点,中断时表示.text段已经解压完毕,这时候再在.text下断点,找到OEP

附加数据的处理

  • 脱壳后关键数据也被脱掉,程序无法运行
  • 使用winHex打开加壳程序,拉到末尾向上找到全部为0的地方(或者通过计算出来后面区段的起始位置)
  • 选择0后面的所有内容,复制选块
  • 打开脱壳后修复的文件,拉到最后面,复制刚才的内容

程序自校验的解除

  • 方法:
    • 一个OD找到OEP,dump下来后
    • 再打开一个OD,载入脱壳修复后的程序
    • 两个OD都在CreateFIleA下断点,中断后都Alt+F9返回,F8通过对比跟踪找到自校验(关键条件跳转)
  • 校验点
    • 大小
    • 类型
    • 时间
    • CRC
    • 校验码

手脱EncryptPE+附加数据处理

  • 忽略所有异常
  • 手动添加两个异常(否则会提示异常无法继续调试)
    • 0EEDFADE
    • C0000000(IVALID HANDLE)
  • esp定律+内存断点
  • 添加附加数据

手脱穿山甲(Armadillo)1.xx~2.xx 单进程

  • 先确定是不是单进程(进程控制器)
  • 两次断点法
    1. - bp GetModuleHandleA/hr GetModuleHandleA/bp GetModuleHandleA+5/hr GetModuleHandleA+5
    2. - bp GetCurrentThreadId
    • 下断点1,shift+f9,到一次大时间缓冲后,取消断点,Alt+F9返回,找magic_jmp(je、大跳转、LoadLibrary下面的je)
    • 把je改成jmp
    • 下断点2,shift+f9,到一次大时间缓冲后,取消断点,Alt+F9返回,F8单步,call edi找到OEP

手脱穿山甲 4.xx(Armadillo)双进程(太复杂没看完。。。)

  • 查看有多个同名进程(LoadPE)
  • 尽量下赢家断点(he)
  • 注意返回的时机!!
    • 返回的地址是系统领空
    • Shift+F9过程中找到时间缓冲比较大的
      • 下断点:bp OpenMutexA,F9提示异常,添加到异常里‘
      • Shift+F9,断下
      • 搜索00401000,到空数据,打补丁(好多代码哦),右键新建EIP

破解工具介绍

PEiD

  • 通过特征码(signature)判断壳的类别

    LordPE

  • 先纠正镜像大小再脱壳

    PETools

  • 等于LordPE,用于dump

    OllyDump

    ImportREC

  • 修复IAT

    Scylla

  • 修复IAT

如何区分加密壳和压缩壳

  • 普通压缩壳OD调试时没有异常
  • 加密壳全部有反跟踪代码,会有很多SEH陷阱,使OD调试时产生异常