作者:amnesiac 首發(fā):官方論壇之中文版
導言:一些游戲在運行時能檢測并屏蔽腳本外掛骂因,原理是什么徘键?有什么辦法可以知道當前系統(tǒng)中開了多少腳本兑牡?包括使用默認托盤圖標央碟、自定義圖標甚至隱藏了托盤圖標的腳本。還有均函,能發(fā)現(xiàn)已編譯成可執(zhí)行文件的腳本嗎亿虽?是否能控制這些腳本?苞也?
檢測在運行的腳本
獲取系統(tǒng)中當前運行的所有 AutoHotkey 腳本的信息(下面的腳本獲取腳本標題和進程路徑):
DetectHiddenWindows, on
WinGet, AHKWinList, List, ahk_class AutoHotkey
Loop, %AHKWinList%
{
AHKWinHWND := AHKWinList%A_Index%
WinGetTitle, AHKWinTitle, ahk_id %AHKWinHWND%
WinGet, AHKWinProcessPath, ProcessPath, ahk_id %AHKWinHWND%
MsgBox, % "腳本標題:" AHKWinTitle "`n腳本進程路徑:" AHKWinProcessPath
}
return
由于可以獲取到窗口句柄洛勉,所以可以直接通過窗口命令獲取指定腳本的各種信息。其中腳本標題中包含了腳本文件名和執(zhí)行腳本的 AutoHotkey.exe 版本號如迟,例如:
D:\Software\AutoHotkey\Scripts\test.ahk - AutoHotkey v1.1.15.00
當然收毫,還可以使用其他方法。下面通過消息獲取某腳本的進程 ID:
AHKScriptName := "MyScript.ahk"
SetTitleMatchMode, 2
DetectHiddenWindows, on
SendMessage, 0x44, 0x405, 0, , %AHKScriptName% ahk_class AutoHotkey
MsgBox %ErrorLevel% is the process id.
想判斷哪些是未編譯腳本, 哪些是已編譯腳本, 請看下圖:

圖中顯示當前系統(tǒng)運行了兩個 AutoHotkey 腳本氓涣,我們對比這兩個腳本的窗口名稱:
- D:\Software\AutoHotkey\Scripts\test.ahk - AutoHotkey v1.1.15.00
- D:\Software\AutoHotkey\Scripts\test.exe
可以看出一個是未編譯腳本牛哺,一個是已編譯腳本陋气,因此可以根據窗口名判斷(其他信息也有差異)劳吠。注:從我使用這種方法開始到現(xiàn)在,窗口名稱的規(guī)律沒有發(fā)生變化巩趁,不過這里無法保證以后的所有版本都會遵從痒玩。
對這些腳本進行控制
在寫腳本時,我們都知道可以很方便的對當前腳本進行控制议慰,如:
Pause::Pause
^!s::Suspend
^!r::Reload
^+q::ExitApp
!l::ListLines
!v::ListVars
!k::KeyHistory
提示:我以前寫腳本時習慣加上許多這樣的熱鍵蠢古,包括暫停、重啟别凹、列出熱鍵草讶、列出執(zhí)行行、列出變量炉菲、顯示按鍵歷史等堕战,調試時很方便。那么拍霜,對其他腳本我們可以實現(xiàn)這些功能嗎嘱丢?
AHKScriptName := "MyScript.ahk"
DetectHiddenWindows On ; 才可以檢測到腳本的隱藏主窗口.
SetTitleMatchMode 2 ; 避免為下面的文件指定完整的路徑.
WM_COMMAND := 0x111
ID_FILE_PAUSE := 65403
ID_FILE_SUSPEND := 65404
PostMessage, WM_COMMAND, ID_FILE_PAUSE,,, %AHKScriptName% ahk_class AutoHotkey
PostMessage, WM_COMMAND, ID_FILE_SUSPEND,,, %AHKScriptName% ahk_class AutoHotkey
WinClose, %AHKScriptName% ahk_class AutoHotkey ; 關閉腳本,也可以使用消息祠饺,不過這里使用窗口命令可能直觀一些越驻。
; 下面兩個同樣是掛起和暫停的功能
PostMessage, 0x111, 65305,,, %AHKScriptName% ahk_class AutoHotkey ; 掛起
PostMessage, 0x111, 65306,,, %AHKScriptName% ahk_class AutoHotkey ; 暫停
注意:當前我不清楚如何判斷腳本當前處于哪種狀態(tài)(當前腳本可使用 A_IsSuspended、A_IsPaused)。
還有哪些可用的消息缀旁?我提供幾點思路供參考:
- 執(zhí)行操作時通過工具截取消息(消息很多记劈,這些屬于 WM_COMMAND)
- 直接到官方論壇詢問作者
我比較懶,下面是通過源代碼提取的一些消息號(可能不完整并巍,前面部分是消息號分配的說明):
0: unused (possibly special in some contexts)
1: IDOK
2: IDCANCEL
3 to 1002: GUI window control IDs (these IDs must be unique only within their parent, not across all GUI windows)
1003 to 65299: User Defined Menu IDs
65300 to 65399: Standard tray menu items.
65400 to 65534: main menu items
消息號 | 含義 |
---|---|
65300 | ID_TRAY_OPEN |
65400 | ID_FILE_RELOADSCRIPT, ID_TRAY_RELOADSCRIPT |
65401 | ID_FILE_EDITSCRIPT, ID_TRAY_EDITSCRIPT |
65402 | ID_FILE_WINDOWSPY, ID_TRAY_WINDOWSPY |
65403 | ID_FILE_PAUSE, ID_TRAY_PAUSE |
65404 | ID_FILE_SUSPEND, ID_TRAY_SUSPEND |
65405 | ID_FILE_EXIT, ID_TRAY_EXIT |
65406 | ID_VIEW_LINES |
65407 | ID_VIEW_VARIABLES |
65408 | ID_VIEW_HOTKEYS |
65409 | ID_VIEW_KEYHISTORY |
65410 | ID_VIEW_REFRESH |
65411 | ID_HELP_USERMANUAL, ID_TRAY_HELP |
65412 | ID_HELP_WEBSITE |
注:一般而言在更新版本時消息號的用途不太可能發(fā)生變化抠蚣,不過為了安全,在使用前最好明確其用途履澳,否則可能發(fā)生意外情況嘶窄。
實現(xiàn)的具體原理
在前面的腳本中我們應該注意到兩點:
- 開啟了對隱藏窗口的檢測
- 使用 AutoHotkey 類名獲取窗口
每個 AutoHotkey 運行時都有類名為 AutoHotkey 的主窗口(這個窗口為什么稱為主窗口?請參閱 A_ScriptHwnd)距贷,與是否創(chuàng)建自定義 GUI 窗口(自定義窗口的類名為 AutoHotkeyGUI)柄冲、是否隱藏托盤圖標、是否打開調試窗口(這里的調試窗口即是主窗口忠蝗,未打開時為隱藏狀態(tài))等無關现横。
說到這里,我想起了一個有趣的事情:為什么 AutoHotkey 被稱為模擬多線程呢阁最?從這里可以判斷出戒祠,每個腳本運行時至少有兩個線程:
- 主線程,運行主窗口速种,負責接受消息姜盈、緩沖熱鍵及偽線程的中斷和切換等
這里的描述可能不太準確和全面,不過大體上可以這么理解配阵,其中的偽線程是指幫助中所說的線程概念(例如 Thread 中所描述的線程馏颂,注意幫助中除了 A_ScriptHwnd 外從未涉及到主線程)。 - 腳本線程棋傍,實際執(zhí)行腳本的線程救拉,這不用多說了,它執(zhí)行的就是我們寫的腳本瘫拣。
從 Microsoft Spy++ 中可以看到亿絮,實際上每個腳本也只有兩個線程(你多開幾個熱鍵,多用幾個計時器并不會出現(xiàn)更多線程)麸拄。
小結
盡管未談到游戲派昧,不過主要內容前面都說完了。因此感帅,要檢測 AutoHotkey 腳本的外掛只需在腳本啟動及運行時定期執(zhí)行:
DetectHiddenWindows, on
While WinExist("ahk_class AutoHotkey")
WinKill
游戲不大可能用 AutoHotkey 寫斗锭,這里的演示大家能看懂它的用途吧?不過這種檢測方法只是我猜測的,對于如 AutoIt、按鍵精靈這樣的腳本語言應該具有一定的可行性(如果是 C 語言這種估計沒那么容易預防了)导而。正常的腳本如改鍵工具也無法例外了歹篓,有了解游戲開發(fā)的朋友能否能爆個真實情況葡粒。規(guī)避的方法也很簡單胁澳,自己下載源碼修改過類名編譯喔炕檩。
本文與游戲關系不大留攒,最開始的標題為腳本主窗口的妙用聪轿,不過這個標題是否更好呢爷肝?