头文件sum.inc
include Irvine32.inc
MySample proto,
first:dword,second:dword,third:dword
ShowParams proto,
paramCounts:dword
ShowParams.asm
include sum.inc
paramCount = 3
.data
msg1 byte "Stack parameters:",0ah,0dh,0
msg2 byte "--------------------------",0ah,0dh,0
.code
MySample proc,
first:dword,second:dword,third:dword
invoke ShowParams,paramCount
ret
MySample endp
ShowParams proc uses ebp eax ebx ecx edx,
paramCounts:dword
push ebp
mov ebp,esp
mov ebx,3
mov ecx,ebx ;此处出现bug,调试的时候ecx的值发生自动变化
mov eax,1
mov edx,offset msg1
call WriteString
mov edx,offset msg2
call WriteString
mov esi,44
L:
;需要找出esp+44,esp+48,esp+52部分的数
;即内存中存放1234h,5000h,6543h的部位
;并且显示出来
mov eax,esp
add eax,esi ;显示ebx中的数据
call WriteHex
mov al,' '
call WriteChar
mov al,'='
call WriteChar
mov al,' '
call WriteChar
mov eax,[esp+esi]
call WriteHex
call Crlf
inc esi
inc esi
inc esi
inc esi
loop L
pop ebp
ret
ShowParams endp
end
addpacked.asm
include sum.inc
.data
.code
main proc
call Clrscr
invoke MySample,1234h,5000h,6543h
exit
main endp
end main
这个程序主要是将用函数向MySample传递三个值:1234h,5000h,6543h,通过多次调用后将1234h,5000h,6543h显示出来,在debug中发现程序出现问题
paramCount传入函数中的值应该为3
从这个截图也可以看出,在运行到push ebp的时候,paramCounts的参数也是0x00000003,
但是再往下面调试运行两步,运行到mov ecx,paramCounts之后
可以看出这里面的局部变量paramCounts的值已经发生了变化,paramCounts传入的值不是应该为3吗?为什么会发生变化?
观察内存中的内容可知
栈顶指针此时为010FFE20h的位置,由图中的内容可知
在0x010FFE20往后4B的位置的时候,显示的数据为0122 100a
也就是说局部变量默认从栈顶指针010FFE20h往后4B的位置开始读取数据,读取的数据为0x0122 100a栈顶压入的数据为ebp寄存器的内容(程序开始读取的时候有push ebp指令的内容),也就是说伪指令uses ebp eax ebx ecx edx会将ebp,eax,ebx,ecx,edx的内容压入寄存器之中,对于程序取出局部变量的操作产生影响
接下来我们去掉uses ebp eax ebx ecx edx对程序进行调试
运行到push ebp之前,查看内存中的数据
可以看出从地址0x001FF9B8开始的8B数据存放函数的返回地址(因为是x86 32位系统所以地址占用8B),后面的0000003h为传入函数的局部变量
接下来运行push ebp指令
然后继续运行
paramCounts改变数值
接下来将mov ebp,esp注释掉
单步调试后发现能够得到正确的结果
通过实验可得,在不使用伪指令uses的情况下,将push ebp指令和mov ebp,esp指令去除掉一条后即可正确运行,这是由于在使用指令mov ebp,esp指令时,系统自动从内存中读取栈顶指针esp-8的值赋给局部变量paramCounts,所以如果两条都使用的话,esp-8会指向错误的位置,导致局部变量paramCounts读取数据错误
结论
在执行mov ebp,esp时,程序告知操作系统栈会发生变化,从而程序认为栈内数据发生变化,此时程序会从内存中找寻局部变量,找寻的方法为越过8B的数据(局部变量)去找寻,
找寻到相应的局部变量对paramCounts进行赋值,所以paramCounts的数值会发生变化,解决的方法为提前先将寄存器压入栈中,将相应的局部变量赋值给寄存器后,再将栈顶指针esp的值赋值给寄存器
(push ebp与mov ebp,esp的操作任意一个放在
mov ecx,paramCounts后面执行都可以,如果将push ebp放在后面的话,还要注意函数不能使用uses的伪指令)