一米丶阳光 发表于 2019-11-4 22:01

ELF64手脱UPX壳实战

本帖最后由 一米丶阳光 于 2019-11-4 22:12 编辑

最近在做CTF逆向习题时,遇到一个带有UPX壳的ELF CrackMe,题目的目标是找到flag。
由于此前只对PE做过UPX脱壳,本来使用UPX的脱壳工具,用命令就能脱壳,但是出于研究的目的,看看ELF文件的UPX如何手动脱壳,话不多说,进入正题~

### 0x1 工具和环境
* IDA
* Ubuntu18.04

### 0x2 寻找OEP
* 首先在Ubuntu上运行程序,观察程序的运行情况


* Ubuntu上打开终端使用命令查看当前IP

* 将IDA文件夹内的linux_server64拷贝到Ubuntu系统中,给与运行权限并运行


* 将ELF文件拖入Win上的IDA内,选择Linux远程调试器,填入Ubuntu的IP地址启动调试,弹框点击确定


* 开始单步调试,单步调试遵循两个原则:1.除非F8跑飞,否则不用F7。2.循环直接跳过。








### 0x3 Dump内存文件
* 顺利找到OEP,准备dump内存

* dump文件执行结束,在对应目录生成dump文件


* 将dump文件拖入Ubuntu系统给与权限,并运行查看结果


### 0x4 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("G:\\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);
      }
}
```

### 0x5 总结
* 样本来源于CTF的逆向题,各位可放心下载练习,如果有兴趣,可以继续找出目标flag,好啦,附件拿走,免费评分留下:lol ~
* 链接: https://pan.baidu.com/s/1v_uL26C6FooLhHHSbPUhmQ 提取码: ubmc
* 解压密码:52pojie.cn

lishua 发表于 2021-2-23 16:59

本帖最后由 lishua 于 2021-3-25 15:47 编辑

一米丶阳光 发表于 2021-1-7 14:59
因为只有LOAD和DYNAMIC段才是运行时真正用到的
网上找了一篇文章(ELF文件的加载过程 https://blog.csdn.net/gatieme/article/details/51628257 其实只是大致看了elf加载的流程)。ELF加载后内存中只有标识为PT_LOAD或PT_DYNAMIC的segment,所以如果想要还原原始的程序信息,是不是也只有PT_LOAD或PT_DYNAMIC的segment可以下手,这样让自己理解感觉又很牵强
今天使用楼主提供的idc脚本成功将一个找到OEP的64 bits程序给dump脱壳了。
我仿照楼主代码写的32位的脱壳脚本不知道为啥脱了一个32位程序,运行后是segment fault,楼主大大看到帖子能否抽空帮忙看一下? 解答一下困惑
#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=0x08048000;
StartImg=0x08048000;
EndImg=0x0;
if (Dword(ImageBase)==0x7f454c46 || Dword(ImageBase)==0x464c457f )
{
    if(dumpfile=fopen("d:\\dumpfile","wb"))
    {
      e_phoff=ImageBase+Dword(ImageBase+0x1c);
      Message("e_phoff = 0x%x\n", e_phoff);
      e_phnum=Word(ImageBase+0x2c);
      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=Dword(e_phoff+0x4);
            StartImg=Dword(e_phoff+0x8);//p_vaddr
            EndImg=StartImg+Dword(e_phoff+0x14);//p_memsz
            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+0x20;
      }

      fseek(dumpfile,0x30,0);//e_shnum e_shstrndx
      fputc(0x00,dumpfile);
      fputc(0x00,dumpfile);
      fputc(0x00,dumpfile);
      fputc(0x00,dumpfile);

      fseek(dumpfile,0x20,0);//e_shoff
      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);
}
}

一米丶阳光 发表于 2019-11-6 19:38

zhengyg 发表于 2019-11-6 19:34
按照您的教程我也弄出来了,好厉害,谢谢您,那个脚本怎么写的呀,只能看懂一点点,想学的话从哪里入手好呢 ...

嘿嘿 恭喜你,要想写那个脚本,你得先去了解一下ELF64的头部结构,然后结合脚本代码你就明白啦

wl960612 发表于 2019-11-4 22:47

支持一下

夜步城 发表于 2019-11-4 23:30

支持楼主

xiao135140 发表于 2019-11-5 05:58

谢谢分享啊啊

Hmily 发表于 2019-11-5 08:09

elf程序脱壳资料不多,加精鼓励,期待更多分享。

GJH588 发表于 2019-11-5 08:25

这类教程很少,期待更多的教学,支持一下

一米丶阳光 发表于 2019-11-5 09:08

Hmily 发表于 2019-11-5 08:09
elf程序脱壳资料不多,加精鼓励,期待更多分享。

谢H大,我会继续努力:victory:

yaoyao7 发表于 2019-11-5 09:37

elf脱壳的少见啊,多分享一下

A-new 发表于 2019-11-5 10:20

为什么不直接用edb呢

daymissed 发表于 2019-11-5 10:21

视频学习起来更好点。感谢分享
页: [1] 2 3 4 5 6 7 8
查看完整版本: ELF64手脱UPX壳实战