当前位置 博文首页 > KOOKNUT的博客:内存修改(Ring0)

    KOOKNUT的博客:内存修改(Ring0)

    作者:[db:作者] 时间:2021-07-03 09:19

    实现两个Ring3层进程虚拟地址空间中的数据拷贝,实现思路:
    1.使用两个进程的EPROCESS和VirtualAddress作为参数传递
    2.若需要拷贝的数据长度大于阈值,则用映射MDL的方式拷贝,否则直接只用内核虚拟地址空间进行拷贝。
    3.例程上下背景文切换,完成数据拷贝。

    NTSTATUS KtCopyVirtualMemory(
    	__in PEPROCESS SourceEProcess,
    	__in PVOID SourceVirtualAddress,
    	__in PEPROCESS TargetEProcess,
    	__in PVOID TargetVirtualAddress,
    	__in SIZE_T BufferLength,
    	__in KPROCESSOR_MODE AccessMode,
    	__out PSIZE_T ReturnLength)
    {
    
    #define STACK_COPY_BYTES 0x200
    #define MAPPED_COPY_PAGES 14 
    //#define POOL_COPY_OVERFLOW 0x3ff
    #define POOL_COPY_OVERFLOW 0x50   //可以修改这个值,为了测试MDL是否成功
    
    	PFN_NUMBER PfnNumber[(sizeof(MDL) / sizeof(PFN_NUMBER))];
    	KAPC_STATE KApcState;
    	
    	BOOLEAN IsMdl;//是否使用MDL方式进行内存拷贝
    	BOOLEAN IsPagesLocked;//页面是否上锁
    	BOOLEAN IsCopyingToTarget = FALSE;
    
    	BOOLEAN IsMapping = FALSE;
    	BOOLEAN IsBad;
    	ULONG_PTR BadVirtualAddress;
    
    	PVOID v10;  //源虚拟地址   游走指针
    	PVOID v20;	//目标虚拟地址 游走指针
    	UCHAR BufferData[STACK_COPY_BYTES];
    	PVOID v1;	//存放Temp数据的游走指针
    	SIZE_T MappedTotalLength = 0;
    	SIZE_T v7;  //拷贝数据总长
    	SIZE_T BlockLength;//截止长度
    	BOOLEAN IsOk = FALSE;
    	PMDL Mdl = (PMDL)PfnNumber;
    	PVOID VirtualAddress = NULL;   //MDL使用
    	
    	PAGED_CODE();//中断请求级太高属于kernel部分,避免它
    
    
    	v10 = SourceVirtualAddress;  
    	v20 = TargetVirtualAddress;
    
    	v1 = BufferData;
    
    	//预先设定一个拷贝值 最多拷贝12页虚拟内存这么大(人为设定的)
    	MappedTotalLength = (MAPPED_COPY_PAGES - 2) * PAGE_SIZE;
    	//如果需要拷贝的数据长度小于设定值  则赋值
    	if (MappedTotalLength > BufferLength)
    	{
    		//按照BufferLength来拷贝
    		MappedTotalLength = BufferLength;
    	}
    
    	v7 = BufferLength;   //传入的数据长度
    	BlockLength = MappedTotalLength;   //如果BufferLength>MappedTotalLength则按照12页截断 一次只能拷贝12页
    
    	while (v7)
    	{
    		if (BlockLength > v7)
    		{
    			BlockLength = v7;
    		}
    		
    		if (BlockLength > POOL_COPY_OVERFLOW)
    		{
    			//使用MDl拷贝
    			IsMdl = TRUE;
    		}
    		else
    		{
    			IsMdl = FALSE;
    
    			if (BlockLength <= STACK_COPY_BYTES)
    			{
    				//不使用动态堆内存直接使用栈区内存
    				if (v1 != BufferData)
    				{
    					ExFreePool(v1);
    				}
    				//直接使用栈区内存即可
    				v1 = BufferData;
    			}
    			else
    			{
    
    				//若拷贝的数据长度太大,则使用堆内存,防止栈溢出
    				if (v1 == BufferData)
    				{
    					//动态申请内存
    					while (TRUE)
    					{
    						//申请不分页内存
    						v1 = ExAllocatePool(NonPagedPool, BlockLength);
    						if (v1)
    						{
    							//申请成功 退出申请
    							break;
    						}
    						//数据长度太大,无法成功,则折半继续申请
    						BlockLength /= 2;
    						
    						if (BlockLength <= STACK_COPY_BYTES)
    						{
    							//如果有机会  就使用栈区内存
    							v1 = BufferData;
    							break;
    						}
    					}
    				}
    			}
    		}
    		VirtualAddress = NULL;//用来保存MDL映射地址
    		IsPagesLocked = FALSE;
    		IsCopyingToTarget = FALSE;
    		
    		KeStackAttachProcess(SourceEProcess, &KApcState);
    		//每个对KeStackAttachProcess的调用都必须与随后对KeUnstackDetachProcess的调用匹配。
    		__try
    		{
    
    			if (v10 == SourceVirtualAddress && AccessMode != KernelMode)
    			{
    				IsOk = TRUE;
    				ProbeForRead(v10, BufferLength, sizeof(UCHAR));
    				IsOk = FALSE;
    			}
    
    			if (IsMdl)
    			{
    				// 初始化MDL,建立与Ring3虚拟内存的对应关系
    				MmInitializeMdl(Mdl, v10, BlockLength);
    				/*
    				2: kd> dt _MDL 0x8e9b26e0
    					nt!_MDL
    					   +0x000 Next             : (null)
    					   +0x004 Size             : 0n32
    					   +0x006 MdlFlags         : 0n0
    					   +0x008 Process          : 0x8c001b28 _EPROCESS
    					   +0x00c MappedSystemVa   : 0x8e9b2708 Void
    					   +0x010 StartVa          : 0x001af000 Void         //页面起始地址
    					   +0x014 ByteCount        : 0x200					//页面总字节数(对齐粒度)
    					   +0x018 ByteOffset       : 0xb10					//目标地址相对于StartVA得偏移
    				*/
    				//MmProbeAndLockPages例程探测指定的虚拟内存页,使它们驻留并锁定他们所在的那片物理内存。
    				/*
    					//
    					// Mark the MDL as locked *now*
    					//
    					Mdl->MdlFlags |= MDL_PAGES_LOCKED;
    				*/
    				MmProbeAndLockPages(Mdl, AccessMode, IoReadAccess); //上锁
    				IsPagesLocked = TRUE;
    
    				// 映射锁定的那片物理内存页到内核虚拟内存中来
    				/*
    						//
    						// Mark it as mapped
    						//
    						ASSERT((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) == 0);
    						Mdl->MappedSystemVa = Base;//将Ring3对应的物理内存映射到Ring0虚拟地址中来,返回VirtualAddress
    						Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
    				*/
    				VirtualAddress = MmMapLockedPagesSpecifyCache(
    					Mdl,
    					KernelMode,
    					MmCached,
    					NULL,
    					FALSE,
    					HighPagePriority
    				);
    				//VirtualAddress = 0xa57c5b10
    				/*
    				2: kd> db 0xa57c5b10
    					a57c5b10  48 00 65 00 6c 00 6c 00-6f 00 57 00 6f 00 72 00  H.e.l.l.o.W.o.r.
    					a57c5b20  6c 00 64 00 00 00 00 00-00 00 00 00 00 00 00 00  l.d.............
    				*/
    
    				if (!VirtualAddress)
    				{
    					// Insufficient resources; exit.
    					IsMapping = TRUE;
    					ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
    				}
    			}
    			else
    			{
    			//直接进行内存拷贝
    				memcpy(v1, v10, BlockLength);
    			}
    
    			KeUnstackDetachProcess(&KApcState);		//例程回到当前进程
    
    			//把当前进程附加到目标进程的地址空间
    			KeStackAttachProcess(TargetEProcess, &KApcState);
    
    			if (v20 == TargetVirtualAddress && AccessMode != KernelMode)
    			{
    				IsOk = TRUE;
    				ProbeForWrite(v20, BufferLength, sizeof(UCHAR));
    				IsOk = FALSE;
    			}
    			IsCopyingToTarget = TRUE;
    
    			if (IsMdl)
    			{
    				//直接从Mdl中拷贝数据
    				memcpy(v20, VirtualAddress, BlockLength);
    			}
    			else
    			{
    				//从v1(临时的变量)中拷贝
    				memcpy(v20, v1, BlockLength);
    			}
    
    		}
    		__except
    			(KGetCopyExceptionInformation(
    				GetExceptionInformation(),
    				&IsBad,
    				&BadVirtualAddress
    			))
    		{
    			KeUnstackDetachProcess(&KApcState);
    			//善后处理
    			if (VirtualAddress)
    			{
    				MmUnmapLockedPages(VirtualAddress, Mdl);
    			}
    			if (IsPagesLocked)
    			{
    				MmUnlockPages(Mdl);
    			}
    			if (v1 != BufferData)
    			{
    				ExFreePool(v1);
    			}
    			if (IsOk || IsMapping)
    			{
    				return GetExceptionCode();
    			}
    			if (IsCopyingToTarget && IsBad)
    			{
    				*ReturnLength = (ULONG)(BadVirtualAddress - (ULONG_PTR)v10);
    			}
    			else
    			{
    				*ReturnLength = BufferLength - v7;
    			}
    			return STATUS_PARTIAL_COPY;
    		}
    
    		KeUnstackDetachProcess(&KApcState);
    
    		if (IsMdl)
    		{
    			MmUnmapLockedPages(VirtualAddress, Mdl);
    			MmUnlockPages(Mdl);
    		}
    
    		v7 -= BlockLength;
    		v10 = (PVOID)((ULONG_PTR)v10 + BlockLength);
    		v20 = (PVOID)((ULONG_PTR)v20 + BlockLength);
    	}
    
    	if (v1 != BufferData)
    	{
    		ExFreePool(v1);
    	}
    	*ReturnLength = BufferLength;
    	return STATUS_SUCCESS;
    }
    

    “You can like the life you are living.You can live the life you like.”

    cs