mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-08-26 08:53:21 +00:00
1056 lines
30 KiB
C
1056 lines
30 KiB
C
/**
|
|
* @file Transparency.c
|
|
* @author Sina Karvandi (sina@hyperdbg.org)
|
|
* @brief try to hide the debugger from anti-debugging and anti-hypervisor methods
|
|
* @details
|
|
* @version 0.1
|
|
* @date 2020-07-07
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
|
|
/**
|
|
* @brief Hide debugger on transparent-mode (activate transparent-mode)
|
|
*
|
|
* @param TransparentModeRequest
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
TransparentHideDebugger(PDEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE TransparentModeRequest)
|
|
{
|
|
//
|
|
// Check whether the transparent-mode was already initialized or not
|
|
//
|
|
if (!g_TransparentMode)
|
|
{
|
|
//
|
|
// Allocate buffer for the transparent-mode trap flag state
|
|
//
|
|
g_TransparentModeTrapFlagState = (TRANSPARENT_MODE_TRAP_FLAG_STATE *)PlatformMemAllocateZeroedNonPagedPool(sizeof(TRANSPARENT_MODE_TRAP_FLAG_STATE));
|
|
|
|
//
|
|
// Intercept trap flags #DBs and #BPs for the transparent-mode
|
|
//
|
|
BroadcastEnableDbAndBpExitingAllCores();
|
|
|
|
//
|
|
// Enable the transparent-mode
|
|
//
|
|
g_TransparentMode = TRUE;
|
|
TransparentModeRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
|
|
//
|
|
// Successfully enabled the transparent-mode
|
|
//
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TransparentModeRequest->KernelStatus = DEBUGGER_ERROR_DEBUGGER_ALREADY_HIDE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Deactivate transparent-mode
|
|
* @param TransparentModeRequest
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
TransparentUnhideDebugger(PDEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE TransparentModeRequest)
|
|
{
|
|
if (g_TransparentMode)
|
|
{
|
|
//
|
|
// Disable the transparent-mode
|
|
//
|
|
g_TransparentMode = FALSE;
|
|
|
|
//
|
|
// Unset the trap flags #DBs and #BPs for the transparent-mode
|
|
//
|
|
BroadcastDisableDbAndBpExitingAllCores();
|
|
|
|
//
|
|
// Free the buffer for the transparent-mode trap flag state
|
|
//
|
|
PlatformMemFreePool(g_TransparentModeTrapFlagState);
|
|
|
|
TransparentModeRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TransparentModeRequest->KernelStatus = DEBUGGER_ERROR_DEBUGGER_ALREADY_UNHIDE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Handle Cpuid Vmexits when the Transparent mode is enabled
|
|
*
|
|
* @param CpuInfo The temporary logical processor registers
|
|
* @param Regs Vcpu's GP registers
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
TransparentCPUID(INT32 CpuInfo[], PGUEST_REGS Regs)
|
|
{
|
|
if (Regs->rax == CPUID_PROCESSOR_AND_PROCESSOR_FEATURE_IDENTIFIERS)
|
|
{
|
|
//
|
|
// Unset the Hypervisor Present-bit in RCX, which Intel and AMD have both
|
|
// reserved for this indication
|
|
//
|
|
CpuInfo[2] &= ~HYPERV_HYPERVISOR_PRESENT_BIT;
|
|
}
|
|
else if (Regs->rax == CPUID_HV_VENDOR_AND_MAX_FUNCTIONS || Regs->rax == HYPERV_CPUID_INTERFACE)
|
|
{
|
|
//
|
|
// When transparent, all CPUID leaves in the 0x40000000+ range should contain no usable data
|
|
//
|
|
CpuInfo[0] = CpuInfo[1] = CpuInfo[2] = CpuInfo[3] = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief This function makes sure to unset the RFLAGS.TF on next trigger of #DB
|
|
* on the target process/thread
|
|
* @param ProcessId
|
|
* @param ThreadId
|
|
* @param Context
|
|
* @param Params
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
TransparentStoreProcessInformation(UINT32 ProcessId,
|
|
UINT32 ThreadId,
|
|
UINT64 Context,
|
|
TRANSPARENT_MODE_CONTEXT_PARAMS * Params)
|
|
{
|
|
UINT32 Index;
|
|
BOOLEAN Result;
|
|
BOOLEAN SuccessfullyStored;
|
|
TRANSPARENT_MODE_PROCESS_THREAD_INFORMATION ProcThrdInfo = {0};
|
|
|
|
//
|
|
// Form the process id and thread id into a 64-bit value
|
|
//
|
|
ProcThrdInfo.Fields.ProcessId = ProcessId;
|
|
ProcThrdInfo.Fields.ThreadId = ThreadId;
|
|
|
|
//
|
|
// Make sure, nobody is in the middle of modifying the list
|
|
//
|
|
SpinlockLock(&TransparentModeTrapListLock);
|
|
|
|
//
|
|
// *** Search the list of processes/threads for the current process's trap flag state ***
|
|
//
|
|
Result = BinarySearchPerformSearchItem((UINT64 *)&g_TransparentModeTrapFlagState->ThreadInformation[0],
|
|
g_TransparentModeTrapFlagState->NumberOfItems,
|
|
&Index,
|
|
ProcThrdInfo.asUInt);
|
|
|
|
if (Result)
|
|
{
|
|
//
|
|
// It means that we already find this entry in the stored list
|
|
// so, just imply that the addition was successful (no need for extra addition)
|
|
//
|
|
SuccessfullyStored = TRUE;
|
|
goto Return;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Insert the thread into the list as the item is not already present
|
|
//
|
|
SuccessfullyStored = InsertionSortInsertItem((UINT64 *)&g_TransparentModeTrapFlagState->ThreadInformation[0],
|
|
&g_TransparentModeTrapFlagState->NumberOfItems,
|
|
MAXIMUM_NUMBER_OF_THREAD_INFORMATION_FOR_TRANSPARENT_MODE_TRAPS,
|
|
&Index,
|
|
ProcThrdInfo.asUInt);
|
|
|
|
if (SuccessfullyStored)
|
|
{
|
|
//
|
|
// Successfully inserted the thread/process into the list
|
|
// Now let's store the context of the caller along with parameters
|
|
//
|
|
g_TransparentModeTrapFlagState->Context[Index] = Context;
|
|
memcpy(&g_TransparentModeTrapFlagState->Params[Index], Params, sizeof(TRANSPARENT_MODE_CONTEXT_PARAMS));
|
|
}
|
|
|
|
goto Return;
|
|
}
|
|
|
|
Return:
|
|
//
|
|
// Unlock the list modification lock
|
|
//
|
|
SpinlockUnlock(&TransparentModeTrapListLock);
|
|
|
|
return SuccessfullyStored;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the trap flag in the guest after a syscall
|
|
*
|
|
* @param VCpu The virtual processor's state
|
|
* @param ProcessId The process id of the thread
|
|
* @param ThreadId The thread id of the thread
|
|
* @param Context The context of the caller
|
|
* @param Params The (optional) parameters of the caller
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
TransparentSetTrapFlagAfterSyscall(VIRTUAL_MACHINE_STATE * VCpu,
|
|
UINT32 ProcessId,
|
|
UINT32 ThreadId,
|
|
UINT64 Context,
|
|
TRANSPARENT_MODE_CONTEXT_PARAMS * Params)
|
|
{
|
|
//
|
|
// Do not add anything to the list if the transparent-mode is not enabled (or disabled by the user)
|
|
//
|
|
if (!g_TransparentMode)
|
|
{
|
|
//
|
|
// Transparent-mode is not enabled
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Insert the thread/process into the list of processes/threads
|
|
//
|
|
if (!TransparentStoreProcessInformation(ProcessId, ThreadId, Context, Params))
|
|
{
|
|
//
|
|
// Failed to store the process/thread information
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// *** Successfully stored the process/thread information ***
|
|
//
|
|
|
|
//
|
|
// Set the trap flag to TRUE because we want to intercept the thread again
|
|
// once it returns to the user-mode (SYSRET) instruction
|
|
//
|
|
// Here the RFLAGS is in the R11 register (See Intel manual about the SYSCALL register)
|
|
//
|
|
VCpu->Regs->r11 |= X86_FLAGS_TF;
|
|
|
|
//
|
|
// Create log message for the syscall
|
|
//
|
|
// LogInfo("Transparent set trap flag for process: %x, thread: %x\n", ProcessId, ThreadId);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Handle the trap flags as the result of interception of the return of the
|
|
* system-call
|
|
*
|
|
* @param VCpu The virtual processor's state
|
|
* @param ProcessId The process id of the thread
|
|
* @param ThreadId The thread id of the thread
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
TransparentCheckAndHandleAfterSyscallTrapFlags(VIRTUAL_MACHINE_STATE * VCpu,
|
|
UINT32 ProcessId,
|
|
UINT32 ThreadId)
|
|
{
|
|
RFLAGS Rflags = {0};
|
|
UINT32 Index;
|
|
UINT64 Context = NULL64_ZERO;
|
|
TRANSPARENT_MODE_CONTEXT_PARAMS Params;
|
|
TRANSPARENT_MODE_PROCESS_THREAD_INFORMATION ProcThrdInfo = {0};
|
|
BOOLEAN Result;
|
|
BOOLEAN ResultToReturn;
|
|
|
|
//
|
|
// Read the trap flag
|
|
//
|
|
Rflags.AsUInt = HvGetRflags();
|
|
|
|
if (!Rflags.TrapFlag)
|
|
{
|
|
//
|
|
// The trap flag is not set, so we don't need to do anything
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Form the process id and thread id into a 64-bit value
|
|
//
|
|
ProcThrdInfo.Fields.ProcessId = ProcessId;
|
|
ProcThrdInfo.Fields.ThreadId = ThreadId;
|
|
|
|
//
|
|
// Make sure, nobody is in the middle of modifying the list
|
|
//
|
|
SpinlockLock(&TransparentModeTrapListLock);
|
|
|
|
//
|
|
// *** Search the list of processes/threads for the current process's trap flag state ***
|
|
//
|
|
Result = BinarySearchPerformSearchItem((UINT64 *)&g_TransparentModeTrapFlagState->ThreadInformation[0],
|
|
g_TransparentModeTrapFlagState->NumberOfItems,
|
|
&Index,
|
|
ProcThrdInfo.asUInt);
|
|
|
|
//
|
|
// Check whether this thread is expected to have trap flag
|
|
// by the transparent-mode or not
|
|
//
|
|
if (Result)
|
|
{
|
|
//
|
|
// Read the context of the caller
|
|
//
|
|
Context = g_TransparentModeTrapFlagState->Context[Index];
|
|
|
|
//
|
|
// Read the (optional) parameters of the caller
|
|
//
|
|
memcpy(&Params, &g_TransparentModeTrapFlagState->Params[Index], sizeof(TRANSPARENT_MODE_CONTEXT_PARAMS));
|
|
|
|
//
|
|
// Clear the trap flag from the RFLAGS register
|
|
//
|
|
HvSetRflagTrapFlag(FALSE);
|
|
|
|
//
|
|
// Remove the thread/process from the list of processes/threads
|
|
//
|
|
InsertionSortDeleteItem((UINT64 *)&g_TransparentModeTrapFlagState->ThreadInformation[0],
|
|
&g_TransparentModeTrapFlagState->NumberOfItems,
|
|
Index);
|
|
|
|
//
|
|
// Handled by the transparent-mode
|
|
//
|
|
ResultToReturn = TRUE;
|
|
|
|
goto ReturnResult;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not related to the transparent-mode
|
|
//
|
|
ResultToReturn = FALSE;
|
|
|
|
goto ReturnResult;
|
|
}
|
|
|
|
ReturnResult:
|
|
|
|
//
|
|
// Unlock the list modification lock
|
|
//
|
|
SpinlockUnlock(&TransparentModeTrapListLock);
|
|
|
|
//
|
|
// Call the callback function to handle the trap flag if its needed
|
|
// Note that we call it here so we already unlocked the list lock
|
|
// to optimize the performance (avoid holding the lock for a long time)
|
|
//
|
|
if (ResultToReturn)
|
|
{
|
|
TransparentCallbackHandleAfterSyscall(VCpu, ProcessId, ThreadId, Context, &Params);
|
|
}
|
|
|
|
return ResultToReturn;
|
|
}
|
|
|
|
/**
|
|
* @brief Callback function to handle returns from the syscall
|
|
*
|
|
* @param VCpu The virtual processor's state
|
|
* @param ProcessId The process id of the thread
|
|
* @param ThreadId The thread id of the thread
|
|
* @param Context The context of the caller
|
|
* @param Params The (optional) parameters of the caller
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
TransparentCallbackHandleAfterSyscall(VIRTUAL_MACHINE_STATE * VCpu,
|
|
UINT32 ProcessId,
|
|
UINT32 ThreadId,
|
|
UINT64 Context,
|
|
TRANSPARENT_MODE_CONTEXT_PARAMS * Params)
|
|
{
|
|
LogInfo("Transparent callback handle the trap flag for process: %x, thread: %x, rip: %llx, context: %llx (p1: %llx, p2: %llx, p3: %llx, p4: %llx)\n",
|
|
ProcessId,
|
|
ThreadId,
|
|
VCpu->LastVmexitRip,
|
|
Context,
|
|
Params->OptionalParam1,
|
|
Params->OptionalParam2,
|
|
Params->OptionalParam3,
|
|
Params->OptionalParam4);
|
|
}
|
|
|
|
//
|
|
// /**
|
|
// * @brief maximum random value
|
|
// */
|
|
// #define MY_RAND_MAX 32768
|
|
//
|
|
// /**
|
|
// * @brief pre-defined log result
|
|
// * @details we used this because we want to avoid using floating-points in
|
|
// * kernel
|
|
// */
|
|
// int TransparentTableLog[] =
|
|
// {
|
|
// 0,
|
|
// 69,
|
|
// 110,
|
|
// 139,
|
|
// 161,
|
|
// 179,
|
|
// 195,
|
|
// 208,
|
|
// 220,
|
|
// 230,
|
|
// 240,
|
|
// 248,
|
|
// 256,
|
|
// 264,
|
|
// 271,
|
|
// 277,
|
|
// 283,
|
|
// 289,
|
|
// 294,
|
|
// 300,
|
|
// 304,
|
|
// 309,
|
|
// 314,
|
|
// 318,
|
|
// 322,
|
|
// 326,
|
|
// 330,
|
|
// 333,
|
|
// 337,
|
|
// 340,
|
|
// 343,
|
|
// 347,
|
|
// 350,
|
|
// 353,
|
|
// 356,
|
|
// 358,
|
|
// 361,
|
|
// 364,
|
|
// 366,
|
|
// 369,
|
|
// 371,
|
|
// 374,
|
|
// 376,
|
|
// 378,
|
|
// 381,
|
|
// 383,
|
|
// 385,
|
|
// 387,
|
|
// 389,
|
|
// 391,
|
|
// 393,
|
|
// 395,
|
|
// 397,
|
|
// 399,
|
|
// 401,
|
|
// 403,
|
|
// 404,
|
|
// 406,
|
|
// 408,
|
|
// 409,
|
|
// 411,
|
|
// 413,
|
|
// 414,
|
|
// 416,
|
|
// 417,
|
|
// 419,
|
|
// 420,
|
|
// 422,
|
|
// 423,
|
|
// 425,
|
|
// 426,
|
|
// 428,
|
|
// 429,
|
|
// 430,
|
|
// 432,
|
|
// 433,
|
|
// 434,
|
|
// 436,
|
|
// 437,
|
|
// 438,
|
|
// 439,
|
|
// 441,
|
|
// 442,
|
|
// 443,
|
|
// 444,
|
|
// 445,
|
|
// 447,
|
|
// 448,
|
|
// 449,
|
|
// 450,
|
|
// 451,
|
|
// 452,
|
|
// 453,
|
|
// 454,
|
|
// 455,
|
|
// 456,
|
|
// 457,
|
|
// 458,
|
|
// 460,
|
|
// 461};
|
|
//
|
|
// /**
|
|
// * @brief Generate a random number by utilizing RDTSC instruction.
|
|
// *
|
|
// * Masking 16 LSB of the measured clock time.
|
|
// * @return UINT32
|
|
// */
|
|
// UINT32
|
|
// TransparentGetRand()
|
|
// {
|
|
// UINT64 Tsc;
|
|
// UINT32 Rand;
|
|
//
|
|
// Tsc = __rdtsc();
|
|
// Rand = Tsc & 0xffff;
|
|
//
|
|
// return Rand;
|
|
// }
|
|
//
|
|
// /**
|
|
// * @brief Integer power function definition.
|
|
// *
|
|
// * @params x Base Value
|
|
// * @params p Power Value
|
|
// * @return int
|
|
// */
|
|
// int
|
|
// TransparentPow(int x, int p)
|
|
// {
|
|
// int Res = 1;
|
|
// for (int i = 0; i < p; i++)
|
|
// {
|
|
// Res = Res * x;
|
|
// }
|
|
// return Res;
|
|
// }
|
|
//
|
|
// /**
|
|
// * @brief Integer Natural Logarithm function estimation.
|
|
// *
|
|
// * @params x input value
|
|
// * @return int
|
|
// */
|
|
// int
|
|
// TransparentLog(int x)
|
|
// {
|
|
// int n = x;
|
|
// int Digit = 0;
|
|
//
|
|
// while (n >= 100)
|
|
// {
|
|
// n = n / 10;
|
|
// Digit++;
|
|
// }
|
|
//
|
|
// //
|
|
// // Use pre-defined values of logarithms and estimate the total value
|
|
// //
|
|
// return TransparentTableLog[n] / 100 + (Digit * 23) / 10;
|
|
// }
|
|
// /**
|
|
// * @brief Integer root function estimation.
|
|
// *
|
|
// * @params x input value
|
|
// * @return int
|
|
// */
|
|
// int
|
|
// TransparentSqrt(int x)
|
|
// {
|
|
// int Res = 0;
|
|
// int Bit;
|
|
//
|
|
// //
|
|
// // The second-to-top bit is set.
|
|
// //
|
|
// Bit = 1 << 30;
|
|
//
|
|
// //
|
|
// // "Bit" starts at the highest power of four <= the argument.
|
|
// //
|
|
// while (Bit > x)
|
|
// Bit >>= 2;
|
|
//
|
|
// while (Bit != 0)
|
|
// {
|
|
// if (x >= Res + Bit)
|
|
// {
|
|
// x -= Res + Bit;
|
|
// Res = (Res >> 1) + Bit;
|
|
// }
|
|
// else
|
|
// Res >>= 1;
|
|
// Bit >>= 2;
|
|
// }
|
|
// return Res;
|
|
// }
|
|
//
|
|
// /**
|
|
// * @brief Integer Gaussian Random Number Generator(GRNG) based on Box-Muller method. A Float to Integer
|
|
// * mapping is used in the function.
|
|
// *
|
|
// * @params Average Mean
|
|
// * @parans Sigma Standard Deviation of the targeted Gaussian Distribution
|
|
// * @return int
|
|
// */
|
|
// int
|
|
// TransparentRandn(int Average, int Sigma)
|
|
// {
|
|
// int U1, r1, U2, r2, W, Mult;
|
|
// int X1, X2 = 0, XS1;
|
|
// int LogTemp = 0;
|
|
//
|
|
// do
|
|
// {
|
|
// r1 = TransparentGetRand();
|
|
// r2 = TransparentGetRand();
|
|
//
|
|
// U1 = (r1 % MY_RAND_MAX) - (MY_RAND_MAX / 2);
|
|
//
|
|
// U2 = (r2 % MY_RAND_MAX) - (MY_RAND_MAX / 2);
|
|
//
|
|
// W = U1 * U1 + U2 * U2;
|
|
// } while (W >= MY_RAND_MAX * MY_RAND_MAX / 2 || W == 0);
|
|
//
|
|
// LogTemp = (TransparentLog(W) - TransparentLog(MY_RAND_MAX * MY_RAND_MAX));
|
|
//
|
|
// Mult = TransparentSqrt((-2 * LogTemp) * (MY_RAND_MAX * MY_RAND_MAX / W));
|
|
//
|
|
// X1 = U1 * Mult / MY_RAND_MAX;
|
|
// XS1 = U1 * Mult;
|
|
//
|
|
// X2 = U2 * Mult / MY_RAND_MAX;
|
|
//
|
|
// return (Average + (Sigma * XS1) / MY_RAND_MAX);
|
|
// }
|
|
//
|
|
// /**
|
|
// * @brief Add name or process id of the target process to the list
|
|
// * of processes that HyperDbg should apply transparent-mode on them
|
|
// *
|
|
// * @param Measurements
|
|
// * @return BOOLEAN
|
|
// */
|
|
// BOOLEAN
|
|
// TransparentAddNameOrProcessIdToTheList(PDEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE Measurements)
|
|
// {
|
|
// SIZE_T SizeOfBuffer;
|
|
// PTRANSPARENCY_PROCESS PidAndNameBuffer;
|
|
//
|
|
// //
|
|
// // Check whether it's a process id or it's a process name
|
|
// //
|
|
// if (Measurements->TrueIfProcessIdAndFalseIfProcessName)
|
|
// {
|
|
// //
|
|
// // It's a process Id
|
|
// //
|
|
// SizeOfBuffer = sizeof(TRANSPARENCY_PROCESS);
|
|
// }
|
|
// else
|
|
// {
|
|
// //
|
|
// // It's a process name
|
|
// //
|
|
// SizeOfBuffer = sizeof(TRANSPARENCY_PROCESS) + Measurements->LengthOfProcessName;
|
|
// }
|
|
//
|
|
// //
|
|
// // Allocate the Buffer
|
|
// //
|
|
// PidAndNameBuffer = PlatformMemAllocateZeroedNonPagedPool(SizeOfBuffer);
|
|
//
|
|
// if (PidAndNameBuffer == NULL)
|
|
// {
|
|
// return FALSE;
|
|
// }
|
|
//
|
|
// //
|
|
// // Save the address of the buffer for future de-allocation
|
|
// //
|
|
// PidAndNameBuffer->BufferAddress = PidAndNameBuffer;
|
|
//
|
|
// //
|
|
// // Check again whether it's a process id or it's a process name
|
|
// // then fill the structure
|
|
// //
|
|
// if (Measurements->TrueIfProcessIdAndFalseIfProcessName)
|
|
// {
|
|
// //
|
|
// // It's a process Id
|
|
// //
|
|
// PidAndNameBuffer->ProcessId = Measurements->ProcId;
|
|
// PidAndNameBuffer->TrueIfProcessIdAndFalseIfProcessName = TRUE;
|
|
// }
|
|
// else
|
|
// {
|
|
// //
|
|
// // It's a process name
|
|
// //
|
|
// PidAndNameBuffer->TrueIfProcessIdAndFalseIfProcessName = FALSE;
|
|
//
|
|
// //
|
|
// // Move the process name string to the end of the buffer
|
|
// //
|
|
// RtlCopyBytes((void *)((UINT64)PidAndNameBuffer + sizeof(TRANSPARENCY_PROCESS)),
|
|
// (const void *)((UINT64)Measurements + sizeof(DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE)),
|
|
// Measurements->LengthOfProcessName);
|
|
//
|
|
// //
|
|
// // Set the process name location
|
|
// //
|
|
// PidAndNameBuffer->ProcessName = (PVOID)((UINT64)PidAndNameBuffer + sizeof(TRANSPARENCY_PROCESS));
|
|
// }
|
|
//
|
|
// //
|
|
// // Link it to the list of process that we need to transparent
|
|
// // vm-exits for them
|
|
// //
|
|
// InsertHeadList(&g_TransparentModeMeasurements->ProcessList, &(PidAndNameBuffer->OtherProcesses));
|
|
//
|
|
// return TRUE;
|
|
// }
|
|
//
|
|
// /**
|
|
// * @brief Hide debugger on transparent-mode (activate transparent-mode)
|
|
// *
|
|
// * @param Measurements
|
|
// * @return NTSTATUS
|
|
// */
|
|
// NTSTATUS
|
|
// TransparentHideDebugger(PDEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE Measurements)
|
|
// {
|
|
// //
|
|
// // Check whether the transparent-mode was already initialized or not
|
|
// //
|
|
// if (!g_TransparentMode)
|
|
// {
|
|
// //
|
|
// // Allocate the measurements buffer
|
|
// //
|
|
// g_TransparentModeMeasurements = (PTRANSPARENCY_MEASUREMENTS)PlatformMemAllocateZeroedNonPagedPool(sizeof(TRANSPARENCY_MEASUREMENTS));
|
|
//
|
|
// if (!g_TransparentModeMeasurements)
|
|
// {
|
|
// return STATUS_INSUFFICIENT_RESOURCES;
|
|
// }
|
|
//
|
|
// //
|
|
// // Initialize the lists
|
|
// //
|
|
// InitializeListHead(&g_TransparentModeMeasurements->ProcessList);
|
|
//
|
|
// //
|
|
// // Fill the transparency details CPUID
|
|
// //
|
|
// g_TransparentModeMeasurements->CpuidAverage = Measurements->CpuidAverage;
|
|
// g_TransparentModeMeasurements->CpuidMedian = Measurements->CpuidMedian;
|
|
// g_TransparentModeMeasurements->CpuidStandardDeviation = Measurements->CpuidStandardDeviation;
|
|
//
|
|
// //
|
|
// // Fill the transparency details RDTSC
|
|
// //
|
|
// g_TransparentModeMeasurements->RdtscAverage = Measurements->RdtscAverage;
|
|
// g_TransparentModeMeasurements->RdtscMedian = Measurements->RdtscMedian;
|
|
// g_TransparentModeMeasurements->RdtscStandardDeviation = Measurements->RdtscStandardDeviation;
|
|
//
|
|
// //
|
|
// // add the new process name or Id to the list
|
|
// //
|
|
// TransparentAddNameOrProcessIdToTheList(Measurements);
|
|
//
|
|
// //
|
|
// // Enable RDTSC and RDTSCP exiting on all cores
|
|
// //
|
|
// BroadcastEnableRdtscExitingAllCores();
|
|
//
|
|
// //
|
|
// // Finally, enable the transparent-mode
|
|
// //
|
|
// g_TransparentMode = TRUE;
|
|
// }
|
|
// else
|
|
// {
|
|
// //
|
|
// // It's already initialized, we just need to
|
|
// // add the new process name or Id to the list
|
|
// //
|
|
// TransparentAddNameOrProcessIdToTheList(Measurements);
|
|
// }
|
|
//
|
|
// return STATUS_SUCCESS;
|
|
// }
|
|
//
|
|
// /**
|
|
// * @brief Deactivate transparent-mode
|
|
// *
|
|
// * @return NTSTATUS
|
|
// */
|
|
// NTSTATUS
|
|
// TransparentUnhideDebugger()
|
|
// {
|
|
// PLIST_ENTRY TempList = 0;
|
|
// PVOID BufferToDeAllocate = 0;
|
|
//
|
|
// if (g_TransparentMode)
|
|
// {
|
|
// //
|
|
// // Disable the transparent-mode
|
|
// //
|
|
// g_TransparentMode = FALSE;
|
|
//
|
|
// //
|
|
// // Disable RDTSC and RDTSCP emulation
|
|
// //
|
|
// BroadcastDisableRdtscExitingAllCores();
|
|
//
|
|
// //
|
|
// // Free list of allocated buffers
|
|
// //
|
|
// // Check for process id and process name, if not match then we don't emulate it
|
|
// //
|
|
// TempList = &g_TransparentModeMeasurements->ProcessList;
|
|
// while (&g_TransparentModeMeasurements->ProcessList != TempList->Flink)
|
|
// {
|
|
// TempList = TempList->Flink;
|
|
// PTRANSPARENCY_PROCESS ProcessDetails = (PTRANSPARENCY_PROCESS)CONTAINING_RECORD(TempList, TRANSPARENCY_PROCESS, OtherProcesses);
|
|
//
|
|
// //
|
|
// // Save the buffer so we can de-allocate it
|
|
// //
|
|
// BufferToDeAllocate = ProcessDetails->BufferAddress;
|
|
//
|
|
// //
|
|
// // We have to remove the event from the list
|
|
// //
|
|
// RemoveEntryList(&ProcessDetails->OtherProcesses);
|
|
//
|
|
// //
|
|
// // Free the buffer
|
|
// //
|
|
// PlatformMemFreePool(BufferToDeAllocate);
|
|
// }
|
|
//
|
|
// //
|
|
// // Deallocate the measurements buffer
|
|
// //
|
|
// PlatformMemFreePool(g_TransparentModeMeasurements);
|
|
// g_TransparentModeMeasurements = NULL;
|
|
//
|
|
// return STATUS_SUCCESS;
|
|
// }
|
|
// else
|
|
// {
|
|
// return STATUS_UNSUCCESSFUL;
|
|
// }
|
|
// }
|
|
//
|
|
// /**
|
|
// * @brief VM-Exit handler for different exit reasons
|
|
// * @details Should be called from vmx-root
|
|
// *
|
|
// * @param VCpu The virtual processor's state
|
|
// * @param ExitReason Exit Reason
|
|
// * @return BOOLEAN Return True we should emulate RDTSCP
|
|
// * or return false if we should not emulate RDTSCP
|
|
// */
|
|
// BOOLEAN
|
|
// TransparentModeStart(VIRTUAL_MACHINE_STATE * VCpu, UINT32 ExitReason)
|
|
// {
|
|
// UINT32 Aux = 0;
|
|
// PLIST_ENTRY TempList = 0;
|
|
// PCHAR CurrentProcessName = 0;
|
|
// UINT32 CurrentProcessId;
|
|
// UINT64 CurrrentTime;
|
|
// HANDLE CurrentThreadId;
|
|
// BOOLEAN Result = TRUE;
|
|
// BOOLEAN IsProcessOnTransparencyList = FALSE;
|
|
//
|
|
// //
|
|
// // Save the current time
|
|
// //
|
|
// CurrrentTime = __rdtscp(&Aux);
|
|
//
|
|
// //
|
|
// // Save time of vm-exit on each logical processor separately
|
|
// //
|
|
// VCpu->TransparencyState.PreviousTimeStampCounter = CurrrentTime;
|
|
//
|
|
// //
|
|
// // Find the current process id and name
|
|
// //
|
|
// CurrentProcessId = HANDLE_TO_UINT32(PsGetCurrentProcessId());
|
|
// CurrentProcessName = CommonGetProcessNameFromProcessControlBlock(PsGetCurrentProcess());
|
|
//
|
|
// //
|
|
// // Check for process id and process name, if not match then we don't emulate it
|
|
// //
|
|
// TempList = &g_TransparentModeMeasurements->ProcessList;
|
|
// while (&g_TransparentModeMeasurements->ProcessList != TempList->Flink)
|
|
// {
|
|
// TempList = TempList->Flink;
|
|
// PTRANSPARENCY_PROCESS ProcessDetails = (PTRANSPARENCY_PROCESS)CONTAINING_RECORD(TempList, TRANSPARENCY_PROCESS, OtherProcesses);
|
|
// if (ProcessDetails->TrueIfProcessIdAndFalseIfProcessName)
|
|
// {
|
|
// //
|
|
// // This entry is process id
|
|
// //
|
|
// if (ProcessDetails->ProcessId == CurrentProcessId)
|
|
// {
|
|
// //
|
|
// // Let the transparency handler to handle it
|
|
// //
|
|
// IsProcessOnTransparencyList = TRUE;
|
|
// break;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// //
|
|
// // This entry is a process name
|
|
// //
|
|
// if (CurrentProcessName != NULL && CommonIsStringStartsWith(CurrentProcessName, ProcessDetails->ProcessName))
|
|
// {
|
|
// //
|
|
// // Let the transparency handler to handle it
|
|
// //
|
|
// IsProcessOnTransparencyList = TRUE;
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// //
|
|
// // Check whether we find this process on transparency list or not
|
|
// //
|
|
// if (!IsProcessOnTransparencyList)
|
|
// {
|
|
// //
|
|
// // No, we didn't let's do the normal tasks
|
|
// //
|
|
// return TRUE;
|
|
// }
|
|
//
|
|
// //
|
|
// // Get current thread Id
|
|
// //
|
|
// CurrentThreadId = PsGetCurrentThreadId();
|
|
//
|
|
// //
|
|
// // Check whether we are in new thread or in previous thread
|
|
// //
|
|
// if (VCpu->TransparencyState.ThreadId != CurrentThreadId)
|
|
// {
|
|
// //
|
|
// // It's a new thread Id reset everything
|
|
// //
|
|
// VCpu->TransparencyState.ThreadId = CurrentThreadId;
|
|
// VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc = NULL64_ZERO;
|
|
// VCpu->TransparencyState.CpuidAfterRdtscDetected = FALSE;
|
|
// }
|
|
//
|
|
// //
|
|
// // Now, it's time to check and play with RDTSC/P and CPUID
|
|
// //
|
|
//
|
|
// if (ExitReason == VMX_EXIT_REASON_EXECUTE_RDTSC || ExitReason == VMX_EXIT_REASON_EXECUTE_RDTSCP)
|
|
// {
|
|
// if (VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc == NULL64_ZERO)
|
|
// {
|
|
// //
|
|
// // It's a timing and the previous time for the thread is null
|
|
// // so we need to save the time (maybe) for future use
|
|
// //
|
|
// VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc = CurrrentTime;
|
|
// }
|
|
// else if (VCpu->TransparencyState.CpuidAfterRdtscDetected == TRUE)
|
|
// {
|
|
// //
|
|
// // Someone tries to know about the hypervisor
|
|
// // let's play with them
|
|
// //
|
|
//
|
|
// // LogInfo("Possible RDTSC+CPUID+RDTSC");
|
|
// }
|
|
// else if (VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc != NULL64_ZERO &&
|
|
// VCpu->TransparencyState.CpuidAfterRdtscDetected == FALSE)
|
|
// {
|
|
// //
|
|
// // It's a new rdtscp, let's save the new value
|
|
// //
|
|
// VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc +=
|
|
// TransparentRandn((UINT32)g_TransparentModeMeasurements->CpuidAverage,
|
|
// (UINT32)g_TransparentModeMeasurements->CpuidStandardDeviation);
|
|
// }
|
|
//
|
|
// //
|
|
// // Adjust the rdtsc based on RevealedTimeStampCounterByRdtsc
|
|
// //
|
|
// VCpu->Regs->rax = 0x00000000ffffffff &
|
|
// VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc;
|
|
//
|
|
// VCpu->Regs->rdx = 0x00000000ffffffff &
|
|
// (VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc >> 32);
|
|
//
|
|
// //
|
|
// // Check if we need to adjust rcx as a result of rdtscp
|
|
// //
|
|
// if (ExitReason == VMX_EXIT_REASON_EXECUTE_RDTSCP)
|
|
// {
|
|
// VCpu->Regs->rcx = 0x00000000ffffffff & Aux;
|
|
// }
|
|
// //
|
|
// // Shows that vm-exit handler should not emulate the RDTSC/P
|
|
// //
|
|
// Result = FALSE;
|
|
// }
|
|
// else if (ExitReason == VMX_EXIT_REASON_EXECUTE_CPUID &&
|
|
// VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc != NULL64_ZERO)
|
|
// {
|
|
// //
|
|
// // The guy executed one or more CPUIDs after an rdtscp so we
|
|
// // need to add new cpuid value to previous timer and also
|
|
// // we need to store it somewhere to remember this behavior
|
|
// //
|
|
// VCpu->TransparencyState.RevealedTimeStampCounterByRdtsc +=
|
|
// TransparentRandn((UINT32)g_TransparentModeMeasurements->CpuidAverage,
|
|
// (UINT32)g_TransparentModeMeasurements->CpuidStandardDeviation);
|
|
//
|
|
// VCpu->TransparencyState.CpuidAfterRdtscDetected = TRUE;
|
|
// }
|
|
//
|
|
// return Result;
|
|
// }
|
|
//
|