当前位置 博文首页 > KOOKNUT的博客:内存修改(Ring0)
实现两个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