iczelion Vxd cntut7

請求執行時間段與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。

請求執行時間段Shell服務

當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等待一個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宏返回到調用者。


在這個程序中的指令是簡單的:初始化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結構,其後緊跟着想要運行的程序名。


 



 

翻譯:呂駿,整理:LuoYunBin's Win32 ASM Page, http://asm.yeah.net
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章