驱动断链的研究
准备
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给隐藏了

、
相关文章:
驱动断链的研究
准备 source insight 从现在开始我们正式进入内核编程,但是很多内核里面的结构和类型是需要我们额外声明的,我们就需要一个工具来快速的阅读WIn内核源码。这里我贴出我所参考的博客 羽夏看Win系统内核——SourceInsight 配置 WRK - 寂静的羽夏 - 博客…...
在 Windows WSL 上部署 Ollama 和大语言模型:从镜像冗余问题看 Docker 最佳实践20241208
🛠️ 在 Windows WSL 上部署 Ollama 和大语言模型:从镜像冗余问题看 Docker 最佳实践 ⭐ 引言 随着大语言模型(LLM)和人工智能技术的迅猛发展,开发者们越来越多地尝试在本地环境中部署模型进行实验。 但部署过程中常…...
做题时HashSet、TreeSet、LinkedHashSet的选择
一、HashSet 此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。 代码: import java.util.HashSet; import java.util.LinkedHashSet; import ja…...
Manus手套动作捕捉AI训练灵巧手
随着人工智能(AI)和机器人技术的融合日益紧密,使用真实动作数据AI扩容训练机器人的方式正在被用于开发更富表现力的机器人。Manus手套凭借精准的动作捕捉技术和导出数据的强大兼容性,在灵巧手的研发和应用中发挥了重要作用。 手部…...
嵌入式驱动开发详解4(内核定时器)
文章目录 前言通用定时器系统节拍节拍数与时间转换基本框架定时器使用代码展示通用定时器特点 高精度定时器 前言 LInux内核定时器是一种基于未来时间点的计时方式,以当前时刻来启动的时间点,以未来的某一时刻为终止点。比如,现在是10点5分&…...
Linux:信号的预备和产生
引入: 比如当前快递小哥需要通知你下来取快递(产生信号),然后通过电话或短信告知了你(发送信号),但是当前你正在打游戏,所以你并不会马上去处理,但是你会记得这件事&…...
国城杯2024——Curve
相关知识链接:https://tangcuxiaojikuai.xyz/post/187210a7.html #sagemath from Crypto.Util.number import *def add(P, Q):(x1, y1) P(x2, y2) Qx3 (x1*y2 y1*x2) * inverse(1 d*x1*x2*y1*y2, p) % py3 (y1*y2 - a*x1*x2) * inverse(1 - d*x1*x2*y1*y2, p…...
AI生成不了复杂前端页面?也许有解决方案了
在2024年,编程成为了人工智能领域最热门的赛道。AI编程技术正以惊人的速度进步,但在生成前端页面方面,AI的能力还是饱受质疑。自从ScriptEcho平台上线以来,我们收到了不少用户的反馈,他们表示:“生成的页面…...
常见矩阵分析法(BCG、GE、IE、SPACE、TOWS、优先、战略优先级、安索夫、风险矩阵):如何通过系统化方法助力战略决策与数据驱动决策
在快速变化的商业环境中,企业决策者面临着诸多复杂的选择与挑战。矩阵分析法作为战略分析的重要工具,能够系统化地分析企业的内外部环境,帮助管理层做出更加科学、合理的决策。本文将全面解析常见的矩阵分析法,并探讨它们在数据驱…...
JWT 在 SaaS 系统中的作用与分布式 SaaS 系统设计的最佳实践
在现代 SaaS(软件即服务) 系统中,随着服务规模的扩大和用户需求的多样化,如何高效、安全地进行用户身份验证、权限控制以及租户隔离,成为了系统架构中的核心问题之一。**JWT(JSON Web Token)**作…...
基于C#和Sql Server的网上书店管理系统
基于C#和Sql Server的网上书店管理系统 摘要 本系统是建立在 Windows 平台上,基于 B/S 结构的一个网上书店。通过这个网上书店,可以实 现简单的电子商务功能。 整个网站风格一致,较为美观,有完善的导航机制。普通用户从前台首页…...
特高频局放装置在现代配电设施中的应用
引言 随着电力系统的快速发展,尤其是现代配电系统的不断升和智能化,配电网的安全、稳定和运行变得愈发重要。为了确保电力系统能够及时应对各种运行问题,并提高故障诊断和监控的能力,现代配电系统中的监测技术也不断得到创新与提…...
FSC认证是什么?FSC认证费用
FSC认证是指森林管理委员会(Forest Stewardship Council)颁发的一种认证,以下是对FSC认证的详细介绍: 一、FSC认证的定义与目的 FSC认证标志着一件产品来自经过环境友好、社会有益和经济可行的可持续管理的森林。FSC是一个独立的…...
JAVA数据结构
1.数组 (Array): 固定大小的容器,用于存储相同类型的元素,数组在内存中是连续存储的,支持通过索引快 速访问元素。 int[] numbers = new int[10]; numbers[0] = 1;2.Java Collections Framework (JCF) JCF提供了一组接口和类用于管理和操作集合(如列表,集合,…...
mysql8 主从复制一直失败
问题描述: 开启同步后从服务器一直失败,报错如下: Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction ANONYMOUS at source log …...
EDA - Spring Boot构建基于事件驱动的消息系统
文章目录 概述事件驱动架构的基本概念工程结构Code创建事件和事件处理器创建事件总线创建消息通道和发送逻辑创建事件处理器消息持久化创建消息发送事件配置 Spring Boot 启动类测试运行项目 概述 在微服务架构和大规模分布式系统中,事件驱动架构(EDA&a…...
使用vue-seamless-scroll实现echarts图表大屏滚动,出现空白间隔的解决方案
一、背景介绍 最近的业务开发需求,想要实现echarts图表大屏滚动,小编首先采用vue-seamless-scroll进行实现,结果发现第二屏出现空白间隔,尝试了多种解决方案均不生效,最终选择换一个方案。 二、封装的ScrollList组件…...
ios使用UIScrollView和PageControl创建图片轮播
1.创建cocoa touch class 2.同时创建xib页面 3.SceneDelegate设置根视图控制器 // // SceneDelegate.m // iosstudy2024 // // Created by figo on 2024/8/5. //#import "SceneDelegate.h" #import "WidgetViewController.h"interface SceneDelegate …...
3D 生成重建024-LGM第一个开源的3D生成大模型!
3D 生成重建024-LGM第一个开源的3D生成大模型 文章目录 0 论文工作1 论文方法2 实验效果 0 论文工作 这篇论文介绍了一种名为LGM(大型多视角高斯模型)的新方法,用于从单视角图像或文本提示生成高分辨率的三维内容。该方法的核心思想是双重的…...
linux目录权限
一、目录权限的基本概念 Linux中的每个文件和目录都有与之关联的权限,这些权限决定了谁可以读取、写入或执行它们。权限分为三组: 所有者(Owner)权限:目录所有者的权限群组(Group)权限&#x…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...
