 突破TP,NP保护跨进程读写内存2

2021在线班
郁金香灬老师 QQ 150330575
交流群:158280115


学习目标: 
    突破TP,NP保护跨进程读写内存2

	
	League of Legends.exe
	0x400000
	#include<ntifs.h>


MmMapLockedPages
MmGetSystemAddressForMdlSafe 进行实际的映射操作，并设置MdlFlags的MDL_MAPPED_TO_SYSTEM_VA标志。

MmProbeAndLockPages 并不将物理页面映射到内核地址空间，而仅锁定物理页面
MmProbeAndLockPages 将MdlFlags=MDL_WRITE_OPERATION | MDL_ALLOCATED_FIXED_SIZE | MDL_PAGES_LOCKED
当您不再需要 MDL 描述的页时，请调用 MmUnlockPages 将它们解除锁定，然后调用 IoFreeMdl 来释放它们。


#include <ntifs.h>



//OK 测试通过 遇到2个坑 
//第1个坑 sizeof(PKAPC_STATE)是指针 得改结构大小 sizeof(KAPC_STATE)
//第2个坑 KeStackAttachProcess后 进程空间变化了 得用内核内存 中转 BUF缓冲区
//Address为目标进程的内存地址
//Buffer //当前进程的地址
BOOLEAN KReadProcessMemory2(IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, IN PVOID UserBuffer)
{

	KAPC_STATE apc_state;
	RtlZeroMemory(&apc_state, sizeof(KAPC_STATE));
  //1为UserBuffer 创建 MDL内存描述
  //创建MDL来读取内存
	PMDL g_pmdl = IoAllocateMdl(UserBuffer, 8, 0, 0, NULL); //8 可以修改成 要读取的内存大小
	if (!g_pmdl)
	{
		return FALSE;
	}

//2转换成 非分页内存
	MmBuildMdlForNonPagedPool(g_pmdl);
	g_pmdl->MdlFlags = MDL_WRITE_OPERATION | MDL_ALLOCATED_FIXED_SIZE | MDL_PAGES_LOCKED;
//3锁定 映射用户内存 到 内核内存
	unsigned char* Mapped = (unsigned char*)MmMapLockedPages(g_pmdl, KernelMode); //UserMode
	if (!Mapped)
	{ //映射失败
		IoFreeMdl(g_pmdl);
		return FALSE;
	}
	//成功 映射了 地址
	//切换到 目标进程
	KeStackAttachProcess((PVOID)Process, &apc_state);
	//判断目标地址是否可以访问
	BOOLEAN dwRet = MmIsAddressValid(Address);
	if (dwRet)
	{
		KdPrint(("yjx[sys64] RtlCopyMemory(Address, Buffer, Length);\r\n", Address, UserBuffer, Length));

		 //如果目标地址 可以访问 直接复制目标地址内容 到映射的内核地址区域
		RtlCopyMemory(Mapped, Address, Length); //memcpy 

	}
	else
	{
		KdPrint(("yjx:sys64:Error Line37"));
	}
	//分离目标进程空间 恢复环境
	KeUnstackDetachProcess(&apc_state);
	DbgPrint("yjx: sys分离目标进程");
	 
	//MDL清理工作
	////释放MDL相关 资源
	MmUnmapLockedPages((PVOID)Mapped, g_pmdl);
	IoFreeMdl(g_pmdl);
 
	return dwRet;
}
//dwPid为目标进程id
//lpBaseAddress 目标进程地址

//lpBuffer 当前进程地址 1
//内核内存地址 当前进程地址 2
int ReadProcessMemoryForPid2(UINT32 dwPid, PVOID pBase, PVOID lpBuffer, UINT32 nSize)
{
	//根据pid获取PEPROCESS
	PEPROCESS Seleted_pEPROCESS = NULL;
	DbgPrint("yjx:sys64 ReadMemory pid=%d pBase=%p", dwPid, pBase);
	if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(dwPid), &Seleted_pEPROCESS) == STATUS_SUCCESS)
	{

		BOOLEAN br = KReadProcessMemory2(Seleted_pEPROCESS, (PVOID)pBase, nSize, lpBuffer);
		ObDereferenceObject(Seleted_pEPROCESS);
		if (br)
		{
			return nSize;
		}
	}
	else
	{
		KdPrint(("yjx sys64 PsLookupProcessByProcessId Fail..."));
	}

	return 0;// STATUS_UNSUCCESSFUL;

}

//int ReadProcessMemoryForPid2(UINT32 dwPid, PVOID pBase, PVOID lpBuffer, UINT32 nSize);
NTSTATUS  IRP_ReadProcessMemory2(PDEVICE_OBJECT device_Object, PIRP pirp)
{

	UNREFERENCED_PARAMETER(device_Object); //未使用的参数 禁止警告
	DbgPrint("yjx:sysNtAllocateVirtualMemory 进入 IRP_YJX_VirtualAllocEx \n");
	NTSTATUS ntStatus = STATUS_SUCCESS;
	PIO_STACK_LOCATION     irpStack = NULL;
	irpStack = IoGetCurrentIrpStackLocation(pirp);

#pragma pack(push)
#pragma pack(1)
	typedef struct TINPUT_BUF
	{
		DWORD32 dwPid;
		PVOID pBase; //目标进程地址
		DWORD32 nSize;//缓冲区大小

	}TINPUT_BUF;
#pragma pack(pop)
	//结构

	PVOID BaseAddress = NULL; //返回地址

	PEPROCESS selectedprocess = NULL;//目标进程	
	SIZE_T RegionSize = 0;//分配大小


	TINPUT_BUF*bufInput = pirp->AssociatedIrp.SystemBuffer; //输入 输出 缓冲区
 
	ReadProcessMemoryForPid2(bufInput->dwPid, bufInput->pBase, bufInput, bufInput->nSize);

	//ENDCODE:
	//pirp->IoStatus.Status = STATUS_SUCCESS;//
	////pirp->IoStatus.Information = 4;//返回给DeviceIoControl中的 倒数第二个参数lpBytesReturned
	//IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作 并且不增加优先级 
	if (irpStack) //
	{
		if (ntStatus == STATUS_SUCCESS)
		{ //成功则返回 缓冲区大小
			pirp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;//DeviceIoControl
		}
		else
		{ //失败则不返回
			pirp->IoStatus.Information = 0;
		}
		//完成请求
		IoCompleteRequest(pirp, IO_NO_INCREMENT);
	}

	pirp->IoStatus.Status = ntStatus;
	return ntStatus;
}


BOOLEAN KWriteProcessMemory2(IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, IN PVOID UserBuffer)
{

	KAPC_STATE apc_state;
	RtlZeroMemory(&apc_state, sizeof(KAPC_STATE));
	unsigned char* Mapped = 0;
	PMDL g_pmdl = 0;
	//1为UserBuffer 创建 MDL内存描述
	//创建MDL来读取内存
		//成功 映射了 地址
	//切换到 目标进程
	KeStackAttachProcess((PVOID)Process, &apc_state);
	BOOLEAN dwRet = MmIsAddressValid(Address);
	if (dwRet)
	{
		 g_pmdl = IoAllocateMdl(Address, 8, 0, 0, NULL); //8 可以修改成 要读取的内存大小
		if (!g_pmdl)
		{
			return FALSE;
		}

		//2转换成 非分页内存
		MmBuildMdlForNonPagedPool(g_pmdl);
		g_pmdl->MdlFlags = MDL_WRITE_OPERATION;// | MDL_ALLOCATED_FIXED_SIZE | MDL_PAGES_LOCKED;
		//3锁定 映射用户内存 到 内核内存
		Mapped = (unsigned char*)MmGetSystemAddressForMdlSafe(g_pmdl, KernelMode); //UserMode
		if (!Mapped)
		{ //映射失败
			IoFreeMdl(g_pmdl);
			return FALSE;
		}
		KdPrint(("yjx[sys64] KWriteProcessMemory2(Address=%p, Buffer=%p, Length=%d) line=%d\r\n", Address, UserBuffer, Length, __LINE__));
				
	}
	KeUnstackDetachProcess(&apc_state);

	//判断目标地址是否可以访问
	
	if (dwRet&&g_pmdl)
	{
		KdPrint(("yjx[sys64] KWriteProcessMemory2(Address=%p, Buffer=%p, Length=%d) line=%d>>>\r\n", Address, UserBuffer, Length, __LINE__));

		//如果目标地址 可以访问 直接复制目标地址内容 到映射的内核地址区域
		//UINT64 buf1 = 12345678;
		//RtlCopyMemory(Address, &buf1, Length); //memcpy  RtlCopyMemory(Mapped,Address, Length);
		RtlCopyMemory(Mapped, UserBuffer, Length);

	}
	else
	{
		KdPrint(("yjx:sys64:Error Line37"));
	}
	//分离目标进程空间 恢复环境

	DbgPrint("yjx: sys分离目标进程 line=%d\n",__LINE__);

	//MDL清理工作
	////释放MDL相关 资源
	MmUnmapLockedPages((PVOID)Mapped, g_pmdl);
	IoFreeMdl(g_pmdl);

	return dwRet;
}

//lpBuffer 当前进程地址 1
//内核内存地址 当前进程地址 2
int WriteProcessMemoryForPid2(UINT32 dwPid, PVOID pBase, PVOID lpBuffer, UINT32 nSize)
{
	//根据pid获取PEPROCESS
	PEPROCESS Seleted_pEPROCESS = NULL;
	DbgPrint("yjx:sys64 WriteProcessMemoryForPid2 pid=%d pBase=%p", dwPid, pBase);
	if (PsLookupProcessByProcessId((PVOID)(UINT_PTR)(dwPid), &Seleted_pEPROCESS) == STATUS_SUCCESS)
	{

		BOOLEAN br = KWriteProcessMemory2(Seleted_pEPROCESS, (PVOID)pBase, nSize, lpBuffer);
		ObDereferenceObject(Seleted_pEPROCESS);
		if (br)
		{
			return nSize;
		}
	}
	else
	{
		KdPrint(("yjx sys64 PsLookupProcessByProcessId Fail..."));
	}

	return 0;// STATUS_UNSUCCESSFUL;

}


NTSTATUS  IRP_WriteProcessMemory2(PIRP pirp) 
{

	 
	DbgPrint("yjx:%s line=%d \n",__FUNCDNAME__,__LINE__);
	NTSTATUS ntStatus = STATUS_SUCCESS;
	PIO_STACK_LOCATION     irpStack = NULL;
	irpStack = IoGetCurrentIrpStackLocation(pirp);

#pragma pack(push)
#pragma pack(1)
	typedef struct TINPUT_BUF
	{
		DWORD32 dwPid;
		PVOID pBase; //目标进程地址
		DWORD32 nSize;//缓冲区大小
		UINT64 buf;

	}TINPUT_BUF;
#pragma pack(pop)
	//结构

	PVOID BaseAddress = NULL; //返回地址

	PEPROCESS selectedprocess = NULL;//目标进程	
	SIZE_T RegionSize = 0;//分配大小


	TINPUT_BUF*bufInput = pirp->AssociatedIrp.SystemBuffer; //输入 输出 缓冲区

	WriteProcessMemoryForPid2(bufInput->dwPid, bufInput->pBase, bufInput->buf, bufInput->nSize);

	//ENDCODE:
	//pirp->IoStatus.Status = STATUS_SUCCESS;//
	////pirp->IoStatus.Information = 4;//返回给DeviceIoControl中的 倒数第二个参数lpBytesReturned
	//IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作 并且不增加优先级 
	if (irpStack) //
	{
		if (ntStatus == STATUS_SUCCESS)
		{ //成功则返回 缓冲区大小
			pirp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;//DeviceIoControl
		}
		else
		{ //失败则不返回
			pirp->IoStatus.Information = 0;
		}
		//完成请求
		IoCompleteRequest(pirp, IO_NO_INCREMENT);
	}

	pirp->IoStatus.Status = ntStatus;
	return ntStatus;
}