MmCopyVirtualMemory 失败,代码正确
MmCopyVirtualMemory failing, code is correct
我的情况是 MmCopyVirtualMemory 几乎总是(%99 的时间)returns STATUS_PARTIAL_COPY。
(我在 Ring0 驱动程序中运行)
我尝试了很多不同的方法,比如使用不同的变量大小和类型、不同的地址等...总是 returns STATUS_PARTIAL_COPY.
在线也没有任何帮助,这不是一个真正常见的错误。
错误描述:
{Partial Copy} Due to protection conflicts not all the requested bytes could be copied.
我读取进程内存的方式:
DWORD64 Read(DWORD64 SourceAddress, SIZE_T Size)
{
SIZE_T Bytes;
NTSTATUS Status = STATUS_SUCCESS;
DWORD64 TempRead;
DbgPrintEx(0, 0, "\nRead Address:%p\n", SourceAddress); // Always Prints Correct Address
DbgPrintEx(0, 0, "Read szAddress:%x\n", Size); // Prints Correct Size 8 bytes
Status = MmCopyVirtualMemory(Process, SourceAddress, PsGetCurrentProcess(), &TempRead, Size, KernelMode, &Bytes);
DbgPrintEx(0, 0, "Read Bytes:%x\n", Bytes); // Copied bytes - prints 0
DbgPrintEx(0, 0, "Read Output:%p\n", TempRead); // prints 0 as expected since it failed
if (!NT_SUCCESS(Status))
{
DbgPrintEx(0, 0, "Read Failed:%p\n", Status);
return NULL;
}
return TempRead;
}
我如何使用它的示例:
NetMan = Read(BaseAddr + NET_MAN, sizeof(DWORD64));
//BaseAddr is a DWORD64 and NetMan is also a DWORD64
我已经检查了我的代码很多次了,所有这些似乎都是正确的。
在调查 MiDoPoolCopy(MmCopyVirtualMemoy 称之为)之后,它似乎在移动操作期间失败了:
// MiDoPoolCopy function
// Probe to make sure that the specified buffer is accessible in
// the target process.
//Wont execute (supplied KernelMode)
if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
Probing = TRUE;
ProbeForRead (FromAddress, BufferSize, sizeof(CHAR));
Probing = FALSE;
}
//Failing either here, copying inside the target process's address space to the buffer
RtlCopyMemory (PoolArea, InVa, AmountToMove);
KeUnstackDetachProcess (&ApcState);
KeStackAttachProcess (&ToProcess->Pcb, &ApcState);
//
// Now operating in the context of the ToProcess.
//
//Wont execute (supplied KernelMode)
if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
Probing = TRUE;
ProbeForWrite (ToAddress, BufferSize, sizeof(CHAR));
Probing = FALSE;
}
Moving = TRUE;
//or failing here - moving from the Target Process to Source (target process->Kernel)
RtlCopyMemory (OutVa, PoolArea, AmountToMove);
这是返回的 SEH STATUS_PARTIAL_COPY(包含在 try 和 except 中)
//(wrapped in try and except)
//
// If the failure occurred during the move operation, determine
// which move failed, and calculate the number of bytes
// actually moved.
//
*NumberOfBytesRead = BufferSize - LeftToMove;
if (Moving == TRUE) {
//
// The failure occurred writing the data.
//
if (ExceptionAddressConfirmed == TRUE) {
*NumberOfBytesRead = (SIZE_T)((ULONG_PTR)(BadVa - (ULONG_PTR)FromAddress));
}
}
return STATUS_PARTIAL_COPY;
MmCopyVirtualMemory(未记录的结构)
NTSTATUS NTAPI MmCopyVirtualMemory
(
PEPROCESS SourceProcess,
PVOID SourceAddress,
PEPROCESS TargetProcess,
PVOID TargetAddress,
SIZE_T BufferSize,
KPROCESSOR_MODE PreviousMode,
PSIZE_T ReturnSize
);
这是 MmCopyVirtualMemory 和 MiDoPoolCopy 的源代码:
https://lacicloud.net/custom/open/leaks/Windows%20Leaked%20Source/wrk-v1.2/base/ntos/mm/readwrt.c
任何帮助将不胜感激,我已经坚持了很长时间...
我知道这是旧的,但因为我遇到了同样的问题并修复了它,也许将来其他人会偶然发现这个问题。
阅读您的代码,问题在于您要复制数据的目标地址。您正在使用单个定义的 DWORD64,这就是当 运行 函数是一个简单变量(寄存器或堆栈)而不是您可以写入的内存区域时。
解决方案是提供一个正确的缓冲区,您之前使用 malloc 为其分配了内存。
示例(你想读取一个 DWORD64,基于你的代码并进行一些调整):
DWORD64* buffer = malloc(sizeof(DWORD64))
Status = MmCopyVirtualMemory(Process, (void*)SourceAddress, PsGetCurrentProcess(), (void*)buffer, sizeof(DWORD64), UserMode, &Bytes);
不要忘记在使用后释放缓冲区以防止内存泄漏。
我的情况是 MmCopyVirtualMemory 几乎总是(%99 的时间)returns STATUS_PARTIAL_COPY。 (我在 Ring0 驱动程序中运行)
我尝试了很多不同的方法,比如使用不同的变量大小和类型、不同的地址等...总是 returns STATUS_PARTIAL_COPY.
在线也没有任何帮助,这不是一个真正常见的错误。
错误描述:
{Partial Copy} Due to protection conflicts not all the requested bytes could be copied.
我读取进程内存的方式:
DWORD64 Read(DWORD64 SourceAddress, SIZE_T Size)
{
SIZE_T Bytes;
NTSTATUS Status = STATUS_SUCCESS;
DWORD64 TempRead;
DbgPrintEx(0, 0, "\nRead Address:%p\n", SourceAddress); // Always Prints Correct Address
DbgPrintEx(0, 0, "Read szAddress:%x\n", Size); // Prints Correct Size 8 bytes
Status = MmCopyVirtualMemory(Process, SourceAddress, PsGetCurrentProcess(), &TempRead, Size, KernelMode, &Bytes);
DbgPrintEx(0, 0, "Read Bytes:%x\n", Bytes); // Copied bytes - prints 0
DbgPrintEx(0, 0, "Read Output:%p\n", TempRead); // prints 0 as expected since it failed
if (!NT_SUCCESS(Status))
{
DbgPrintEx(0, 0, "Read Failed:%p\n", Status);
return NULL;
}
return TempRead;
}
我如何使用它的示例:
NetMan = Read(BaseAddr + NET_MAN, sizeof(DWORD64));
//BaseAddr is a DWORD64 and NetMan is also a DWORD64
我已经检查了我的代码很多次了,所有这些似乎都是正确的。
在调查 MiDoPoolCopy(MmCopyVirtualMemoy 称之为)之后,它似乎在移动操作期间失败了:
// MiDoPoolCopy function
// Probe to make sure that the specified buffer is accessible in
// the target process.
//Wont execute (supplied KernelMode)
if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
Probing = TRUE;
ProbeForRead (FromAddress, BufferSize, sizeof(CHAR));
Probing = FALSE;
}
//Failing either here, copying inside the target process's address space to the buffer
RtlCopyMemory (PoolArea, InVa, AmountToMove);
KeUnstackDetachProcess (&ApcState);
KeStackAttachProcess (&ToProcess->Pcb, &ApcState);
//
// Now operating in the context of the ToProcess.
//
//Wont execute (supplied KernelMode)
if ((InVa == FromAddress) && (PreviousMode != KernelMode)){
Probing = TRUE;
ProbeForWrite (ToAddress, BufferSize, sizeof(CHAR));
Probing = FALSE;
}
Moving = TRUE;
//or failing here - moving from the Target Process to Source (target process->Kernel)
RtlCopyMemory (OutVa, PoolArea, AmountToMove);
这是返回的 SEH STATUS_PARTIAL_COPY(包含在 try 和 except 中)
//(wrapped in try and except)
//
// If the failure occurred during the move operation, determine
// which move failed, and calculate the number of bytes
// actually moved.
//
*NumberOfBytesRead = BufferSize - LeftToMove;
if (Moving == TRUE) {
//
// The failure occurred writing the data.
//
if (ExceptionAddressConfirmed == TRUE) {
*NumberOfBytesRead = (SIZE_T)((ULONG_PTR)(BadVa - (ULONG_PTR)FromAddress));
}
}
return STATUS_PARTIAL_COPY;
MmCopyVirtualMemory(未记录的结构)
NTSTATUS NTAPI MmCopyVirtualMemory
(
PEPROCESS SourceProcess,
PVOID SourceAddress,
PEPROCESS TargetProcess,
PVOID TargetAddress,
SIZE_T BufferSize,
KPROCESSOR_MODE PreviousMode,
PSIZE_T ReturnSize
);
这是 MmCopyVirtualMemory 和 MiDoPoolCopy 的源代码: https://lacicloud.net/custom/open/leaks/Windows%20Leaked%20Source/wrk-v1.2/base/ntos/mm/readwrt.c
任何帮助将不胜感激,我已经坚持了很长时间...
我知道这是旧的,但因为我遇到了同样的问题并修复了它,也许将来其他人会偶然发现这个问题。
阅读您的代码,问题在于您要复制数据的目标地址。您正在使用单个定义的 DWORD64,这就是当 运行 函数是一个简单变量(寄存器或堆栈)而不是您可以写入的内存区域时。
解决方案是提供一个正确的缓冲区,您之前使用 malloc 为其分配了内存。
示例(你想读取一个 DWORD64,基于你的代码并进行一些调整):
DWORD64* buffer = malloc(sizeof(DWORD64))
Status = MmCopyVirtualMemory(Process, (void*)SourceAddress, PsGetCurrentProcess(), (void*)buffer, sizeof(DWORD64), UserMode, &Bytes);
不要忘记在使用后释放缓冲区以防止内存泄漏。