程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 請求執行時間段與Shell函數

請求執行時間段與Shell函數

編輯:匯編語言

請求執行時間段通常被簡稱為"appy time"。是指當系統VM穩定到充許VxDs和ring-3級別的應用軟件(特別是16-bit的應用軟件)交互時的時間段。例如,在一個特定時間段,VxDs能加載並調用在16-bit Dlls中的函數。這個appy time在Windows 3.x中是無效的。在Windows3.x,一個VxD能包含在16-bit DLLs中的任意函數的地址,並模擬一個遠調用到這個地址。然而,因為造成了VMM重入,這個操作將中斷所有正在ring-3中執行的任務。所以能被VxDs能調用的APIs被要求是中斷安全的,象PostMessage。在Windows 95,一個VxD在appy time的幫助下能調用任意一個在16-bit DLLs中的函數。

假如你的VxDs被通知正處在appy time,它就能加載16-bit DLLs並調用其中的函數。VxDs怎麼知道appy time到來了呢?這就要使用Shell VxD請求一個appy time。當系統VM在穩定狀態,Shell VxD將調用某VxD的一個回調函數,此函數是在VxD請求appy time時指定的。Shell VxD發生一次appy time事件僅僅調用一次你的回調函數。這就象找工作。你到職業介紹所,登記你的名字和電話號碼。當你回到家,如有一個工作適合你,職業介紹所將電話通知你這個好消息。當你收到了這個消息,他們就不再通知你了。

在一個appy time起作用前要花上一些時間進行相關處理。appy time事件以下環境中將不起作用:

1、系統啟動或關機時。

2、當系統VM在臨界段或等待一個信號量時。

管理一個appy time事件

你可以通過調用_SHELL_CallAtAppyTime來注冊一個appy time事件,它的定義如下:

VxDCall _SHELL_CallAtAppyTime, <<OFFSET32 pfnCallback>, dwRefData, dwFlags, dwTimeout>

pfnCallBack -- 當appy time事件發生時你要Shell VxD調用的回調函數的平板地址。這個函數接收兩個參數,dwRefData和dwFlags,與你傳送給_SHELL_CallAtAppyTime的兩個一樣。記住,Shell VxD采用C調用順序調用你的回調函數。總而言之,你要象這樣定義你的回調函數:
   BeginProc OnAppyTime, CCALL, PUBLIC

ArgVar dwRefData,DWORD ; declare argument name and type

ArgVar dwFlags, DWORD

EnterProc

你的代碼...

LeaveProc

Return

EndProc OnAppyTime

dwRefData -- 你要Shell VxD傳送給你的回調函數的參考數據。可以是你想要的任何東西。

dwFlags -- 事件標志。

如下值之一:

CAAFL_RING0 ring-0事件

CAAFL_TIMEOUT 由dwTimeout指定的時間到期事件。

假如你只想在一定的時間內等待appy time事件,使用CAAFL_TIMEOUT標志。如你想一直等待appy time事件,使用NULL。CAAFL_RING0作用不明。

dwTimeout -- 在appy time事件發生前,VxD能等待時間段長度。時間段的單位不明。

這個服務是異步的,意味著你為appy time事件注冊回調函數之後立即返回。

如果這個服務調用是成功的,在eax中返回appy time事件句柄。假如調用失敗,在eax返回0。

你可以調用_SHELL_CancelAppyTimeEvent來撤消appy time事件注冊,它僅有一個參數,就是由_SHELL_CallAtAppyTime返回的appy time事件句柄。

你應當在appy time事件到來時檢查系統。例如,當你在系統關閉時注冊appy time會發生什麼?你的VxD的回調函數將不會得到調用!當appy time事件到來時,你應當調用_SHELL_QueryAppyTimeAvailable來查詢系統狀態。這個服務沒有參數。如果appy time無效,在eax中返回0,例如:當系統關閉時或消息服務程序產生一個一般保護性錯誤時。

這個服務不會告訴你現在是不是appy time:它僅僅告訴你可能有一個appy time事件到來。簡而言之,如果你想安全運行,首先調用_SHELL_QueryAppyTimeAvailable並檢查eax中的值是否非零值,然後才可繼續調用_SHELL_CallAtAppyTime。

  當appy time到達時,你可以使用幾個Shell服務調用:

_SHELL_CallDll
_SHELL_FreeLibrary
_SHELL_GetProcAddress
_SHELL_LoadLibrary
_SHELL_LocalAllocEx
_SHELL_LocalFree

使用提供的這6個服務,VxDs可以調用在16-bit DLLs/EXE中的16-bit函數,象WinHelp。然而,我們馬上要進步到32-bit時代(未來是64-bit) ,所以我不會仔細研究它們。如你對此感興趣,你可以在Windows 95/98DDK文檔中了解它們。

另外一些只請求執行時間段服務我想更有用處:_SHELL_ShellExecute和 _SHELL_BroadcastSystemMessage。使用_SHELL_BroadcastSystemMessage,你能在一次調用中發送消息到頂端的窗口和所有的VxDs。如果appy time有效,你可以發送消息到窗口和VxDs。如果appy time無效,你只能發送消息到VxDs。

_SHELL_ShellExecute是在ring-3中的函數ShellExecute在ring-0中的對應函數。實際上,它調用ring-3中的ShellExecute完成這個工作。使用外殼服務,你可以運行/打開/打印任意文件。

_SHELL_ShellExecute的定義如下所示:

VxDCall _SHELL_ShellExecute,<OFFSET32 ShexPacket>

它僅有一個參數,SHEXPACKET結構的平板地址。它從ShellExecute函數中返回一個值到eax中。讓我們研究一下SHEXPACKET結構:

shex_dwTotalSize SHEXPACKET結構的字節數加上可選的參數rgchBaggage的大小,它直接跟隨在這個結構之後。我等一下描述rgchBaggage。

shex_dwTotalSize SHEXPACKET結構的字節數加上可選的參數rgchBaggage的大小,它直接跟隨在這個結構之後。我等一下描述rgchBaggage。

shex_dwSize SHEXPACKET結構的字節數,不包括rgchBaggage。結合上面的shex_dwTotalSize值,外殼VxD能計算任意長度的rgchBaggage的大小。

shex_ibOp 你要完成的操作。假如你指定0,意味著你想要打開一個文件。如果是一個可執行文件,就運行它。如果你想要完成其他的操作,你必須在rgchBaggage中指定操作的名字,在這個域中,必須包括從這個SHEXPACKET結構開始到一個ASCII字符串的距離,此距離大小以字節計數,字符串指定你要完成的操作的名稱。SHEXPACKET結構的大小是32字節。如果操作字符串緊跟在SHEXPACKET結構後,shex_ibOp中的值必須是32。要知道你可以完成的操作,請查看ShellExecute服務。有三個操作被定義,"open"、"print"和"explore"。

shex_ibFile 從此結構開始到一個ASCII字符串的距離,這個字符串是你想要傳遞給ShellExecute的文件名,就象Shex_ibOp成員。

shex_ibParams 你想傳遞到由shex_ibFile指定的文件的可選參數。假如此文件是一個文檔文件,你不想傳遞任何參數給它,就用0。假如你想傳遞參數給那個文件,在把從此結構開始到此成員指定的字符串的距離放在這個成員中。簡而言之,就象shex_ibOp和shex_ibFile成員。

shex_ibDir 工作目錄。假如你想使用Windows目錄就指定0,否則指定其為在此結構後的首選目錄名字符串,並把從此結構開始到目錄名字符串的距離值放到這個成員中。

shex_dwReserved 如其名字所指,它是保留的。不要理它。

shex_nCmdShow 應用程序窗口怎樣被顯示。這是一個你正常傳遞給ShowWindow的值,比如,SW_XXXX值。可在windows.inc中查看這些值。

所有成員的大小都是雙字的。在這裡我介紹剛才我承諾的rgchBaggage成員。僅有一點不同,因為其大小是可變的,所以它作為SHEXPACKET結構的一員卻不能包括在此結構的定義中。查看shell.inc,你看到rgchBaggage並不在SHEXPACKET結構的定義中,盡管在Windows 9x DDK文檔中,聲明其是SHEXPACKET結構的一員。
   rgchBaggage是什麼?簡單說來其是跟在SHEXPACKET結構後的一個字符串數組。在這個數組中,你可以把你要對文件完成的操作名稱、文件的名字、你要傳遞給文件的參數和工作目錄放在其中。首先得到從SHEXPACKET結構到這些字符串的第一個字符之間的距離(即此結構的一些成員值),再把這些值加上SHEXPACKET結構的平板編移量,Shell VxD就能得到這些字符串在rgchBaggage數組中的偏移量。例如,假如SHEXPACKET結構從60000h開始,字符串緊跟其後,結構與字符串之間的距離是結構本身的大小,32字節(20h)。所以Shell VxD知道字符串定位在60020h。

例子

這是一個顯示如何注冊一個appy time事件並且使用_SHELL_ShellExecute的例子。VxD是動態的,被一個簡單的Win32應用程序使用。當一個用戶按下"run Calculator"按紐,win32應用程序調用DeviceIoControl去要求VxD注冊一個appy time事件並且運行在Windows目錄中的calc.exe。


;---------------------------------------------------------------------------------
; VxD Source Code
;---------------------------------------------------------------------------------
.386p
include \masm\include\vmm.inc
include \masm\include\vwin32.inc
include \masm\include\shell.inc
VxDName TEXTEQU
ControlName TEXTEQU
VxDMajorVersion TEXTEQU <1>
VxDMinorVersion TEXTEQU <0>
VxD_STATIC_DATA_SEG
VxD_STATIC_DATA_ENDS
VXD_LOCKED_CODE_SEG
;----------------------------------------------------------------------------
; Remember: The name of the vxd MUST be uppercase else it won't work/unload
;----------------------------------------------------------------------------
DECLARE_VIRTUAL_DEVICE %VxDName,%VxDMajorVersion,%VxDMinorVersion, %ControlName,UNDEFINED_DEVICE_ID,UNDEFINED_INIT_ORDER
Begin_control_dispatch %VxDName
Control_Dispatch W32_DEVICEIOCONTROL, OnDeviceIoControl
End_control_dispatch %VxDName
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==1
VxDCall _SHELL_CallAtAppyTime,<,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,
LeaveProc
Return
EndProc OnAppyTime
VXD_PAGEABLE_CODE_ENDS
VXD_PAGEABLE_DATA_SEG
File SHEXPACKET <>
EXEName db "calc.exe",0
VXD_PAGEABLE_DATA_ENDS
end
   講解

VxD等待一個DeviceIoControl消息:第1號服務。當它收到上述消息,它將注冊一個appy time事件。

VxDCall _SHELL_CallAtAppyTime,<<OFFSET32 OnAppyTime>,0,0,0>

它將傳送OnAppyTime函數的平板地址到_SHELL_CallAtAppyTime,這樣,當appy time事件發生時,Shell VxD將調用它。因我們不需要使用任何參考數據並且不需要處理過期情況,所以緊跟OnAppyTime函數的三個參數都是0。

當appy time事件發生時, Shell VxD調用OnAppyTime函數。

BeginProc OnAppyTime, CCALL

我們用BeginProc描述一個函數。因為Shell VxD用C調用順序調用OnAppyTime,我們需要指定CCALL屬性。


ArgVar RefData,DWORD
ArgVar TheFlag,DWORD
EnterProc
...
LeaveProc
Return

因為Shell VxD用兩個參數調用OnAppyTime,我們必須設置堆棧結構。ArgVar宏用來調整每個要傳遞到函數的參數的堆棧結構。它的語法如下:

ArgVar varname, size, used

varname是參數的名字。你可以使用你喜歡的任意名字。size是參數的大小。你可以使用BYTE、WORD、DWORD或1,2,4。used通常被忽略。

緊接著ArgVar宏,我們需要使用EnterProc和LeaveProc宏來標志在程序中存放變量和參數的結構的開始與結束,使其能被正確訪問。使用Return宏返回到調用者。


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,

在這個程序中的指令是簡單的:初始化SHEXPACKET結構並且調用_SHELL_ShellExecute服務。記住 shex_dwTotalSize包含SHEXPACKET結構自身的和跟著它的字符串的組合大小。這是一個簡單的事情。假如字符串不緊跟在此結構之後的,你必須計算從結構第一個字節到到字符串最後一個字節之間的距離。shex_ibFile包含此結構自身的大小,因為程序名緊跟在此結構之後。shex_ibDir是0,意味著把Windows目錄作為工作目錄。這並不意味著程序必須在Windows目錄中。程序可以在Windows能找到的任意地方。


shex_nCmdShow是1,即SW_SHOWNORMAL的值。
File SHEXPACKET <>
EXEName db "calc.exe",0

我們定義一個SHEXPACKET結構,其後緊跟著想要運行的程序名。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved