#include "VadRoutines.h"
#include "VadHelpers.h"
#pragma alloc_text(PAGE, BBProtectVAD)
#pragma alloc_text(PAGE, BBUnlinkVAD)
#pragma alloc_text(PAGE, BBGetVadType)
#pragma alloc_text(PAGE, BBFindVAD)
extern DYNAMIC_DATA dynData;
ULONG MmProtectToValue[32] =
{
PAGE_NOACCESS,
PAGE_READONLY,
PAGE_EXECUTE,
PAGE_EXECUTE_READ,
PAGE_READWRITE,
PAGE_WRITECOPY,
PAGE_EXECUTE_READWRITE,
PAGE_EXECUTE_WRITECOPY,
PAGE_NOACCESS,
PAGE_NOCACHE | PAGE_READONLY,
PAGE_NOCACHE | PAGE_EXECUTE,
PAGE_NOCACHE | PAGE_EXECUTE_READ,
PAGE_NOCACHE | PAGE_READWRITE,
PAGE_NOCACHE | PAGE_WRITECOPY,
PAGE_NOCACHE | PAGE_EXECUTE_READWRITE,
PAGE_NOCACHE | PAGE_EXECUTE_WRITECOPY,
PAGE_NOACCESS,
PAGE_GUARD | PAGE_READONLY,
PAGE_GUARD | PAGE_EXECUTE,
PAGE_GUARD | PAGE_EXECUTE_READ,
PAGE_GUARD | PAGE_READWRITE,
PAGE_GUARD | PAGE_WRITECOPY,
PAGE_GUARD | PAGE_EXECUTE_READWRITE,
PAGE_GUARD | PAGE_EXECUTE_WRITECOPY,
PAGE_NOACCESS,
PAGE_WRITECOMBINE | PAGE_READONLY,
PAGE_WRITECOMBINE | PAGE_EXECUTE,
PAGE_WRITECOMBINE | PAGE_EXECUTE_READ,
PAGE_WRITECOMBINE | PAGE_READWRITE,
PAGE_WRITECOMBINE | PAGE_WRITECOPY,
PAGE_WRITECOMBINE | PAGE_EXECUTE_READWRITE,
PAGE_WRITECOMBINE | PAGE_EXECUTE_WRITECOPY
};
///
/// Change VAD protection flags
///
/// Target process object
/// Target address
/// New protection flags
/// Status code
NTSTATUS BBProtectVAD( IN PEPROCESS pProcess, IN ULONG_PTR address, IN ULONG prot )
{
NTSTATUS status = STATUS_SUCCESS;
PMMVAD_SHORT pVadShort = NULL;
status = BBFindVAD( pProcess, address, &pVadShort );
if (NT_SUCCESS( status ))
pVadShort->u.VadFlags.Protection = prot;
return status;
}
#pragma warning(disable : 4055)
///
/// Hide memory from NtQueryVirtualMemory
///
/// Target process object
/// Target address
/// Status code
NTSTATUS BBUnlinkVAD( IN PEPROCESS pProcess, IN ULONG_PTR address )
{
NTSTATUS status = STATUS_SUCCESS;
PMMVAD_SHORT pVadShort = NULL;
status = BBFindVAD( pProcess, address, &pVadShort );
if (!NT_SUCCESS( status ))
return status;
// Erase image name
if (pVadShort->u.VadFlags.VadType == VadImageMap)
{
PMMVAD pVadLong = (PMMVAD)pVadShort;
if (pVadLong->Subsection && pVadLong->Subsection->ControlArea && pVadLong->Subsection->ControlArea->FilePointer.Object)
{
PFILE_OBJECT pFile = (PFILE_OBJECT)(pVadLong->Subsection->ControlArea->FilePointer.Value & ~0xF);
pFile->FileName.Buffer[0] = L'\0';
pFile->FileName.Length = 0;
}
else
return STATUS_INVALID_ADDRESS;
}
// Make NO_ACCESS
else if (pVadShort->u.VadFlags.VadType == VadDevicePhysicalMemory)
{
pVadShort->u.VadFlags.Protection = MM_ZERO_ACCESS;
}
// Invalid VAD type
else
status = STATUS_INVALID_PARAMETER;
return status;
}
#pragma warning(default : 4055)
///
/// Get region VAD type
///
/// Target process object
/// Target address
/// Resulting VAD type
/// Status code
NTSTATUS BBGetVadType( IN PEPROCESS pProcess, IN ULONG_PTR address, OUT PMI_VAD_TYPE pType )
{
NTSTATUS status = STATUS_SUCCESS;
PMMVAD_SHORT pVad = NULL;
status = BBFindVAD( pProcess, address, &pVad );
if (!NT_SUCCESS( status ))
return status;
*pType = pVad->u.VadFlags.VadType;
return status;
}
///
/// Find VAD that describes target address
///
/// Target process object
/// Address to find
/// Found VAD. NULL if not found
/// Status code
NTSTATUS BBFindVAD( IN PEPROCESS pProcess, IN ULONG_PTR address, OUT PMMVAD_SHORT* pResult )
{
NTSTATUS status = STATUS_SUCCESS;
ULONG_PTR vpnStart = address >> PAGE_SHIFT;
ASSERT( pProcess != NULL && pResult != NULL );
if (pProcess == NULL || pResult == NULL)
return STATUS_INVALID_PARAMETER;
if (dynData.VadRoot == 0)
{
DPRINT( "BlackBone: %s: Invalid VadRoot offset\n", __FUNCTION__ );
status = STATUS_INVALID_ADDRESS;
}
PMM_AVL_TABLE pTable = (PMM_AVL_TABLE)((PUCHAR)pProcess + dynData.VadRoot);
PMM_AVL_NODE pNode = GET_VAD_ROOT( pTable );
// Search VAD
if (MiFindNodeOrParent( pTable, vpnStart, &pNode ) == TableFoundNode)
{
*pResult = (PMMVAD_SHORT)pNode;
}
else
{
DPRINT( "BlackBone: %s: VAD entry for address 0x%p not found\n", __FUNCTION__, address );
status = STATUS_NOT_FOUND;
}
return status;
}
///
/// Convert protection flags
///
/// Protection flags.
/// If TRUE - convert to PTE protection, if FALSE - convert to Win32 protection
/// Resulting protection flags
ULONG BBConvertProtection( IN ULONG prot, IN BOOLEAN fromPTE )
{
if (fromPTE != FALSE)
{
// Sanity check
if (prot < ARRAYSIZE( MmProtectToValue ))
return MmProtectToValue[prot];
}
else
{
for (int i = 0; i < ARRAYSIZE( MmProtectToValue ); i++)
if (MmProtectToValue[i] == prot)
return i;
}
return 0;
}