扬中做网站,网上销售 网站建设,网站建设费用自建,网站栏目规划叫什么在Windows内核中#xff0c;每个设备驱动程序都需要一个DRIVER_OBJECT对象#xff0c;该对象由系统创建并传递给驱动程序的DriverEntry函数。驱动程序使用此对象来注册与设备对象和其他系统对象的交互#xff0c;并在操作系统需要与驱动程序进行交互时使用此对象。DRIVER_OB…在Windows内核中每个设备驱动程序都需要一个DRIVER_OBJECT对象该对象由系统创建并传递给驱动程序的DriverEntry函数。驱动程序使用此对象来注册与设备对象和其他系统对象的交互并在操作系统需要与驱动程序进行交互时使用此对象。DRIVER_OBJECT对象还包含了与驱动程序所管理的设备对象相关联的设备扩展结构以及用于处理I/O请求的函数指针等信息。它是驱动程序与操作系统内核之间的桥梁用于协调设备的操作和管理。
本章将探索驱动程序开发的基础部分了解驱动对象DRIVER_OBJECT结构体的定义一般来说驱动程序DriverEntry入口处都会存在这样一个驱动对象该对象内所包含的就是当前所加载驱动自身的一些详细参数例如驱动大小驱动标志驱动名驱动节等等每一个驱动程序都会存在这样的一个结构首先来看一下微软对其的定义
typedef struct _DRIVER_OBJECT {CSHORT Type; // 驱动类型CSHORT Size; // 驱动大小PDEVICE_OBJECT DeviceObject; // 驱动对象ULONG Flags; // 驱动的标志PVOID DriverStart; // 驱动的起始位置ULONG DriverSize; // 驱动的大小PVOID DriverSection; // 指向驱动程序映像的内存区对象PDRIVER_EXTENSION DriverExtension; // 驱动的扩展空间UNICODE_STRING DriverName; // 驱动名字PUNICODE_STRING HardwareDatabase;PFAST_IO_DISPATCH FastIoDispatch;PDRIVER_INITIALIZE DriverInit;PDRIVER_STARTIO DriverStartIo;PDRIVER_UNLOAD DriverUnload; // 驱动对象的卸载地址PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION 1];
} DRIVER_OBJECT;那么如果我们想要遍历出当前自身驱动的一些基本信息我们只需要在驱动的头部解析_DRIVER_OBJECT即可得到全部的数据这段代码可以写成如下样子其中的IRP_MJ_这一系列则是微软的调用号不同的RIP代表着不同的涵义但一般驱动也就会用到如下这几种调用号。
#include ntifs.hVOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint((Uninstall Driver Is OK \n));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint(hello lyshark \n);Driver-DriverUnload UnDriver;DbgPrint(驱动名字 %wZ \n, Driver-DriverName);DbgPrint(驱动起始地址 %p | 大小 %x | 结束地址 %p \n,Driver-DriverStart,Driver-DriverSize,(ULONG64)Driver-DriverStart Driver-DriverSize);DbgPrint(卸载地址 %p\n, Driver-DriverUnload);DbgPrint(IRP_MJ_READ地址 %p\n, Driver-MajorFunction[IRP_MJ_READ]);DbgPrint(IRP_MJ_WRITE地址 %p\n, Driver-MajorFunction[IRP_MJ_WRITE]);DbgPrint(IRP_MJ_CREATE地址 %p\n, Driver-MajorFunction[IRP_MJ_CREATE]);DbgPrint(IRP_MJ_CLOSE地址 %p\n, Driver-MajorFunction[IRP_MJ_CLOSE]);DbgPrint(IRP_MJ_DEVICE_CONTROL地址 %p\n, Driver-MajorFunction[IRP_MJ_DEVICE_CONTROL]);// 输出完整的调用号for (auto i 0; i IRP_MJ_MAXIMUM_FUNCTION; i){DbgPrint(IRP_MJ调用号 %d | 函数地址 %p \r\n, i, Driver-MajorFunction[i]);}Driver-DriverUnload UnDriver;return STATUS_SUCCESS;
}编译这段程序签名并运行我们即可看到如下输出信息此时当前自身驱动的详细参数都可以被输出 当然运用_DRIVER_OBJECT对象中的DriverSection字段我们完全可以遍历输出当前系统下所有的驱动程序的具体信息DriverSection结构指向了一个_LDR_DATA_TABLE_ENTRY结构结构的微软定义如下
typedef struct _LDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;LIST_ENTRY InMemoryOrderLinks;LIST_ENTRY InInitializationOrderLinks;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT TlsIndex;union {LIST_ENTRY HashLinks;struct {PVOID SectionPointer;ULONG CheckSum;};};union {struct {ULONG TimeDateStamp;};struct {PVOID LoadedImports;};};
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;为了能够遍历出所有的系统驱动我们需要得到pLdr结构该结构可通过Driver-DriverSection的方式获取到获取到之后通过pLdr-InLoadOrderLinks.Flink得到当前驱动的入口地址而每一次调用pListEntry-Flink都将会指向下一个驱动对象通过不断地循环CONTAINING_RECORD解析即可输出当前系统内所有驱动的详细信息。这段程序的写法可以如下所示
#include ntifs.htypedef struct _LDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;LIST_ENTRY InMemoryOrderLinks;LIST_ENTRY InInitializationOrderLinks;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT TlsIndex;union {LIST_ENTRY HashLinks;struct {PVOID SectionPointer;ULONG CheckSum;};};union {struct {ULONG TimeDateStamp;};struct {PVOID LoadedImports;};};
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint((Uninstall Driver Is OK \n));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint(hello lyshark \n);Driver-DriverUnload UnDriver;PLDR_DATA_TABLE_ENTRY pLdr NULL;PLIST_ENTRY pListEntry NULL;PLIST_ENTRY pCurrentListEntry NULL;PLDR_DATA_TABLE_ENTRY pCurrentModule NULL;pLdr (PLDR_DATA_TABLE_ENTRY)Driver-DriverSection;pListEntry pLdr-InLoadOrderLinks.Flink;pCurrentListEntry pListEntry-Flink;// 判断是否结束while (pCurrentListEntry ! pListEntry){// 获取LDR_DATA_TABLE_ENTRY结构pCurrentModule CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);if (pCurrentModule-BaseDllName.Buffer ! 0){DbgPrint(模块名 %wZ | 模块基址 %p | 模块入口 %p | 模块时间戳 %d \n,pCurrentModule-BaseDllName,pCurrentModule-DllBase,pCurrentModule-EntryPoint,pCurrentModule-TimeDateStamp);}pCurrentListEntry pCurrentListEntry-Flink;}Driver-DriverUnload UnDriver;return STATUS_SUCCESS;
}编译这段程序签名并运行我们即可看到如下输出信息此时当前自身驱动的详细参数都可以被输出 通过使用上一篇文章《内核字符串拷贝与比较》中所介绍的的RtlCompareUnicodeString函数还可用于对比与过滤特定结果以此来实现通过驱动名返回驱动基址的功能。
LONGLONG GetModuleBaseByName(PDRIVER_OBJECT pDriverObj, UNICODE_STRING ModuleName)
{PLDR_DATA_TABLE_ENTRY pLdr NULL;PLIST_ENTRY pListEntry NULL;PLIST_ENTRY pCurrentListEntry NULL;PLDR_DATA_TABLE_ENTRY pCurrentModule NULL;pLdr (PLDR_DATA_TABLE_ENTRY)pDriverObj-DriverSection;pListEntry pLdr-InLoadOrderLinks.Flink;pCurrentListEntry pListEntry-Flink;while (pCurrentListEntry ! pListEntry){// 获取LDR_DATA_TABLE_ENTRY结构pCurrentModule CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);if (pCurrentModule-BaseDllName.Buffer ! 0){// 对比模块名if (RtlCompareUnicodeString(pCurrentModule-BaseDllName, ModuleName, TRUE) 0){return (LONGLONG)pCurrentModule-DllBase;}}pCurrentListEntry pCurrentListEntry-Flink;}return 0;
}上这段代码的使用也非常简单通过传入一个UNICODE_STRING类型的模块名即可获取到模块基址并返回至于如何初始化UNICODE_STRING则在《内核字符串转换方法》中有详细的介绍此处你只需要这样来写。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint(hello lyshark \n);UNICODE_STRING unicode;// 获取WinDDK驱动基地址RtlUnicodeStringInit(unicode, LWinDDK.sys);LONGLONG winddk_address GetModuleBaseByName(Driver, unicode);DbgPrint(WinDDK模块基址 %p \n, winddk_address);// 获取ACPI驱动基地址RtlUnicodeStringInit(unicode, LACPI.sys);LONGLONG acpi_address GetModuleBaseByName(Driver, unicode);DbgPrint(ACPI模块基址 %p \n, acpi_address);Driver-DriverUnload UnDriver;return STATUS_SUCCESS;
}运行这段驱动程序即可分别输出WinDDK.sys以及ACPI.sys两个驱动模块的基地址