欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]揭示《shellcoder's handbook》中一个函数的运行机制

[原创]揭示《shellcoder's handbook》中一个函数的运行机制

下面的这个函数是在《shellcoder's handbook》一书里遇到的,通过这个精心构造的函数可以执行我们的shellcode。看看这个C程序,它的功能就是执行我们的shellcode。也许你会问这一系列的赋值语句,怎么会执行我们的shellcode的呢?它又是如何做到的呢?《shellcoder's handbook》一书中并没有介绍这个函数的内在机制,只是用这个函数来运行我们写的shellcode.
如果你不明白这段代码是如何做到执行我们的shellcode的,我觉着这篇文章就有了它的价值意义。

/*shellcode_tester.c*/
#include <stdio.h>
char shellcode[]="\xbb\x02\x00\x00\x00"
     "\xb8\x01\x00\x00\x00"
     "\xcd\x80";
/*
上面的shellcode的意思就是:
movl $2,%ebx
movl $1,%eax
int  $0x80
该功能就是调用exit(2)
*/
int main()
{
  int *ret;
  ret=(int *)&ret+2;
  (*ret)=(int)shellcode;
}

首先,我们编译一下这段代码:gcc -o test shellcode_tester.c
接着,我们调试这段代码,并在main函数处下断点,如图所示

然后,运行至断点处,并反汇编EIP运行处周围的二进制代码,如图

此时,我们查看一下栈中的情况,如图

从这幅图中我们可以看出,此时寄存器ebp的值是0xbffffd28,在执行push %ebp之前,寄存器ebp的值是0xbffffda8,而地址0xbffffd2c处就存储着我们的返回地址,我们要做的就是更改这个地址。
紧接着,我们执行到leave指令(leave指令还没有被执行),如图

执行完上图中的两个赋值语句后,寄存器eax所存的值是0xbffffd2c,而地址0x8049628就是我们的shellcode的地址,该值被存放在寄存器edx中,最后使用mov指令将shellcode的地址重写到eax所指的地址处。现在我们查看一下栈中的情况如何,如图

看到了吧,我们已经成功地改写了地址为0xbffffd2c处的值,其值就是我们的shellcode的起始地址。此时,我们看看几个寄存器中的值如何,如下图

当我们执行完leave指令,而ret指令还没被执行时,如图

我们再来看看寄存器的情况,如下图

对比一下leave指令执行前后寄存器ebp,esp的变量,你发现什么了么。通过对比推导,我们可以总结出leave指令的功能,它是将当前子程序在堆栈中的局部变量进行释放,其功能相当于下面的这两条指令
    mov %ebp,%esp
    pop %ebp

经过leave指令后,我们的栈顶esp重新回到了0xbffffd2c地址处,而该栈顶的值是0x08049628。还记得这个值吧,这个值就是我们的shellcode的地址。
当我们执行完最后一条ret指令时,将执行一个出栈操作,将栈顶的元素赋值于EIP。此时,我想你已经知道了shellcode为什么会执行的原因了吧。

上传的附件 1.png
2.png
3.png
4.png
5.png
6.png
7.png
8.png

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功