Appy Time(應用程式執行時間)是 Windows 9x VxD 在系統穩定狀態下,安全呼叫 16 位 DLL/EXE 函數(如 WinHelp、ShellExecute)的關鍵機制。本文完整解析 _SHELL_CallAtAppyTime 註冊流程、回呼函數建構、_SHELL_ShellExecute 參數封裝、SHEXPACKET 結構與 rgchBaggage 變長資料區,並提供動態 VxD 啟動計算機完整範例。
VxDCall _SHELL_CallAtAppyTime, <<OFFSET32 pfnCallback>, dwRefData, dwFlags, dwTimeout>
| 參數 | 說明 |
|---|---|
pfnCallback | 回呼函數平坦位址 (CCALL 慣例),接收 dwRefData, dwFlags |
dwRefData | 使用者自訂參考資料,原樣傳給回呼 |
dwFlags | CAAFL_RING0 (Ring-0 事件)、CAAFL_TIMEOUT (逾時觸發) |
dwTimeout | 逾時計數 (單位未文件化,約系統時鐘節拍),0/NULL = 無限等待 |
EAX ≠ 0:事件控制代碼 (供 _SHELL_CancelAppyTimeEvent 取消)EAX = 0:註冊失敗VxD_PAGEABLE_CODE_SEG
BeginProc OnAppyTime, CCALL
ArgVar RefData, DWORD
ArgVar TheFlag, DWORD
EnterProc
; 此處安全呼叫 Shell 服務
LeaveProc
Return
EndProc OnAppyTime
VxD_PAGEABLE_CODE_ENDS
CCALL:C 呼叫慣例 (參數由呼叫者清理堆疊),Shell VxD 要求。ArgVar/EnterProc/LeaveProc/Return:自動建構/銷毀堆疊框架。_SHELL_CallDll、_SHELL_FreeLibrary、_SHELL_GetProcAddress、_SHELL_LoadLibrary:16-bit DLL 操作_SHELL_LocalAllocEx、_SHELL_LocalFree:16-bit 堆疊記憶體_SHELL_BroadcastSystemMessage:單次呼叫送訊息給頂層視窗與所有 VxD_SHELL_ShellExecute:Ring-0 版 ShellExecute,啟動/開啟/列印任意檔案VxDCall _SHELL_QueryAppyTimeAvailable
; EAX ≠ 0 → 可能有 Appy Time 到來
; EAX = 0 → 系統關機、GP Fault 等,不可註冊
建議流程:QueryAppyTimeAvailable → 檢查 EAX → CallAtAppyTime。
shex_dwTotalSize DD ? ; 結構大小 + rgchBaggage 大小
shex_dwSize DD ? ; 結構大小 (固定 32 位元組)
shex_ibOp DD ? ; 操作字串偏移 (0=預設"open"),相對結構起始
shex_ibFile DD ? ; 檔名字串偏移
shex_ibParams DD ? ; 參數字串偏移 (0=無)
shex_ibDir DD ? ; 工作目錄偏移 (0=Windows 目錄)
shex_dwReserved DD ? ; 保留
shex_nCmdShow DD ? ; 顯示模式 (SW_SHOWNORMAL=1 等)
; 緊接著 rgchBaggage: 操作、檔名、參數、目錄字串陣列
字串位址 = 結構位址 + shex_ibXxx。60000h,檔名在結構後 → shex_ibFile = 20h,Shell 讀取 60020h。.386p
include vmm.inc
include vwin32.inc
include shell.inc
DECLARE_VIRTUAL_DEVICE CALCLOAD, 1, 0, CALCLOAD_Control, \
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
Begin_Control_Dispatch CALCLOAD
Control_Dispatch W32_DeviceIoControl, OnDeviceIoControl
End_Control_Dispatch CALCLOAD
VXD_LOCKED_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode == 1
VxDCall _SHELL_CallAtAppyTime, <<OFFSET32 OnAppyTime>, 0, 0, 0
.endif
xor eax, eax
ret
EndProc OnDeviceIoControl
VXD_LOCKED_CODE_ENDS
VXD_PAGEABLE_CODE_SEG
BeginProc OnAppyTime, CCALL
ArgVar RefData, DWORD
ArgVar TheFlag, DWORD
EnterProc
mov File.shex_dwTotalSize, sizeof SHEXPACKET
add File.shex_dwTotalSize, sizeof EXEName
mov File.shex_dwSize, sizeof SHEXPACKET
mov File.shex_ibOp, 0
mov File.shex_ibFile, sizeof SHEXPACKET
mov File.shex_ibParams, 0
mov File.shex_ibDir, 0
mov File.shex_dwReserved, 0
mov File.shex_nCmdShow, 1
VxDCall _SHELL_ShellExecute, <OFFSET32 File>
LeaveProc
Return
EndProc OnAppyTime
VXD_PAGEABLE_CODE_ENDS
VXD_PAGEABLE_DATA_SEG
File SHEXPACKET <>
EXEName db "calc.exe", 0
VXD_PAGEABLE_DATA_ENDS
end
DeviceIoControl 控制碼 1 觸發註冊 Appy Time。OnAppyTime 中初始化 SHEXPACKET:shex_ibFile = sizeof SHEXPACKET 指向緊隨的 "calc.exe"。shex_ibDir = 0 使用 Windows 目錄作為工作目錄 (非指定程式必須在該目錄)。shex_nCmdShow = 1 (SW_SHOWNORMAL)。_SHELL_ShellExecute 完成啟動。invoke CreateFile, addr VxDName, 0,0,0,0, FILE_FLAG_DELETE_ON_CLOSE, 0
.if eax != INVALID_HANDLE_VALUE
mov hVxD, eax
invoke DeviceIoControl, hVxD, 1, 0, 0, 0, 0, 0, 0
invoke CloseHandle, hVxD
.endif
Appy Time 機制解決了 VxD 安全呼叫 16-bit 代碼的核心難題。_SHELL_CallAtAppyTime 註冊回呼,_SHELL_ShellExecute 封裝 SHEXPACKET+rgchBaggage 實現檔案啟動,_SHELL_BroadcastSystemMessage 提供高效廣播。掌握這些服務,VxD 即可作為系統級代理執行使用者層面操作,是 Windows 9x 核心擴充的關鍵技術。