首页
社区
课程
招聘
[求助]64位下ELF脱UPX壳
发表于: 2015-12-13 23:50 13629

[求助]64位下ELF脱UPX壳

2015-12-13 23:50
13629
是个UPX 3.91的壳(这是我自己写的一个测试的,还有个复杂点的不知道源代码的程序,不过壳和内容估计没太大关系),压缩选项为--overlay=strip --no-reloc -k
(为了使源程序够大,gcc编译的时候加上了-static)
然后程序原本的功能非常简单,是:
用scanf读取一个int型的数a      -->
a传一个函数calc中处理,是奇数就加1,偶数就减2;   -->
用printf输出返回的结果printf("a = %d\n", a);

现在我的问题是:(我首先用的是IDA远程连接调试)
它一开头就是call loc_xxx,这样的,然后我尝试直接在下一句下断点,但是在call loc_xxx的执行的过程中发现它遇到了int 3,然后我尝试取消处理,然后一直ctrl + F7(执行到返回),然后程序就退出了。。。

(然后用的gdb的attach功能)
然后我用gdb attach来调试了一下,发现attacch进去的时候它正好在一条syscall后面,然后输入n就会读取输入,然后一直跟到一个类似call [rax + 70h]这样的地方,在这个函数里,发现rdi + 28h(具体加多少忘记了)的地方直接就有一个字符串"a = 10\n",然后输出的这个字符串而不是像一般的
push res
push format_string
call printf@plt这样,说明它在前面某处已经计算出了答案,但linux下我不知道有什么比较好的工具,而且自己的调试能力也有待加强。。。所以还没找到计算这部分的代码

已经看了这两篇http://bbs.pediy.com/showthread.php?t=38035
http://bbs.pediy.com/showthread.php?t=79061
但我的问题其中没有提及,也有可能是这对他们而言是比较简单,但是我目前确实是不太明白,虽然UPX是最弱的壳,但是以前太过依赖工具了。。。

希望各位大牛指点指点,多谢了

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (13)
雪    币: 161
活跃值: (231)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
upx -d直接脱壳了事
2015-12-14 11:26
0
雪    币: 6
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
不懂帮顶。
2015-12-14 12:35
0
雪    币: 4
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
。。。我当然知道upx -d可以脱,但是另外那个不知道源代码的程序修改了,upx -d不可以直接脱。也是为了学习一下
2015-12-14 13:54
0
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
5
手脱upx根本不用管壳做了什么。init_array返回之后,直接dump内存就行了
2015-12-14 14:03
0
雪    币: 161
活跃值: (231)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
readelf -a ./test1
显示:
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000047715 0x0000000000047715  R E    200000
  LOAD           0x00000000000c41a8 0x00000000006c41a8 0x00000000006c41a8
                 0x0000000000000000 0x0000000000000000  RW     200000
你运行test1程序后,gdb attach,附加到调试进程,然后dump出起始地址:400000,结束地址:6C5000进程内容到文件test2中。怎么DUMP,请在gdb中输入help dump命令查看。

再用readelf -a ./test2文件,可以看到:
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400f4e
  Start of program headers:          64 (bytes into file)
  Start of section headers:          794024 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         6
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 28

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0] <no-name>         NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] <no-name>         NULL             0000000000000000  00000000
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000bf478 0x00000000000bf478  R E    200000
  LOAD           0x00000000000bfea0 0x00000000006bfea0 0x00000000006bfea0
                 0x0000000000001d90 0x0000000000004308  RW     200000
  NOTE           0x0000000000000190 0x0000000000400190 0x0000000000400190
                 0x0000000000000044 0x0000000000000044  R      4
  TLS            0x00000000000bfea0 0x00000000006bfea0 0x00000000006bfea0
                 0x0000000000000020 0x0000000000000058  R      10
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x00000000000bfea0 0x00000000006bfea0 0x00000000006bfea0
                 0x0000000000000160 0x0000000000000160  R      1
从上面信息我们可以找到正确的程式入口点  Entry point address:               0x400f4e,重新GDB载入test1,在入口点处下断点,运行,中断在入口点后,重新dump程式进程内容。
我们还需要修改:
  Start of section headers:          794024 (bytes into file)
改此处值为0,程序载入器用不着这个数据。
由于我们是直接dump出连续的内存空间,所以我们还需要修改:
Program Headers:
各程序段的offset与virtaddr相符合。
修改完这两处后,就算是脱壳完成了。
UPX壳很简单,不需要修复符号信息和重定位信息。建议你在脱壳前先看看ELF格式。
2015-12-14 16:08
0
雪    币: 4
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
。。。。修改错了,应该修改的下面的回复修改到这了,,,,
2015-12-14 16:16
0
雪    币: 4
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
好的我试试,谢谢~
2015-12-14 16:18
0
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
9
要断在linker里面。根据实际情况。如果只有UPX的话,so加载完了再dump就行,根本不用下断点。
断linker里面就是为了防止在后续的代码里面,把一些没用的加载信息抹去,那还要修复,麻烦。
2015-12-14 16:31
0
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
10
卧槽~穿越了。x64的upx,还是可执行文件。之前的当我没说。
按PC的手脱呗,upx的oep特征还是很明显。
简单看了一下你的问题,第一个call是不一定有返回的,因为壳运行完了,会jmp到oep执行。
2015-12-14 16:47
0
雪    币: 4
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
你好,我刚才试了一下(下午那会后来有点事所以现在才试),
就是:运行后再attach的话,程序已经就断在真正程序的系统调用里了(因为调用了scanf),然后这时候下entry的断点没办法运行到入口点;
然后gdb直接加载test1的话是没办法start的,它提示
warning: no loadable sections found in added symbol-file /home/targetnull/Desktop/Xiao_CTF/upx-3.91-amd64_linux/test1
(no debugging symbols found)...done.


不知道你是怎么用gdb调试的呢,能否告知一下,谢谢

------------------------------------------------------

刚才又试了一下,发现因为attach的时候没法断在入口点,而是直接断在了程序中,可以直接/x20i entry来看入口的代码,但是要得到完整程序估计还是dump出来比较好。
然后请问你dump的时候结束地址怎么选取的呢,直接选取(start + size)的最大值再以4K一页对齐后的值吗?
最后就是你说要修复program header使得size和virtaddr相等,我看了下,那就是应该只有那个第二个LOAD的segment需要修改了,但是这个要追究原因的话估计和装载机制有关了吧,能否推荐一两篇相关的资料学习学习呢?网上的一些博客讲的太笼统,太原理化了。。。
2015-12-14 23:56
0
雪    币: 4
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
你好,请问你说的这个方法该如何下断点呢,用什么来调试呢?
它断的时候就是在系统调用了(程序里有scanf),这时已经过了真正入口点了,只能dump或者用x/10i这样来看了

------------------------------------------------------------

刚才试了下楼上的方法,可以得到正确入口点了,然后接下来估计就是更改header的一些数据了吧
不过还是没办法去动态跟踪到程序入口点
2015-12-14 23:58
0
雪    币: 30
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
内存dump可以参考http://bbs.pediy.com/showthread.php?t=79061,不过这个在IDA6.8下有BUG,会将0A输出为0D 0A。。也是醉了,可以自己写脚本从/proc/pid/mem中dump
使用IDA远程调试啊,IDA里断在start,然后F9启动远程调试,然后找OEP就好了啊
2016-7-15 10:26
0
雪    币: 141
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
试了下这题,最终还是要单步调到eop,dump出来才能正常跑。采臣取eop的方法是不行的。
2016-12-25 23:09
0
游客
登录 | 注册 方可回帖
返回
//