前言

本文汇总五个重点,为了学起来更加方便我将他们按照递进关系重新排列。分别是:

函数、传参、ESP寻址、堆栈平衡、EBP寻址。

看完本文就能感受到我这么安排的用意。

环境

为了更加深入理解,先假设你接到了一项任务:用汇编语言实现一个两数相加求结果的功能,并且要多次使用。

函数

因为要多次使用该功能,所以我们要选择函数来解决。和c语言差不多,汇编的函数也是在一个“模块”中调用另一个“模块”。这只是笼统的介绍,下面演示一下实际操作:

构架模型

函数外部:

1、将第一个数存入寄存器;

2、将第二个数存入另一个寄存器;

函数内部:

3、将他们两个相加,返回值会覆盖第一个寄存器的数据。

4、将返回值复制到EAX寄存器(为了规范,返回值默认存入EAX)

编写代码:

1
2
3
4
5
6
7
8
CODE
MOV ECX,1 //第一个数存入ECX

MOV EDX,2 //第二个数存入EDX

ADD ECX,EDX //相加,返回值覆盖ECX

MOV EAX,ECX

F8单步执行,观察寄存器数值变化。

执行完结果应如图所示:

6wHYan.png

这里为了直观,进行了简写,将函数外部的赋值也加了进来,实际上只有3、4实在函数里的;

函数内部功能已经实现了,如果要调用这个函数使用CALL指令和JMP指令都可以,如果忘了这两个指令的区别,再去看一下我前面的博客。

1
2
CODE
CALL 271000

相必很多人都发现了,假如要求二十个数的计算式,但是寄存器就这么几个,这种方法肯定就不适用了。

我们采用的这种方式,叫做寄存器传参,当然也有堆栈传参;

堆栈传参

ESP寻址

上面已经介绍了寄存器传参,接下来针对堆栈传参进行学习;

跳过模型构建直接来看我写好的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
CODE
PUSH 1

PUSH 2

CALL 0027100D

call指向地址:

MOV EAX,DWORD PTR SS:[ESP+4] //当内存中括号中包含ESP或者EBP的话 用SS

ADD EAX,DWORD PTR SS:[ESP+8]
RET

运行结果如图所示,注意观察堆栈和寄存器:

60FG1e.png

上面所写的[ESP+4]等就是ESP寻址。

ESP的优点就是,使用起来很方便,很简单。但是缺点就是有时候会改变ESP的值,导致程序错误。

堆栈平衡

堆栈平衡:在函数执行前,堆栈应该是一致的,也就是说ESP的值是相同的。否 则会导致数据错误。

1、如果要返回父程序,则当我们在堆栈中进行堆栈操作的时候,一定要保证在RET这条指令之前,ESP指向的是我们压入栈中的地址。

2、如果通过堆栈传递参数了,那么在函数执行完毕后,要平衡参数导致的堆栈变化。

上一次提到堆栈平衡是在刚接触堆栈时,使用的MOV对堆栈操作,需要sub或者add来恢复ESP的值。之后引入了PUSH和POP指令以后,就默认堆栈平衡。

但是仔细看我们写出来的函数,F7单步执行观察可以发现执行完毕后压入堆栈中的1和3,也就是求和的两个数,还在里面。

60djaR.png

虽然不影响程序,但是会占用更多地空间,浪费资源,这对一个程序员来说是最不能忍受的。

第一个解决方法,使用add指令:

1
2
CODE
ADD ESP,8

同样,也可以使用RET返回父程序:

1
2
CODE
RET 8 //返回父程序,并且堆栈后退八位

使用EBP寻址就可以解决这个问题;

EBP寻址

1
2
3
4
5
6
7
8
9
10
11
CODE
PUSH 1
PUSH 2
CALL 0027100D
PUSH EBP
MOV EBP,ESP
SUB ESP,10 //提升堆栈
MOV EAX,DWORD PTR SS:[EBP+8] //通过EBP获得参数 参数位置 +4
ADD EAX,DWPRD PTR SS:[EBP+0xC]
MOV ESP,EBP
POP EBP //恢复堆栈

1、将EBP中的数据保存在ESP中,ESP向上移动。

2、这样我们就可以利用EBP进行寻址,从而避免了ESP数值收到影响。

3、结束时也要恢复EBP的值。

有些时候,我们不仅需要将数据压入栈中。比如在执行函数前我们需要对原有的寄存器数值进行备份。我还是示范一下吧,有一个坑,就是出栈要倒着来。

1
2
3
4
5
6
7
8
CODE
PUSH ECX
PUSH EDX
PUSH EBX
...................
POP EBX
POP EDX
POP ECX

滴水的汇编差不多就剩下最后的JCC指令了,这就是个打基础的过程,学着学着猛的发现现在软件的汇编代码我多少能看懂一点了,虽然一整块的汇编还是搞不清他到底干了什么,但是随着不断做题不断联系,这都是很容易达到的。