调试驱动程序
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 命令重新加载用户模式符号文件,再次查看调用栈就能看到来自用户空间的操作
基本调试命令
!analyze -v
作用:分析崩溃、蓝屏错误或异常的详细信息。
使用场景:当遇到崩溃(如内核模式 BSOD 或用户模式异常)时,用于获取崩溃的原因及可能的解决方法。
.sympath
作用:设置符号文件路径。
示例:
.sympath srv*C:\Symbols*https://msdl.microsoft.com/download/symbols
说明:符号路径可以是本地路径或微软符号服务器的路径。执行后使用 .reload
重新加载符号。
.reload
作用:重新加载符号文件。
使用场景:符号文件路径修改后,或在符号未正确加载时使用。
!sym noisy
作用:启用符号加载的详细输出信息。
使用场景:用于调试符号加载失败的问题。
lm
作用:列出加载的模块。
示例:
lm
lm m <模块名>
说明:用于查看当前加载的驱动程序或模块信息,常用于确认符号是否加载成功。
断点管理命令
bp <地址>
作用:设置断点。
示例:
bp 0x12345678
说明:当程序执行到指定地址时中断。
bl
作用:列出所有设置的断点。
说明:用于查看当前所有断点的信息。
bc <断点编号>
作用:清除指定断点。
示例:
bc 1
说明:删除编号为 1
的断点。
g
作用:继续执行程序。
说明:在程序被中断时,继续执行。
t
作用:单步执行一条指令(跟踪)。
说明:适用于逐步调试代码逻辑。
p
作用:单步执行一条指令,但不进入子函数。
说明:如果遇到函数调用,不会进入函数内部。
内存和数据检查命令
dd <地址>
作用:以(DWORD)格式显示内存内容。
示例:
dd 0x12345678
说明:用于检查内存数据,常用于调试指针问题。
dps <地址>
作用:以指针形式显示内存内容,并解析符号。
示例:
dps 0x12345678
u <地址>
作用:反汇编指定地址的指令。
示例:
u 0x12345678
说明:用于查看特定地址处的机器指令。
!pool
作用:检查内核模式下的内存池分配。
使用场景:调试内核模式内存泄漏问题。
栈和上下文信息
k
作用:显示当前调用栈(内核模式)。
示例:
k
kv
说明:k
显示基本栈信息,kv
显示附加参数和符号。
!irp <地址>
作用:显示 IRP 结构体的信息。
使用场景:调试驱动程序中 I/O 请求包(IRP)的处理。
!process 0 0
作用:列出当前所有进程。
使用场景:用于调试内核模式下的进程信息。
.formats <值>
作用:以多种格式显示指定值。
示例:
.formats 0x1234
说明:将值以十六进制、十进制、字符等多种格式显示,便于分析。
调试状态与辅助命令
.ecxr
作用:显示当前异常的上下文记录。
使用场景:调试用户模式异常(如访问违例)时使用。
.frame <帧编号>
作用:切换到指定的栈帧。
说明:配合调用栈命令 k
使用,便于查看特定帧的上下文。
!handle
作用:列出当前进程的句柄信息。
示例:
!handle 0 0
.time
作用:显示调试目标的当前时间。
说明:用于记录调试事件时间。
!thread
作用:显示当前线程信息。
使用场景:分析线程状态和当前执行的位置。
-
.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;
}
效果:
视频展示:
- 视频.zip 下载