深入解析Windows内核I/O系统:调试驱动与终止进程
Ba1_Ma0 发表于 四川 二进制安全 260浏览 · 2024-11-22 01:33

调试驱动程序

windbg下载地址

https://learn.microsoft.com/zh-cn/windows-hardware/drivers/debugger/

虚拟机里开启远程调试

bcdedit /debug on

重启后添加配置

bcdedit /dbgsettings net hostip:调试机ip port:55555 key:1.1.1.1


使用windbg进行连接


连接成功,现在中断了系统执行,等待用户的进一步指令,所以无法操控虚拟机的windows

设置断点,运行指定驱动后在中断调试

bu booster!driverentry

bl:列出当前 WinDbg 中所有的断点(breakpoints)


执行g运行


现在可以正常操作windows虚拟机了,启动驱动程序,到达断点处


稳了方便调试,这里进行源码调试,点击设置,放入源代码和程序生成的pdb位置


然后导入程序源代码


在源代码窗口,f9打下断点后,输入g就会运行到对应代码的断点处


这里可以显示程序内的断点处


输入快捷键f10,可以执行代码


在下面窗口处也能查看具体变量的值


在命令窗口执行k命令可以显示当前线程的调用栈

可以看到驱动程序从内核加载到调用 DriverEntry 函数的过程
在监视界面,可以输入想要监视的值,当值变化时就会显示


在 IOCTL 请求的处理函数上设置断点,当用户空间向内核传递参数时,调试器会暂停执行

在调用栈里可以看到一些来自用户空间的数据,执行.reload /user 命令重新加载用户模式符号文件,再次查看调用栈就能看到来自用户空间的操作

基本调试命令

  1. !analyze -v

作用:分析崩溃、蓝屏错误或异常的详细信息。

使用场景:当遇到崩溃(如内核模式 BSOD 或用户模式异常)时,用于获取崩溃的原因及可能的解决方法。

  1. .sympath

作用:设置符号文件路径。

示例:

.sympath srv*C:\Symbols*https://msdl.microsoft.com/download/symbols

说明:符号路径可以是本地路径或微软符号服务器的路径。执行后使用 .reload 重新加载符号。

  1. .reload

作用:重新加载符号文件。

使用场景:符号文件路径修改后,或在符号未正确加载时使用。

  1. !sym noisy

作用:启用符号加载的详细输出信息。

使用场景:用于调试符号加载失败的问题。

  1. lm

作用:列出加载的模块。

示例:

lm
lm m <模块名>

说明:用于查看当前加载的驱动程序或模块信息,常用于确认符号是否加载成功。

断点管理命令

  1. bp <地址>

作用:设置断点。

示例:

bp 0x12345678

说明:当程序执行到指定地址时中断。

  1. bl

作用:列出所有设置的断点。

说明:用于查看当前所有断点的信息。

  1. bc <断点编号>

作用:清除指定断点。

示例:

bc 1

说明:删除编号为 1 的断点。

  1. g

作用:继续执行程序。

说明:在程序被中断时,继续执行。

  1. t

作用:单步执行一条指令(跟踪)。

说明:适用于逐步调试代码逻辑。

  1. p

作用:单步执行一条指令,但不进入子函数。

说明:如果遇到函数调用,不会进入函数内部。

内存和数据检查命令

  1. dd <地址>

作用:以(DWORD)格式显示内存内容。

示例:

dd 0x12345678

说明:用于检查内存数据,常用于调试指针问题。

  1. dps <地址>

作用:以指针形式显示内存内容,并解析符号。

示例:

dps 0x12345678
  1. u <地址>

作用:反汇编指定地址的指令。

示例:

u 0x12345678

说明:用于查看特定地址处的机器指令。

  1. !pool

作用:检查内核模式下的内存池分配。

使用场景:调试内核模式内存泄漏问题。

栈和上下文信息

  1. k

作用:显示当前调用栈(内核模式)。

示例:

k
kv

说明:k 显示基本栈信息,kv 显示附加参数和符号。

  1. !irp <地址>

作用:显示 IRP 结构体的信息。

使用场景:调试驱动程序中 I/O 请求包(IRP)的处理。

  1. !process 0 0

作用:列出当前所有进程。

使用场景:用于调试内核模式下的进程信息。

  1. .formats <值>

作用:以多种格式显示指定值。

示例:

.formats 0x1234

说明:将值以十六进制、十进制、字符等多种格式显示,便于分析。

调试状态与辅助命令

  1. .ecxr

作用:显示当前异常的上下文记录。

使用场景:调试用户模式异常(如访问违例)时使用。

  1. .frame <帧编号>

作用:切换到指定的栈帧。

说明:配合调用栈命令 k 使用,便于查看特定帧的上下文。

  1. !handle

作用:列出当前进程的句柄信息。

示例:

!handle 0 0
  1. .time

作用:显示调试目标的当前时间。

说明:用于记录调试事件时间。

  1. !thread

作用:显示当前线程信息。

使用场景:分析线程状态和当前执行的位置。

  1. .logopen <文件>.logclose

作用:记录调试过程到日志文件。

使用场景:需要保存调试过程以便后续分析时使用。

示例:

.logopen debug_log.txt
.logclose

驱动程序终止指定进程

驱动程序源代码

#include <ntifs.h>
#include <ntddk.h>
#include "C:\Users\baimao\source\repos\shanchuceshi\baimao\input.h"

#ifndef PROCESS_TERMINATE
#define PROCESS_TERMINATE (0x0001)  // 进程终止的权限标志
#endif

void ProcessPowerUnload(PDRIVER_OBJECT);

NTSTATUS ProcessPowerCreateClose(PDEVICE_OBJECT, PIRP Irp);
NTSTATUS ProcessPowerDeviceControl(PDEVICE_OBJECT, PIRP Irp);

extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
    KdPrint(("ProcessPower: DriverEntry\n"));
    KdPrint(("Registry path: %wZ\n", RegistryPath));

    DriverObject->DriverUnload = ProcessPowerUnload;
    DriverObject->MajorFunction[IRP_MJ_CREATE] = ProcessPowerCreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = ProcessPowerCreateClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ProcessPowerDeviceControl;

    UNICODE_STRING devName = RTL_CONSTANT_STRING(L"\\Device\\BaimaoPower");
    PDEVICE_OBJECT DeviceObject;
    NTSTATUS status = IoCreateDevice(DriverObject, 0, &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject);

    if (!NT_SUCCESS(status)) {
        KdPrint(("Failed in IoCreateDevice (0x%X)\n", status));
        return status;
    }

    UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\??\\BaimaoPower");
    status = IoCreateSymbolicLink(&symLink, &devName);
    if (!NT_SUCCESS(status)) {
        IoDeleteDevice(DeviceObject);
        KdPrint(("Failed in IoCreateSymbolicLink (0x%x)\n", status));
        return status;
    }

    return STATUS_SUCCESS;
}

void ProcessPowerUnload(PDRIVER_OBJECT DriverObject) {
    KdPrint(("ProcessPower: Unload\n"));
    UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\??\\BaimaoPower");
    IoDeleteSymbolicLink(&symLink);
    IoDeleteDevice(DriverObject->DeviceObject);
}

NTSTATUS ProcessPowerCreateClose(PDEVICE_OBJECT, PIRP Irp) {
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS ProcessPowerDeviceControl(PDEVICE_OBJECT, PIRP Irp) {
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
    auto& dic = stack->Parameters.DeviceIoControl;
    ULONG len = 0;

    switch (dic.IoControlCode) {
    case IOCTL_OPEN_PROCESS: {
        if (dic.Type3InputBuffer == nullptr || Irp->UserBuffer == nullptr) {
            status = STATUS_INVALID_PARAMETER;
            break;
        }

        if (dic.InputBufferLength < sizeof(ProcessPowerInput) || dic.OutputBufferLength < sizeof(ProcessPowerOutput)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        auto input = (ProcessPowerInput*)dic.Type3InputBuffer;
        auto output = (ProcessPowerOutput*)Irp->UserBuffer;

        OBJECT_ATTRIBUTES attr;
        InitializeObjectAttributes(&attr, nullptr, 0, nullptr, nullptr);

        CLIENT_ID cid = {};
        cid.UniqueProcess = (HANDLE)(ULONG_PTR)input->ProcessId;

        status = ZwOpenProcess(&output->hProcess, PROCESS_ALL_ACCESS, &attr, &cid);
        if (NT_SUCCESS(status)) {
            len = sizeof(*output);
        }

        break;
    }
    case IOCTL_TERMINATE_PROCESS: {
        if (dic.Type3InputBuffer == nullptr) {
            status = STATUS_INVALID_PARAMETER;
            break;
        }

        if (dic.InputBufferLength < sizeof(ProcessPowerInput)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        auto input = (ProcessPowerInput*)dic.Type3InputBuffer;

        HANDLE hProcess;
        OBJECT_ATTRIBUTES attr;
        InitializeObjectAttributes(&attr, nullptr, 0, nullptr, nullptr);

        CLIENT_ID cid = {};
        cid.UniqueProcess = (HANDLE)(ULONG_PTR)input->ProcessId;

        status = ZwOpenProcess(&hProcess, PROCESS_TERMINATE, &attr, &cid);
        if (NT_SUCCESS(status)) {
            status = ZwTerminateProcess(hProcess, 0);
            ZwClose(hProcess);
        }

        break;
    }
    default:
        break;
    }

    Irp->IoStatus.Status = status;
    Irp->IoStatus.Information = len;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return status;
}

头文件

#pragma once

#ifdef _KERNEL_MODE
#include <wdm.h>
#else
#include <Windows.h>
#endif

struct ProcessPowerInput {
    ULONG ProcessId;
};

struct ProcessPowerOutput {
    HANDLE hProcess;
};

#define IOCTL_OPEN_PROCESS CTL_CODE(0x8000, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_TERMINATE_PROCESS CTL_CODE(0x8000, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS)
#pragma once

客户端程序源代码

#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#include "C:\Users\baimao\source\repos\shanchuceshi\baimao\input.h"

void DumpProcessModules(HANDLE hProcess) {
    HMODULE h[4096];
    DWORD needed;

    if (!EnumProcessModulesEx(hProcess, h, sizeof(h), &needed, LIST_MODULES_ALL)) {
        return;
    }

    DWORD count = needed / sizeof(HMODULE);
    printf("%u modules\n", count);

    WCHAR name[MAX_PATH];

    for (int i = 0; i < count; i++) {
        printf("Module: 0x%p ", h[i]);
        if (GetModuleBaseName(hProcess, h[i], name, _countof(name))) {
            printf("%ws", name);
        }
        printf("\n");
    }
}

int TerminateProcessByPid(int pid) {
    HANDLE hDevice = CreateFile(L"\\\\.\\BaimaoPower", GENERIC_WRITE | GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);

    if (hDevice == INVALID_HANDLE_VALUE) {
        printf("Error opening device (%u)\n", GetLastError());
        return 1;
    }

    ProcessPowerInput input;
    input.ProcessId = pid;

    DWORD bytes;
    BOOL ok = DeviceIoControl(hDevice, IOCTL_TERMINATE_PROCESS, &input, sizeof(input), nullptr, 0, &bytes, nullptr);

    if (!ok) {
        printf("Failed to terminate process (%u)\n", GetLastError());
        CloseHandle(hDevice);
        return 1;
    }

    printf("Process terminated successfully.\n");
    CloseHandle(hDevice);
    return 0;
}

int main(int argc, const char* argv[]) {
    if (argc < 3) {
        printf("Usage: %s <pid> <action>\nActions:\n  dump: Dump process modules\n  kill: Terminate process\n", argv[0]);
        return 0;
    }

    int pid = atoi(argv[1]);
    const char* action = argv[2];

    if (strcmp(action, "dump") == 0) {
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
        if (hProcess) {
            DumpProcessModules(hProcess);
            CloseHandle(hProcess);
        }
        else {
            printf("Failed to open process with OpenProcess (%u)\n", GetLastError());
        }
    }
    else if (strcmp(action, "kill") == 0) {
        TerminateProcessByPid(pid);
    }
    else {
        printf("Unknown action: %s\n", action);
    }

    return 0;
}

效果:


视频展示:

附件:
0 条评论
某人
表情
可输入 255