自学内容网 自学内容网

驱动断链的研究

准备

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 IA64
    PVOID 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 IA64
    PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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 IA64
PVOID 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给隐藏了

在这里插入图片描述


原文地址:https://blog.csdn.net/m0_68259687/article/details/144349758

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!