 突破TP,NP保护跨进程读写内存2

2021在线班
郁金香灬老师 QQ 150330575
交流群:158280115


学习目标: 
    突破TP,NP保护跨进程读写内存2

	
	League of Legends.exe
	0x400000
	#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来读取内存 UserBuffer=0x200000
	DbgPrint("yjx:sys64 %s 行号=%d(Process=%p,Address=%p,Length=%d,UserBuffer=%p)", __FUNCDNAME__, __LINE__,Process,Address,Length,UserBuffer);

	PMDL g_pmdl = IoAllocateMdl(UserBuffer, Length, 0, 0, NULL); //8 可以修改成 要读取的内存大小
	if (!g_pmdl)
	{
		return FALSE;
	}

	//2标记为非分页内存
	MmBuildMdlForNonPagedPool(g_pmdl);
	//3锁定 映射用户内存 到 内核内存 0x100000
	unsigned char* Mapped = (unsigned char*)MmMapLockedPages(g_pmdl, KernelMode); //UserMode
	if (!Mapped)
	{ //映射失败
		IoFreeMdl(g_pmdl);
		return FALSE;
	}
	//关键 重点
	//成功 映射了 地址
	//切换到 目标进程 3920  UserBuffer 能被访问   3796 Address 不能访问
	KeStackAttachProcess((PVOID)Process, &apc_state);
	//切换到 目标进程 3920  UserBuffer 不能访问   3796 Address   能访问
	//判断目标地址是否可以访问 UserBuffer不可访问 Mapped可以访问
	
	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 %s 行号=%d %s", __FUNCDNAME__, __LINE__);
	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:sys64 %s 行号=%d %s", __FUNCDNAME__,__LINE__);
	NTSTATUS ntStatus = STATUS_SUCCESS;
	PIO_STACK_LOCATION     irpStack = NULL;
	irpStack = IoGetCurrentIrpStackLocation(pirp);

#pragma pack(push)
#pragma pack(8)
	typedef struct TINPUT_BUF
	{
		UINT64 dwPid;//目标进程PID
		PVOID pBase; //目标进程地址
		UINT64 nSize;//要读取的长度

	}TINPUT_BUF;
#pragma pack(pop)
	//结构

	PVOID BaseAddress = NULL; //返回地址

	PEPROCESS selectedprocess = NULL;//目标进程	
	SIZE_T RegionSize = 0;//分配大小


	TINPUT_BUF*bufInput =(TINPUT_BUF*)(pirp->AssociatedIrp.SystemBuffer); 
	//读“TINPUT_BUF 输入缓冲区” 
	//写  UserBuferr  		&返回数据,//返回缓冲区 UserBuffer=&返回数据

	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;
}

