📄 用masmplus学习win32汇编(4) .txt
字号:
用MasmPlus学习Win32汇编(4)
作者:Zoologist 于2007-11-16上传
--------------------------------------------------------------------------------
介绍一个工具 Spy++
上一期的最后,我卖了关子,没有告诉大家如何使知道记事本窗口的类。这一期我将揭晓谜底,就是 微软的 Spy++
这款软件是用来查看Windows消息窗口等等的利器,当然除此之外还有很多类似的工具,比如国产的软件 Spy4Win 等等。 MS Spy++ 是老牌工具,并且也是其他软件模仿的对象,学会它一通百通,下面我将介绍这个软件。
启动之后,软件界面如下:
上面列出了当前系统中的全部窗口信息。
比如,当前我打开了一个“记事本程序”,在列出的信息中就能看到:
双击会弹出它的属性
我们可以清楚地看到这个窗口的各种信息。
更多的操作可以参考它的帮助文件(中文的哦~)下面介绍查看一个窗口更简单的方法:
选择“监视”下面的“日志消息”
拖动瞄准镜到你要查看的窗口上:
就可以显示出来关于这个窗口的信息:
在这里我们可以选择可以监视的“消息”,当有消息发送给我们监视的窗口时,
Spy++会自动记录下来。点确定之后,就开始了监视,你可以随便监视一下NotePad。
上面就是看到的潮水一般的各种消息。
点这个位置,在开始/暂停之间切换。
消息太多了,我们必须过滤一下,留下我们需要的。比如,我们只想监视菜单的消息。在“消息”页面选择 WM_COMMAND就够了。
确定之后,我们在NotePad 上选 “关于”,再查看监听到的消息:
可以知道发送65弹出关于等等。之后,我们用下面的语句替换上一期程序中自动存盘的命令,就会让NotePad定期弹出关于窗口。
invoke SendMessage,EAX,WM_COMMAND,65,0
有了Spy++, 我们就可以充分发挥自己的好奇心,东看看西看看,看看我们平常经常使用的各种软件究竟是什么东西。就像第一次见到望远镜的孩子。
关于这个工具的工作原理,在参考[1]上有一点介绍。现在看不明白不要紧,慢慢玩下去。我也希望读者每一次看都有新的收获。需要注意的是,如果你安装了杀毒软件,它们之间可能会有冲突,你在观测一些消息的时候也许会有一些差别,另外,可能导致CPU占用率居高不下。因此在使用的时候最好关闭之。
涂鸦之作
一个伟人曾经说过“当你手中只有一把榔头的时候,世界上的一切问题都是钉子”。在上一期,我们学习了一点如何绘图,下面就用这些知识做点乱写乱画的事情。在此之前,还要再学一点东西,免得每次只能写“大王八”三个字,太没有创意了(忽然发现这三个字非常简单,故儿童常常使用,并且不容易错。如果中国作协的那个老头给人题这个字,想必也用不到贾平凹出来捧场)。
下面要玩的就是在NotePad上“写字”,不过不是打开敲进去的,而是画上去的。Windows是图形操作系统,它上面的程序一般都会有窗口,窗口上通常都会有一个叫做 DC的东西,至于具体是什么,后面会讲~ 反正您就记着,DC就好比广告牌面向马路的那个面,画点美女汽车都是在它上面。
除此之外,还要介绍一下创建“一种逻辑字体”。这个名字听起来非常专业,实际上就是设定一个我们需要的字体,给它一个编号(handle),然后我们作画的时候直接说“要XXX号的字体”(拿着handle给出去就可以了),就是这么简单。
HFONT CreateFont(
int nHeight, // 字体高度
int nWidth, // 平均宽度
int nEscapement, // 旋转角度
int nOrientation, // 每个字的倾斜度
int fnWeight, // 字体粗细
DWORD fdwItalic, // 要倾斜否
DWORD fdwUnderline, // 要下划线否
DWORD fdwStrikeOut, // 要删除线否
DWORD fdwCharSet, // 字符集
DWORD fdwOutputPrecision, // 输出精度。输出精度定义了输出与所要求的 //字体高度、宽度、字符方向等的接近程度。
DWORD fdwClipPrecision, //指定剪辑精度。剪辑精度定义了当字符的
//一部分超过剪辑区域时对字符的剪辑方式
DWORD fdwQuality, //输出质量,包括:
DEFAULT_QUALITY (默认质量)
DRAFT_QUALITY (草稿质量)
PROOF_QUALITY (正稿质量)
DWORD fdwPitchAndFamily, //指定字体的字符间距和族
LPCTSTR lpszFace //它指定的所用的字体名。
//如果lfFaceName为NULL,
//图形设备接口将使用默认的字体名。
);
另外一个函数就是 SelectObject ,意思是我要用什么什么作画。这个“什么什么”可以是某个画笔,某张粘贴画,或者某个字体
The SelectObject function selects an object into the specified device context (DC). The new object replaces the previous object of the same type.
HGDIOBJ SelectObject(
HDC hdc, // handle to DC
HGDIOBJ hgdiobj // handle to object
);
Parameters:
hdc
[in] Handle to the DC.
hgdiobj
[in] Handle to the object to be selected. The specified object must have been created by using one of the following functions.
程序如下:
;#Mode=CON
;在内存中查找“NotePad”,并且在上面写字
.586P
.MODEL Flat,StdCall
OPTION CASEMAP:NONE
INCLUDE WINDOWS.INC
INCLUDE KERNEL32.INC
INCLUDE USER32.INC
include masm32.inc
include gdi32.inc
INCLUDELIB KERNEL32.LIB
INCLUDELIB USER32.LIB
includelib masm32.lib
includelib gdi32.lib
include macro.asm
; -----------------------------------
; INPUT red, green & blue BYTE values
; OUTPUT DWORD COLORREF value in eax
; -----------------------------------
RGB MACRO red, green, blue ;输入RGB,合成一个32位值放在EAX中
xor eax, eax
mov ah, blue ; blue
mov al, green ; green
rol eax, 16
mov al, red ; red
ENDM
.DATA?
lpMsg MSG
TimerID dd ?
iCount dd ?
buffer db 100 dup(?)
hMine dd ? ;找到的NotePad的handle
hdc dd ? ;找到的NotePad的DC的Hand
hFont dd ? ;创建一种字体
.CODE
TimerProc proc
local cfRGB:COLORREF
local fnText:HGDIOBJ
invoke FindWindow,CTEXT('notepad'),NULL
.if (EAX==0)
invoke wsprintf,offset buffer,CTEXT("%d 没有找到记事本",10,13),iCount
invoke StdOut, offset buffer
inc iCount
ret
.endif
mov hMine,EAX ;保存NotePad的Handler
invoke GetDC,EAX ;取得 DC
mov hdc,EAX
invoke CreateFont,\
100,\
40,\
0,\
0,\
FW_BLACK,\
0,\
0,\
0,\
ANSI_CHARSET,\
OUT_DEFAULT_PRECIS,\
CLIP_CHARACTER_PRECIS,\
DEFAULT_QUALITY,\
DEFAULT_PITCH or FF_SWISS,\
CTEXT("宋体")
mov hFont,eax ;保存一下这种字体的handle
invoke SelectObject,hdc,hFont ;将这种字体设置给DC
RGB 200,200,50
invoke SetTextColor,hdc,eax ;准备好笔
RGB 0,0,255
invoke SetBkMode,hdc,eax ;准备好背景
invoke TextOut,hdc,50, 50,CTEXT('王朝到此一游'),12 ;写字啦
invoke DeleteObject,hFont ;释放字体
invoke ReleaseDC,hMine,hdc ;释放DC
invoke wsprintf,offset buffer,CTEXT("画一下",13,10),NULL
invoke StdOut, offset buffer
ret
TimerProc endp
Start:
invoke SetTimer, NULL, 0, 1000, addr TimerProc ;200ms一次,触发 TimerProc
mov TimerID,eax ;存一下,释放的时候还要用
.WHILE TRUE
invoke GetMessage, ADDR lpMsg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR lpMsg
invoke DispatchMessage, ADDR lpMsg
.ENDW
invoke KillTimer, NULL, TimerID ;释放定时器
;暂停显示,回车键关闭
invoke StdIn,addr buffer,sizeof buffer
invoke ExitProcess,0
END Start
程序的结构和上一期的没有什么差别,就是找Notepad-à找DC—〉准备字体—〉画,然后就收尾了。
特别需要注意的是CreateFont API中 如果使用 DWORD fdwCharSet, // 字符集 设置为ANSI_CHARSET 是无法输出“华文新魏”这样的字体的,输出始终为“宋体”;如果希望输出其他字体,需要将这项设置为DEFAULT_CHARSET。
另外,告诉大家可以通过invoke GetDC,HWND_DESKTOP取得桌面的DC。我们就可以在屏幕上写字了,有兴趣的读者不妨实验一下。
参考:
[1] Visual C++ Team Blog
http://blogs.msdn.com/vcblog/archive/2007/01/16/spy-internals.aspx 关于SPY++ 内部工作机制的一点介绍
[2] Spy4Win http://www.ccrun.com/spy4win/
--------------------------------------------------------------------------------
<<<上一篇 欢迎访问AoGo汇编小站:http://www.aogosoft.com 下一篇>>>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -