Windows内核开发

应用程和驱动层的通信1

我们在三环的时候窗口程序之间通过MSG传递消息。
而R3和R0的通信依靠IRP(I/O Request Packet)传递消息
R3与R0通信还需要一个关键的角色:设备对象步骤:
1.创建设备对象IoCreateDevice-创建一个设备名称-创建符号链接让3环能找到这个设备
2.设备数据交互方式-DO_BUFFERD_IO 缓冲区读写,将三环缓冲区数据复制到零环-DO_DIRECT_IO 直接读写,三环和零环不同线性地址映射到同一个物理页
3.设置派遣函数处理消息,其实就是回调函数#include <Windows.h>
#include <iostream>int main() {// 打开一个设备HANDLE hFile = CreateFileW(L"\\\\.\\StarHook2",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,NULL);if (hFile) {printf("打开成功");CloseHandle(hFile);}else {printf("打开失败");}system("pause");return 0;
}#include <ntddk.h>void DriverUnload(PDRIVER_OBJECT pDriver) {// 删除符号链接和设备对象UNICODE_STRING linkName = RTL_CONSTANT_STRING(L"\\??\\StarHook2");IoDeleteSymbolicLink(&linkName);IoDeleteDevice(pDriver->DeviceObject); // 删除设备对象DbgPrint("DriverUnload");
}NTSTATUS
DispatchIRQ(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
)
{DbgPrint("IRP_MJ_CREATE 触发了");Irp->IoStatus.Status = STATUS_SUCCESS; // 告诉3环处理结果状态 GetLastError获取的值Irp->IoStatus.Information = 0; // 返回的数据大小0IoCompleteRequest(Irp,IO_NO_INCREMENT); // 表示完成了这次请求响应return STATUS_SUCCESS;
}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath) {// 三环和0环的通信要通过IRP, IRP需要设备对象// 创建设备对象UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\StarHook1");PDEVICE_OBJECT pDevice = NULL;// 1.驱动对象 2.设备扩展大小 0 3.设备名称 4.设备类型 5.设备属性 6.设备是否是一个独占设备 7.输出设备对象NTSTATUS ret = IoCreateDevice(pDriver,0,&DeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&pDevice);if (NT_SUCCESS(ret)) {// 如果创建设备对象成功 我们创建一个符号链接,三环通过符号链接才能访问到0环的设备UNICODE_STRING linkName = RTL_CONSTANT_STRING(L"\\??\\StarHook2");// 符号链接 设备名字ret = IoCreateSymbolicLink(&linkName,&DeviceName);// 指定数据交互方式if (NT_SUCCESS(ret)) {pDevice->Flags = pDevice->Flags | DO_BUFFERED_IO; // 将三环缓存区数据复制到零环// 设置回调函数 我要处理CREATE事件pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchIRQ;}else {IoDeleteDevice(pDevice);}}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

应用程和驱动层之间的通信2

#include <Windows.h>
#include <iostream>int main() {// 打开一个设备HANDLE hFile = CreateFileW(L"\\\\.\\StarHook2",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,NULL);if (hFile) {printf("打开成功");// 往设备中写入数据const char* str = "hello StarHook";DWORD realWrite = 0;DWORD realRead = 0;BOOL ret = WriteFile(hFile, str, strlen(str) + 1,&realWrite,NULL);if (ret) {printf("写入成功");}char readBuff[0x100] = { 0 };ret = ReadFile(hFile, readBuff, 0x100, &realRead, NULL);if (ret) {printf("读取成功:%s\n",readBuff);}CloseHandle(hFile); // 这里其实也会给0环发送一个消息 关闭设备}else {printf("打开失败");}system("pause");return 0;
}#include <ntddk.h>void DriverUnload(PDRIVER_OBJECT pDriver) {UNICODE_STRING DriverLink = RTL_CONSTANT_STRING(L"\\??\\StarHook2");IoDeleteSymbolicLink(&DriverLink);IoDeleteDevice(pDriver->DeviceObject);DbgPrint("DriverUnload");
}NTSTATUS
DispatchIRQ_Create(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
)
{DbgPrint("IRP_MJ_CREATE 触发了");Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS
DispatchIRQ_Close(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {DbgPrint("IRP_MJ_CLOSE 触发了");Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// 收到写入数据的消息
NTSTATUS
DispatchIRQ_Write(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {DbgPrint("IRP_MJ_WRITE 触发了");// 1.获取缓冲区的大小 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(Irp); // 获取当前的Irp栈ULONG buffLen = pStack->Parameters.Write.Length;// 2.获取缓冲区PVOID buff = Irp->AssociatedIrp.SystemBuffer;if (buff) {DbgPrint("Irp收到数据:%s", buff);}// 返回数据Irp->IoStatus.Status = STATUS_SUCCESS;Irp->IoStatus.Information = 0;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// 收到三环需要读取的消息 那么我们就要写入
NTSTATUS
DispatchIRQ_Read(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {// 获取当前IRP栈PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);// 获取缓冲区PVOID buff = Irp->AssociatedIrp.SystemBuffer;// 往缓冲区里面写入数据RtlCopyMemory(buff, "Hello,Three App", strlen("Hello,Three App") + 1);Irp->IoStatus.Status = STATUS_SUCCESS;Irp->IoStatus.Information = strlen("Hello,Three App") + 1;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath) {// 创建设备对象UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"\\Device\\StarHook1");PDEVICE_OBJECT pDevice = NULL;NTSTATUS ret = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice);if (NT_SUCCESS(ret)) {UNICODE_STRING DriverLink = RTL_CONSTANT_STRING(L"\\??\\StarHook2");ret = IoCreateSymbolicLink(&DriverLink,&DriverName);if (NT_SUCCESS(ret)) {pDevice->Flags |= DO_BUFFERED_IO; // 设置数据交互模式// 设置回调函数pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchIRQ_Create;pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchIRQ_Close;pDriver->MajorFunction[IRP_MJ_WRITE] = DispatchIRQ_Write;pDriver->MajorFunction[IRP_MJ_READ] = DispatchIRQ_Read;}else {IoDeleteDevice(pDevice);}}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

应用程和驱动层之间的通信3

#include <Windows.h>
#include <iostream>
// 1.设备类型 2.自定义数字0x800~0xfff 3.数据交互方式  4.权限
#define MSG_CODE_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED,FILE_ANY_ACCESS)
#define MSG_CODE_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED,FILE_ANY_ACCESS)int main() {// 打开一个设备HANDLE hFile = CreateFileW(L"\\\\.\\StarHook2",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,NULL);if (hFile) {printf("打开成功");// 往设备中写入数据const char* str = "hello StarHook";// 通过DeviceIoControl通信// 1.句柄 2.消息码 3.写入缓冲区的指针 4.缓冲区大小 5.输出缓冲区的指针 6.缓冲区大小 // 7.返回实际的大小 8.重叠IOLPVOID inBuff = malloc(0x100);ZeroMemory(inBuff, 0x100);memcpy(inBuff,str, strlen(str) + 1);DWORD returnByte = 0;// 往零环写入数据DeviceIoControl(hFile, MSG_CODE_WRITE, inBuff,0x100,NULL,0,&returnByte,NULL);// 读取零环数据DeviceIoControl(hFile, MSG_CODE_READ, NULL, 0,inBuff, 0x100, &returnByte, NULL);printf("零环返回数据大小:%d,内容:%s", returnByte,inBuff);CloseHandle(hFile); // 这里其实也会给0环发送一个消息 关闭设备}else {printf("打开失败");}system("pause");return 0;
}#include <ntddk.h>void DriverUnload(PDRIVER_OBJECT pDriver) {UNICODE_STRING DriverLink = RTL_CONSTANT_STRING(L"\\??\\StarHook2");IoDeleteSymbolicLink(&DriverLink);IoDeleteDevice(pDriver->DeviceObject);DbgPrint("DriverUnload");
}NTSTATUS
DispatchIRQ_Create(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
)
{DbgPrint("IRP_MJ_CREATE 触发了");Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS
DispatchIRQ_Close(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {DbgPrint("IRP_MJ_CLOSE 触发了");Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// 收到写入数据的消息
NTSTATUS
DispatchIRQ_Write(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {DbgPrint("IRP_MJ_WRITE 触发了");// 1.获取缓冲区的大小 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(Irp); // 获取当前的Irp栈ULONG buffLen = pStack->Parameters.Write.Length;// 2.获取缓冲区PVOID buff = Irp->AssociatedIrp.SystemBuffer;if (buff) {DbgPrint("Irp收到数据:%s", buff);}// 返回数据Irp->IoStatus.Status = STATUS_SUCCESS;Irp->IoStatus.Information = 0;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS
DispatchIRQ_Control(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {DbgPrint("DispatchIRQ_Control 触发了");Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}
// 收到三环需要读取的消息 那么我们就要写入
NTSTATUS
DispatchIRQ_Read(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {// 获取当前IRP栈PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);// 获取缓冲区PVOID buff = Irp->AssociatedIrp.SystemBuffer;// 往缓冲区里面写入数据RtlCopyMemory(buff, "Hello,Three App", strlen("Hello,Three App") + 1);Irp->IoStatus.Status = STATUS_SUCCESS;Irp->IoStatus.Information = strlen("Hello,Three App") + 1;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}#define    MSG_CODE_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED,FILE_ANY_ACCESS)
#define MSG_CODE_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED,FILE_ANY_ACCESS)// 统一入口处理
NTSTATUS
DispatchIRQ_ALL(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {// 获取当前Irp栈PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);ULONG inLen = irpStack->Parameters.DeviceIoControl.InputBufferLength; // 获取缓冲区大小ULONG outLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; // 获取缓冲区大小// 判断消息if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {if (irpStack->Parameters.DeviceIoControl.IoControlCode == MSG_CODE_WRITE){// 读取缓冲区PVOID buff = Irp->AssociatedIrp.SystemBuffer;DbgPrint("%s",buff);Irp->IoStatus.Information = 0;}else if (irpStack->Parameters.DeviceIoControl.IoControlCode == MSG_CODE_READ) {// 那么我们就要写入数据 往三环PVOID buff = Irp->AssociatedIrp.SystemBuffer; // 拿到三环的缓冲区RtlCopyMemory(buff, "Hello,Three App", strlen("Hello,Three App") + 1);Irp->IoStatus.Information = strlen("Hello,Three App") + 1;}}else {Irp->IoStatus.Information = 0;}Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath) {// 创建设备对象UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"\\Device\\StarHook1");PDEVICE_OBJECT pDevice = NULL;NTSTATUS ret = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice);if (NT_SUCCESS(ret)) {UNICODE_STRING DriverLink = RTL_CONSTANT_STRING(L"\\??\\StarHook2");ret = IoCreateSymbolicLink(&DriverLink,&DriverName);if (NT_SUCCESS(ret)) {pDevice->Flags |= DO_BUFFERED_IO; // 设置数据交互模式// 设置回调函数for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {pDriver->MajorFunction[i] = DispatchIRQ_ALL; // 统一入口}// pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchIRQ_Create;// pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchIRQ_Close;// pDriver->MajorFunction[IRP_MJ_WRITE] = DispatchIRQ_Write;// pDriver->MajorFunction[IRP_MJ_READ] = DispatchIRQ_Read;// pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIRQ_Control;}else {IoDeleteDevice(pDevice);}}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

数据交互方式

三环和零环设备进行通信数据交互方式:
1.DO_BUFFERED_IO 缓冲区读写方式
当三环往零环写入数据的时候,需要提供一个缓冲区。-调用API进入零环以后,操作系统会将三环的缓冲区数据复制到零环的一个地址下Irp->AssociatedIrp.SystemBuffer
当三环往零环读取数据的时候,刚好反过来,同样三环提供一个缓冲区。-进入零环后,操作系统不会复制三环的内容。零环将数据写入到零环缓冲区,返回到三环的时候,操作系统会将零环的缓冲区数据复制到三环。
【即读取的时候,复制三环数据到零环,写入的时候,复制零环数据到三环】2.DO_DIRECT_IO 直接读写方式
三环对零环进行读写操作的时候都会提供一个缓冲区,操作系统用内存描述符表MDL记录这块内存
进入零环以后通过MmGetMdlVirtualAddress获取三环地址
MmGetSystemAddressForMdlSafe映射一个零环地址,与三环的缓冲区指向同一个物理页。
直接读写方式WriteFile ReadFile 和 IoDeviceControl略有不同
【两个线性地址映射到同一个物理地址,不用复制操作了】3.其他方式
零环直接使用三环虚拟地址进行读写操作,这种方式不推荐。#include <Windows.h>
#include <iostream>
// 1.设备类型 2.自定义数字0x800~0xfff 3.数据交互方式  4.权限
#define MSG_CODE_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED,FILE_ANY_ACCESS)
#define MSG_CODE_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED,FILE_ANY_ACCESS)int main() {// 打开一个设备HANDLE hFile = CreateFileW(L"\\\\.\\StarHook2",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,NULL);if (hFile) {DWORD realRead = 0;char buff[0x100] = {0};ReadFile(hFile, buff, 0x100, &realRead, NULL);printf("%s\n",buff);CloseHandle(hFile); // 这里其实也会给0环发送一个消息 关闭设备}else {printf("打开失败");}system("pause");return 0;
}#include <ntddk.h>void DriverUnload(PDRIVER_OBJECT pDriver) {UNICODE_STRING DriverLink = RTL_CONSTANT_STRING(L"\\??\\StarHook2");IoDeleteSymbolicLink(&DriverLink);IoDeleteDevice(pDriver->DeviceObject);DbgPrint("DriverUnload");
}NTSTATUS
DispatchIRQ_Create(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
)
{DbgPrint("IRP_MJ_CREATE 触发了");Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// 收到三环需要读取的消息 那么我们就要写入
NTSTATUS
DispatchIRQ_Read(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {// 获取当前IRP栈PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(Irp);// 三环需要读取零环数据 获取缓冲区大小// 直接读写 三环的映射地址保存到MDL表中 Irp->MdlAddress 起始地址ULONG uLen = MmGetMdlByteCount(Irp->MdlAddress); // 直接读写的方式 不能使用之前的方式了DbgPrint("三环缓冲区大小:%d", uLen);// 获取三环的缓冲区地址ULONG r3Addr = MmGetMdlVirtualAddress(Irp->MdlAddress); // 其实是起始地址 + 偏移 = 真正地址DbgPrint("三环缓冲区地址:%x", r3Addr);// 然后我们要把这个地址在零环也映射一份,那么零环和三环就是指向同一个物理页了PVOID r0Buff = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);RtlCopyMemory(r0Buff,"Hello,R3 Direct Io",strlen("Hello,R3 Direct Io") + 1);Irp->IoStatus.Status = STATUS_SUCCESS;Irp->IoStatus.Information = strlen("Hello,R3 Direct Io") + 1;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath) {// 创建设备对象UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"\\Device\\StarHook1");PDEVICE_OBJECT pDevice = NULL;NTSTATUS ret = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice);if (NT_SUCCESS(ret)) {UNICODE_STRING DriverLink = RTL_CONSTANT_STRING(L"\\??\\StarHook2");ret = IoCreateSymbolicLink(&DriverLink,&DriverName);if (NT_SUCCESS(ret)) {// pDevice->Flags |= DO_BUFFERED_IO; // 设置数据交互模式pDevice->Flags |= DO_DIRECT_IO; // 设置数据交互方式为直接读写// 设置回调函数pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchIRQ_Create;pDriver->MajorFunction[IRP_MJ_READ] = DispatchIRQ_Read;}else {IoDeleteDevice(pDevice);}}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

DeviceIoControl实现直接读写

注意:
使用Device 写通信的话 不能使用MDL操作 使用Device control和缓冲区拷贝通信方式一样,而使用读的话就会使用Mdl
【如果三环写入不用MDL,如果三环读取用MDL】#include <Windows.h>
#include <iostream>
// 1.设备类型 2.自定义数字0x800~0xfff 3.数据交互方式  4.权限
#define MSG_CODE_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED,FILE_ANY_ACCESS)
#define MSG_CODE_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED,FILE_ANY_ACCESS)// in 写入数据
#define MSG_DIRECT_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_IN_DIRECT,FILE_ANY_ACCESS)
// out 读取数据
#define MSG_DIRECT_READ CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)int main() {// 打开一个设备HANDLE hFile = CreateFileW(L"\\\\.\\StarHook2",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,NULL);if (hFile) {DWORD returnBytes = 0;LPVOID inBuff = malloc(0x100);ZeroMemory(inBuff,0x100);memcpy(inBuff, "Hello R0 Direct Write", strlen("Hello R0 Direct Write") + 1);// 写入数据到0环DeviceIoControl(hFile, MSG_DIRECT_WRITE,inBuff,0x100,NULL,0,&returnBytes,NULL);// 从0环读取数据到三环DeviceIoControl(hFile, MSG_DIRECT_READ, NULL, 0, inBuff, 0x100, &returnBytes, NULL);printf("从0环读取到数据:%s\n",inBuff);CloseHandle(hFile); // 这里其实也会给0环发送一个消息 关闭设备}else {printf("打开失败");}system("pause");return 0;
}#include <ntddk.h>void DriverUnload(PDRIVER_OBJECT pDriver) {UNICODE_STRING DriverLink = RTL_CONSTANT_STRING(L"\\??\\StarHook2");IoDeleteSymbolicLink(&DriverLink);IoDeleteDevice(pDriver->DeviceObject);DbgPrint("DriverUnload");
}// in 写入数据
#define MSG_DIRECT_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_IN_DIRECT,FILE_ANY_ACCESS)
// out 读取数据
#define MSG_DIRECT_READ CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)NTSTATUS
DispatchIRQ_Create(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
)
{DbgPrint("IRP_MJ_CREATE 触发了");Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS
DispatchIRQ_Control(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {// 获取当前的Irp栈PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(Irp);switch (pIoStack->Parameters.DeviceIoControl.IoControlCode){case MSG_DIRECT_WRITE: { // 如果三环是写入// 直接读写的特点,会把三环的地址信息放到MDL中 我们需要通过MDL去操作// 不过我们使用Device 通信的话 不能使用MDL操作 使用Device control和缓冲区拷贝方式一样PVOID buff = Irp->AssociatedIrp.SystemBuffer;DbgPrint("三环传递过来的数据:%s\n",buff);Irp->IoStatus.Information = 0;break;}case MSG_DIRECT_READ: { // 如果三环是读取 那么它就会使用Mdi了// 那么我们就要往里面写入数据了RtlCopyMemory(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority),"Hello R3 Device Direct", strlen("Hello R3 Device Direct") + 1);Irp->IoStatus.Information = strlen("Hello R3 Device Direct") + 1;break;}}Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}
// 收到三环需要读取的消息 那么我们就要写入
NTSTATUS
DispatchIRQ_Read(struct _DEVICE_OBJECT* DeviceObject,struct _IRP* Irp // 沟通桥梁
) {// 获取当前IRP栈PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(Irp);// 三环需要读取零环数据 获取缓冲区大小// 直接读写 三环的映射地址保存到MDL表中 Irp->MdlAddress 起始地址ULONG uLen = MmGetMdlByteCount(Irp->MdlAddress); // 直接读写的方式 不能使用之前的方式了DbgPrint("三环缓冲区大小:%d", uLen);// 获取三环的缓冲区地址ULONG r3Addr = MmGetMdlVirtualAddress(Irp->MdlAddress); // 其实是起始地址 + 偏移 = 真正地址DbgPrint("三环缓冲区地址:%x", r3Addr);// 然后我们要把这个地址在零环也映射一份,那么零环和三环就是指向同一个物理页了PVOID r0Buff = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);RtlCopyMemory(r0Buff,"Hello,R3 Direct Io",strlen("Hello,R3 Direct Io") + 1);Irp->IoStatus.Status = STATUS_SUCCESS;Irp->IoStatus.Information = strlen("Hello,R3 Direct Io") + 1;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath) {// 创建设备对象UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"\\Device\\StarHook1");PDEVICE_OBJECT pDevice = NULL;NTSTATUS ret = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice);if (NT_SUCCESS(ret)) {UNICODE_STRING DriverLink = RTL_CONSTANT_STRING(L"\\??\\StarHook2");ret = IoCreateSymbolicLink(&DriverLink,&DriverName);if (NT_SUCCESS(ret)) {// pDevice->Flags |= DO_BUFFERED_IO; // 设置数据交互模式pDevice->Flags |= DO_DIRECT_IO; // 设置数据交互方式为直接读写// 设置回调函数pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchIRQ_Create;pDriver->MajorFunction[IRP_MJ_READ] = DispatchIRQ_Read;pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIRQ_Control;}else {IoDeleteDevice(pDevice);}}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}## API的调用过程
```c++
比如:CloseHandle-->Kernel32.dll-->KernelBase.dll-->ntdll-->内核层--->内核层CloseHandle的API三环跟零环的本质区别是什么?【R0 VS R3】-权限区别不一样权限体现在cs ss那些那么提权:调用门 中断门 陷阱门 TSS任务段 任务门...那么权限不一样,肯定要提权,3环不提权怎么进入零环。mov eax,0x32
ntdll中eax的值决定了进入内核层要调用哪个API。mov edx,esp 【给0环的函数,进行参数传值】
sysenter   【进入0环】
retn前面也说三环和零环的本质区别就是权限问题,调用完sysenter以后,它就提权了。总的来说要进入零环,就必须把cs ss eip esp这些东西替换掉,一定要提权,才能进入零环。

快速系统调用

前面:CloseHandle->kernel32.dll->kernelBase.dll->ntdll
eax:系统服务号【即进入内核以后要调用哪个API】然后我们发现无论是调用内核哪个函数edx的值都是0x7FFE0300
0x7FFE0300其实是某结构体的一个成员结构体:_KUSER_SHARED_DATA结构体的首地址:R3:0x7FFE0000 R0:0xFFDF0000结构体所在的内存空间是共享数据区,R3和R0共享,原理就是0环也同样有一个线性地址跟这个共享区指向这里。
线性地址不同但是指向的是一个物理页,这块共享区域主要就是用来用户层和内核层之间快速的传递信息的。
【也就是说虽然R0,R3线性地址不同,但是这个结构体指向的物理页是同一个】0x7FFE0300 = R3:0x7FFE0000 + 0x300
也就是说我们在ntdll进入内核之前,给edx传递的值就是systemCall这个成员的地址KUSER_SHARED_DATA + 0X300 == systemCall 就决定了我们进入内核的函数在哪里
然后观察内存,其实systemCall保存的就是KiFastSystemCall这个函数的地址KiFastSystemCall 快速系统调用然后我们发现快速系统调用就是给内核函数传递参数,调用sysenter这个指令sysenter/sysexit 指令从奔腾||处理器开始引入,在这之前不支持这个指令。
在奔腾||处理器之前是使用KiIntSystemCall:int 2E 进入内核的
后面就是sysenter操作系统在启动的时候,会通过CPUID汇编指令判断是否支持sysenter指令
支持:将KUSER_SHARED_DATA + 0X300即systemCall的函数地址,填上KiFastSystemCall
不支持:将KUSER_SHARED_DATA + 0X300即systemCall的函数地址,填上KiIntSystemCall填上KiIntSystemCall:
.text:77F070C0 arg_4           = byte ptr  8
.text:77F070C0
.text:77F070C0                 lea     edx, [esp+8]
.text:77F070C4                 int     2Eh             ; DOS 2+ internal - EXECUTE COMMAND
.text:77F070C4                                         ; DS:SI -> counted CR-terminated command string
.text:77F070C6                 retn所以早期的CPU应该是通过中断门,陷阱门之类的方式提权的,int指令。sysenter修改cs ss eip esp
从MSR寄存器来的。
MSR寄存器是一堆寄存器的统称,它有很多兄弟姐妹,由于数量太多,没办法每个都取一个名字,所以干脆用序号命名当调用sysenter进入零环的时候,CPU会去
MSR 174加载CS
MSR 175加载ESP
MSR 176加载EIP
MSR 174的值+8 = SS在windbg中通过rdmsr + 序号/地址 指令查看msr寄存器的值
然后我们发现rdmsr 174很熟悉的0环权限的cs的段选择子 0008SysEnter
三环进入零环:
CS SS EIP ESP SysEnter比起KiIntSystemCall,快就快在KiIntSystemCall要去使用内存,完成提权。而Msr只需要通过寄存器读取,通过寄存器肯定比通过内存要快很多。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w45hTQBW-1659295510884)(https://files.mdnice.com/user/28517/3ca924b0-62da-4f83-a01f-a7c8383d0c1f.png)]

SSDT

三环API通过sysEnter快速系统调用进入0环,那么三环的寄存器保存到哪里了呢?因为三环的API进入到0环,肯定还要出来,出来那么肯定需要保存进入0环之前的环境。
寄存器环境啊 EIP那些。其实就是跟我们TSS任务段切换任务一样。其实线程上下文环境不是三环进行保存的,而是0环进行保存的调用完sysEnter会到这个函数进行执行
KiFastCallEntry
那么我们就要IDA分析这个函数,看看他是怎么执行的。在ntkrnlpa.exe里面在3环里面fs的值是3B,fs:[0]指向TEB
在0环里面fs的值是30,fs:[0]指向KPCR【用来记录CPU状态信息】IDA快捷键-T可以把某个偏移修改为结构体的偏移形式
回顾:-R把变量变为ebp偏移-C把ebp偏移变为变量线程上下文环境结构体:
typedef struct _KTRAP_FRAME {+0x000 DbgEbp           : Uint4B+0x004 DbgEip           : Uint4B+0x008 DbgArgMark       : Uint4B+0x00c DbgArgPointer    : Uint4B+0x010 TempSegCs        : Uint2B+0x012 Logging          : UChar+0x013 Reserved         : UChar+0x014 TempEsp          : Uint4B+0x018 Dr0              : Uint4B+0x01c Dr1              : Uint4B+0x020 Dr2              : Uint4B+0x024 Dr3              : Uint4B+0x028 Dr6              : Uint4B+0x02c Dr7              : Uint4B+0x030 SegGs            : Uint4B+0x034 SegEs            : Uint4B+0x038 SegDs            : Uint4B+0x03c Edx              : Uint4B+0x040 Ecx              : Uint4B+0x044 Eax              : Uint4B+0x048 PreviousPreviousMode : Uint4B+0x04c ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD+0x050 SegFs            : Uint4B+0x054 Edi              : Uint4B+0x058 Esi              : Uint4B+0x05c Ebx              : Uint4B+0x060 Ebp              : Uint4B+0x064 ErrCode          : Uint4B+0x068 Eip              : Uint4B+0x06c SegCs            : Uint4B+0x070 EFlags           : Uint4B+0x074 HardwareEsp      : Uint4B+0x078 HardwareSegSs    : Uint4B 【修改完esp已经到了这里】+0x07c V86Es            : Uint4B+0x080 V86Ds            : Uint4B+0x084 V86Fs            : Uint4B+0x088 V86Gs            : Uint4B} KTRAP_FRAME, *PKTRAP_FRAME;KeServiceDescriptorTable SSDT有四个成员:-1.0环函数地址表【四个字节】-2.统计API调用次数-3.0环函数地址表函数数量-4.0环函数参数表【一个字节Byte数组,参数大小】其实除了SSDT表,内核还有一张表叫做shadowSSDT。SSDT主要是处理Kernel32.dll
shadowSSDT主要是处理user32.dll,GDI32.dll

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0O2ghy35-1659295510892)(https://files.mdnice.com/user/28517/947b8870-d373-4a16-b4e5-ffccb5748751.png)]

SSDT HOOK

前面去其实就是三环给了eax一个系统调用号 -> sysEnter -> KiFastCallEntry -> 找到SSDT表 -> 根据系统调用号解析SSDT表调用APIKeServiceDescriptorTable SSDT有四个成员:-1.0环函数地址表【四个字节】-2.统计API调用次数-3.0环函数地址表函数数量-4.0环函数参数表【一个字节Byte数组,参数大小】其实除了SSDT表,内核还有一张表叫做shadowSSDT。SSDT主要是处理Kernel32.dll
shadowSSDT主要是处理user32.dll,GDI32.dll#include <ntifs.h>typedef struct _SSDT {PULONG  funAddrTable; // 函数地址表PULONG  funUseCount;  // 函数使用次数ULONG  funNumber; // 函数个数PULONG funParamTable; // 函数参数字节表
}SSDT,*PSSDT;// 定义函数指针
typedef NTSTATUS (NTAPI* _NtClose)(HANDLE Handle);// SSDT表地址在 Kernel32导出变量中 KeServiceDescriptorTable    000000000056A9C0    915
// 而所有的程序都会引入Kernel32 所以我们可以直接使用这个导出变量,就可以拿到SSDT表的地址
EXTERN_C PSSDT KeServiceDescriptorTable; _NtClose g_OldNtCloseAddr = NULL; // 保存原本的函数地址 HOOK完要给它恢复
PULONG g_funTableAddr = NULL; // HOOK函数 替换掉NtClose
NTSTATUS NTAPI MyNtClose(HANDLE Handle) {DbgPrint("SSDT HOOK成功,HOOK NtClose");return g_OldNtCloseAddr(Handle); // 让原本拿到NtClose完成剩下工作 Hook不能影响原本的函数内容
}// 安装Hook
NTSTATUS InstallSSDTHook() {// 我们Hook CloseHandle 对应 ->  NtClose// KeServiceDescriptorTable->funAddrTable 这个地址是不可以修改的 所以我们做一个新的映射PHYSICAL_ADDRESS pyhAddr = MmGetPhysicalAddress(KeServiceDescriptorTable->funAddrTable); // 获取物理地址g_funTableAddr = MmMapIoSpace(pyhAddr, PAGE_SIZE, MmNonCached); // 物理地址 映射多大 是否需要缓存// g_funTableAddr 映射出来的这个线性地址 就可以直接进行修改操作了g_OldNtCloseAddr = g_funTableAddr[0x32];g_funTableAddr[0x32] = (ULONG)MyNtClose;return STATUS_SUCCESS;
}// 卸载Hook
NTSTATUS UnInstallSSDTHook() {if (g_OldNtCloseAddr != NULL) {g_funTableAddr[0x32] = g_OldNtCloseAddr; // 修改回去原本的NtCloseg_OldNtCloseAddr = NULL;MmUnmapIoSpace(g_funTableAddr, PAGE_SIZE); // 然后取消之前的物理地址映射}return STATUS_SUCCESS;
}void DriverUnload(PDRIVER_OBJECT pDriver) {UnInstallSSDTHook(); // 卸载钩子DbgPrint("DriverUnload");
}// eax KiFaseCallEntry SSDT 函数地址表 eax and 0x0FFF 索引 调用API
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath) {InstallSSDTHook(); // 安装钩子pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}KeServiceDescriptorTable + 0x40 = ShaowSSDT

动态获取调用号-解析ntdll导出表

前面是有缺陷的,因为系统版本不一样,系统调用号可能不一样,那么到别的电脑上可能就运行不了了。所以我们要动态解析。其实就是解析导出表,拿到函数的导出序号~
就跟我们解析PE文件的导出表是一样的#pragma once
#include <ntifs.h>
#include <ntimage.h>
// 加载PE文件
CHAR* PeLoadFile(PHANDLE hFile);
// 获取函数地址
ULONG GetFunAddr(CHAR* g_fileBuff,CHAR* funName);
// Rva转Foa
ULONG RvaToFoa(CHAR* g_fileBuff,ULONG Rva);
// 获取调用号
ULONG GetServiceCode(CHAR *g_fileBuff);#include "petools.h"
// 加载PE文件
CHAR* PeLoadFile(PHANDLE hFile) {// 打开PE文件OBJECT_ATTRIBUTES oa = {0};oa.Length = sizeof(OBJECT_ATTRIBUTES);oa.RootDirectory = NULL;oa.SecurityDescriptor = NULL;oa.SecurityQualityOfService = NULL;UNICODE_STRING objPath = RTL_CONSTANT_STRING(L"\\??\\c:\\Windows\\system32\\ntdll.dll");oa.ObjectName = &objPath;oa.Attributes = OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE; // 不区分大小写 内核句柄IO_STATUS_BLOCK ioStatus = {0};LARGE_INTEGER lai = { 0 };NTSTATUS ret = ZwCreateFile(hFile, GENERIC_READ, &oa,&ioStatus, &lai, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,NULL,0);if (!NT_SUCCESS(ret)) {return ret;}// 打开成功 那么就要把PE文件加载到内存FILE_STANDARD_INFORMATION fileInfomation = {0};// 查询文件基本信息 从而获取文件的大小ZwQueryInformationFile(*hFile, &ioStatus, &fileInfomation, sizeof(FILE_BASIC_INFORMATION),FileStandardInformation);CHAR* g_fileBuff = ExAllocatePool(PagedPool,fileInfomation.EndOfFile.QuadPart);if (g_fileBuff == NULL) { // 创建缓冲区失败return -1;}LARGE_INTEGER offset = { 0 }; // 把整个PE文件读入缓冲区ret = ZwReadFile(*hFile, NULL, NULL, NULL, &ioStatus, g_fileBuff, fileInfomation.EndOfFile.QuadPart,&offset,NULL);if (!NT_SUCCESS(ret)) {return ret;}return g_fileBuff;
}// 获取函数地址
ULONG GetFunAddr(CHAR* g_fileBuff, CHAR* funName) {if (g_fileBuff == NULL) {return 0;}// 解析PE文件 拿到导出表PIMAGE_DOS_HEADER pDosHeader = g_fileBuff;PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + g_fileBuff);PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;PIMAGE_OPTIONAL_HEADER pOptionalHeader = &pNtHeader->OptionalHeader;// 数据目录表IMAGE_DATA_DIRECTORY dataDict = pOptionalHeader->DataDirectory[0];PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)(RvaToFoa(g_fileBuff,dataDict.VirtualAddress) + g_fileBuff);// 然后解析导出表  拿到函数序号PULONG funNameTable = RvaToFoa(g_fileBuff,pExportTable->AddressOfNames) + g_fileBuff;PULONG funAddrTable = RvaToFoa(g_fileBuff,pExportTable->AddressOfFunctions) + g_fileBuff;SHORT* funOrinalsTable = RvaToFoa(g_fileBuff,pExportTable->AddressOfNameOrdinals) + g_fileBuff;for (size_t i = 0; i < pExportTable->NumberOfNames; i++){CHAR* curName = RvaToFoa(g_fileBuff, funNameTable[i]) + g_fileBuff;if (strcmp(funName, curName) == 0) {// 名称和序号是一一对应的return RvaToFoa(g_fileBuff, funAddrTable[funOrinalsTable[i]]) + g_fileBuff;}}return 0;
}// Rva转Foa
ULONG RvaToFoa(CHAR* g_fileBuff,ULONG Rva) {PIMAGE_DOS_HEADER pDosHeader = g_fileBuff;PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + g_fileBuff);PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader;// 获取区段PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);for (size_t i = 0; i < pFileHeader->NumberOfSections; i++) {if (Rva >= pSectionHeader->VirtualAddress &&Rva < (pSectionHeader->Misc.VirtualSize + pSectionHeader->VirtualAddress)) {// Rva - 区段的Rva + 区段的Foa = Foa return (ULONG)(Rva - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData);}pSectionHeader++;}return 0;
}
// 获取函数调用号
ULONG GetServiceCode(CHAR* g_fileBuff)
{ULONG code = -1;ULONG funAddr = GetFunAddr(g_fileBuff, "ZwClose");// 函数地址 + 1个字节保存的就是调用号code = *(PULONG)(funAddr + 1); // 获取调用号 这样就可以动态HOOK了return code;
}#include <ntifs.h>
#include "petools.h"typedef struct _SSDT {PULONG  funAddrTable; // 函数地址表PULONG  funUseCount;  // 函数使用次数ULONG  funNumber; // 函数个数PULONG funParamTable; // 函数参数字节表
}SSDT, * PSSDT;// 定义函数指针
typedef NTSTATUS(NTAPI* _NtClose)(HANDLE Handle);// SSDT表地址在 Kernel32导出变量中 KeServiceDescriptorTable 000000000056A9C0    915
// 而所有的程序都会引入Kernel32 所以我们可以直接使用这个导出变量,就可以拿到SSDT表的地址
EXTERN_C PSSDT KeServiceDescriptorTable;_NtClose g_OldNtCloseAddr = NULL; // 保存原本的函数地址 HOOK完要给它恢复
PULONG g_funTableAddr = NULL;// HOOK函数 替换掉NtClose
NTSTATUS NTAPI MyNtClose(HANDLE Handle) {DbgPrint("SSDT HOOK成功,HOOK NtClose");return g_OldNtCloseAddr(Handle); // 让原本拿到NtClose完成剩下工作 Hook不能影响原本的函数内容
}// 安装Hook
NTSTATUS InstallSSDTHook(ULONG code) {// 我们Hook CloseHandle 对应 ->  NtClose// KeServiceDescriptorTable->funAddrTable 这个地址是不可以修改的 所以我们做一个新的映射PHYSICAL_ADDRESS pyhAddr = MmGetPhysicalAddress(KeServiceDescriptorTable->funAddrTable); // 获取物理地址g_funTableAddr = MmMapIoSpace(pyhAddr, PAGE_SIZE, MmNonCached); // 物理地址 映射多大 是否需要缓存// g_funTableAddr 映射出来的这个线性地址 就可以直接进行修改操作了g_OldNtCloseAddr = g_funTableAddr[code];g_funTableAddr[code] = (ULONG)MyNtClose;return STATUS_SUCCESS;
}// 卸载Hook
NTSTATUS UnInstallSSDTHook() {if (g_OldNtCloseAddr != NULL) {g_funTableAddr[0x32] = g_OldNtCloseAddr; // 修改回去原本的NtCloseg_OldNtCloseAddr = NULL;MmUnmapIoSpace(g_funTableAddr, PAGE_SIZE); // 然后取消之前的物理地址映射}return STATUS_SUCCESS;
}void DriverUnload(PDRIVER_OBJECT pDriver) {UnInstallSSDTHook(); // 卸载钩子DbgPrint("DriverUnload");
}// eax KiFaseCallEntry SSDT 函数地址表 eax and 0x0FFF 索引 调用API
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath) {HANDLE hFile = NULL;CHAR* fileBuff = PeLoadFile(&hFile);if (fileBuff) { // 加载PE文件ULONG code = GetServiceCode(fileBuff); // 获取函数调用号 那么现在就可以动态SSDT HOOK了DbgPrint("动态调用号:%d\n",code);InstallSSDTHook(code); // 安装钩子// 关闭文件句柄ExFreePool(fileBuff);if(hFile) ZwClose(hFile);} pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

逆向基础-Windows驱动开发【SSDT HOOK】相关推荐

  1. Windows驱动开发学习笔记(五)—— SSDT HOOK

    Windows驱动开发学习笔记(五)-- SSDT HOOK 系统服务表 系统服务描述符表 实验一:通过代码获取SSDT表地址 通过页表基址修改页属性 方法1:修改页属性 方法2:修改CR0寄存器 实 ...

  2. Windows驱动开发学习笔记(六)—— Inline HOOK

    Windows驱动开发学习笔记(六)-- Inline HOOK SSDT HOOK Inline Hook 挂钩 执行流程 脱钩 实验一:3环 Inline Hook 实验二:0环 Inline H ...

  3. Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础

    Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...

  4. Windows驱动开发基础(五)驱动程序的数据结构

    Windows驱动开发基础:驱动程序的数据结构.转载请标明出处:http://blog.csdn.net/ikerpeng/article/details/38794405 I/O管理器定义了一些数据 ...

  5. 《Windows驱动开发技术详解》学习笔记

    Abstract   如果推荐 Windows 驱动开发的入门书,我强烈推荐<Windows驱动开发技术详解>.但是由于成书的时间较早,该书中提到的很多工具和环境都已不可用或找不到,而本文 ...

  6. Windows驱动开发学习笔记(七)—— 多核同步内核重载

    Windows驱动开发学习笔记(七)-- 多核同步 基础知识 并发与同步 分析 InterlockedIncrement 原子操作相关API 内核文件 多核同步 临界区 示例一:错误的临界区 示例二: ...

  7. windows驱动开发学习

    序言]  很多人都对驱动开发有兴趣,但往往找不到正确的学习方式.当然这跟驱动开发的本土化资 料少有关系.大多学的驱动开发资料都以英文为主,这样让很多驱动初学者很头疼.本人从 事驱动开发时间不长也不短, ...

  8. windows驱动开发推荐书籍

    [作者]  猪头三  个人网站 :http://www.x86asm.com/ [序言]  很多人都对驱动开发有兴趣,但往往找不到正确的学习方式.当然这跟驱动开发的本土化资 料少有关系.大多学的驱动开 ...

  9. C++开发方向之windows驱动开发

    1.为什么要写这篇文章? 最近浏览招聘网站看到关于windows驱动开发的岗位,前几天一个C++客户端工作岗位,猎头也问我是否有了解windows内核. 所以,调研了一下C++的开发方向:window ...

  10. [Windows驱动开发](一)序言

    笔者学习驱动编程是从两本书入门的.它们分别是<寒江独钓--内核安全编程>和<Windows驱动开发技术详解>.两本书分别从不同的角度介绍了驱动程序的制作方法. 在我理解,驱动程 ...

最新文章

  1. 闵可夫斯基和(Mincowsky sum)
  2. 树莓派 + Windows IoT Core 搭建环境监控系统
  3. 使用Hibernate和Spring构建Java Web应用程序
  4. django models模型 内部类 class Meta 简介
  5. flask中数据库的基本操作-增删改查【备忘】
  6. linphone相关(转)
  7. 比特大陆裁员 85%,区块链行业彻底入深冬
  8. SHAP(SHapley Additive exPlanation):Python的可解释机器学习库
  9. 锐起无盘系统菜鸟教程
  10. matlab怎么画地震反应谱,地震工程学-反应谱和地震时程波的相互转化matlab编程...
  11. 安全bios手册(5)
  12. 推荐C语言编译器(手机APP)
  13. vc使用nmake时报错
  14. 工业相机镜头选型教程
  15. java web 页面布局框架_jsp框架(jsp实现页面框架布局)
  16. python基础系统学习整理,自学者可以参考的不二笔记
  17. 读文万卷036期:警戒状态下自发性眼睑闭合与功能磁共振成像动态连接的联系;自闭症患者的胼胝体扩散峰度成像
  18. 【Chrome 调试技巧】教你一步不用安装插件就可以完成--电脑页面截图
  19. 集成微控制器使太阳能微型逆变器设计成本有效
  20. Java小白入门200例14之求最大公约数

热门文章

  1. IOC流程解析-BeanFactory的创建
  2. 20.P153课后习题6-13 背包问题。设有一个背包可以放入物品的重量为s,现有n件物品,重量分别为w[0],w[1],...w[n-1]。问题是能否从这n件物品中选择若干件放入此背包中使得放入的重
  3. xgboost 怎么读_你真的会读书了吗?五本书让你会读书,读好书,好读书!
  4. 算法之路-圆柱体面积
  5. 地球人都在玩跨境电商
  6. readxmls r语言_R语言批量爬取NCBI基因注释数据
  7. php后端经历,后端学习路线,仅供参考,个人总结
  8. Kafka高性能之页缓存(page cache)使用
  9. 程序员的浪漫之——情侣日常小程序
  10. element-ui+vue给登录界面创建一个走马灯幻灯片切换