利用logger.vxd記錄VXD文件輸出

發表于:2007-07-14來源:作者:點擊數: 標簽:
北京2865信箱160分箱 冉林倉 1.引言: 在調試程序的時候,我們經常使用日志文件記錄調試文件的運行結果,跟蹤程序運行的流程。通過這個文件,即便在調試過程中間系統崩潰,我們也能夠從生成的日志文件中發現些可用信息。有的時候,這個日志文件的作用并不亞
北京2865信箱160分箱 冉林倉

1.引言:  
在調試程序的時候,我們經常使用日志文件記錄調試文件的運行結果,跟蹤程序運行的流程。通過這個文件,即便在調試過程中間系統崩潰,我們也能夠從生成的日志文件中發現些可用信息。有的時候,這個日志文件的作用并不亞于一個調試器。
在調試用戶態應用程序的時候,特別是那些與Com、外殼、鉤子函數打交道的動態鏈接庫的時候,程序員習慣使用WritePrivateProfileString函數或者WritePrivateProfileInt函數,把程序運行的反饋信息記錄到一個文本文件中;在調試wdm驅動程序的時候,編程人員也可以通過下列函數(ZwCreateFile、ZwWriteFile和ZwClose)找到替代方案。這些生成的日志文件,給程序的調試人員帶來了極大的方便。然而,在編寫VXD程序的時候,麻煩出現了,系統提供的VXD服務好像沒有一個能夠把日志信息輸出到文件中,即便VToolsD提供了一些文件IO函數(比如:i_open、i_close、i_write等等),這些函數也只能在VXD初始化階段才能被調用。一旦INIT_COMPLETE 消息被發送之后,這些函數將不能調用。文件系統鉤子服務的確可以解決這個問題,但是其煩瑣的編程讓驅動開發人員望而卻步。這樣,我們每次調試VXD程序的時候都不得不啟動一個調試器來觀察vxd輸出結果,這對我們驅動程序編程人員可以說是非常的不便。
其實Win 95和Win 98 系統都提供了一個名叫logger.vxd的文件,顧名思義,我們可以知道這個文件是生成日志記錄文件用的。遺憾的是,在微軟提供的DDK文檔中,對這個VXD提供的服務只字不提,本文正是在借鑒文獻(1)的基礎上的對這個VXD的輸出服務進行說明,以便任何一個VXD的編程人員都能使用logger.vxd記錄程序輸出。
2.實現的原理:
A).在VXD中調用VXD
就像RING3 的DLL以一個標準的方式供EXE和DLL使用其輸出函數一樣,VXD中的函數也可以被其它的VXD按某種方式調用,當生成VXD時,所有可以被其它VXD調用的函數都被列在一個數組中,每個這樣的函數也稱作一個服務(SERVICE)。當一個VXD調用另一個VXD中的功能時,并不使用服務的名字,而是使用它在數組中的索引號,下面就是一個典型的聲明:
Begin_Service_Table(LOGR0)
LOGR0_Service(LOGR0_Svc_GetVersion)
LOGR0_Service(LOGR0_Svc_PrintLog)
LOGR0_Service(LOGR0_Svc_CloseLog)
LOGR0_Service(LOGR0_Svc_OpenLog)
LOGR0_Service(LOGR0_Svc_FlushLog)
End_Service_Table
一個客戶端VXD對服務器端VXD的LOGR0_Svc_GetVersion調用將調用0號服務, LOGR0_Svc_PrintLog服務調用將使用1號服務,其它依次類推。
為了存取服務端VXD的一個輸出服務函數,客戶端的VXD在調用VXDCall或VXDJmp宏的時候,必須傳遞一個服務端VXD的設備ID標識,和它的一個輸出函數服務號。宏能夠把它擴展成一個INT 20H中斷,其后跟了一個雙字,并根據設備ID和服務號查找目標函數的地址。當目標函數找到后,INT 20H和其后的雙字就被CALL DWORD PTR [目標函數]所代替,它們恰好都是6個字節。有時這種機理也被稱為RING0的動態鏈接。
B).VXD輸出信息的獲得
察看VXD輸出服務需要Soft ICE 工具,通過輸入VXD LOGGER 可以看到有關這個VXD的信息。在這些信息中,其中最主要的信息是,它是否為一個可動態加載的VXD程序、它總共輸出了幾個VXD服務、它的設備ID號是什么。至于這些服務接口類型,就需要我們逆向工程進行反匯編來挖掘了,通過反匯編,我們至少從棧幀指針使用中了解參數的個數。接下來就要依靠我們平時積累的編程經驗來推測參數類型了。譬如,按照慣例,VXD的第一個服務必須為GetVersion,通過反匯編,我們會發現logger.vxd也不例外。文件打開、讀寫、關閉函數一般情況下經常需要一些文件名、文件句柄等參數信息,事實上logger.vxd的服務函數同標準的C函數調用十分類似。這和我們的猜想是吻合的。
C).logger.vxd的輸出函數
logger.vxd共有5個輸出服務,這5個輸出服務接口函數是:
DWORD LOGR0_GetVersion();
HANDLE LOGR0_OpenFile(const char * szFileName,DWORD BufferSize);
HANDLE LOGR0_CloseFile(HANDLE hFile);
void LOGR0_Printf(HANDLE hFile, const char *format,...);
DWORD LOGR0_Flush(HANDLE hFile);
3.logger.vxd的使用
在使用logger.vxd之前,客戶端的VXD必須調用LOGR0_GetVersion()來確認logger.vxd本身是否可用.由于logger.vxd是一個動態的VXD ,不會隨windows系統的啟動自動加載。當程序檢測到logger.vxd尚未加載時,先嘗試加載logger.vxd。加載完畢后,它本身并不需要卸載,這主要是因為,任何一個通過服務表輸出ring0服務的VXD程序,只要它的一個服務被客戶端VXD使用,它本身就不可卸載。
LOGR0_OpenFile將以寫、添加方式打開一個記錄文件,你可以為它指定一個完整路徑,否則它就產生在windows目錄中。這個文件將一直保持到調用LOGR0_CloseFile()為止。緩沖區的大小,你可以指定為零,logger.vxd會自動為你設定一個值,這個值在大多數情況情況下能夠滿足你的要求。注意你必須把記錄文件的大小控制在256k之內,超過這個尺寸,logger.vxd將不再記錄。
LOGR0_Printf函數類似于一個sprintf函數,只不過它把輸出結果定向到一個文件,而不是字符串,它需要一個文件句柄來標識你要寫的目標文件,這個句柄由LOGR0_OpenFile()返回值獲得。全部記錄完畢之后,你可以調用LOGR0_CloseFile()關閉文件。
LOGR0_Flush函數,強制保存在文件緩沖區的任何數據寫到文件中。
為了更方便地使用注冊函數,你除了可以直接使用上述函數之外,還可以使用程序封裝的CLogFile類。使用時你只要派生一個CLogFile類的事例,即可調用其trace成員函數,對象釋放時,析構函數會自動關閉日志文件。
Logger.vxd會自動地在你的VXD程序的記錄文件中添加日志信息,你不需要為每一行寫入的時間信息煞費苦心了。
logger.vxd 看起來像是基于IFSMgr_Ring0_FileIO創建,使用可安裝文件系統的優勢在于你不僅可以打開一個本地的記錄文件,還可以打開一個網絡驅動器的一個遠程文件,利用網絡,把它保存到另外一個遠程計算機上,這在你的本機文件由于某種原因不可存取時,特別有效。
下面是一段記錄的日志文件信息:
07-09-2001 15:54:41.61 - Opened ThreadMon Log
07-09-2001 15:54:44.22 - Thread D5A4DD74 got CREATED; -710615692 threads are being monitored
07-09-2001 15:54:44.22 - Thread D6715D74 got CREATED; -697213580 threads are being monitored
07-09-2001 15:54:45.31 - Thread D6715D74 got CREATED; -697213580 threads are being monitored
07-09-2001 15:54:45.33 - Thread D6719DDC got DESTROYED; it ran for -697197092 msec
07-09-2001 15:54:45.33 - Thread C0FA9D88 got DESTROYED; it ran for -1057317496 msec
07-09-2001 15:54:47.70 - Thread D5EA9DDC got DESTROYED; it ran for -706044452 msec
07-09-2001 15:54:50.82 - Closed ThreadMon Log
4.程序使用:
A)使用函數接口
1.包含logger.vxd 服務函數文件
#include  
2.聲明一個靜態文件柄
static HANDLE hLogFile;
3.在OnSysDynamicDeviceInit()中加入:
DWORD ver = LOGR0_GetVersion();
if (ver == 0)
return FALSE; // logger.vxd 不可用
hLogFile = LOGR0_OpenFile("文件名", NULL);
if (hLogFile == NULL)
return FALSE; //無法打開文件
LOGR0_Printf(hLogFile, "打開文件成功");
return TRUE;
4.在OnSysDynamicDeviceExit()函數過程中加入
if (hLogFile) {
LOGR0_Printf(hLogFile, "關閉記錄文件\n");
LOGR0_CloseFile(hLogFile);//保存文件
}  

5.在其它的消息處理函數中可以自由地使用LOGR0_Printf函數
LOGR0_Printf(hLogFile, " My Result is %d \n",Result);
B).使用CLogFile類舉例
1.聲明一個靜態全局變量
static CLogFile *pLogFile=NULL;
2.在OnSysDynamicDeviceInit()中加入:
pLogFile=new CLogFile("Test.ini",NULL);
if(!pLogFile->m_bActive)return FALSE;//logger.vxd加載不成功時
if(pLogFile->m_hFile==NULL) return FALSE;//文件打開不成功時
pLogFile->trace ( "Opened ThreadMon Log\n");
return TRUE;
3.在OnSysDynamicDeviceExit()函數過程中加入
pLogFile->trace ("Closed ThreadMon Log\n");
delete pLogFile;//釋放事例分配的內存,這時將調用析構函數,關閉打開文件
return TRUE;
4.在程序中使用pLogFile->trace 記錄日志信息。
5.補充說明
本程序在VISUAL C++6 Pwin98 環境下,用VtoolsD調試通過。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97