壳的概念

壳是在一些计算机软件里也有一段专门负责保护软件不被非法修改或反编译的程序。
壳是在一个程序的外面再包裹上另外一段代码,保护里面的代码不被非法修改或反编译的程序。它们一般都是先于程序运行,拿到控制权,然后完成它们保护软件的任务。

壳的分类

壳分为两类:压缩壳加密壳

  1. 压缩壳
    使用压缩壳可以帮助缩减 PE 文件的大小,隐藏了 PE 文件内部代码和资源,便于网络传输和保存。
    压缩壳用途:
    1. 单纯用于压缩普通 PE 文件的压缩壳
    2. 对源文件进行较大变形,严重破坏 PE 文件头,经常用于压缩恶意程序。
    常见的压缩壳
    - UPX
    - ASpack
    - PECompat
  2. 加密壳
    功能:保护 PE 免受代码逆向分析
    用途:
    1. 对安全性要求高,对破解敏感的应用程序
    2. 恶意程序用于避免(降低)杀毒软件的检测查杀
    常见的加密壳:
    - ASProtector
    - Armadillo
    - EXECryptor
    - Themida
    - VMProtect

壳的加载过程

  1. 保存入口参数
    1. 加壳程序初始化时保存各寄存器的值
    2. 外壳执行完毕,恢复各寄存器值
    3. 最后再跳到原程序执行
    通常使用```pushad / popad、pushfd / popfd````指令对寄存器进行保存和恢复
  2. 获取所需函数API
    1. 一般壳的输入表中只有 GetProcAddress、GetModuleHandle 和 LoadLibrary 这几个 API 函数
    2. 如果需要其他 API 函数,则通过 LoadLibraryA(W) 或 LoadLibraryExA(W) 将 DLL 文件映射到调用进程的地址空间中
    3. 如果 DLL 文件已被映射到调用进程的地址空间里,就可以调用 GetModuleHandleA(W) 函数获得 DLL 模块句柄
    4. 一旦 DLL 模块被加载,就可以调用 GetProcAddress 函数获取输入函数的地址
  3. 跳转回原程序入口点(OEP)
    1. 在跳转回入口点之前,恢复填写原PE文件输入表(IAT),并处理好重定位项(主要是 DLL 文件)
    2. 对每一个 DLL 引入的所有函数重新获取地址,并填写到 IAT 表中(因为加壳时外壳自己构造了一个输入表)
    3. 将控制权移交原程序,并继续执行