是否曾经认为直接与硬件交互是火箭科学,或者需要深入Windows内核的深层才能实现?现在,让一起来看看这个“兔子洞”到底有多深。
欢迎来到Kernel-Bridge的世界,这是一个内核模式开发框架,提供了API和现成的内核驱动程序以及用户模式库,全部使用C++17/C++20编写,以便用于内核研究和构建自己的内核组件。
Kernel-Bridge支持用户和内核内存操作、其他进程的内存、I/O、MSR、进程和线程、物理内存、远程代码执行、文件系统过滤、加载未签名的模块和驱动程序等等。
如何在项目中使用它?首先,需要加载这个驱动程序。可以通过两种方式加载:作为普通驱动程序加载或作为minifilter加载。作为minifilter加载可以让使用扩展功能,比如文件系统过滤或用户模式Ob***和Ps***回调。
#include <Windows.h>
#include "WdkTypes.h"
#include "CtlTypes.h"
#include "User-Bridge.h"
int main() {
using namespace KbLoader;
// 卸载之前加载的实例:
KbUnload();
BOOL Status = KbLoadAsFilter(
L"X:\\Folder\\Path\\To\\Kernel-Bridge.sys",
L"260000" // minifilter的高度
);
if (!Status) return 0;
// 无法加载驱动程序!
// 成功加载!
// 现在可以使用User-Bridge API了!...
KbUnload();
return 0;
}
接下来,让开始黑客社区最常见的问题:如何读写进程内存!
using namespace Processes::MemoryManagement;
constexpr int Size = 64;
BYTE Buffer[Size] = {};
BOOL Status = KbReadProcessMemory(
// 或者使用KbWriteProcessMemory来写入
ProcessId,
0x7FFF0000, // ProcessId上下文中期望的地址
&Buffer,
Size
);
再深入一层——读取内核内存:
using namespace VirtualMemory;
constexpr int Size = 64;
BYTE Buffer[Size];
// 将内核内存读取到Buffer:
BOOL Status = KbCopyMoveMemory(
reinterpret_cast
关于硬件特定操作,比如I/O?是的,可以做到!而且更多!可以通过用户模式转发在用户模式下使用IOPL位来使用in/out/cli/sti指令。
#include <intrin.h>
using namespace IO::Iopl;
// 让从用户模式发出系统蜂鸣器的声音!
// 所有的__in***/__out***指令都是Ring0的特权!
KbRaiseIopl();
// 现在__in***/__out***(比如__cli/__sti)在用户模式下是允许的!
ULONG Frequency = 1000;
ULONG Divider = 1193182 / Frequency;
__outbyte(0x43, 0xB6); // 设置蜂鸣器模式
__outbyte(0x42, static_cast
好吧,看到很惊讶!那么在用户模式下执行Ring0 shell呢?
using namespace KernelShells;
// 调用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); // 让CPU暂停1秒
ULONG Value = *static_cast
真正的对话!很惊讶,但是更严肃的功能呢?
嗯,让考虑一下...文件系统过滤子系统!使用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通知器:
CommPortListener
好东西!但是内核开发呢?
是的,这是Kernel-Bridge框架的一个重要部分。它有大量的API用于处理Windows内核的广泛部分,比如方便的容器(比如在C++17上写的字符串或链表)。可以在自己的内核项目中使用它们,而不需要任何外部依赖。
所有的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数组的末尾,将IOCTL编号添加到CtlTypes.h中的Ctls::KbCtlIndices枚举中,与IOCTLHandlers.cpp中的Handlers数组中的相同位置,使用User-Bridge.cpp中的KbSendRequest函数从用户模式调用它。享受Ring0吧!
很棒的工作!之后...
感谢阅读!这个项目有更多的功能,在这里描述的只是冰山一角,对这个项目有很大的计划。但需要帮助。需要贡献者、测试者和内核方面的助手。
如果对这个项目感兴趣,并且有足够的Ring0技能来编写良好、自描述的并且通过SDV检查的代码,非常欢迎成为这个项目的一部分。