0x0 前言
最近分析一个程序,里面是大段的空白内容
strings表里面也几乎都是乱码
使用readelf也可以看到目标程序没有节,应该是使用了加壳保护
$ readelf -e ./vshell_linux_amd64
ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
类别: ELF64
数据: 2 补码,小端序 (little endian)
Version: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
类型: EXEC (可执行文件)
系统架构: Advanced Micro Devices X86-64
版本: 0x1
入口点地址: 0x24632c08
程序头起点: 64 (bytes into file)
Start of section headers: 0 (bytes into file)
标志: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
本文件中没有节。
程序头:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000001000 0x00000000188cb1b0 RW 0x1000
LOAD 0x0000000000000000 0x0000000018ccc000 0x0000000018ccc000
0x000000000b9676f9 0x000000000b9676f9 R E 0x1000
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x8
0x1 Detect_It_Easy
Detect_It_Easy是检查壳工具,类似PEID,可以在linux下运行,github地址为:
https://github.com/horsicq/Detect-It-Easy
下载执行方式如下:
wget https://github.com/horsicq/DIE-engine/releases/download/3.08/Detect_It_Easy-3.08-x86_64.AppImage
chmod +x Detect_It_Easy-3.08-x86_64.AppImage
启动后加载目标程序,可以看到检测到UPX壳:
0x2 Upx自动脱壳失败
UPX自带了脱壳功能,使用-d
参数即可,效果如下:
但目标程序作了修改,使用UPX无法脱壳
查看了以下UPX自动脱壳相关代码,脱壳之前会获取壳版本Version信息、Format等信息来判断具体加壳版本,再去执行相应脱壳代码
目标程序这些信息都已被删除,因此无法使用UPX自动脱壳
https://github.com/upx/upx/blob/33f4f3a5a1a62e9173a0435f09f59e5b3c06a24e/src/packmast.cpp#L135
0x3 dbg手动脱壳
手动脱壳参考了以下几篇文章:
https://bbs.kanxue.com/thread-79061.htm
https://xz.aliyun.com/t/6881
Linux系统下没有ollydbg这种比较好用的调试工具,但可以使用IDApro远程调试,Linux系统端启动IDApro调试服务工具:
$ ./linux_server64
IDApro远程调试选择Remote Linux debugger
:
调试设置远程服务端的ip和端口
远程附加上后,先在start处下断点
执行后一路f8,循环很多,出现一个大跳
第一个call f7单步进入,之后一直f8,循环体f4跳过
最后会来到一个jmp语句,这里即将回到OEP,f7一下
基址来到0x464660
执行dump脚本
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);
}
}
生成的dumpfile文件,可以直接执行