Kernel-Bridge 框架






4.79/5 (9投票s)
用 C++17 编写的 Windows 内核黑客库和开发框架
引言
你是否曾梦想过进行 Windows 内核黑客攻击?想做一些被操作系统限制的事情?或者深入 Windows 内核的内部,直接操作硬件,但却认为这很难?好吧,让我们看看这个兔子洞到底有多深!
《红色药丸》与《黑客帝国》,尼奥!
GitHub: https://github.com/HoShiMin/Kernel-Bridge
那么,它是什么?
我很高兴向您展示这款内核模式开发框架、API 以及现成的内核驱动和用户模式库,它使用 C++17/C++20 编写,可用于您的内核研究和构建自己的内核组件。
它支持用户模式和内核模式内存、其他进程的内存、IO、MSR、进程和线程、物理内存、远程代码执行、文件系统过滤、加载未签名模块和驱动程序等等。
那么,如何在我的项目中实现它?
Kernel-Bridge 框架的文件层级结构
- /User-Bridge/API - 所有用户模式封装、头文件和 API,供您的用户模式项目使用
- /Kernel-Bridge/API - 所有内核模式 API(无外部依赖),您可以在自己的驱动程序中使用
- /SharedTypes/ - 用户模式和内核模式共享的头文件
好的,首先,您需要加载此驱动程序。您可以通过 2 种方式加载:将其加载为普通驱动程序或加载为迷你筛选器。加载为迷你筛选器允许您使用扩展功能,如文件系统过滤或用户模式的 Ob*** 和 Ps*** 回调。
#include <Windows.h>
#include "WdkTypes.h"
#include "CtlTypes.h"
#include "User-Bridge.h"
int main()
{
using namespace KbLoader;
// Unloading previous loaded instance:
KbUnload();
BOOL Status = KbLoadAsFilter(
L"X:\\Folder\\Path\\To\\Kernel-Bridge.sys",
L"260000" // Altitude of minifilter
);
if (!Status)
return 0; // Unable to load driver!
// Successfully loaded!
// Now you can use the User-Bridge API!
...
KbUnload();
return 0;
}
好的,接下来呢?我想黑客!
耐心点,亲爱的!
好吧,让我们从黑客社区中最常见的问题开始:如何读取/写入进程内存!
using namespace Processes::MemoryManagement;
constexpr int Size = 64;
BYTE Buffer[Size] = {};
BOOL Status = KbReadProcessMemory( // Or KbWriteProcessMemory if you want to write
ProcessId,
0x7FFF0000, // Desired address in context of ProcessId
&Buffer,
Size
);
现在,深入一层——读取内核内存
using namespace VirtualMemory;
constexpr int Size = 64;
BYTE Buffer[Size];
// Reading the kernel memory to Buffer:
BOOL Status = KbCopyMoveMemory(
reinterpret_cast<WdkTypes::PVOID>(Buffer),
0xFFFFF80000C00000, // Any kernel address
Size,
FALSE // Buffers doesn't intersects
);
硬件特定的操作,比如 I/O 呢?是的,我们可以做到!而且还有更多!我们可以在用户模式下通过用户模式转发来实现,利用 EFlags 寄存器中的 IOPL 位,允许我们在用户模式下使用 *in*/ *out*/ *cli*/ *sti* 指令。
#include <intrin.h>
using namespace IO::Iopl;
// Let's beep on the system beeper from usermode!
// All of __in***/__out*** instructions are privileged for the Ring0!
KbRaiseIopl(); // Now __in***/__out*** (such as __cli/__sti) are allowed in usermode!
ULONG Frequency = 1000; // 1 kHz
ULONG Divider = 1193182 / Frequency;
__outbyte(0x43, 0xB6); // Set the beeper regime
// Set the beeper divider:
__outbyte(0x42, static_cast<unsigned char>(Divider));
__outbyte(0x42, static_cast<unsigned char>(Divider >> 8));
__outbyte(0x61, __inbyte(0x61) | 3); // Start the beeper!
for (int i = 0; i < 5000; i++); // Check it with Sleep(); but IOPL may resets in some cases!
__outbyte(0x61, __inbyte(0x61) & 252); // Stop the beeper!
KbResetIopl();
嗯,我看到您惊叹不已!那么,用户模式下的 `Ring0` shell 执行呢?
using namespace KernelShells;
// Calling KeStallExecutionProcessor:
ULONG Result = 1337;
KbExecuteShellCode(
[](
_GetKernelProcAddress GetKernelProcAddress,
PVOID Argument
) -> ULONG {
using _KeStallExecutionProcessor = VOID(WINAPI*)(ULONG Microseconds);
auto Stall = reinterpret_cast<_KeStallExecutionProcessor>(
GetKernelProcAddress(L"KeStallExecutionProcessor")
);
Stall(1000 * 1000); // Stalling CPU for 1 second
ULONG Value = *static_cast<PULONG>(Argument);
return Value == 1337 ? 0x1EE7C0DE : 0;
},
&Result, // Argument
&Result // Result
);
// Returns Result = 0x1EE7C0DE
实话实说!我很惊讶,但更严肃的功能呢?
嗯,让我想想……关于过滤子系统!
使用 Kernel-Bridge 项目的过滤功能,您可以轻松过滤文件系统 IO 的最常见部分以及 *Ps*** 和 *Ob*** 事件(通过 `ObRegisterCallbacks` 和 `PsSet***NotifyRoutine`)。
它基于简单的方案工作
- Kernel-Bridge 驱动程序注册为筛选器或设置 Ob***/Ps*** 回调
- 用户模式应用程序连接到驱动程序打开的通信端口
- 在过滤例程中,驱动程序将事件广播给连接的用户模式客户端
- 用户模式客户端执行一些过滤(阻止对文件的访问,降低句柄的访问权限等)
- 将处理后的数据返回内核,该数据适用于筛选请求
让我们订阅 *Ob*** 和 *Ps*** 过滤器
#include <Windows.h>
#include <fltUser.h>
#include "CommPort.h"
#include "WdkTypes.h"
#include "FltTypes.h"
#include "Flt-Bridge.h"
...
// ObRegisterCallbacks notifier:
CommPortListener<KB_FLT_OB_CALLBACK_INFO, KbObCallbacks> ObCallbacks;
// Prevent to open our process with PROCESS_VM_READ rights:
Status = ObCallbacks.Subscribe([](
CommPort& Port,
MessagePacket<KB_FLT_OB_CALLBACK_INFO>& Message
) -> VOID {
auto Data = static_cast<PKB_FLT_OB_CALLBACK_INFO>(Message.GetData());
if (Data->Target.ProcessId == GetCurrentProcessId()) {
Data->CreateResultAccess &= ~PROCESS_VM_READ;
Data->DuplicateResultAccess &= ~PROCESS_VM_READ;
}
ReplyPacket<KB_FLT_OB_CALLBACK_INFO> Reply(Message, ERROR_SUCCESS, *Data);
Port.Reply(Reply); // Reply info to driver
});
// Ps***-callbacks:
CommPortListener<KB_FLT_PS_IMAGE_INFO, KbPsImage> ProcessCallbacks;
Status = ProcessCallbacks.Subscribe([](
CommPort& Port,
MessagePacket<KB_FLT_PS_IMAGE_INFO>& Message
) -> VOID {
auto Data = static_cast<PKB_FLT_PS_IMAGE_INFO>(Message.GetData());
printf(
"[PID: %i | Base: 0x%I64X | Size: %ull]: %ws\r\n",
(int)Data->ProcessId, Data->BaseAddress, (int)Data->ImageSize, Data->FullImageName
);
});
好东西!但内核开发怎么办?
是的,这是 Kernel-Bridge 框架的重要组成部分。
它拥有一套丰富的 API,可用于操作 Windows 内核的广泛部分,例如方便的容器(如在 C++17 中编写的 `string` 或链表)。您可以在自己的内核项目中使用它们,而无需任何外部依赖。
所有 Kernel-Bridge 内核 API 都位于 * `/Kernel-Bridge/API/` * 文件夹中。
仅举例说明,使用内核 `StringsAPI`
#include <wdm.h>
#include <ntstrsafe.h>
#include <stdarg.h>
#include "StringsAPI.h"
WideString wString = L"Some string";
AnsiString aString = wString.GetAnsi().GetLowerCase() + " and another string!";
if (aString.Matches("*another*"))
DbgPrint("%s\r\n", aString.GetData());
但我想实现我自己的东西!
如果您想添加自己的 IOCTL 处理程序
- 在 * `/Kernel-Bridge/Kernel-Bridge/IOCTLHandlers.cpp` * 文件中编写处理程序
- 在 `DispatchIOCTL` 函数的 * `Handlers` * 数组末尾添加它
- 在 * `CtlTypes.h` * 中 `Ctls::KbCtlIndices` `enum` 中添加 IOCTL 编号,使其与 * `IOCTLHandlers.cpp` * 中的 `Handlers` 数组中的位置**相同**
- 在 * `User-Bridge.cpp` * 中使用 * `KbSendRequest` * 函数从用户模式调用它
- 享受 `Ring0`!
出色的工作!然后呢……
感谢您的阅读!这个项目还有很多我在这里没有描述的功能,我为它制定了宏伟的计划。
但我需要您的帮助。我需要贡献者、测试人员和助手来处理深入的内核问题。
如果您对此感兴趣,并且具备足够的 Ring0 技能来编写良好、自描述且通过 SDV 测试的代码,非常欢迎您加入本项目。
计划中的内容
- 用于运行时内核研究和脚本引擎的 GUI 平台
- 代码注入器
- 支持插桩回调
- 基于 PTE 的直接内存操作以及内核内存的用户模式暴露
- `ObRegisterCallbacks` 绕过
- 包含文档的 Wiki 页面
- EV 和 Microsoft Hardware Center 签名并向所有人发布
- 通过 HLK 测试,获得 WHQL 认证(这将是太棒了!)
所以,欢迎您成为贡献者!如果您有兴趣,请在下面的评论区留言。