驱动管家:安全、高效、精准的专业驱动下载站!

ESP被PUSH到堆栈解析 如何调用一个函数?

2018-03-17 09:58:19责编:llp   来源:驱动管家     人气:

而如果ESP被PUSH到堆栈,这是堆栈的表示:

_parametre_I___| EBP 12

_parametre II__| EBP 8

_return adress_| EBP 4

___saved_ESP___| EBP ESP

_local var I __| EBP-4

_local var II__| EBP-8

在上面的图中,变量I 和II是传递给函数的参数。在返回地址和保存ESP之后,var I和II是函数的局部变量。现在,如果我们总结所有我们所讲的,当调用一个函数的时候:

ESP被PUSH到堆栈解析 如何调用一个函数?

1.我们保存老的堆栈指针,PUSH它到堆栈 2.我们保存下一个指令的地址(返回地址),PUSH它到堆栈。3.我们开始执行程序指令。

当我们调用一个函数时,上面3步都做了。

让我们在一个生动的例子中看堆栈的操作。

a.c :

void f(int a, int b, int c)

{

char z[4];

}

void main()

{

f(1, 2, 3);

}用-g标志编译这个从而能够调试:

[murat@victim murat]$ gcc -g a.c -o a

让我们看看这里发生了什么:

[murat@victim murat]$ gdb -q ./a

(gdb) disas main

Dump of assembler code for function main:

0x8048448 : pushl雙

0x8048449 : movl %esp,雙

0x804844b : pushl$0x3

0x804844d : pushl$0x2

0x804844f : pushl$0x1

0x8048451 : call 0x8048440

0x8048456 :addl $0xc,%esp

0x8048459 :leave

0x804845a :ret

End of assembler dump.

(gdb)

以上可见,main()函数中第一个指令是:

0x8048448 : pushl 雙

它支持老的指针,并把它压入堆栈。接着,拷贝老的堆栈指针倒ebp寄存器:

0x8048449 : movl %esp,雙

因而,从那时起,在函数中,我们将用EBP引用函数的局部变量。这两个指令被称为”程序引入”。接着,我们反序PUSH函数f()的参数到堆栈中。

0x804844b : pushl$0x3

0x804844d : pushl$0x2

0x804844f : pushl$0x1

我们调用这个函数:

0x8048451 : call 0x8048440

如我们已经通过CALL调用解释的那样,我们PUSH指令addl $0xc,%esp的地址0x8048456到堆栈。函数RET调用后,我们加12或者十六进制中的0xc(因为我们推入3个参数到堆栈中,每一个分配了4个字节(整型))。接着我们离开main()函数,并且返回:

0x8048459 :leave

0x804845a :ret

好,在函数f()内部发生了什么呢?

(gdb)

disas f

Dump of assembler code for function f:

0x8048440 :pushl雙

0x8048441 :movl %esp,雙

0x8048443 :subl $0x4,%esp

0x8048446 :leave

0x8048447 :ret

End of assembler dump.

(gdb)

开始两个指令都是一样的。它们是程序引入。接着我们看a:

0x8048443 : subl $0x4,%esp

从ESP减去了4个字节。这是为局部变量z分配空间。记得我们定义它为char z[4]?它是一个4字节的字符数组。最后,在末尾,函数返回:

0x8048446 :leave

0x8048447 :ret

好,让我们看另外一个例子:

b.c :

void f(int a, int b, int c)

{

char foo1[6];

char foo2[9];

}

void main()

{

f(1,2,3);

}

编译并且启动gdb,解析f:

[murat@victim murat]$ gcc -g b.c -o b

[murat@victim murat]$ gdb -q ./b

(gdb) disas f

Dump of assembler code for function f:

0x8048440 :pushl雙

0x8048441 :movl %esp,雙

0x8048443 :subl $0x14,%esp

0x8048446 :leave

0x8048447 :ret

End of assembler dump.

(gdb)

可以看出,从ESP中减去了0x14(20字节),尽管foo1和foo2的总长度只有9 6=15。这样的原因是,内存,还有堆栈,在4字节框架下编址。这意味着,你不能简单的PUSH 1字节数据到堆栈中。或者4字节或者为空。f()北调用时,堆栈将象这样:

_______$1_______| EBP 16

_______$2_______| EBP 12

_______$3_______| EBP 8

_return address_| EBP 4

___saved_ESP____| EBP ESP

______foo1______| EBP-4

______foo1______| EBP-8

______foo2______| EBP-12

______foo2______| EBP-16

______foo2______| EBP-20

你可以相信,当我们对f001装载超过8个字节对和对foo2超过12个字节,我们将溢出他们的空间。如果你对foo1写入超过4个字节,你将重写被保护的EBP,而且……如果你写入超过4个字节,你将重写返回地址……而这不正是我们都想要的吗?这是内存溢出的基础……让我设法用一段简单的代码稍微阐明一下这种现象,假设我们有这样的代码:

c.c :

#include

void f(char *str)

{

char foo[16];

strcpy(foo, str);

}

void main()

{

char large_one[256];

memset(large_one, 'A', 255);

f(large_one);

}

[murat@victim murat]$ make c

cc -W -Wall -pedantic -gc.c -o c

[murat@victim murat]$ ./c

Segmentation fault (core dumped)

[murat@victim murat]$

我们在上面做的是简单的写255字节到一个只能容纳16字节的数组里。我们传递了一个256字节的大数组作为一个参数给f()函数。在函数内部,没有边界检测我们拷贝了整个large_one到foo,溢出了foo和其它数据。因此缓冲区被填写了,同样的strcpy()用A填写了内存的其它部分,包括返回地址。

这里是用gdb生成核文件代码的检查:

[murat@victim murat]$ gdb -q c core

Core was generated by `./c'.

Program terminated with signal 11, Segmentation fault.

find_solib: Can't read pathname for load map: Input/output error

#00x41414141 in ?? ()

(gdb)

可以看出,CPU在EIP中看到0x41414141(041是字母A的十六进制ASCII码),试图存储和执行此处的指令。然而,0x41414141不是我们的程序被允许存储的内存地址。最后操作系统发了一个SIGSEGV(Segmentation Violation)段侵犯信号给程序并且停止了任何进一步的操作。

我们调用f()时,堆栈看起来象这样:

______*str______| EBP 8

_return address_| EBP 4

___saved_ESP____| EBP ESP

______foo1______| EBP-4

______foo1______| EBP-8

______foo1______| EBP-12

______foo1______| EBP-16

strcpy()从foo1的开头,EBP-16开始,拷贝large_one到foo,没有边界检查,用A填充了整个堆栈。

现在我们能够重写返回地址,如果我们放一些其它的内存段地址,我们能在那里执行指令码?答案是肯定的。假如我们放了一些 /bin/sh spawn出的指令在一些内存地址中,而我们把这个地址放到我们溢出的这个函数返回地址中,我们就能spawn出一个shell,而且很有可能,既然你已经对setuid二进制程序感兴趣了,我们将spawn出一个root shell。

  • ms挂马方法 ms如何挂马?

    ms挂马方法 ms如何挂马?

    SQL语句如下:用游标遍历所有表里如下数据类型的字段,然后UPDATE挂马。(全部是允许写入字符的字段)xtype=99 ntextxtype=35 text

    详情2018-03-01 10:26:01责编:llp   来源:驱动管家     
  • php注入的万能密码是什么?为什么这个万能密码能进入后台?

    php注入的万能密码是什么?为什么这个万能密码能进入后台?

    可是有的人说对PHP的站如果是GPC魔术转换开启,就会对特殊符号转义,就彻底杜绝了PHP注入。其实说这话的人没有好好想过,更没有尝试过用万能密码进PHP的后台。其实GPC魔术转换是否开启对用万能密码进后台一点影响

    详情2018-01-24 12:27:47责编:llp   来源:驱动管家     
  • 图片隐藏文件秘密的方法 文件秘密如何隐藏在图片中?

    图片隐藏文件秘密的方法 文件秘密如何隐藏在图片中?

    每个人都有自己的秘密,不过有些朋友却喜欢将秘密,以文件的形式放到电脑里,来供自己欣赏。虽然这些“秘密”放在电脑上大多都是加了密的,但是有些只能防止菜鸟破解,根本达不到真正隐藏的目的。于是笔者想了很

    详情2018-02-04 13:20:07责编:llp   来源:驱动管家     
  • mcu是什么?mcu是怎么被黑客破解的?

    mcu是什么?mcu是怎么被黑客破解的?

    MCU就是大家所熟悉的微控制单元,或者单片微型计算机,或者单片机,攻破MCU有很多种方法,下面小编就为大家具体的讲解黑客是怎么破解MCU的。这篇文章是俄国人Sergei P Skorobogatov就读英吉利剑桥大学之博士论文

    详情2018-01-24 20:07:20责编:llp   来源:驱动管家     
  • 用regedt32.exe对sam键设置完全控制权限

    用regedt32.exe对sam键设置完全控制权限

    对regedit exe大家都很熟悉,但却不能对注册表的项键设置权限,而regedt32 exe最大的优点就是能够对注册表的项键设置权限。nt 2000 xp的帐户信息都在注册表的HKEY_LOCAL_MACHINE\SAM\SAM键下,但是除了系统用户

    详情2018-03-07 08:49:44责编:llp   来源:驱动管家     
  • linux服务器下syn攻防战 syn攻击的相关知识

    linux服务器下syn攻防战 syn攻击的相关知识

    如何打响Linux服务器下的攻防战,感兴趣的小伙伴们可以参考一下本文,或许会有所收获。

    详情2018-03-01 15:31:20责编:llp   来源:驱动管家     
  • 2016年木马病毒查杀软件的排行榜

    2016年木马病毒查杀软件的排行榜

    现在的电脑杀毒软件种类很多,在选择的时候,很多人并不知道如何去进行选,按照什么标准来进行选择,其实在选择杀毒软件首先要看杀毒能力,其次可以根据杀毒软件的功能来进行判定排名,下面就和大家一起来分析一

    详情2018-01-05 13:58:41责编:llp   来源:驱动管家     
  • 139端口入侵怎么禁止?如何处理512端口入侵?

    139端口入侵怎么禁止?如何处理512端口入侵?

    139端口的入侵,主要是通过建立空连接,而获得用户名和共享名,接着用字典法或穷举法来猜测ADMINISTRATORS的密码,这样可获得最高权限。解决方法:1、禁止匿名共享。2、禁止管理共享。1433端口的入侵,主要是利用

    详情2018-02-01 16:50:14责编:llp   来源:驱动管家     
  • 后门木马的查找教程 手工怎么查找后门木马?

    后门木马的查找教程 手工怎么查找后门木马?

    后门木马又称特洛伊木马(Trojan horse),是一种基于远程控制的黑客工具。包括客户端和服务端。一起来看看手工查找后门木马的教程吧。1、首先最需要注意的地方是系统的启动项,可以在“运行”-输入“msconfig命

    详情2018-01-06 11:53:37责编:llp   来源:驱动管家     
  • 搜狐微博也有漏洞?搜狐微博的漏洞和修复方法分析

    搜狐微博也有漏洞?搜狐微博的漏洞和修复方法分析

    搜狐某处CSRF漏洞,可能导致蠕虫蔓延,在未经用户同意的情况下发布微博

    详情2018-01-13 16:51:22责编:llp   来源:驱动管家