dycc 发表于 2013-5-15 21:31:50

Enter和Leave指令(转)

  Leave指令相当于move esp,ebp和pop ebp。  Enter SRC1,SRC2 也不复杂,只是不了解的话动态调试起来会很晕,Enter作了下面的事。  push ebp  mov ebp,esp  现在栈顶上是上一个函数的基地址(就是上一个函数里的ebp,刚被压入;这个ebp很重要,习惯上进入一个子函数时,在call的时候自动压入call后面那条语句的epi,然后压入ebp来保存这个即将被改变的ebp值,然后把ebp指向当前的栈顶,这样调用这个函数领空里用到的所有本地局部变量用ebp就能找到了,所以这时ebp的值叫基址),用这个刚保存的基址,去栈的深处(也不深,也就是调用本函数的父函数的领空)把这个基址上SRC2-1个内容复制到栈顶往上的相同大小的空间里,最后再把ebp的值压上去。  上面这段话里莫名其妙的操作正好使用了SRC2那么大的栈空间。  sub esp,SRC1  就走了这四步,而除了第三步,剩下那三步大家都很熟悉(如果不熟这篇文章还不是你该看的时候)并且经常自己会写的。关键是这个第三步有什么用?  很多书上都叫第二参数是“嵌套层数”。Bingo,很正解。比如说主程序调用了proc1,而proc1调用了proc2,而proc2调用了proc3……总之突然procN要调用procM(当然N>M)中的一个局部变量,按照传统的调用子函数编写方法,这个访问实现起来简直无计可施。而如果你在proc1中用了个 enter SRC1,1 ,proc2中用了个 enter SRC1,2 ……这样就有个简单的方法了。假设procN中要被赋值的的变量是第一个,procM中要被读取的变量也是第一个,在要赋值时这样就可以:  mov eax, DWORD PTR   ;把procM的基地址暂存到eax里  push DWORD PTR   ;把按这个地址找到的procM中的变量入栈(草,寄存器不够使了)  pop DWORD PTR   ;出栈,把值赋给procN中的那个饥渴的变量。  思考一下吧,很简单。可见要使用enter必须保证要访问的那个proc到现在所处的proc之间的一系列proc都在开头用了enter。当然,当SRC2为零时就无所谓了,而且比自己写push ebp 和 mov ebp , esp省劲的多。这样在一系列的enter作用下,到了procN时,栈中最上面的一部分是procN的领空,而这个领空的内容是这样的(从下往上):返回procN-1(调用procN的proc)的地址(call是epi应有的内容);刚进入procN的ebp,即procN-1的基址;大小为SRC2*4的一段指针列表(指向前面各个用了enter的proc的基址),这段类表的原理就是递推的方法,其中SRC2*4-4的内容是从procN-1的领空中复制的,为了能让procN+1也能用enter创建一断指针列表,列表最上面也要压入指向procN自己基址的指针,虽然在procN中,这最后一个没什么用处;然后是依据SRC1开辟的本地局部变量区域。其实这个结构有个名字,堆栈桢,貌似《编译原理》里会学到这个概念。利用堆栈桢,就可以方便的访问之前嵌套了自己的各辈函数的本地局部变量。总之,要使用这个功能,必须保证一路上都用了enter,否则即使procN用了enter,在复制procN-1的指针段的时候复制的东西根本不是指针,而是,比如procN-1的本地局部变量什么的(因为procN-1根本没有这么一段指针表啊)。下面给段代码,可以动态调试一下便于理解    .486                              ; create 32 bit code
    .model flat, stdcall                ; 32 bit memory model
    option casemap :none                ; case sensitive


    .data


    .code
proc5 proc
enter 8,5
mov DWORD PTR ,54
mov eax,DWORD PTR
push DWORD PTR
pop DWORD PTR
;这里把第二个本地变量设为proc1的值
leave
ret
proc5 endp
proc4 proc
enter 4,4
mov DWORD PTR ,53
call proc5
leave
ret
proc4 endp
proc3 proc
enter 8,3
mov DWORD PTR ,52
mov eax,DWORD PTR
push DWORD PTR
pop DWORD PTR
;这里把第二个本地变量设为proc2的值
call proc4
leave
ret
proc3 endp
proc2 proc
enter 4,2
mov DWORD PTR ,51
call proc3
leave
ret
proc2 endp
proc1 proc
enter 4,1
mov DWORD PTR ,50
call proc2
leave
ret
proc1 endp
start:
call proc1
ret
end start


dycc 发表于 2013-5-15 21:32:52

淡定,淡定,淡定……

翱翔飛龍 发表于 2013-5-15 21:59:05

请问这二个指令的作用是什么?当编程时什么时候会用到?菜鸟求教!

cqk2980 发表于 2013-5-16 11:13:23

无回帖,不论坛,这才是人道。

dycc 发表于 2013-5-17 13:02:35

翱翔飛龍 发表于 2013-5-15 21:59 static/image/common/back.gif
请问这二个指令的作用是什么?当编程时什么时候会用到?菜鸟求教!

这个编程的时候基本用不到,一般在逆向的时候跟进call里面会看到,对堆栈的操作什么的,我也不太懂

dycc 发表于 2013-5-19 00:47:55

淡定,淡定,淡定……

dycc 发表于 2013-5-19 00:48:59

淡定,淡定,淡定……

dycc 发表于 2013-5-19 00:52:49

淡定,淡定,淡定……

dycc 发表于 2013-5-19 01:18:58

淡定,淡定,淡定……

dycc 发表于 2013-5-19 01:27:52

淡定,淡定,淡定……

dycc 发表于 2013-5-19 01:28:55

淡定,淡定,淡定……

dycc 发表于 2013-5-19 01:29:59

楼主加油,鱼C加油!我们都看好你哦!

dycc 发表于 2013-5-19 01:31:10

楼主加油,鱼C加油!我们都看好你哦!

dycc 发表于 2013-5-19 01:32:52

楼主加油,鱼C加油!我们都看好你哦!

dycc 发表于 2013-5-19 01:33:55

楼主加油,鱼C加油!我们都看好你哦!

dycc 发表于 2013-5-19 01:36:23

淡定,淡定,淡定……

dycc 发表于 2013-5-19 01:37:24

淡定,淡定,淡定……

dycc 发表于 2013-5-19 01:38:27

淡定,淡定,淡定……

dycc 发表于 2013-5-19 01:39:34

淡定,淡定,淡定……

dycc 发表于 2013-5-19 15:20:40

楼主加油,鱼C加油!我们都看好你哦!
页: [1] 2
查看完整版本: Enter和Leave指令(转)