Linux逆向之加壳&脱壳
字数 1042 2025-08-24 20:49:31
Linux逆向之加壳与脱壳技术详解
一、加壳技术概述
加壳是一种保护可执行文件的技术,通过对原始程序进行压缩或加密,并在程序运行时进行解压/解密,从而达到保护程序的目的。在Linux系统中,UPX是最常见的开源加壳工具。
UPX壳特点
- 开源免费
- 支持多种平台
- 压缩率高
- 执行速度快
- 易于使用
二、环境准备与示例程序
1. 示例程序
#include <stdio.h>
void fun1() {
puts("fun1:hello,world!");
sleep(1);
}
void fun2() {
puts("fun2:hello,world!");
sleep(1);
}
int main(int argc, char const *argv[]) {
puts("main:hello,world!");
fun1();
fun2();
return 0;
}
2. 编译要求
使用静态编译以确保文件大小足够(UPX要求大于40KB):
gcc ./test.c -o test --static
三、UPX基本操作
1. 加壳操作
./upx test
常用参数:
-d:脱壳-1~-9:压缩等级(1最快压缩率最低,9最慢压缩率最高)-k:保留原程序备份
2. 加壳效果验证
加壳后程序应能正常运行:
./test
四、加壳原理分析
1. ELF文件结构变化
使用readelf工具查看加壳前后变化:
readelf -hlS --w test
加壳后:
- ELF头部信息被修改
- 段表信息被大幅简化
- 仅保留UPX自定义的程序入口执行地址
2. 壳识别方法
常用检测工具:
checksec:检查安全属性strings:查看可打印字符串
UPX壳特征:
- 包含"UPX"等特征字符串
- 特定的段名和入口点特征
五、UPX壳隐藏技术
1. 手动修改特征
使用二进制编辑器(如010 Editor):
- 修改UPX相关字符串
- 替换UPX关键词
效果:
- 避免被检测工具识别
- UPX工具无法自动脱壳
六、手动脱壳技术
1. 脱壳原理
加壳程序运行时会在内存中解压原始代码,手动脱壳的关键是:
- 找到原始入口点(OEP)
- 从内存中dump出解压后的程序
2. 脱壳步骤
准备工作
- 准备IDA调试环境
- 将
linux_server64复制到目标系统并运行
IDA远程调试
- 选择调试器:Remote Linux Debugger
- 配置远程文件路径和IP地址
- 在start函数设置断点
- 开始调试
跟踪执行流程
- 按F8步过执行
- 遇到跳转循环时坚持向下执行原则
- 关键点:
- 注意
jmp r13跳转 - 进入新段后的第一个call
- 跳过三个向上循环
- 最终回到OEP(如0x400890)
- 注意
内存dump脚本
使用IDC脚本dump内存:
#include <idc.idc>
#define PT_LOAD 1
#define PT_DYNAMIC 2
static main(void) {
auto ImageBase, StartImg, EndImg;
auto e_phoff;
auto e_phnum, p_offset;
auto i, dumpfile;
ImageBase = 0x400000;
StartImg = 0x400000;
EndImg = 0x0;
if(Dword(ImageBase) == 0x7f454c46 || Dword(ImageBase) == 0x464c457f) {
if(dumpfile = fopen("dumpfile", "wb")) {
e_phoff = ImageBase + Qword(ImageBase + 0x20);
Message("e_phoff = 0x%x\n", e_phoff);
e_phnum = Word(ImageBase + 0x38);
Message("e_phnum = 0x%x\n", e_phnum);
for(i = 0; i < e_phnum; i++) {
if(Dword(e_phoff) == PT_LOAD || Dword(e_phoff) == PT_DYNAMIC) {
p_offset = Qword(e_phoff + 0x8);
StartImg = Qword(e_phoff + 0x10);
EndImg = StartImg + Qword(e_phoff + 0x28);
Message("start = 0x%x, end = 0x%x, offset = 0x%x\n", StartImg, EndImg, p_offset);
dump(dumpfile, StartImg, EndImg, p_offset);
Message("dump segment %d ok.\n", i);
}
e_phoff = e_phoff + 0x38;
}
fseek(dumpfile, 0x3c, 0);
fputc(0x00, dumpfile); fputc(0x00, dumpfile); fputc(0x00, dumpfile); fputc(0x00, dumpfile);
fseek(dumpfile, 0x28, 0);
fputc(0x00, dumpfile); fputc(0x00, dumpfile); fputc(0x00, dumpfile); fputc(0x00, dumpfile);
fputc(0x00, dumpfile); fputc(0x00, dumpfile); fputc(0x00, dumpfile); fputc(0x00, dumpfile);
fclose(dumpfile);
} else Message("dump err.");
}
}
static dump(dumpfile, startimg, endimg, offset) {
auto i;
auto size;
size = endimg - startimg;
fseek(dumpfile, offset, 0);
for(i = 0; i < size; i = i + 1) {
fputc(Byte(startimg + i), dumpfile);
}
}
验证脱壳结果
- 用IDA分析dumpfile
- 检查反编译逻辑是否清晰
- 在Ubuntu中运行验证功能
七、进阶研究建议
- 研究UPX源码实现
- 分析不同压缩等级的效果差异
- 探索其他加壳工具和技术
- 研究反调试和反脱壳技术
八、参考资源
- UPX官方源码和文档
- ELF文件格式规范
- IDA Pro高级调试技术
- Linux二进制分析相关书籍