目录

什么是壳及其原理
-
壳是软件加壳技术,用于保护PE可执行文件。
-
原理是附加一段自执行代码,控制原始代码的加载和执行。以下详细输出原理逻辑,补充缺失的部分如内存分配细节,并以文本模式画出通讯流程图和调用逻辑图。
+---------------+ +---------------+
| 系统加载器 | ----> | PE头部检查 |
+---------------+ +---------------+
| |
v v
+---------------+ +---------------+
| 执行壳入口 | <---- | 解密/解压 |
+---------------+ +---------------+
| |
v v
+---------------+ +---------------+
| 修复导入表 | ----> | 跳转OEP |
+---------------+ +---------------+
壳的定义:
壳(Packer/Shell)是一种程序,附加到目标PE上,形成新PE,运行时先运行壳代码,处理原始内容后转移控制。
壳的原理(详细逻辑):
-
附加壳代码到PE新节或覆盖。
-
修改PE头ImageBase、EntryPoint指向壳。
-
运行时,壳分配内存,解压/解密原始镜像。
-
修复重定位、导入表(补充:使用GetProcAddress动态加载API)。
-
跳转到原始OEP执行。
壳的知识点以及原理
壳本质上就是对PE文件上的一种应用
-
加密壳
-
免杀壳
-
虚拟化壳
-
压缩壳
-
反调试
-
反虚拟机
-
正常情况我们需要在源码加(壳代码)
-
如果我们是壳直接对exe程序直接的附加然后我们exe有附加的功能,就不需要直接在线程开一个tls不断监视是否被调试。
-
壳的定义:壳是一段程序代码,它被加入到PE(Portable Executable)文件的结构中。
-
功能:壳代码为原有程序"包裹"了一层,目的是保护原始代码,防止被直接查看或修改。
-
执行过程:
- 当程序运行时,首先执行壳代码,然后壳代码会处理代码段解密或解压的操作,最后跳转到原始程序的入口点,继续执行原有程序的逻辑。
核心概念匹配
-
在末尾节或者新节的部分加入新的代码:
-
是的,这是典型的加壳实现方式。PE文件(Windows的可执行文件格式)由多个节(Section)组成,加壳工具通常会:
-
在现有节(如.text或.data)的末尾追加壳代码和加密后的原代码(如果空间足够)。
-
或者添加一个全新的节(例如名为.UPX或自定义名称),用于存放壳代码和打包后的数据。
-
这避免了直接修改原有节的内容,保持文件结构的完整性。
-
也就是加密混淆的代码
-
加入的"新代码"主要是壳代码(shell code),它本身可能被混淆或加密,但更重要的是,壳代码负责处理原程序的加密/压缩部分。
-
原程序的代码、资源等通常会被压缩(e.g., 使用LZMA、UPX算法)或加密(e.g., XOR、AES),然后存储在壳中。
-
壳代码的目的是在运行时"脱壳"(unpack),恢复原内容。所以,不是所有新代码都只是"加密混淆",而是壳 + 加密后的原内容。
程序开始运行的时候首先走到壳代码:
-
加壳后,PE文件的入口点(Entry Point,在IMAGE_NT_HEADERS中的AddressOfEntryPoint字段)会被修改为指向壳代码的地址。
-
这样,Windows加载器(loader)启动程序时,会先执行壳代码,而不是直接跳到原入口点(OEP - Original Entry Point)。
-
壳代码运行完成后走到原始入口点 执行原有程序的代码:
这是加壳的经典流程
-
分配内存。
-
解压缩/解密原代码和资源。
-
修复导入表(IAT - Import Address Table)、重定位等PE结构(因为解压后地址可能变化)。
-
跳转(jump)到OEP,继续执行原程序逻辑。
-
用户感觉上程序"正常运行",但实际上多了一个前置的脱壳过程。
+---------------+ // 系统API调用加载PE
| LoadLibrary |
+---------------+
|
v
+---------------+ // 检查PE签名,映射到内存
| PE解析器 |
+---------------+
| // 如果加壳,入口指向壳
v
+---------------+ // 壳代码启动,分配额外内存
| Shell_Init | <-- VirtualAlloc(SizeOfImage)
+---------------+
|
v
+---------------+ // 遍历节,XOR解密每个字节
| DecryptSections | // 补充:检查Characteristics是否CODE/DATA
+---------------+
|
v
+---------------+ // 动态加载DLL,填充IAT
| FixImports | <-- GetProcAddress(kernel32, "Function")
+---------------+
|
v
+---------------+ // 调整地址偏移
| RelocateBase | // 补充:ImageBase + RVA计算
+---------------+
|
v
+---------------+ // 转移控制
| JumpToOEP |
+---------------+
额外知识:
-
加壳有不同类型,如压缩壳(UPX)、加密壳(ASPack)、保护壳(Armadillo)。
-
有些壳还会添加反调试、反虚拟机检查,以增加破解难度。
-
脱壳后,程序在内存中恢复原貌,但文件本身仍是被加壳的。
总体来说
- 如果想深入,可以学习PE文件格式细节或试用工具如PEiD来分析加壳文件。
PE文件的基本结构介绍
原理解释:
-
PE文件从DOS头开始,用于兼容旧系统。
-
跟随NT头,包含文件签名和头部信息。
-
然后是节头,描述每个节的位置和属性。
-
最后是节数据,如代码、数据等。
通俗来说,PE像一栋楼:DOS头是旧大门,NT头是总蓝图,节头是房间目录,节是实际房间。
案例:
-
一个简单的exe文件,如notepad.exe,其PE结构可以通过工具如PEView查看:
-
DOS头偏移0x3C指向NT头,NT头有"PE\0\0"签名。
壳在PE文件中的作用
原理解释:
-
壳代码附加到PE末尾或新节中。
-
修改PE入口点到壳代码。
-
运行时,壳先执行,解开原始代码。
-
跳转到原始入口点(OEP)。
-
通俗如包裹礼物:壳是外包装,打开后露出原物,但包装有锁(加密)。
-
案例: 使用UPX壳压缩一个exe,文件大小变小,运行时自动解压。
加壳过程对PE结构的修改
原理解释:
-
添加新节存放壳代码。
-
更新节头数量和虚拟大小。
-
加密原始节数据。
-
重定位导入地址表(IAT)。
通俗比喻:像装修房子,加壳是加一层防护墙,调整门窗(入口和导入)。
案例:
- 一个未加壳的hello.exe,加壳后节数从3增加到4,新节名为.UPX0含加密数据。
脱壳与反向工程
- "脱壳是逆向壳过程,恢复原始PE"。
原理解释:
-
调试运行到壳解开时刻。
-
转储内存中的解开代码。
-
修复PE头和重定位。
-
保存为新PE文件。
通俗:像剥洋葱,层层去除壳,露出核心。
案例: 使用OllyDbg调试加壳exe,设置断点于跳转OEP,dump内存修复。
