65.9K
CodeProject 正在变化。 阅读更多。
Home

Kernel-Bridge 框架

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (9投票s)

2018年11月1日

GPL3

4分钟阅读

viewsIcon

15534

用 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`)。

它基于简单的方案工作

  1. Kernel-Bridge 驱动程序注册为筛选器或设置 Ob***/Ps*** 回调
  2. 用户模式应用程序连接到驱动程序打开的通信端口
  3. 在过滤例程中,驱动程序将事件广播给连接的用户模式客户端
  4. 用户模式客户端执行一些过滤(阻止对文件的访问,降低句柄的访问权限等)
  5. 将处理后的数据返回内核,该数据适用于筛选请求

让我们订阅 *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 处理程序

  1. 在 * `/Kernel-Bridge/Kernel-Bridge/IOCTLHandlers.cpp` * 文件中编写处理程序
  2. 在 `DispatchIOCTL` 函数的 * `Handlers` * 数组末尾添加它
  3. 在 * `CtlTypes.h` * 中 `Ctls::KbCtlIndices` `enum` 中添加 IOCTL 编号,使其与 * `IOCTLHandlers.cpp` * 中的 `Handlers` 数组中的位置**相同**
  4. 在 * `User-Bridge.cpp` * 中使用 * `KbSendRequest` * 函数从用户模式调用它
  5. 享受 `Ring0`!

出色的工作!然后呢……

感谢您的阅读!这个项目还有很多我在这里没有描述的功能,我为它制定了宏伟的计划。

但我需要您的帮助。我需要贡献者、测试人员和助手来处理深入的内核问题。

如果您对此感兴趣,并且具备足够的 Ring0 技能来编写良好、自描述且通过 SDV 测试的代码,非常欢迎您加入本项目。

计划中的内容

  • 用于运行时内核研究和脚本引擎的 GUI 平台
  • 代码注入器
  • 支持插桩回调
  • 基于 PTE 的直接内存操作以及内核内存的用户模式暴露
  • `ObRegisterCallbacks` 绕过
  • 包含文档的 Wiki 页面
  • EV 和 Microsoft Hardware Center 签名并向所有人发布
  • 通过 HLK 测试,获得 WHQL 认证(这将是太棒了!)

所以,欢迎您成为贡献者!如果您有兴趣,请在下面的评论区留言。

© . All rights reserved.