分享
 
 
 

利用logger.vxd记录VXD文件输出

王朝厨房·作者佚名  2007-01-04
窄屏简体版  字體: |||超大  

北京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,DWORDBufferSize);

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调试通过。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有