HyperDbg/hyperdbg/hyperhv/code/memory/MemoryManager.c

244 lines
7 KiB
C

/**
* @file MemoryManager.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Reading/Writing memory and all memory affairs
*
* @version 0.1
* @date 2020-04-24
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
/**
* @brief Read physical memory from the physical address (used in VMI mode)
*
* @param PhysicalAddress Physical Address
* @param Buffer Buffer to save the memory
* @param BufferSize Size of the buffer
*
* @return BOOLEAN
*/
BOOLEAN
ReadPhysicalMemoryUsingMapIoSpace(PVOID PhysicalAddress, PVOID Buffer, SIZE_T BufferSize)
{
PHYSICAL_ADDRESS PhysicalAddressTemp = {0};
PhysicalAddressTemp.QuadPart = (LONGLONG)PhysicalAddress;
PVOID VirtualAddress = MmMapIoSpaceEx(PhysicalAddressTemp, BufferSize, PAGE_READWRITE | PAGE_NOCACHE);
if (VirtualAddress == NULL)
{
return FALSE;
}
RtlCopyMemory(Buffer, VirtualAddress, BufferSize);
MmUnmapIoSpace(VirtualAddress, BufferSize);
return TRUE;
}
/**
* @brief Write physical memory to the physical address (used in VMI mode)
*
* @param PhysicalAddress Physical Address
* @param Buffer Buffer to write to the memory
* @param BufferSize Size of the buffer
*
* @return BOOLEAN
*/
BOOLEAN
WritePhysicalMemoryUsingMapIoSpace(PVOID PhysicalAddress, PVOID Buffer, SIZE_T BufferSize)
{
PHYSICAL_ADDRESS PhysicalAddressTemp = {0};
PhysicalAddressTemp.QuadPart = (LONGLONG)PhysicalAddress;
PVOID VirtualAddress = MmMapIoSpaceEx(PhysicalAddressTemp, BufferSize, PAGE_READWRITE | PAGE_NOCACHE);
if (VirtualAddress == NULL)
{
return FALSE;
}
RtlCopyMemory(VirtualAddress, Buffer, BufferSize);
MmUnmapIoSpace(VirtualAddress, BufferSize);
return TRUE;
}
/**
* @brief Read process memory
*
* @details This function should not be called from vmx-root mode
*
* @param PID Target Process Id
* @param Address Target Address
* @param MemType Type of memory
* @param UserBuffer Buffer to save to the user. This buffer must be in nonpageable memory.
* @param Size Size of read
* @param ReturnSize Return Size
*
* @return BOOLEAN
*/
BOOLEAN
MemoryManagerReadProcessMemoryNormal(HANDLE PID,
PVOID Address,
DEBUGGER_READ_MEMORY_TYPE MemType,
PVOID UserBuffer,
SIZE_T Size,
PSIZE_T ReturnSize)
{
PEPROCESS SourceProcess;
MM_COPY_ADDRESS CopyAddress = {0};
KAPC_STATE State = {0};
PHYSICAL_ADDRESS TempPhysicalAddress = {0};
//
// Check if we want another process memory, this way we attach to that process
// the find the physical address of the memory and read it from here using physical
// address
//
// The second thing that we consider here is reading a physical address doesn't
// need to attach to another process
//
if (PsGetCurrentProcessId() != PID && MemType == DEBUGGER_READ_VIRTUAL_ADDRESS)
{
//
// User needs another process memory
//
if (PsLookupProcessByProcessId(PID, &SourceProcess) != STATUS_SUCCESS)
{
//
// if the process not found
//
return FALSE;
}
__try
{
KeStackAttachProcess(SourceProcess, &State);
//
// We're in context of another process let's read the memory
//
TempPhysicalAddress = MmGetPhysicalAddress(Address);
KeUnstackDetachProcess(&State);
//
// Now we have to read the physical address
//
CopyAddress.PhysicalAddress.QuadPart = TempPhysicalAddress.QuadPart;
MmCopyMemory(UserBuffer, CopyAddress, Size, MM_COPY_MEMORY_PHYSICAL, ReturnSize);
ObDereferenceObject(SourceProcess);
return TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
KeUnstackDetachProcess(&State);
ObDereferenceObject(SourceProcess);
return FALSE;
}
}
else
{
//
// Process needs itself memory
//
__try
{
if (MemType == DEBUGGER_READ_VIRTUAL_ADDRESS)
{
CopyAddress.VirtualAddress = Address;
MmCopyMemory(UserBuffer, CopyAddress, Size, MM_COPY_MEMORY_VIRTUAL, ReturnSize);
}
else if (MemType == DEBUGGER_READ_PHYSICAL_ADDRESS)
{
//
// Check whether the physical memory is valid or not
//
if (!CheckAddressPhysical((UINT64)Address))
{
return FALSE;
}
CopyAddress.PhysicalAddress.QuadPart = (LONGLONG)Address;
if (MmCopyMemory(UserBuffer, CopyAddress, Size, MM_COPY_MEMORY_PHYSICAL, ReturnSize) != STATUS_SUCCESS && *ReturnSize == 0)
{
//
// If the memory is not readable, it might be an MMIO address
// Try again with another method
//
// LogInfo("reading using MMIO Map IO Space using VMCALL");
if (AsmVmxVmcall(VMCALL_READ_PHYSICAL_MEMORY, (UINT64)Address, (UINT64)UserBuffer, (UINT64)Size) == STATUS_SUCCESS)
{
*ReturnSize = Size;
return TRUE;
}
else
{
//
// unknown error
//
*ReturnSize = 0;
return FALSE;
}
}
}
else
{
//
// Type is not recognized
//
return FALSE;
}
//
// MmCopyVirtualMemory(SourceProcess, Address, TargetProcess, UserBuffer, Size, KernelMode, ReturnSize);
// memcpy(UserBuffer, Address, Size);
//
return TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return FALSE;
}
}
}
/**
* @brief Write process memory
*
* @details This function should not be called from vmx-root mode
*
* @param TargetAddress Target Address
* @param UserBuffer Buffer to write to the memory
* @param Size Size of the buffer
*
* @return BOOLEAN
*/
BOOLEAN
MemoryManagerWritePhysicalMemoryNormal(PVOID TargetAddress,
PVOID UserBuffer,
SIZE_T Size)
{
if (AsmVmxVmcall(VMCALL_WRITE_PHYSICAL_MEMORY, (UINT64)TargetAddress, (UINT64)UserBuffer, (UINT64)Size) == STATUS_SUCCESS)
{
return TRUE;
}
else
{
return FALSE;
}
}