文章作者:Asm
信息来源:邪恶八进制信息安全团队(
http://www.eviloctal.com/)
最近在回顾一下经典的汇编入门程序 "hello word"的时候,由于忘记了一个传递的参数,程序提示:“你的程序遇到问题需要关闭”:
来看一下错误的代码:
复制内容到剪贴板
代码:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szCaption db '恭喜',0
szText db 'hello word',0
.code
start:
invoke MessageBox,NULL,offset szText,szCaption,MB_OK
invoke ExitProcess,NULL
end start 很显然,在利用伪指令调用MessageBox的时候,忘记了一个offset,正确的应该是:
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK.
估计是什么寄存器传递时候的错误,现在我们来分析一下。
先看反汇编正确程序看看机器码:
复制内容到剪贴板
代码:
push 00401000 ;push MB_OK 由先进后出的顺序压栈
push 00401002 ;push offset szCaption
push 00401007 ;push offset szText
push 0040100C ;push NULL
call 0040100E ;MessageBox
push 00401013 ;NULL
call 00401012 ;ExitProcess 正确的是将内存地址为00401002H,也就是szCaption在内存中的地址压栈,这样的话才能够正确执行。那么错误的代码程序,反汇编后会是怎么样的?
复制内容到剪贴板
代码:
push 00401000 ;push MB_OK
push 00401002 ;NULL
mov al,byte ptr [00403000]
movzx ax,al
push ax
push 0040100F ;push szText
push 00401004 ;push NULL
call 00401016 ;MessageBox
push 0040100B ;NULL
call 0040101D ;ExitProcess 问题出在这里,mov al,byte ptr [00403000],这句的意思是,把内存地址为00403000的变量地址强制转换成一个8位的字节,保存在al,然后讲8位的al扩展成16位,在执行push ax压栈操作。实际上就等于了DS:[00403000],那么[00403000]的实际地址是多少?在直接寻址方式中,例如 mov ax,[2000h],和mov ax,2000h是不一样的,后者直接把2000h赋给ax,前者是讲2000h的物理地址,也就是 物理地址=(DS)*16D+有效地址存到ax,[2000h]只是一个有效地址,假设DS=3000H,执行后,AX=16D*3000H+2000H=32000H,实际上,AX的值不是1000H了。现在很容易明白,mov al,byte ptr [00403000]后,要压入堆栈的内存地址,已经不是00403000,而是另有所指,具体位置可以这样算:al=(DS)*16D+00403000H 因为我们不知道DS的值,所以也就无法知道最后al等于多少.接着扩展了一下al成为ax,例如01H是al,扩展后,ax=0001H,所以我估计,mov al,byte ptr [00403000]后al只存着一个八位数的值,最终压栈的也就是一个16位的,这样,根据堆栈先进后出的原则,还原成汇编代码是:
复制内容到剪贴板
代码:
invoke MessageBox,NULL,offset szText,offset ax,NULL,MB_OK 根据MSDN中对MessageBox的声明,很显然,错在此咯..并且,ax也不可能直接成为一个参数,至少,在没有扩展movzx eax,ax之前,这样已经是一个明显的错误咯。
以上分析是本人愚见,如有错漏,请指出 [s:39]
PS:这个"hello word"隐藏在背后的东西真是不少呀 [s:37]