汇编语言局部变量bug探究

头文件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的伪指令)

发布了30 篇原创文章 · 获赞 9 · 访问量 3568

猜你喜欢

转载自blog.csdn.net/znevegiveup1/article/details/104142458