驱动断链的研究
准备
source insight
从现在开始我们正式进入内核编程,但是很多内核里面的结构和类型是需要我们额外声明的,我们就需要一个工具来快速的阅读WIn内核源码。这里我贴出我所参考的博客
羽夏看Win系统内核——SourceInsight 配置 WRK - 寂静的羽夏 - 博客园
就怕以后文章挂了,我还是走一遍流程
首先安装好sourceinsight之后,新建项目
WRK
WRK(windows Research Kernel ) 是微软公开的一部分
windows 内核源码,用来供给开发人员学习。
下载地址:http://www.awarenetwork.org/home/iqlord/other/wrk.rar
在上面的步骤后一路ok,直到下面,选择add Tree
然后关掉这个窗口,按f7导入符号表,这就完成了
理论准备
关于断链,我之前已经写过了文章
R3隐藏导入表_loader函数导入表隐藏-CSDN博客
在R3中有这么一个结构
3: kd> dt _PEB_LDR_DATA
nt!_PEB_LDR_DATA+0x000 Length : Uint4B+0x004 Initialized : UChar+0x008 SsHandle : Ptr64 Void+0x010 InLoadOrderModuleList : _LIST_ENTRY+0x020 InMemoryOrderModuleList : _LIST_ENTRY+0x030 InInitializationOrderModuleList : _LIST_ENTRY+0x040 EntryInProgress : Ptr64 Void+0x048 ShutdownInProgress : UChar+0x050 ShutdownThreadId : Ptr64 Void
我们复习一下,这个结构中的InLoadOrderModuleList,InMemoryOrderModuleList,InInitializationOrderModuleList都指向了一个双向链表,这个链表里面存储了我们模块信息,如果我们给链表里面的节点断链,那么就可以让其他软件在遍历链表的时候找不到我们的模块
现在在R0里面也是同理的,只是结构变成了,在WRK的ntldr.h这个头文件中,且由于没有PNON_PAGED_DEBUG_INFO的定义,所以还要补上一个。
typedef struct _KLDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;PVOID ExceptionTable;ULONG ExceptionTableSize;// ULONG padding on IA64PVOID GpValue;PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT __Unused5;PVOID SectionPointer;ULONG CheckSum;// ULONG padding on IA64PVOID LoadedImports;PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
typedef struct _NON_PAGED_DEBUG_INFO {USHORT Signature;USHORT Flags;ULONG Size;USHORT Machine;USHORT Characteristics;ULONG TimeDateStamp;ULONG CheckSum;ULONG SizeOfImage;ULONGLONG ImageBase;
} NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;
可以从上面的结构中看见R0中只保留了一个InLoadOrderLinks,但是思路也是一样的
代码实现
在知道了上面所提到的内核中的两个结构之后,我们首先要看下系统中的这个双向链表长什么样,这里用一个DbgBreakPoint来断下
#include<ntifs.h>
#include<ntstrsafe.h>//要用RtlStringCbPrintfA就别忘了这个库typedef struct _NON_PAGED_DEBUG_INFO {USHORT Signature;USHORT Flags;ULONG Size;USHORT Machine;USHORT Characteristics;ULONG TimeDateStamp;ULONG CheckSum;ULONG SizeOfImage;ULONGLONG ImageBase;
} NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;typedef struct _KLDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;PVOID ExceptionTable;ULONG ExceptionTableSize;// ULONG padding on IA64PVOID GpValue;PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT __Unused5;PVOID SectionPointer;ULONG CheckSum;// ULONG padding on IA64PVOID LoadedImports;PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("Driver has benn Unloaded");}
int count = 0;NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {//DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;DbgBreakPoint();pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
同时在windbg中指定新的符号路径,并使用.reload /f 命令重载符号表,这样我们的调试就方便多了
如果没有符号表,有些结构我们是没有办法展现出来的
首先来看看我们的pDriver这个结构
0: kd> dt pDriver
Local var @ 0x903289e0 Type _DRIVER_OBJECT*
0x8be44160 +0x000 Type : 0n4+0x002 Size : 0n168+0x004 DeviceObject : (null) +0x008 Flags : 2+0x00c DriverStart : 0x9709c000 Void+0x010 DriverSize : 0x6000+0x014 DriverSection : 0x8898b7b8 Void+0x018 DriverExtension : 0x8be44208 _DRIVER_EXTENSION+0x01c DriverName : _UNICODE_STRING "\Driver\MyDriver2"+0x024 HardwareDatabase : 0x841ab250 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM"+0x028 FastIoDispatch : (null) +0x02c DriverInit : 0x970a0000 long MyDriver2!GsDriverEntry+0+0x030 DriverStartIo : (null) +0x034 DriverUnload : (null) +0x038 MajorFunction : [28] 0x83ef4da3 long nt!IopInvalidDeviceRequest+0
着重关注两个值,DriverStart和DriverInit,分别是我们的模块基址和模块入口
之后我们根据之前得到的知识,pDriver中的DriverSection就是我们的_KLDR_DATA_TABLE_ENTRY结构存放的地址,我们在代码中把它转进变量ldr中,dt看一下,这里就可以看见DllBase和EntryPoint和我们的DriverStart和DriverInit相互对应
0: kd> dt ldr
Local var @ 0x903289d4 Type _KLDR_DATA_TABLE_ENTRY*
0x8898b7b8 +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x83f89850 - 0x889a4e98 ]//Flink和Blink+0x008 ExceptionTable : 0xffffffff Void+0x00c ExceptionTableSize : 0xffffffff+0x010 GpValue : 0x00000005 Void+0x014 NonPagedDebugInfo : (null) +0x018 DllBase : 0x9709c000 Void+0x01c EntryPoint : 0x970a0000 Void+0x020 SizeOfImage : 0x6000+0x024 FullDllName : _UNICODE_STRING "\??\C:\Users\su\Desktop\MyDriver2.sys"+0x02c BaseDllName : _UNICODE_STRING "MyDriver2.sys"+0x034 Flags : 0x49104000+0x038 LoadCount : 1+0x03a __Unused5 : 0+0x03c SectionPointer : (null) +0x040 CheckSum : 0xab05+0x044 LoadedImports : 0x0034f110 Void+0x048 PatchInformation : (null)
我们看见了第一个InLoadOrderLinks里面的双向链表,所以我们用它给的Flink来访问链表里面的下一个节点,由于我们的MyDriver2是最后一个加载的驱动,所以它的下一个也就是我们的第一个驱动,果不其然,是我们的内核
0: kd> dt PKLDR_DATA_TABLE_ENTRY 0x83f89850
MyDriver2!PKLDR_DATA_TABLE_ENTRY
0x86a4cc98 +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x86a4cc20 - 0x83f89850 ]+0x008 ExceptionTable : 0x83eb7544 Void+0x00c ExceptionTableSize : 0x12+0x010 GpValue : (null) +0x014 NonPagedDebugInfo : (null) +0x018 DllBase : 0x83e3f000 Void+0x01c EntryPoint : 0x83f5e4d8 Void+0x020 SizeOfImage : 0x412000+0x024 FullDllName : _UNICODE_STRING "\SystemRoot\system32\ntkrnlpa.exe"+0x02c BaseDllName : _UNICODE_STRING "ntoskrnl.exe"+0x034 Flags : 0x8004000+0x038 LoadCount : 0x6b+0x03a __Unused5 : 0+0x03c SectionPointer : (null) +0x040 CheckSum : 0x3c88ac+0x044 LoadedImports : (null) +0x048 PatchInformation : (null)
所以我们稍微修改一下我们的代码
#include<ntifs.h>
#include<ntstrsafe.h>//要用RtlStringCbPrintfA就别忘了这个库typedef struct _NON_PAGED_DEBUG_INFO {USHORT Signature;USHORT Flags;ULONG Size;USHORT Machine;USHORT Characteristics;ULONG TimeDateStamp;ULONG CheckSum;ULONG SizeOfImage;ULONGLONG ImageBase;
} NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;typedef struct _KLDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;PVOID ExceptionTable;ULONG ExceptionTableSize;// ULONG padding on IA64PVOID GpValue;PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT __Unused5;PVOID SectionPointer;ULONG CheckSum;// ULONG padding on IA64PVOID LoadedImports;PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("Driver has benn Unloaded");}
int count = 0;NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {//DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink;PKLDR_DATA_TABLE_ENTRY next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink;while (next != pre){DbgPrint("[%d] %wZ", count, &next->BaseDllName);next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;count++;} pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
这样重新编译之后,用DbgView可以看见我们确实遍历所有模块
那既然我们已经正确的找到这个双向链表了,剩下的事情就好办多了,使用我们之前驱动篇基础里面介绍过的API来初始化一个Unicode字符串,然后用这个字符串去对比某个目标模块,如果一致,就按照链表断链的方式将其从双向链表中删除,继续修改我们的代码
#include<ntifs.h>
#include<ntstrsafe.h>//要用RtlStringCbPrintfA就别忘了这个库typedef struct _NON_PAGED_DEBUG_INFO {USHORT Signature;USHORT Flags;ULONG Size;USHORT Machine;USHORT Characteristics;ULONG TimeDateStamp;ULONG CheckSum;ULONG SizeOfImage;ULONGLONG ImageBase;
} NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;typedef struct _KLDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;PVOID ExceptionTable;ULONG ExceptionTableSize;// ULONG padding on IA64PVOID GpValue;PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT __Unused5;PVOID SectionPointer;ULONG CheckSum;// ULONG padding on IA64PVOID LoadedImports;PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("Driver has benn Unloaded");}
int count = 0;NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {//DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink;PKLDR_DATA_TABLE_ENTRY next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink;UNICODE_STRING target = { 0 };RtlInitUnicodeString(&target, L"srv2.sys");while (next != pre){//gPrint("[%d] %wZ", count, &next->BaseDllName);if (!RtlCompareUnicodeString(&target, &next->BaseDllName, TRUE)) {DbgPrint("[db] target has been found,the num is %d\r\n",count);//RemoveEntryList(&next);DbgBreakPoint();RemoveEntryList(&next->InLoadOrderLinks);//这个api和直接操作链表断链是等价的//PKLDR_DATA_TABLE_ENTRY PreNode = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Blink;//PKLDR_DATA_TABLE_ENTRY NextNode = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;//PreNode->InLoadOrderLinks.Flink = next->InLoadOrderLinks.Flink;//NextNode->InLoadOrderLinks.Blink = next->InLoadOrderLinks.Blink;break;}next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;count++;} //DbgBreakPoint();//ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;//第二次遍历内核模块,看看有没有真的断链pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink;next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink;DbgPrint("%wZ\r\n", &pre->BaseDllName);DbgPrint("%wZ\r\n", &next->BaseDllName);count = 0;while (next != pre){DbgPrint("[+] %d %wZ", count, &next->BaseDllName);next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;count++;}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
可以看见我们的模块在149,在DbgView中向下翻,可以看见149已经不是我们的模块了
继续深入的研究
这是真正的断掉了吗?我打开了我的PChunter,这种简单的断链即使已经没有办法被遍历出来,还是没有办法逃过它的检测,换句话说,如果这是一个AV或者那些Anti-Cheat程序,它还是有办法能找到你
这里我们就可以提到刚刚我们所强调的DriverInit和DriverSection,我们不仅要断掉双向链表,还要保证我们的驱动入口不被找到(这里先暂时不考虑我们的后续怎么找到自己的驱动)
ObReferenceObjectByName
介绍一个新的未导出的内核函数,这里函数后面ByName是我们可以通过名字来查询驱动对象,类似的还有句柄等等,只是我们这里已经定义了字符串
NTKERNELAPI
NTSTATUS
ObReferenceObjectByName(__in PUNICODE_STRING ObjectName,__in ULONG Attributes,__in_opt PACCESS_STATE AccessState,__in_opt ACCESS_MASK DesiredAccess,__in POBJECT_TYPE ObjectType,__in KPROCESSOR_MODE AccessMode,__inout_opt PVOID ParseContext,__out PVOID *Object);
它的作用就是帮助我们去获取驱动对象的指针,方便我们进行操作,由于它未导出,我们得先声明一下
我们修改我们的代码
#include<ntifs.h>
#include<ntstrsafe.h>//要用RtlStringCbPrintfA就别忘了这个库typedef struct _NON_PAGED_DEBUG_INFO {USHORT Signature;USHORT Flags;ULONG Size;USHORT Machine;USHORT Characteristics;ULONG TimeDateStamp;ULONG CheckSum;ULONG SizeOfImage;ULONGLONG ImageBase;
} NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;typedef struct _KLDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;PVOID ExceptionTable;ULONG ExceptionTableSize;// ULONG padding on IA64PVOID GpValue;PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT __Unused5;PVOID SectionPointer;ULONG CheckSum;// ULONG padding on IA64PVOID LoadedImports;PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;NTSTATUS ObReferenceObjectByName(__in PUNICODE_STRING ObjectName,__in ULONG Attributes,__in_opt PACCESS_STATE AccessState,__in_opt ACCESS_MASK DesiredAccess,__in POBJECT_TYPE ObjectType,__in KPROCESSOR_MODE AccessMode,__inout_opt PVOID ParseContext,__out PVOID *Object
);extern POBJECT_TYPE *IoDriverObjectType;VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("Driver has benn Unloaded");}
int count = 0;NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {//DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;//DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink;PKLDR_DATA_TABLE_ENTRY next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink;UNICODE_STRING target = { 0 };RtlInitUnicodeString(&target, L"srv2.sys");UNICODE_STRING ObName = { 0 };RtlInitUnicodeString(&ObName, L"\\FileSystem\\srv2");//这里如果不知道自己的驱动在什么路径可以在windbg中使用!drvobj srv2 1这个命令while (next != pre){//gPrint("[%d] %wZ", count, &next->BaseDllName);if (!RtlCompareUnicodeString(&target, &next->BaseDllName, TRUE)) {PDRIVER_OBJECT TargetDriver = NULL;NTSTATUS status = ObReferenceObjectByName(&ObName, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &TargetDriver);DbgPrint("[db] target has been found,the num is %d\r\n",count);//RemoveEntryList(&next);DbgBreakPoint();if (NT_SUCCESS(status)) {TargetDriver->DriverSection = NULL;//去除掉我们的驱动入口TargetDriver->DriverInit = NULL;RemoveEntryList(&next->InLoadOrderLinks);}//PKLDR_DATA_TABLE_ENTRY PreNode = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Blink;//PKLDR_DATA_TABLE_ENTRY NextNode = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;//PreNode->InLoadOrderLinks.Flink = next->InLoadOrderLinks.Flink;//NextNode->InLoadOrderLinks.Blink = next->InLoadOrderLinks.Blink;break;}next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;count++;} //DbgBreakPoint();//ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;//第二次遍历内核模块pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink;next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink;DbgPrint("%wZ\r\n", &pre->BaseDllName);DbgPrint("%wZ\r\n", &next->BaseDllName);count = 0;while (next != pre){DbgPrint("[+] %d %wZ\r\n", count, &next->BaseDllName);next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;count++;}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
按照这个运行之后,再打开PCHunter,这下是彻底被藏住了
1: kd> g
Driver has benn Unloaded[db] target has been found,the num is 149//这次我们在149
Break instruction exception - code 80000003 (first chance)
Unable to load image MyDriver2.sys, Win32 error 0n2
MyDriver2+0x10bf:
9d17c0bf cc int 3
我们马上就可以想到,那能不能用这种方法隐藏自己呢?
继续稍微修改我们的代码
#include<ntifs.h>
#include<ntstrsafe.h>//要用RtlStringCbPrintfA就别忘了这个库typedef struct _NON_PAGED_DEBUG_INFO {USHORT Signature;USHORT Flags;ULONG Size;USHORT Machine;USHORT Characteristics;ULONG TimeDateStamp;ULONG CheckSum;ULONG SizeOfImage;ULONGLONG ImageBase;
} NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;typedef struct _KLDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;PVOID ExceptionTable;ULONG ExceptionTableSize;// ULONG padding on IA64PVOID GpValue;PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT __Unused5;PVOID SectionPointer;ULONG CheckSum;// ULONG padding on IA64PVOID LoadedImports;PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;NTSTATUS ObReferenceObjectByName(__in PUNICODE_STRING ObjectName,__in ULONG Attributes,__in_opt PACCESS_STATE AccessState,__in_opt ACCESS_MASK DesiredAccess,__in POBJECT_TYPE ObjectType,__in KPROCESSOR_MODE AccessMode,__inout_opt PVOID ParseContext,__out PVOID *Object
);extern POBJECT_TYPE *IoDriverObjectType;VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("Driver has benn Unloaded");}
int count = 0;NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {//DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;//DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink;PKLDR_DATA_TABLE_ENTRY next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink;UNICODE_STRING target = { 0 };RtlInitUnicodeString(&target, L"MyDriver2.sys");UNICODE_STRING ObName = { 0 };RtlInitUnicodeString(&ObName, L"\\Driver\\MyDriver2");//这里路径改了while (next != pre){//gPrint("[%d] %wZ", count, &next->BaseDllName);if (!RtlCompareUnicodeString(&target, &next->BaseDllName, TRUE)) {PDRIVER_OBJECT TargetDriver = NULL;NTSTATUS status = ObReferenceObjectByName(&ObName, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &TargetDriver);DbgPrint("[db] target has been found,the num is %d\r\n",count);//RemoveEntryList(&next);DbgBreakPoint();if (NT_SUCCESS(status)) {TargetDriver->DriverSection = NULL;//去除掉我们的驱动入口TargetDriver->DriverInit = NULL;RemoveEntryList(&next->InLoadOrderLinks);}//PKLDR_DATA_TABLE_ENTRY PreNode = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Blink;//PKLDR_DATA_TABLE_ENTRY NextNode = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;//PreNode->InLoadOrderLinks.Flink = next->InLoadOrderLinks.Flink;//NextNode->InLoadOrderLinks.Blink = next->InLoadOrderLinks.Blink;DbgPrint("%d", status);break;}next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;count++;} //DbgBreakPoint();//ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;//第二次遍历内核模块pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink;next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink;DbgPrint("%wZ\r\n", &pre->BaseDllName);DbgPrint("%wZ\r\n", &next->BaseDllName);count = 0;while (next != pre){DbgPrint("[+] %d %wZ\r\n", count, &next->BaseDllName);next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;count++;}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
一运行,蓝屏了
*** Fatal System Error: 0x0000007e(0xC0000005,0x83FE1943,0x9BF03900,0x9BF03360)Break instruction exception - code 80000003 (first chance)A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.A fatal system error has occurred.For analysis of this file, run !analyze -v
nt!RtlpBreakWithStatusInstruction:
83e99110 cc int 3
这是为什么呢,因为我们在把驱动的入口给抹掉了,但是还是有一些操作要用到这个驱动入口,所以我们不能加载自己的一瞬间就把自己的入口抹掉,还需要一点延时
线程延时
在内核中,我们一般不使用sleep函数,这其中当然也有sleep函数容易被Hook的原因
我们如果要想达成一个类似延时的效果,可以在自己的驱动模块中起一个内核线程,然后延时启动这个线程,延时是为了保证所有之前用过的驱动入口都正确的运行后释放(不知道怎么说,描述不清楚)
我们要新用到两个函数
NTSTATUS PsCreateSystemThread([out] PHANDLE ThreadHandle,[in] ULONG DesiredAccess,[in, optional] POBJECT_ATTRIBUTES ObjectAttributes,[in, optional] HANDLE ProcessHandle,[out, optional] PCLIENT_ID ClientId,[in] PKSTART_ROUTINE StartRoutine,[in, optional] PVOID StartContext
);
NTSTATUS KeDelayExecutionThread([in] KPROCESSOR_MODE WaitMode,[in] BOOLEAN Alertable,[in] PLARGE_INTEGER Interval
);
改进代码如下
#include<ntifs.h>
#include<ntstrsafe.h>//要用RtlStringCbPrintfA就别忘了这个库typedef struct _NON_PAGED_DEBUG_INFO {USHORT Signature;USHORT Flags;ULONG Size;USHORT Machine;USHORT Characteristics;ULONG TimeDateStamp;ULONG CheckSum;ULONG SizeOfImage;ULONGLONG ImageBase;
} NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;typedef struct _KLDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;PVOID ExceptionTable;ULONG ExceptionTableSize;// ULONG padding on IA64PVOID GpValue;PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;USHORT LoadCount;USHORT __Unused5;PVOID SectionPointer;ULONG CheckSum;// ULONG padding on IA64PVOID LoadedImports;PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;NTSTATUS ObReferenceObjectByName(__in PUNICODE_STRING ObjectName,__in ULONG Attributes,__in_opt PACCESS_STATE AccessState,__in_opt ACCESS_MASK DesiredAccess,__in POBJECT_TYPE ObjectType,__in KPROCESSOR_MODE AccessMode,__inout_opt PVOID ParseContext,__out PVOID *Object
);extern POBJECT_TYPE *IoDriverObjectType;void DriverHide(PWCH ObName) {LARGE_INTEGER in = { 0 };in.QuadPart = -10000 * 20000;//规定时间KeDelayExecutionThread(KernelMode, FALSE, &in);//不到时间不启动UNICODE_STRING ObjName = { 0 };RtlInitUnicodeString(&ObjName, ObName);PDRIVER_OBJECT TargetDriver = NULL;NTSTATUS status = ObReferenceObjectByName(&ObjName, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &TargetDriver);if (NT_SUCCESS(status)) {//DbgBreakPoint();PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)TargetDriver->DriverSection;RemoveEntryList(&ldr->InLoadOrderLinks);TargetDriver->DriverSection = NULL;//去除掉我们的驱动入口TargetDriver->DriverInit = NULL;ObDereferenceObject(TargetDriver);DbgPrint("Success!!\r\n");}return;
}VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("Driver has benn Unloaded");}
int count = 0;NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {HANDLE pThread = NULL;NTSTATUS status = PsCreateSystemThread(&pThread, THREAD_ALL_ACCESS,NULL, NULL, NULL, DriverHide, L"\\Driver\\MyDriver2");DbgBreakPoint();if (NT_SUCCESS(status)) {NtClose(pThread);}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
最后是成功的将我们的自己的驱动MyDriver2.sys给隐藏了
、