罗云斌的书在Clock的五角星画时钟标记的地方卡住了,于是初衷是想试试一堆POINT如何初始化
和使用。没想到···学的不扎实,出了小错误竟然卡住了。就OD了一下。
简单说,就是eax和ax与格式说明符%d的匹配问题,刚开始纳闷,弄明白就觉得自己好白痴!
下面是源代码:
.386
.model flat, stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data?
lpPoint POINT 5 dup(<>)
szBuffer1 dd 1024 dup (?)
szBuffer2 dd 1024 dup (?)
szBuffer3 dd 1024 dup (?)
.data
szFmt db 'x = %d', 0dh, 0ah
db 'y = %d', 0
szCaption db 'Test', 0
.code
start:
xor eax, eax
xor ebx, ebx
mov lpPoint[0].x, byte ptr 2
mov lpPoint[0].y, byte ptr 2
mov ax, word ptr lpPoint[0].x
mov bx, word ptr lpPoint[0].y
invoke wsprintf,offset szBuffer1, offset szFmt, eax, ebx
xor eax, eax
xor ebx, ebx
mov lpPoint[1].x, byte ptr 3
mov lpPoint[1].y, byte ptr 3
mov ax, word ptr lpPoint[1].x
mov bx, word ptr lpPoint[1].y
invoke wsprintf,offset szBuffer2, offset szFmt, dword ptr ax, dword ptr bx
xor eax, eax
xor ebx, ebx
mov lpPoint[2].x, byte ptr 4
mov lpPoint[2].y, byte ptr 4
mov ax, word ptr lpPoint[2].x
mov bx, word ptr lpPoint[2].y
invoke wsprintf,offset szBuffer3, offset szFmt, eax, ebx
invoke MessageBox, NULL, offset szBuffer1, offset szCaption, MB_OK
invoke MessageBox, NULL, offset szBuffer2, offset szCaption, MB_OK
invoke MessageBox, NULL, offset szBuffer3, offset szCaption, MB_OK
end start
下边是反汇编的新手入门简单分析:
00401000 >xor eax, eax
00401002 xor ebx, ebx
00401004 mov dword ptr [403014], 2
0040100E mov dword ptr [403018], 2
00401018 mov ax, word ptr [403014]
0040101E mov bx, word ptr [403018]
00401025 push ebx ; /<%d>
00401026 push eax ; |<%d>
00401027 push 00403000 ; |Format = "x = %d",CR,LF,"y = %d"
0040102C push 0040303C ; |s = eaxANDax.0040303C
00401031 call <jmp.&user32.wsprintfA> ; \wsprintfA
00401036 add esp, 10
00401039 xor eax, eax
0040103B xor ebx, ebx
0040103D mov dword ptr [403015], 3
00401047 mov dword ptr [403019], 3
00401051 mov ax, word ptr [403015]
00401057 mov bx, word ptr [403019]
;问题就在这里
0040105E push 0 ; 这里0默认类型dword
00401060 push bx
00401062 push 0 ; /<%d> = 0
00401064 push ax ; |<%d>
00401066 push 00403000 ; |Format = "x = %d",CR,LF,"y = %d"
0040106B push 0040403C ; |s = eaxANDax.0040403C
00401070 call <jmp.&user32.wsprintfA> ; \wsprintfA
00401075 add esp, 10
00401078 xor eax, eax
0040107A xor ebx, ebx
0040107C mov dword ptr [403016], 4
00401086 mov dword ptr [40301A], 4
00401090 mov ax, word ptr [403016]
00401096 mov bx, word ptr [40301A]
0040109D push ebx ; /<%d>
0040109E push eax ; |<%d>
0040109F push 00403000 ; |Format = "x = %d",CR,LF,"y = %d"
004010A4 push 0040503C ; |s = eaxANDax.0040503C
004010A9 call <jmp.&user32.wsprintfA> ; \wsprintfA
;--------------------------------------------------------------------------------
这里,分析一下问题:
0040105E push 0 ; 这里0默认类型dword
00401060 push bx
00401062 push 0 ; /<%d> = 0
00401064 push ax ; |<%d>
1.这里的0默认类型是dword的双字类型,先入栈:
0012FFAA 00000000
(入门朋友注意:入栈时esp是向低地址移动)
2.然后push bx;这里bx是word类型,于是只是占2字节:(这里按照源程序给出的数据)
0012FFA8 00000003
0012FFAC 00000000
3.然后push 0 ;这里同第一步,入栈一个双字类型数据:
0012FFA4 00000000
0012FFA8 00000003
0012FFAC 00000000
4.然后push ax;同第二步,入栈一个字类型(2字节)数据:
0012FFA2 00000003
0012FFA6 00030000
0012FFAA 00000000
0012FFAE 00000000
最终x = %d, y = %d,其中%d从内存中取dword的数据,于是x = 00000003H, y = 00030000H
这样就产生了结果给出的y = 196608(也就是十六进制的30000)
注意地址的变化,对应的也就是变量的类型了。
附注:多动动脑子!刚碰到这个问题什么思路都没有,思路太窄!如果想到C里边%d输出的是int型数据,而int型在32位系统中就是32位的双字节,唉···只好告诫和我一样的入门者,多思考,别钻牛角尖,拓展思维。多动脑,长寿!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课