返回顶部
扶摇直上九万里,展翅高飞岂可待。

驱动断链

实验环境:Win7_x32

打开PCHunter32,点开驱动模块可以看到所有的加载的驱动基本上都在这里。包括PCHunter本身加载的驱动都被罗列出来了

这个PCHunter的遍历驱动列表的方式和我们常规的遍历方式不太一样,他这个遍历是通过查询模块,然后还查了目录

查的就是Driver这个目录,这里面有所有的驱动,还有FileSystem也去遍历了。他是由这两个目录组合起来的。

如果我们去遍历,铁定没有他这么多。

这里我们来认识一个结构:DRIVER_OBJECT
我们在windbg下一个断点。然后dt命令查看一下。

1: kd> dt nt!_DRIVER_OBJECT
   +0x000 Type             : Int2B
   +0x002 Size             : Int2B
   +0x004 DeviceObject     : Ptr32 _DEVICE_OBJECT
   +0x008 Flags            : Uint4B
   +0x00c DriverStart      : Ptr32 Void
   +0x010 DriverSize       : Uint4B
   +0x014 DriverSection    : Ptr32 Void
   +0x018 DriverExtension  : Ptr32 _DRIVER_EXTENSION
   +0x01c DriverName       : _UNICODE_STRING
   +0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
   +0x028 FastIoDispatch   : Ptr32 _FAST_IO_DISPATCH
   +0x02c DriverInit       : Ptr32     long 
   +0x030 DriverStartIo    : Ptr32     void 
   +0x034 DriverUnload     : Ptr32     void 
   +0x038 MajorFunction    : [28] Ptr32     long 

他一共有这么多成员,我们主要关注DriverSection这个成员,他是一个类似三环下PEB的链表。
但是结构没有显示出来,我们来弄一个结构出来

typedef struct _KLDR_DATA_TABLE_ENTRY {
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY exp;
	ULONG un;
	ULONG NonPagedDebugInfo;
	ULONG DllBase;
	ULONG EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	USHORT LoadCount;
	USHORT __Undefined5;
	ULONG  __Undefined6;
	ULONG  CheckSum;
	ULONG  TimeDateStamp;

} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;

我们先不着急断链,我们先把指向改过去。

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver,PUNICODE_STRING pReg) {
	DbgBreakPoint();
	PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;
	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

我们下个断点来看看

加载驱动断下。我们走到ldr创建完成,我们去命令窗口dt一下ldr

  • +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x83f8c850 - 0x87df01b0 ]这个是一个加载的双向循环链表,整个都是串起来的
  • +0x018 DllBase : 0x8bd62000 这里就是是这个模块地址。
  • +0x01c EntryPoint : 0x8bd66000 这个就是入口点

我们再去看一下:dt pDriver
在驱动结构中:

  • +0x00c DriverStart : 0x8bd62000 Void 在驱动结构中这个是起始地址

有没有发现这个DriverStartDllBase是一样的。
我们再来观察一下我们驱动的名字:FullDllName : _UNICODE_STRING "\??\C:\Users\Catsay\Desktop\驱动断链.sys"

这里显示的是我们只被加载了一次
我们来看一下这个双向循环链表:
dt _KLDR_DATA_TABLE_ENTRY 0x83f8c850
windbg运行一下命令可以看到

2: kd> dt _KLDR_DATA_TABLE_ENTRY 0x83f8c850
____!_KLDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x86342c98 - 0x8674d318 ]
   +0x008 exp              : _LIST_ENTRY [ 0x7 - 0xcde ]
   +0x010 un               : 0x83e0b000
   +0x014 NonPagedDebugInfo : 0x83e42000
   +0x018 DllBase          : 0x84254000
   +0x01c EntryPoint       : 0
   +0x020 SizeOfImage      : 0
   +0x024 FullDllName      : _UNICODE_STRING ""
   +0x02c BaseDllName      : _UNICODE_STRING "은菸좀菸"
   +0x034 Flags            : 0x83f7e800
   +0x038 LoadCount        : 0x63d0
   +0x03a __Undefined5     : 0x8791
   +0x03c __Undefined6     : 0
   +0x040 CheckSum         : 0
   +0x044 TimeDateStamp    : 0

这里是啥都没有,我们继续往上看一个节点:

2: kd> dt _KLDR_DATA_TABLE_ENTRY 0x86342c98
____!_KLDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x86342c20 - 0x83f8c850 ]
   +0x008 exp              : _LIST_ENTRY [ 0x83eba544 - 0x12 ]
   +0x010 un               : 0
   +0x014 NonPagedDebugInfo : 0
   +0x018 DllBase          : 0x83e42000
   +0x01c EntryPoint       : 0x83f614d8
   +0x020 SizeOfImage      : 0x412000
   +0x024 ReadVirtual: 8b400fb8 not properly sign extended
FullDllName      : _UNICODE_STRING "\SystemRoot\system32\ntkrnlpa.exe"
   +0x02c ReadVirtual: 86342cf4 not properly sign extended
BaseDllName      : _UNICODE_STRING "ntoskrnl.exe"
   +0x034 Flags            : 0x8004000
   +0x038 LoadCount        : 0x6e
   +0x03a __Undefined5     : 0
   +0x03c __Undefined6     : 0
   +0x040 CheckSum         : 0x3c88ac
   +0x044 TimeDateStamp    : 0

我们看到了:ntkrnlpa.exe
继续往前,就看到了:

2: kd> dt _KLDR_DATA_TABLE_ENTRY 0x86342c20
____!_KLDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x86342ba0 - 0x86342c98 ]
   +0x008 exp              : _LIST_ENTRY [ 0x83e0cd50 - 0x3 ]
   +0x010 un               : 0
   +0x014 NonPagedDebugInfo : 0
   +0x018 DllBase          : 0x83e0b000
   +0x01c EntryPoint       : 0x83e0b000
   +0x020 SizeOfImage      : 0x37000
   +0x024 ReadVirtual: 8b400f68 not properly sign extended
FullDllName      : _UNICODE_STRING "\SystemRoot\system32\halmacpi.dll"
   +0x02c ReadVirtual: 86342c7c not properly sign extended
BaseDllName      : _UNICODE_STRING "hal.dll"
   +0x034 Flags            : 0x8004000
   +0x038 LoadCount        : 0x57
   +0x03a __Undefined5     : 0
   +0x03c __Undefined6     : 0
   +0x040 CheckSum         : 0x37fb1
   +0x044 TimeDateStamp    : 0

也就是说我们通过遍历这个链表就可以把所有驱动都遍历出来
我们先来写代码把所有驱动遍历出来。

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver,PUNICODE_STRING pReg) {
	PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;
	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)
	{
		DbgPrintEx(77, 0, "[db]:driver name = %wZ\r\n", &next->FullDllName);
		next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;
	}
	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

这时候我们可以看到已经遍历出来了。那么我们现在想断链某个驱动就很简单了。我们找到名字然后找到对应的驱动,把它从这个链中摘掉。
我们去把PCHunter32aq.sys给摘掉。

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver,PUNICODE_STRING pReg) {
	PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;
	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 driverName = {0};
	RtlInitUnicodeString(&driverName, L"PCHunter32aq.sys");
	while (next!= pre)
	{
		if (next->BaseDllName.Length!=0&&RtlCompareUnicodeString(&driverName, &next->BaseDllName,TRUE)==0)
		{
			DbgPrintEx(77, 0, "[db]:driver name = %wZ\r\n", &next->FullDllName);
			RemoveEntryList(&next->InLoadOrderLinks);
			break;
		}
		next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;
	}
	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

断掉之后发现PCHunter卡死了
我们来看看他为啥卡死了
windbg执行:!process 0 0打印出所有进程信息。然后找到PCHunter:

PROCESS 86694288  SessionId: 1  Cid: 0f40    Peb: 7ffdd000  ParentCid: 09a8
    DirBase: 7f045480  ObjectTable: 99651880  HandleCount: 282.
    Image: PCHunter32.exe

然后!process 86694288,把它里面所有的线程都打印出来看看。

应该就是卡死在这附近。那我们就换一个断掉。我们去断HTTP.sys

我们现在的断链是已经成功了,但是被PCHunter检测出来了。

这时候我们需要用到一个没有导出的函数,我们用ida扣一下这个函数。
_ObReferenceObjectByName就是这个函数,把它文档化一下:

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>
typedef struct _KLDR_DATA_TABLE_ENTRY {
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY exp;
	ULONG un;
	ULONG NonPagedDebugInfo;
	ULONG DllBase;
	ULONG EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	USHORT LoadCount;
	USHORT __Undefined5;
	ULONG  __Undefined6;
	ULONG  CheckSum;
	ULONG  TimeDateStamp;

} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;

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
);


VOID DriverUnload(PDRIVER_OBJECT pDriver) {

}
extern POBJECT_TYPE * IoDriverObjectType;
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver,PUNICODE_STRING pReg) {
	PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;
	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 driverName = {0};
	RtlInitUnicodeString(&driverName, L"HTTP.sys");
	UNICODE_STRING driverName1 = { 0 };
	RtlInitUnicodeString(&driverName1, L"\\driver\\HTTP");
	while (next!= pre)
	{
		DbgPrintEx(77, 0, "[db]:driver name = %wZ\r\n", &next->FullDllName);
		if (next->BaseDllName.Length!=0&&RtlCompareUnicodeString(&driverName, &next->BaseDllName,TRUE)==0)
		{
			PDRIVER_OBJECT httpDriver = NULL;
			NTSTATUS status = ObReferenceObjectByName(&driverName1, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &httpDriver);
			if (NT_SUCCESS(status))
			{
				RemoveEntryList(&next->InLoadOrderLinks);
				httpDriver->DriverInit = NULL;
				httpDriver->DriverSection = NULL;
			}
			
			break;
		}
		next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;
	}
	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}


我们就可以发现已经隐藏掉了,通过PCHunter也检测不到了。

那么我们用这一份代码来隐藏自己可以吗?
不可以。会直接蓝屏。
我们在入口点隐藏自己,想一下我们在做PE加载的时候,我们去调用入口点调用完之后是不是还会有可能拿入口点和PE头做一些其他事情。
所以我们在这不能够把自己头抹掉。我们想要把自己隐藏需要把握一下时机。我们要让他调用完自己之后再把自己抹掉。

#include <ntifs.h>

typedef struct _KLDR_DATA_TABLE_ENTRY {
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY exp;
	ULONG un;
	ULONG NonPagedDebugInfo;
	ULONG DllBase;
	ULONG EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	USHORT LoadCount;
	USHORT __Undefined5;
	ULONG  __Undefined6;
	ULONG  CheckSum;
	ULONG  TimeDateStamp;

} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;

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
);


extern POBJECT_TYPE * IoDriverObjectType;


void DriverHide(PWCH ObjName)
{
	//延时
	LARGE_INTEGER in = { 0 };
	in.QuadPart = -10000 * 5000;
	KeDelayExecutionThread(KernelMode, FALSE, &in);



	UNICODE_STRING driverName1 = { 0 };
	RtlInitUnicodeString(&driverName1, ObjName);
	PDRIVER_OBJECT httpDriver = NULL;
	NTSTATUS status = ObReferenceObjectByName(&driverName1, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &httpDriver);

	if (NT_SUCCESS(status))
	{
		PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)httpDriver->DriverSection;
		DbgPrintEx(77, 0, "[db]: driver name = %wZ\r\n", &ldr->FullDllName);
		httpDriver->DriverSection = ldr->InLoadOrderLinks.Flink;
		RemoveEntryList(&ldr->InLoadOrderLinks);
		httpDriver->DriverInit = NULL;
		ObDereferenceObject(httpDriver);
	}
	return;
}


VOID DriverUnload(PDRIVER_OBJECT pDriver)
{

}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	//启动一个线程
	HANDLE hThread = NULL;
	NTSTATUS status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, DriverHide, L"\\driver\\day");
	if (NT_SUCCESS(status))
	{
		NtClose(hThread);
	}
	
	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

我们创建一个线程去操作。

断了之后就没有了。我们再去使用这份代码去断掉PCHunter。

可以看到PCHunter的驱动也已经隐藏掉了

posted @ 2021-07-07 18:05  唯君画馨  阅读(439)  评论(0编辑  收藏  举报