读取另一驱动

驱动通过"\\Driver\\XueTr"获取到了XueTr工具的驱动,并Hook了XueTr驱动的分发函数。

具体的驱动代码如下:

 //FilterDriver.c
//2016.07.15 #include "ntddk.h" NTKERNELAPI
NTSTATUS
ObReferenceObjectByName(
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE PassedAccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext OPTIONAL,
OUT PVOID *Object
); extern POBJECT_TYPE *IoDriverObjectType; //global
PDRIVER_OBJECT g_FilterDriverObject;
PDRIVER_DISPATCH gfn_OrigReadCompleteRoutine; //我们的驱动分发函数
NTSTATUS FilterReadCompleteRoutine(
__in struct _DEVICE_OBJECT *DeviceObject,
__inout struct _IRP *Irp)
{
KdPrint(("IRP_MJ_DEVICE_CONTROL coming.")); //处理完毕后,要调用原分发例程
return gfn_OrigReadCompleteRoutine(DeviceObject, Irp);
} //驱动卸载函数
VOID UnFilterDriverRoutine(__in struct _DRIVER_OBJECT *DriverObject)
{
//此内存可读时,恢复
if (MmIsAddressValid(gfn_OrigReadCompleteRoutine))
{
KdPrint(("UnFilterDriverRoutine Success.")); //卸载时恢复原分发例程
g_FilterDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = gfn_OrigReadCompleteRoutine;
}
} //过滤函数
NTSTATUS FilterDriverQuery()
{
NTSTATUS Status;
UNICODE_STRING usObjectName; RtlInitUnicodeString (&usObjectName, L"\\Driver\\XueTr"); //根据驱动名称获得驱动对象
Status = ObReferenceObjectByName (
&usObjectName,
OBJ_CASE_INSENSITIVE, //大小写不敏感
NULL,
, //访问权限,0是所有权限
*IoDriverObjectType,
KernelMode, //处理器模式
NULL,
(PVOID*)&g_FilterDriverObject
);
if (!NT_SUCCESS(Status))
{
KdPrint(("Filter Failed!"));
return Status;
} KdPrint(("0x%X", g_FilterDriverObject)); //打印驱动对象地址 //保存原分发例程,并修改为我们的函数
gfn_OrigReadCompleteRoutine = g_FilterDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
g_FilterDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)FilterReadCompleteRoutine; ObDereferenceObject(g_FilterDriverObject); //清除引用计数 return STATUS_SUCCESS;
} //驱动程序入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
pDriverObject->DriverUnload = UnFilterDriverRoutine;
FilterDriverQuery (); return STATUS_SUCCESS;
}

FilterDriver.c

其中,ObReferenceObjectByName函数能够根据驱动名获取到相应的驱动对象,函数原型如下:

 NTKERNELAPI
NTSTATUS
ObReferenceObjectByName(
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE PassedAccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext OPTIONAL,
OUT PVOID *Object
);

由于ObReferenceObjectByName函数没有文档化,但是被导出了。所以我们需要在代码中对ObReferenceObjectByName函数进行声明。

另外调用ObReferenceObjectByName函数后,要调用ObDereferenceObject来清除对象的引用计数,否则会造成内存泄漏。

根据XueTr获取到XueTr的驱动对象地址是0x84F79858,大小是0x00068000

根据WinObj工具获得XueTr驱动的路径为"\\Driver\\XueTr"

用InstDrv安装并启动驱动FilterDriver.sys后,DbgView输出0x84F79858,此地址与上面用XueTr查看的地址相同。说明获取到的XueTr驱动对象的地址是正确的。

在WinDbg输入以下命令查看XueTr驱动的详细信息:

dt _DRIVER_OBJECT -b 84F79858

WinDbg输出如下:

 lkd> dt_DRIVER_OBJECT -b 84F79858
nt!_DRIVER_OBJECT
+0x000 Type :
+0x002 Size :
+0x004 DeviceObject : 0x8617b100
+0x008 Flags : 0x12
+0x00c DriverStart : 0xed5ce000
+0x010 DriverSize : 0x68000
+0x014 DriverSection : 0x862e2220
+0x018 DriverExtension : 0x84f79900
+0x01c DriverName : _UNICODE_STRING "\Driver\XueTr"
+0x000 Length : 0x1a
+0x002 MaximumLength : 0x1a
+0x004 Buffer : 0xe1605358 "\Driver\XueTr"
+0x024 HardwareDatabase : 0x80691b90
+0x028 FastIoDispatch : (null)
+0x02c DriverInit : 0xed62b03e
+0x030 DriverStartIo : (null)
+0x034 DriverUnload : 0xed619668
+0x038 MajorFunction :
[] 0xed619792
[] 0x804fe101
[] 0xed619792
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0xf7c37000
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101
[] 0x804fe101

上面代码中修改的分发函数是IRP_MJ_DEVICE_CONTROL,也就是14号分发例程(0至27)

XueTr驱动的14号分发函数地址为0xf7c37000

由XueTr知道我们的驱动FilterDriver.sys基地址为0xF7C36000,大小为0x00006000。

所以XueTr驱动的14号分发函数地址(0xf7c37000)在我们的驱动内(0xF7C36000~0xF7C36000+0x00006000)

然后当我们在XueTr工具内刷新时,DbgView内输出

IRP_MJ_DEVICE_CONTROL coming.

遍历所有驱动

遍历所有驱动需要用到一个结构_LDR_DATA_TABLE_ENTRY,具体的驱动代码如下:

 //EnumDriver.c
//2016.07.17 #include <ntddk.h> typedef struct _LDR_DATA_TABLE_ENTRY{
LIST_ENTRY InLoadOrderLinks; //链表 保存了所有已经读取到内存中的驱动地址
LIST_ENTRY InMemoryOrderLinks; //链表 保存了已经安装,但没启动(没执行DriverEntry)的驱动地址
LIST_ENTRY InInitializationOrderLinks; //链表 保存了已经安装,同时也启动了(执行了DriverEntry)的驱动地址
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashLinks;
PVOID SectionPointer;
ULONG CheckSum;
ULONG TimeDateStamp;
PVOID LoadedImports;
PVOID EntryPointActivationContext;
PVOID PatchInformation;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; VOID MyDriverUnload(PDRIVER_OBJECT pDriverObject)
{
//
KdPrint(("Unload EnumDriver.sys Success."));
} VOID EnumDriver(PDRIVER_OBJECT pDriverObject)
{
PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry, pTempLdrDataTableEntry;
PLIST_ENTRY pList;
int i = ; pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
if (!MmIsAddressValid(pLdrDataTableEntry))
{
return;
} pList = &pLdrDataTableEntry->InLoadOrderLinks; while (pList != pLdrDataTableEntry->InLoadOrderLinks.Blink)
{
//ToDo
pTempLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pList;
i++; if(MmIsAddressValid(pTempLdrDataTableEntry))
{
if (MmIsAddressValid(&pTempLdrDataTableEntry->BaseDllName) && MmIsAddressValid(&pTempLdrDataTableEntry->BaseDllName))
KdPrint(("%d:%wZ\t%wZ", i, &pTempLdrDataTableEntry->BaseDllName, &pTempLdrDataTableEntry->FullDllName));
} pList = pList->Flink;
}
} NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
pDriverObject->DriverUnload = MyDriverUnload;
EnumDriver(pDriverObject); return STATUS_SUCCESS;
}

EnumDriver.c

用Windbg在XP虚拟机下查看该结构

lkd> dt_LDR_DATA_TABLE_ENTRY
nt!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY
+0x008 InMemoryOrderLinks : _LIST_ENTRY
+0x010 InInitializationOrderLinks : _LIST_ENTRY
+0x018 DllBase : Ptr32 Void
+0x01c EntryPoint : Ptr32 Void
+0x020 SizeOfImage : Uint4B
+0x024 FullDllName : _UNICODE_STRING
+0x02c BaseDllName : _UNICODE_STRING
+0x034 Flags : Uint4B
+0x038 LoadCount : Uint2B
+0x03a TlsIndex : Uint2B
+0x03c HashLinks : _LIST_ENTRY
+0x03c SectionPointer : Ptr32 Void
+0x040 CheckSum : Uint4B
+0x044 TimeDateStamp : Uint4B
+0x044 LoadedImports : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 Void
+0x04c PatchInformation : Ptr32 Void

因为结构_LDR_DATA_TABLE_ENTRY是未导出的,所以要在代码开头定义一下:

 typedef struct _LDR_DATA_TABLE_ENTRY{
LIST_ENTRY InLoadOrderLinks; //链表 保存了所有已经读取到内存中的驱动地址
LIST_ENTRY InMemoryOrderLinks; //链表 保存了已经安装,但没启动(没执行DriverEntry)的驱动地址
LIST_ENTRY InInitializationOrderLinks; //链表 保存了已经安装,同时也启动了(执行了DriverEntry)的驱动地址
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashLinks;
PVOID SectionPointer;
ULONG CheckSum;
ULONG TimeDateStamp;
PVOID LoadedImports;
PVOID EntryPointActivationContext;
PVOID PatchInformation;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
InLoadOrderLinks是一个双向的循环链表,保存了所有驱动的地址。我们只要遍历它,就能够找到所有的驱动了。
FullDllName是驱动的完整路径(路径+名称),BaseDllName是驱动的名称(不包含路径)

驱动加载后的输出如下:

其中的第二个 2:(null)(null)是XueTr的驱动,应该是做了特殊处理

梦织未来Windows驱动编程 第05课 小结(读取另一驱动,遍历所有驱动)的更多相关文章

  1. 梦织未来Windows驱动编程 第03课 驱动的编程规范

    最近根据梦织未来论坛的驱动教程学习了一下Windows下的驱动编程,做个笔记备忘.这是第03课<驱动的编程规范>. 驱动部分包括基本的驱动卸载函数.驱动打开关闭读取写入操作最简单的分发例程 ...

  2. 梦织未来Windows驱动编程 第06课 驱动对磁盘文件的操作

    代码部分: 实现一个文件C:\\text.txt,并读取写入内容到文件,然后将文件设置为只读,并隐藏文件.代码如下: //MyCreateFile.c //2016.07.22 #include &l ...

  3. 梦织未来Windows驱动编程 第04课 驱动相关的数据结构

  4. Windows游戏编程之从零开始d

    Windows游戏编程之从零开始d I'm back~~恩,几个月不见,大家还好吗? 这段时间真的好多童鞋在博客里留言说或者发邮件说浅墨你回来继续更新博客吧. woxiangnifrr童鞋说每天都在来 ...

  5. (转)Windows驱动编程基础教程

    版权声明     本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括 ...

  6. 《天书夜读:从汇编语言到windows内核编程》五 WDM驱动开发环境搭建

    (原书)所有内核空间共享,DriverEntery是内核程序入口,在内核程序被加载时,这个函数被调用,加载入的进程为system进程,xp下它的pid是4.内核程序的编写有一定的规则: 不能调用win ...

  7. 《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求

    1)跳入到基础篇的内核编程第7章,驱动入口函数DriverEnter的返回值决定驱动程序是否加载成功,当打算反汇编阅读驱动内核程序时,可寻找该位置. 2)DRIVER_OBJECT下的派遣函数(分发函 ...

  8. 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D中的顶点缓存和索引缓存

    第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物 ...

  9. storysnail的Windows串口编程笔记

    storysnail的Windows串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据 ...

随机推荐

  1. redis系列:通过通讯录案例学习hash命令

    前言 这一篇文章将讲述Redis中的hash类型命令,同样也是通过demo来讲述,其他部分这里就不在赘述了. 项目Github地址:https://github.com/rainbowda/learn ...

  2. 微信H5支付----报undened index openid

    1.检查传过来的订单号是否是恒定不变的 2.检查总价是否为整数(微信要求订单金额是整数).以及不能为0 以下是这次错误的具体原因: 主要是前面读取的金额数据需要读取接口的,而不是数据库的(接口读取的是 ...

  3. 【Python之os模块】使用

    目录 1. os.path 2. os.work   主要介绍在平时遇到的os模块的使用方法: 1. os.path 1.1 os.path.sep # 系统路径分隔符 # ============= ...

  4. 手写堆的dijkstra

    颓废.. #include <cstdio> #include <cstring> #include <algorithm> using namespace std ...

  5. git 把文件从 版本管理中移除 andorid版本

    刚学git时,一股脑吧所有文件全部加到版本管理中,现在做Android开发,这样做就有很大的问题了,gen  和bin  文件夹下的文件是编译生成的,最好不要加到版本管理中,最好加入到.gitigno ...

  6. [转] ios打包IPA的各种问题和解决方法

    最近做了一个东西,在打包ipa文件时遇到了各种问题,纠结了我好几天. 由于我一直是做android的,在打包时以为ios打包也和android一样:用IDE(eclipse)生成一个签名证书,然后打包 ...

  7. scrapy框架爬取蜂鸟网的人像图片

    今天有点无聊,本来打算去蜂鸟网爬点图片存起来显得自己有点内涵,但是当我点开人像的时候就被里面的小姐姐所吸引了,下面就是整个爬图片的思路和过程了 第一步:先创建一个爬虫项目 scrapy startpr ...

  8. 洛谷P2826 LJJ的数学课

    题目背景 题目描述(本题是提高组第二题难度+) 题目描述 \(LJJ\)又要开始上数学课啦!(\(T1\),永恒不变的数学) \(LJJ\)的\(Teacher\)对上次的考试很不满意(其实是出题人对 ...

  9. 如何在手机项目中使用rem单位

    rem这是个低调的css单位,近一两年开始崭露头角,有许多同学对rem的评价不一,有的在尝试使用,有的在使用过程中遇到坑就弃用了.但是我对rem综合评价是用来做web app它绝对是最合适的人选之一. ...

  10. 对sass通过compass进行编译

    1.创建一个Compass项目:compass create myproject 其中myproject是项目名称.2.编写scss文件.3.编译成css文件:①:Compass的编译命令是:comp ...