一丶认识全局的 (静态变量全局变量)
高级代码:
int RetInt() { int n = 0; scanf("%d",&n); return n; } static int g_Number = RetInt(); int main(int argc, char* argv[]) { g_Number = 3; scanf("%d",&g_Number); return g_Number; }
我们的静态局部变量 g_Number 会通过一个函数进行赋值初始化
VC6.0调试查看.
我们发现通过栈回朔会调用4个函数
调用顺序:
_cinit()
_initterm()
$E2()
#E1();
首先讲解一下, _cinit函数是初始化函数,其中里面有个_initterm用来初始化全局变量的(不管是静态的全局变量,还是局部的全局变量,还是全局变量)
E1() E2()函数,这里的两个函数涉及到一个设计的问题.要理解这个问题,我们看下调用_initterm里面是做的什么.
_initterm()
可以看到内部,函数指针遍历,建立了一个表来查询,然后调用这个函数指针.
这个函数指针就是E2() 为了保证参数一致,返回值一致,所以调用了E2函数,当做一个固定接口
那么E1函数就是具体做事情的
E2函数中查看E1函数调用:
所以说E2只是为了 _initterm的表的接口.
E1函数内部:
所以真正工作的函数是在E1内部,因为我们知道,在main函数之前定义全局变量,它会优先于main函数的开始进行初始化,怎么初始化的,就是通过_initerm遍历全局变量表,E2做接口,调用E1函数,进行初始化的.
上面属于Debug下的汇编
Release下的汇编
PS: Release下的汇编会做优化,有可能你看不到E2这个代理函数了.
找的方法同上,优先于main函数之前找_cinit 然后找到_initterm(注意有多个,不确定是哪个,可以看下入口点特征,前几讲已经说过)
然后看_initterm的参数,指向的是那个函数指针,我们跳过去即可.
IDA
所以有时我们会看到一个.
二丶认识局部静态变量
高级代码:
int main(int argc, char* argv[]) { static number = argc; scanf("%d",&number); return number; }
注意我是初始化给的变量,常量的话优化会直接优化了.很简单,不讲解.
Debug下的汇编代码
我们说过,静态局部变量,其实也是一个全局变量,只不过限制了作用域,但是限制的前提是什么,前提就是加标记,所以我们才会看到一个跳转.判断标记的.
识别局部变量和参数
这个很简单了,因为一直在用, 一般来说,局部变量都是使用ebp或者esp寻址, 如果碰到ebp-xxx,也就是减量的时候就是访问局部变量,如果变为增量的话就是寻找参数.
转载于:
作者:IBinary
出处:http://www.cnblogs.com/iBinary/