汇编语言基础之九- 关于栈指针的规律性的总结

栈底指针可以被用来判断传递的参数的值,还有函数的局部变量的值。

让我们继续用上一个例子来说明一下吧。

ChildEBP RetAddr 
0012ff34 00401121 Simple!Foo2+0x64 [C:\Labfiles\Module04\Simple\Simple.cpp @ 82]
0012ff4c 004010da Simple!Foo1+0x31 [C:\Labfiles\Module04\Simple\Simple.cpp @ 65]
0012ff64 00401096 Simple!Foo+0x2d [C:\Labfiles\Module04\Simple\Simple.cpp @ 49]
0012ff80 00404739 Simple!main+0x36 [C:\Labfiles\Module04\Simple\Simple.cpp @ 33]
0012ffc0 7c817077 Simple!mainCRTStartup+0xe9 [crt0.c @ 206]

栈中的内容如下:

dd esp

0012ff14  cccccccc cccccccc cccccccc cccccccc
0012ff24  cccccccc cccccccc cccccccc cccccccc
0012ff34  0012ff4c 00401121 00000001 00000002
0012ff44  00000002 00000001 0012ff64 004010da
0012ff54  0012ff60 0012ff5c 00000002 00000001
0012ff64  0012ff80 00401096 00000001 00000002
0012ff74  00000002 00000001 cccccccc 0012ffc0
0012ff84  00404739 00000001 00420e90 00420de0

dd

0012ff94  43010000 00000000 7ffde000 00000001
0012ffa4  00000006 0012ff94 80621a58 0012ffe0
0012ffb4  00408084 00417218 00000000 0012fff0
0012ffc4  7c817077 43010000 00000000 7ffde000
0012ffd4  8054c6ed 0012ffc8 8918f3e8 ffffffff
0012ffe4  7c839ad8 7c817080 00000000 00000000
0012fff4  00000000 00404650 00000000 78746341
00130004  00000020 00000001 000024b8 000000c4

 

利用EBP确定参数

==============

函数Foo2的栈底位置为0012ff34 ,而函数返回值的位置就在栈底的下方,即ebp+4. 在这里为00401121。

第一个参数在参数表的最左边,是最后一个压栈的参数,所以第一个参数的起始地址为ebp+8,根据前面我们的程序Simple.cpp,可以看出第一个参数的值为1, 第二个参数的值为2.

运行如下的命令来验证。可以看到ebp+8所指向的内存中,值为1。第二个参数的位置为ebp+12,在下面的内存dump中,可以看到该位置的值确实为2.

dd ebp+8

0012ff3c  00000001 00000002 00000002 00000001
0012ff4c  0012ff64 004010da 0012ff60 0012ff5c
0012ff5c  00000002 00000001 0012ff80 00401096
0012ff6c  00000001 00000002 00000002 00000001
0012ff7c  cccccccc 0012ffc0 00404739 00000001
0012ff8c  00420e90 00420de0 43010000 00000000
0012ff9c  7ffde000 00000001 00000006 0012ff94
0012ffac  80621a58 0012ffe0 00408084 00417218

 

Windbg有个查看函数ebp,返回值和前三个参数的命令,很方便。

ChildEBP RetAddr  Args to Child             
0012ff34 00401121 00000001 00000002 00000002 Simple!Foo2+0x64 [C:\Labfiles\Module04\Simple\Simple.cpp @ 82]
0012ff4c 004010da 0012ff60 0012ff5c 00000002 Simple!Foo1+0x31 [C:\Labfiles\Module04\Simple\Simple.cpp @ 65]
0012ff64 00401096 00000001 00000002 00000002 Simple!Foo+0x2d [C:\Labfiles\Module04\Simple\Simple.cpp @ 49]
0012ff80 00404739 00000001 00420e90 00420de0 Simple!main+0x36 [C:\Labfiles\Module04\Simple\Simple.cpp @ 33]
0012ffc0 7c817077 43010000 00000000 7ffde000 Simple!mainCRTStartup+0xe9 [crt0.c @ 206]
WARNING: Stack unwind information not available. Following frames may be wrong.
0012fff0 00000000 00404650 00000000 78746341 kernel32!RegisterWaitForInputIdle+0x49

 

利用EBP确定局部变量

==============

局部变量的地址是按照与EBP的距离由近到远,从第一个往后分配地址的。

所以,第一个局部变量的位置是ebp-4,第二个是ebp-8.

由于有些局部变量在函数中非常的常用,所以有时局部变量不一定会被压入栈中,而在寄存器中。所以,确定局部变量有可能需要去查看汇编代码,来看变量时从哪里来的,如何移动的,以及如何改变的。

 

总结一下

项目 根据EBP的计算公式
当前函数栈底的位置 EBP
上一个函数栈底位置 [EBP]
当前函数的返回地址 EBP+4
第一个局部变量 EBP-4
第二个局部变量 EBP-0x8
第三个局部变量 EBP-0xc
第一个参数 EBP+8
第二个参数 EBP+0xc

posted on 2009-11-06 11:01  中道学友  阅读(1682)  评论(0编辑  收藏  举报

导航

技术追求准确,态度积极向上