HyperDbg/hyperdbg/script-eval/code/Functions.c
2026-04-25 18:02:48 +02:00

2060 lines
49 KiB
C

/**
* @file Functions.c
* @author M.H. Gholamrezaei (mh@hyperdbg.org)
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Script engine functions implementations
* @details
* @version 0.2
* @date 2022-06-29
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
//
// User-mode Global Variables
//
#ifdef SCRIPT_ENGINE_USER_MODE
extern UINT64 g_CurrentExprEvalResult;
extern BOOLEAN g_CurrentExprEvalResultHasError;
#endif // SCRIPT_ENGINE_USER_MODE
//
// *** Definitions ***
//
UINT64
GetValue(PGUEST_REGS GuestRegs,
PACTION_BUFFER ActionBuffer,
PSCRIPT_ENGINE_GENERAL_REGISTERS ScriptGeneralRegisters,
PSYMBOL Symbol,
BOOLEAN ReturnReference);
//
// *** Functions ***
//
/**
* @brief Implementation of eq function
*
* @param Address
* @param Value
* @param HasError
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionEq(UINT64 Address, QWORD Value, BOOL * HasError)
{
UNREFERENCED_PARAMETER(HasError);
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety(Address, sizeof(QWORD)))
{
//
// Instead of indicating an error, just return false
// to assign it as a return result to a variable
//
// *HasError = TRUE;
return FALSE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
#ifdef SCRIPT_ENGINE_USER_MODE
*(UINT64 *)Address = Value;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperWriteMemorySafeOnTargetProcess(Address, &Value, sizeof(QWORD));
#endif // SCRIPT_ENGINE_KERNEL_MODE
return TRUE;
}
/**
* @brief Implementation of ed function
*
* @param Address
* @param Value
* @param HasError
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionEd(UINT64 Address, DWORD Value, BOOL * HasError)
{
UNREFERENCED_PARAMETER(HasError);
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety(Address, sizeof(DWORD)))
{
//
// Instead of indicating an error, just return false
// to assign it as a return result to a variable
//
// *HasError = TRUE;
return FALSE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
#ifdef SCRIPT_ENGINE_USER_MODE
*(DWORD *)Address = Value;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperWriteMemorySafeOnTargetProcess(Address, &Value, sizeof(DWORD));
#endif // SCRIPT_ENGINE_KERNEL_MODE
return TRUE;
}
/**
* @brief Implementation of eb function
*
* @param Address
* @param Value
* @param HasError
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionEb(UINT64 Address, BYTE Value, BOOL * HasError)
{
UNREFERENCED_PARAMETER(HasError);
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety(Address, sizeof(BYTE)))
{
//
// Instead of indicating an error, just return false
// to assign it as a return result to a variable
//
// *HasError = TRUE;
return FALSE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
#ifdef SCRIPT_ENGINE_USER_MODE
*(BYTE *)Address = Value;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperWriteMemorySafeOnTargetProcess(Address, &Value, sizeof(BYTE));
#endif // SCRIPT_ENGINE_KERNEL_MODE
return TRUE;
}
/**
* @brief Implementation of eq function (Physical Memory)
*
* @param Address
* @param Value
* @param HasError
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionEqPa(UINT64 Address, QWORD Value, BOOL * HasError)
{
UNREFERENCED_PARAMETER(HasError);
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAddressPhysical(Address))
{
//
// Instead of indicating an error, just return false
// to assign it as a return result to a variable
//
// *HasError = TRUE;
return FALSE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, using physical address functions (eq_pa) is not possible in user-mode\n");
return FALSE;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperWriteMemorySafeByPhysicalAddress(Address, (UINT64)&Value, sizeof(QWORD));
#endif // SCRIPT_ENGINE_KERNEL_MODE
return TRUE;
}
/**
* @brief Implementation of ed function (Physical Memory)
*
* @param Address
* @param Value
* @param HasError
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionEdPa(UINT64 Address, DWORD Value, BOOL * HasError)
{
UNREFERENCED_PARAMETER(HasError);
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAddressPhysical(Address))
{
//
// Instead of indicating an error, just return false
// to assign it as a return result to a variable
//
// *HasError = TRUE;
return FALSE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, using physical address functions (ed_pa) is not possible in user-mode\n");
return FALSE;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperWriteMemorySafeByPhysicalAddress(Address, (UINT64)&Value, sizeof(DWORD));
#endif // SCRIPT_ENGINE_KERNEL_MODE
return TRUE;
}
/**
* @brief Implementation of eb function (Physical Memory)
*
* @param Address
* @param Value
* @param HasError
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionEbPa(UINT64 Address, BYTE Value, BOOL * HasError)
{
UNREFERENCED_PARAMETER(HasError);
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAddressPhysical(Address))
{
//
// Instead of indicating an error, just return false
// to assign it as a return result to a variable
//
// *HasError = TRUE;
return FALSE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, using physical address functions (eb_pa) is not possible in user-mode\n");
return FALSE;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperWriteMemorySafeByPhysicalAddress(Address, (UINT64)&Value, sizeof(BYTE));
#endif // SCRIPT_ENGINE_KERNEL_MODE
return TRUE;
}
/**
* @brief Check whether the address is valid or not
*
* @param Address
* @param Length
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionCheckAddress(UINT64 Address, UINT32 Length)
{
#ifdef SCRIPT_ENGINE_USER_MODE
if (CheckAccessValidityAndSafety(Address, Length))
{
return TRUE;
}
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (CheckAccessValidityAndSafety(Address, Length))
{
return TRUE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
return FALSE;
}
/**
* @brief A VMX-compatible equivalent of memcpy function in C
*
* @param Destination
* @param Source
* @param Num
* @param HasError
* @return VOID
*/
VOID
ScriptEngineFunctionMemcpy(UINT64 Destination, UINT64 Source, UINT32 Num, BOOL * HasError)
{
UINT64 PrevReadLen = 0;
BYTE MovingBuffer[DebuggerScriptEngineMemcpyMovingBufferSize] = {0};
#ifdef SCRIPT_ENGINE_USER_MODE
//
// Check the destination address
//
if (!CheckAccessValidityAndSafety(Destination, Num))
{
*HasError = TRUE;
return;
}
//
// Check the source address
//
if (!CheckAccessValidityAndSafety(Source, Num))
{
*HasError = TRUE;
return;
}
//
// Address is valid, perform the memcpy in user-mode
//
memcpy((void *)Destination, (void *)Source, Num);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Check the destination address
//
if (!CheckAccessValidityAndSafety(Destination, Num))
{
*HasError = TRUE;
return;
}
//
// Check the source address
//
if (!CheckAccessValidityAndSafety(Source, Num))
{
*HasError = TRUE;
return;
}
//
// Address is valid, perform the memcpy in kernel-mode (VMX-root mode)
//
while (Num > 0)
{
//
// Check the target buffer size
//
if (Num > DebuggerScriptEngineMemcpyMovingBufferSize)
{
//
// *** The size of read buffer is greater to maximum the moving buffer size ***
//
//
// Read memory into the buffer
//
MemoryMapperReadMemorySafeOnTargetProcess(Source + PrevReadLen, MovingBuffer, DebuggerScriptEngineMemcpyMovingBufferSize);
//
// Write the moving buffer into the target buffer
//
MemoryMapperWriteMemorySafeOnTargetProcess(Destination + PrevReadLen, MovingBuffer, DebuggerScriptEngineMemcpyMovingBufferSize);
//
// Computing the bytes that we read
//
PrevReadLen += DebuggerScriptEngineMemcpyMovingBufferSize;
Num -= DebuggerScriptEngineMemcpyMovingBufferSize;
}
else
{
//
// *** The size of read buffer is lower than or equal to the moving buffer size ***
//
//
// Read memory into the buffer
//
MemoryMapperReadMemorySafeOnTargetProcess(Source + PrevReadLen, MovingBuffer, Num);
//
// Write the moving buffer into the target buffer
//
MemoryMapperWriteMemorySafeOnTargetProcess(Destination + PrevReadLen, MovingBuffer, Num);
//
// Computing the bytes that we gonna read
//
PrevReadLen += Num;
Num = 0; // or Num -= Num;
}
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief A VMX-compatible equivalent of memcpy function in C for physical memory
*
* @param Destination
* @param Source
* @param Num
* @param HasError
* @return VOID
*/
VOID
ScriptEngineFunctionMemcpyPa(UINT64 Destination, UINT64 Source, UINT32 Num, BOOL * HasError)
{
UINT64 PrevReadLen = 0;
BYTE MovingBuffer[DebuggerScriptEngineMemcpyMovingBufferSize] = {0};
#ifdef SCRIPT_ENGINE_USER_MODE
//
// Show an error message in user-mode
//
ShowMessages("err, using physical address functions (memcpy_pa) is not possible in user-mode\n");
return;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Check the destination address (physical)
//
if (!CheckAddressPhysical(Destination))
{
*HasError = TRUE;
return;
}
//
// Check the source address (physical)
//
if (!CheckAddressPhysical(Source))
{
*HasError = TRUE;
return;
}
//
// Address is valid, perform the memcpy in kernel-mode (VMX-root mode)
//
while (Num > 0)
{
//
// Check the target buffer size
//
if (Num > DebuggerScriptEngineMemcpyMovingBufferSize)
{
//
// *** The size of read buffer is greater to maximum the moving buffer size ***
//
//
// Read memory into the buffer
//
MemoryMapperReadMemorySafeByPhysicalAddress(Source + PrevReadLen, (UINT64)MovingBuffer, DebuggerScriptEngineMemcpyMovingBufferSize);
//
// Write the moving buffer into the target buffer
//
MemoryMapperWriteMemorySafeByPhysicalAddress(Destination + PrevReadLen, (UINT64)MovingBuffer, DebuggerScriptEngineMemcpyMovingBufferSize);
//
// Computing the bytes that we read
//
PrevReadLen += DebuggerScriptEngineMemcpyMovingBufferSize;
Num -= DebuggerScriptEngineMemcpyMovingBufferSize;
}
else
{
//
// *** The size of read buffer is lower than or equal to the moving buffer size ***
//
//
// Read memory into the buffer
//
MemoryMapperReadMemorySafeByPhysicalAddress(Source + PrevReadLen, (UINT64)MovingBuffer, Num);
//
// Write the moving buffer into the target buffer
//
MemoryMapperWriteMemorySafeByPhysicalAddress(Destination + PrevReadLen, (UINT64)MovingBuffer, Num);
//
// Computing the bytes that we gonna read
//
PrevReadLen += Num;
Num = 0; // or Num -= Num;
}
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
//
// Convert virtual address to physical address
//
UINT64
ScriptEngineFunctionVirtualToPhysical(UINT64 Address)
{
#ifdef SCRIPT_ENGINE_USER_MODE
//
// There is no conversion in user-mode
//
return NULL;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
return VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)Address);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Convert physical address to virtual address
*
* @param Address
* @return UINT64
*/
UINT64
ScriptEngineFunctionPhysicalToVirtual(UINT64 Address)
{
#ifdef SCRIPT_ENGINE_USER_MODE
//
// There is no conversion in user-mode
//
return NULL;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
return PhysicalAddressToVirtualAddressOnTargetProcess((PVOID)Address);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of print function
*
* @param Tag
* @param ImmediateMessagePassing
* @param Value
* @return VOID
*/
VOID
ScriptEngineFunctionPrint(UINT64 Tag, BOOLEAN ImmediateMessagePassing, UINT64 Value)
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("%llx\n", Value);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Prepare a buffer to bypass allocating a huge stack space for logging
//
char TempBuffer[20] = {0};
UINT32 TempBufferLen = sprintf(TempBuffer, "%llx\n", Value);
LogSimpleWithTag((UINT32)Tag, ImmediateMessagePassing, TempBuffer, TempBufferLen + 1);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of test_statement function
*
* @param Tag
* @param ImmediateMessagePassing
* @param Value
* @return VOID
*/
VOID
ScriptEngineFunctionTestStatement(UINT64 Tag, BOOLEAN ImmediateMessagePassing, UINT64 Value)
{
UNREFERENCED_PARAMETER(Tag);
UNREFERENCED_PARAMETER(ImmediateMessagePassing);
UNREFERENCED_PARAMETER(Value);
#ifdef SCRIPT_ENGINE_USER_MODE
g_CurrentExprEvalResult = Value;
g_CurrentExprEvalResultHasError = FALSE;
#endif // SCRIPT_ENGINE_USER_MODE
}
/**
* @brief Implementation of spinlock_lock function
*
* @param Lock
* @param HasError
* @return VOID
*/
VOID
ScriptEngineFunctionSpinlockLock(volatile LONG * Lock, BOOL * HasError)
{
#ifdef SCRIPT_ENGINE_USER_MODE
SpinlockLock(Lock);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety((UINT64)Lock, sizeof(LONG)))
{
*HasError = TRUE;
return;
}
SpinlockLock(Lock);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of spinlock_unlock function
*
* @param Lock
* @param HasError
* @return VOID
*/
VOID
ScriptEngineFunctionSpinlockUnlock(volatile LONG * Lock, BOOL * HasError)
{
#ifdef SCRIPT_ENGINE_USER_MODE
SpinlockUnlock(Lock);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety((UINT64)Lock, sizeof(LONG)))
{
*HasError = TRUE;
return;
}
SpinlockUnlock(Lock);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of spinlock_lock_custom_wait function
*
* @param Lock
* @param MaxWait
* @param HasError
* @return VOID
*/
VOID
ScriptEngineFunctionSpinlockLockCustomWait(volatile long * Lock, unsigned MaxWait, BOOL * HasError)
{
#ifdef SCRIPT_ENGINE_USER_MODE
SpinlockLockWithCustomWait(Lock, MaxWait);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety((UINT64)Lock, sizeof(LONG)))
{
*HasError = TRUE;
return;
}
SpinlockLockWithCustomWait(Lock, MaxWait);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of strlen function
*
* @param Address
* @return UINT64
*/
UINT64
ScriptEngineFunctionStrlen(const char * Address)
{
UINT64 Result = 0;
#ifdef SCRIPT_ENGINE_USER_MODE
Result = strlen(Address);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
Result = VmFuncVmxCompatibleStrlen(Address);
#endif // SCRIPT_ENGINE_KERNEL_MODE
return Result;
}
/**
* @brief Implementation of disassemble_len function
*
* @param Address
* @param Is32Bit
*
* @return UINT64
*/
UINT64
ScriptEngineFunctionDisassembleLen(PVOID Address, BOOLEAN Is32Bit)
{
UINT64 Result = 0;
#ifdef SCRIPT_ENGINE_USER_MODE
Result = HyperDbgLengthDisassemblerEngine((unsigned char *)Address, MAXIMUM_INSTR_SIZE, Is32Bit ? FALSE : TRUE);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
Result = DisassemblerLengthDisassembleEngineInVmxRootOnTargetProcess(Address, Is32Bit);
#endif // SCRIPT_ENGINE_KERNEL_MODE
return Result;
}
/**
* @brief Implementation of wcslen function
*
* @param Address
* @return UINT64
*/
UINT64
ScriptEngineFunctionWcslen(const wchar_t * Address)
{
UINT64 Result = 0;
#ifdef SCRIPT_ENGINE_USER_MODE
Result = wcslen(Address);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
Result = VmFuncVmxCompatibleWcslen(Address);
#endif // SCRIPT_ENGINE_KERNEL_MODE
return Result;
}
#ifdef SCRIPT_ENGINE_USER_MODE
VOID
UserModeMicroSleep(UINT64 Us)
{
LARGE_INTEGER Start, End, Frequency;
QueryPerformanceFrequency(&Frequency);
LONGLONG TickPerUs = Frequency.QuadPart / 1000000;
LONGLONG Ticks = TickPerUs * Us;
QueryPerformanceCounter(&Start);
while (TRUE)
{
QueryPerformanceCounter(&End);
if (End.QuadPart - Start.QuadPart > Ticks)
{
break;
}
}
}
#endif // SCRIPT_ENGINE_USER_MODE
/**
* @brief Implementation of microsleep function
*
* @param Us delay in micro second
*/
VOID
ScriptEngineFunctionMicroSleep(UINT64 Us)
{
#ifdef SCRIPT_ENGINE_USER_MODE
UserModeMicroSleep(Us);
#endif
#ifdef SCRIPT_ENGINE_KERNEL_MODE
VmFuncVmxCompatibleMicroSleep(Us);
#endif
}
/**
* @brief Implementation of rdtsc function
*
*/
UINT64
ScriptEngineFunctionRdtsc()
{
return __rdtsc();
}
/**
* @brief Implementation of rdtscp function
*
*/
UINT64
ScriptEngineFunctionRdtscp()
{
unsigned int Aux;
return __rdtscp(&Aux);
}
/**
* @brief Implementation of interlocked_exchange function
*
* @param Target
* @param Value
* @param HasError
* @return long long
*/
long long
ScriptEngineFunctionInterlockedExchange(long long volatile * Target,
long long Value,
BOOL * HasError)
{
long long Result = 0;
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety((UINT64)Target, sizeof(long long)))
{
*HasError = TRUE;
return (long long)NULL;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
Result = InterlockedExchange64(Target, Value);
return Result;
}
/**
* @brief Implementation of interlocked_exchange_add function
*
* @param Addend
* @param Value
* @param HasError
* @return long long
*/
long long
ScriptEngineFunctionInterlockedExchangeAdd(long long volatile * Addend,
long long Value,
BOOL * HasError)
{
long long Result = 0;
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety((UINT64)Addend, sizeof(long long)))
{
*HasError = TRUE;
return (long long)NULL;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
Result = InterlockedExchangeAdd64(Addend, Value);
return Result;
}
/**
* @brief Implementation of interlocked_exchange_increment function
*
* @param Addend
* @param HasError
* @return long long
*/
long long
ScriptEngineFunctionInterlockedIncrement(long long volatile * Addend,
BOOL * HasError)
{
long long Result = 0;
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety((UINT64)Addend, sizeof(long long)))
{
*HasError = TRUE;
return (long long)NULL;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
Result = InterlockedIncrement64(Addend);
return Result;
}
/**
* @brief Implementation of interlocked_exchange_decrement function
*
* @param Addend
* @param HasError
* @return long long
*/
long long
ScriptEngineFunctionInterlockedDecrement(long long volatile * Addend,
BOOL * HasError)
{
long long Result = 0;
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety((UINT64)Addend, sizeof(long long)))
{
*HasError = TRUE;
return (long long)NULL;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
Result = InterlockedDecrement64(Addend);
return Result;
}
/**
* @brief Implementation of interlocked_compare_exchange function
*
* @param Destination
* @param ExChange
* @param Comperand
* @param HasError
* @return long long
*/
long long
ScriptEngineFunctionInterlockedCompareExchange(
long long volatile * Destination,
long long ExChange,
long long Comperand,
BOOL * HasError)
{
long long Result = 0;
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!CheckAccessValidityAndSafety((UINT64)Destination, sizeof(long long)))
{
*HasError = TRUE;
return (long long)NULL;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
Result = InterlockedCompareExchange64(Destination, ExChange, Comperand);
return Result;
}
/**
* @brief Implementation of event_enable function
*
* @param EventId
*
* @return VOID
*/
VOID
ScriptEngineFunctionEventEnable(UINT64 EventId)
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, enabling events is not possible in user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!DebuggerEnableEvent(EventId + DebuggerEventTagStartSeed))
{
LogInfo("Invalid tag id (%x)", EventId);
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of event_disable function
*
* @param EventId
*
* @return VOID
*/
VOID
ScriptEngineFunctionEventDisable(UINT64 EventId)
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, disabling events is not possible in user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (!DebuggerDisableEvent(EventId + DebuggerEventTagStartSeed))
{
LogInfo("Invalid tag id (%x)", EventId);
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of event_clear function
*
* @param EventId
*
* @return VOID
*/
VOID
ScriptEngineFunctionEventClear(UINT64 EventId)
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, disabling events is not possible in user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
BOOLEAN PoolManagerAllocatedMemory = FALSE;
if (g_KernelDebuggerState && EnableInstantEventMechanism)
{
PoolManagerAllocatedMemory = TRUE;
}
if (!DebuggerClearEvent(EventId + DebuggerEventTagStartSeed, VmFuncVmxGetCurrentExecutionMode(), PoolManagerAllocatedMemory))
{
LogInfo("Invalid tag id (%x)", EventId);
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of pause function
*
* @param ActionDetail
* @param GuestRegs
*
* @return VOID
*/
VOID
ScriptEngineFunctionPause(
ACTION_BUFFER * ActionDetail,
PGUEST_REGS GuestRegs)
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, breaking is not possible in user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// pause(); function is only working when kernel debugger is working
// it's not designed to work on vmi-mode (local debugging)
//
if (g_KernelDebuggerState && g_DebuggeeHaltReason == DEBUGGEE_PAUSING_REASON_NOT_PAUSED)
{
DEBUGGER_TRIGGERED_EVENT_DETAILS TriggeredEventDetail = {0};
ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
//
// Make the details of context
//
TriggeredEventDetail.Tag = ActionDetail->Tag;
TriggeredEventDetail.Context = (PVOID)ActionDetail->Context;
if (ActionDetail->CallingStage == 1)
{
TriggeredEventDetail.Stage = VMM_CALLBACK_CALLING_STAGE_POST_EVENT_EMULATION;
}
else
{
TriggeredEventDetail.Stage = VMM_CALLBACK_CALLING_STAGE_PRE_EVENT_EMULATION;
}
if (VmFuncVmxGetCurrentExecutionMode() == TRUE)
{
//
// The guest is already in vmx-root mode
// Halt other cores
//
KdHandleBreakpointAndDebugBreakpointsCallback(
CurrentCore,
DEBUGGEE_PAUSING_REASON_DEBUGGEE_EVENT_TRIGGERED,
&TriggeredEventDetail);
}
else
{
//
// The guest is on vmx non-root mode, the first parameter
// is context and the second parameter is tag
//
VmFuncVmxVmcall(DEBUGGER_VMCALL_VM_EXIT_HALT_SYSTEM_AS_A_RESULT_OF_TRIGGERING_EVENT,
(UINT64)&TriggeredEventDetail,
(UINT64)GuestRegs,
(UINT64)NULL);
}
}
else
{
LogInfo("The 'pause();' function is either called from the vmi-mode or is "
"evaluated by the '?' command. It's not allowed to use it on vmi-mode "
"(local debugging) or by the '?' command");
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of flush function
*
* @return VOID
*/
VOID
ScriptEngineFunctionFlush()
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, it's not possible to flush buffers in user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Mark all buffers as read
//
LogMarkAllAsRead(TRUE);
LogMarkAllAsRead(FALSE);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of event_ignore function
* @param State
* @param ActionDetail
*
* @return VOID
*/
VOID
ScriptEngineFunctionShortCircuitingEvent(UINT64 State, ACTION_BUFFER * ActionDetail)
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, it's not possible to short-circuit events in user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (ActionDetail->CallingStage == 1)
{
LogWarning("Warning, calling the 'event_sc' function in the 'post' calling stage doesn't make sense as the emulation is already performed!\n"
"You can use this function in the 'pre' calling stage");
return;
}
ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
if (State != 0)
{
g_DbgState[CurrentCore].ShortCircuitingEvent = TRUE;
}
else
{
g_DbgState[CurrentCore].ShortCircuitingEvent = FALSE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of formats function
*
* @param Tag
* @param ImmediateMessagePassing
* @param Value
* @return VOID
*/
VOID
ScriptEngineFunctionFormats(UINT64 Tag, BOOLEAN ImmediateMessagePassing, UINT64 Value)
{
#ifdef SCRIPT_ENGINE_USER_MODE
ScriptEngineFunctionTestStatement(Tag, ImmediateMessagePassing, Value);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (g_KernelDebuggerState)
{
KdSendFormatsFunctionResult(Value);
}
else if (g_UserDebuggerState)
{
UdSendFormatsFunctionResult(Value);
}
else
{
//
// Prepare a buffer to bypass allocating a huge stack space for logging
//
char TempBuffer[20] = {0};
UINT32 TempBufferLen = sprintf(TempBuffer, "%llx\n", Value);
LogSimpleWithTag((UINT32)Tag, ImmediateMessagePassing, TempBuffer, TempBufferLen + 1);
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Custom VMX-root compatible strlen
*
* @param StrAddr
* @param IsWstring
* @return UINT32
*/
UINT32
CustomStrlen(UINT64 StrAddr, BOOLEAN IsWstring)
{
#ifdef SCRIPT_ENGINE_USER_MODE
if (IsWstring)
{
return (UINT32)wcslen((const wchar_t *)StrAddr);
}
else
{
return (UINT32)strlen((const char *)StrAddr);
}
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
if (IsWstring)
{
return VmFuncVmxCompatibleWcslen((const wchar_t *)StrAddr);
}
else
{
return VmFuncVmxCompatibleStrlen((const CHAR *)StrAddr);
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Check if string is safe to be accessed or not (in vmx-root mode)
*
* @param StrAddr
* @param IsWstring
* @return BOOLEAN
*/
BOOLEAN
CheckIfStringIsSafe(UINT64 StrAddr, BOOLEAN IsWstring)
{
#ifdef SCRIPT_ENGINE_USER_MODE
return TRUE;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// At least two chars (wchar_t is 4 byte)
//
if (CheckAccessValidityAndSafety(StrAddr, IsWstring ? 4 : 2))
{
return TRUE;
}
else
{
return FALSE;
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Apply format specifiers (%d, %x, %llx, etc.)
*
* @param CurrentSpecifier
* @param FinalBuffer
* @param CurrentProcessedPositionFromStartOfFormat
* @param CurrentPositionInFinalBuffer
* @param Val
* @param SizeOfFinalBuffer
* @return VOID
*/
VOID
ApplyFormatSpecifier(const CHAR * CurrentSpecifier, CHAR * FinalBuffer, PUINT32 CurrentProcessedPositionFromStartOfFormat, PUINT32 CurrentPositionInFinalBuffer, UINT64 Val, UINT32 SizeOfFinalBuffer)
{
UINT32 TempBufferLen = 0;
CHAR TempBuffer[50 + 1] = {
0}; // Maximum uint64_t is 18446744073709551615 + 1 thus its 20 character
// for maximum buffer + 1 end char null but we alloc 50 to be sure
*CurrentProcessedPositionFromStartOfFormat =
*CurrentProcessedPositionFromStartOfFormat + (UINT32)strlen(CurrentSpecifier);
sprintf_s(TempBuffer, sizeof(TempBuffer), CurrentSpecifier, Val);
TempBufferLen = (UINT32)strlen(TempBuffer);
//
// Check final buffer capacity
//
if (*CurrentPositionInFinalBuffer + TempBufferLen > SizeOfFinalBuffer)
{
//
// Over passed buffer
//
return;
}
memcpy(&FinalBuffer[*CurrentPositionInFinalBuffer], TempBuffer, TempBufferLen);
*CurrentPositionInFinalBuffer = *CurrentPositionInFinalBuffer + TempBufferLen;
}
/**
* @brief Convert WCHAR* to CHAR*
*
* @param src
* @param dest
* @param dest_len
* @return size_t
*/
size_t
WcharToChar(const wchar_t * src, char * dest, size_t dest_len)
{
wchar_t Code;
size_t i;
i = 0;
while ((src[i] != '\0') && i < (dest_len - 1))
{
Code = src[i];
if (Code < 128)
dest[i] = (char)Code;
else
{
dest[i] = '?';
if (Code >= 0xD800 && Code <= 0xD8FF)
{
//
// Lead surrogate, skip the next code unit, which is the trail
//
i++;
}
}
i++;
}
return i - 1;
}
/**
* @brief Apply string format specifiers (%s, %ws, etc.)
*
* @param CurrentSpecifier
* @param FinalBuffer
* @param CurrentProcessedPositionFromStartOfFormat
* @param CurrentPositionInFinalBuffer
* @param Val
* @param IsWstring
* @param SizeOfFinalBuffer
* @return BOOLEAN
*/
BOOLEAN
ApplyStringFormatSpecifier(const CHAR * CurrentSpecifier, CHAR * FinalBuffer, PUINT32 CurrentProcessedPositionFromStartOfFormat, PUINT32 CurrentPositionInFinalBuffer, UINT64 Val, BOOLEAN IsWstring, UINT32 SizeOfFinalBuffer)
{
UINT32 StringSize;
wchar_t WstrBuffer[50];
CHAR AsciiBuffer[sizeof(WstrBuffer) / 2];
UINT32 StringSizeInByte; /* because of wide-char */
UINT32 CountOfBlocks;
UINT32 CopiedBlockLen;
//
// First we have to check if string is valid or not
//
if (!CheckIfStringIsSafe(Val, IsWstring))
{
return FALSE;
}
//
// get the length of the string (format) identifier
//
*CurrentProcessedPositionFromStartOfFormat += (UINT32)strlen(CurrentSpecifier);
//
// Get string len
//
StringSize = CustomStrlen(Val, IsWstring);
//
// Check final buffer capacity
//
if (*CurrentPositionInFinalBuffer + StringSize > SizeOfFinalBuffer)
{
//
// Over passed buffer
//
return TRUE;
}
//
// Move the buffer string into the target buffer
//
if (IsWstring)
{
//
// Parse wstring
//
StringSizeInByte = StringSize * 2; /* because of wide-char */
//
// compute the ceiling
//
if (StringSizeInByte % sizeof(WstrBuffer) == 0)
{
CountOfBlocks = StringSizeInByte / sizeof(WstrBuffer);
}
else
{
CountOfBlocks = (StringSizeInByte / sizeof(WstrBuffer)) + 1;
}
for (size_t i = 0; i < CountOfBlocks; i++)
{
//
// Zero the buffers
//
RtlZeroMemory(WstrBuffer, sizeof(WstrBuffer));
RtlZeroMemory(AsciiBuffer, sizeof(AsciiBuffer));
//
// Check for the last block
//
if (i == CountOfBlocks - 1)
{
//
// A portion of block
//
#ifdef SCRIPT_ENGINE_USER_MODE
memcpy(WstrBuffer, (void *)(Val + (i * sizeof(WstrBuffer))), StringSizeInByte % sizeof(WstrBuffer));
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperReadMemorySafeOnTargetProcess(
(UINT64)(Val + (i * sizeof(WstrBuffer))),
WstrBuffer,
StringSizeInByte % sizeof(WstrBuffer));
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
else
{
//
// A complete block
//
#ifdef SCRIPT_ENGINE_USER_MODE
memcpy(WstrBuffer, (void *)(Val + (i * sizeof(WstrBuffer))), sizeof(WstrBuffer));
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperReadMemorySafeOnTargetProcess(
(UINT64)(Val + (i * sizeof(WstrBuffer))),
WstrBuffer,
sizeof(WstrBuffer));
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
//
// Here we have the filled WstrBuffer
// We should convert WstrBuffer to AsciiBuffer
//
CopiedBlockLen =
(UINT32)WcharToChar(WstrBuffer, AsciiBuffer, sizeof(AsciiBuffer) + 1);
//
// Now we should move the AsciiBuffer to the target buffer
// (when we filled AsciiBuffer the memory here is safe so we
// can use memcpy in both user-mode and vmx-root mode)
//
memcpy(&FinalBuffer[*CurrentPositionInFinalBuffer], (void *)AsciiBuffer, CopiedBlockLen + 1);
*CurrentPositionInFinalBuffer += CopiedBlockLen + 1;
}
}
else
{
//
// Parse string
//
#ifdef SCRIPT_ENGINE_USER_MODE
memcpy(&FinalBuffer[*CurrentPositionInFinalBuffer], (void *)Val, StringSize);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
MemoryMapperReadMemorySafeOnTargetProcess(
Val,
&FinalBuffer[*CurrentPositionInFinalBuffer],
StringSize);
#endif // SCRIPT_ENGINE_KERNEL_MODE
*CurrentPositionInFinalBuffer += StringSize;
}
return TRUE;
}
/**
* @brief Implementation of printf function
*
* @param GuestRegs
* @param ActionDetail
* @param ScriptGeneralRegisters
* @param Tag
* @param ImmediateMessagePassing
* @param Format
* @param ArgCount
* @param FirstArg
* @param HasError
* @return VOID
*/
VOID
ScriptEngineFunctionPrintf(PGUEST_REGS GuestRegs,
ACTION_BUFFER * ActionDetail,
SCRIPT_ENGINE_GENERAL_REGISTERS * ScriptGeneralRegisters,
UINT64 Tag,
BOOLEAN ImmediateMessagePassing,
char * Format,
UINT64 ArgCount,
PSYMBOL FirstArg,
BOOLEAN * HasError)
{
//
// *** The printf function ***
//
char FinalBuffer[PacketChunkSize] = {0};
UINT32 CurrentPositionInFinalBuffer = 0;
UINT32 CurrentProcessedPositionFromStartOfFormat = 0;
BOOLEAN WithoutAnyFormatSpecifier = TRUE;
UINT64 Val;
UINT32 Position;
UINT32 LenOfFormats = (UINT32)strlen(Format) + 1;
PSYMBOL Symbol;
*HasError = FALSE;
for (int i = 0; i < ArgCount; i++)
{
WithoutAnyFormatSpecifier = FALSE;
Symbol = FirstArg + i;
//
// Address is either wstring (%ws) or string (%s)
//
Position = (Symbol->Type >> 32) + 1;
SYMBOL TempSymbol = {0};
memcpy(&TempSymbol, Symbol, sizeof(SYMBOL));
TempSymbol.Type &= 0x7fffffff;
Val = GetValue(GuestRegs, ActionDetail, ScriptGeneralRegisters, &TempSymbol, FALSE);
CHAR PercentageChar = Format[Position];
// printf("position = %d is %c%c \n", Position, PercentageChar, IndicatorChar1);
if (CurrentProcessedPositionFromStartOfFormat != Position)
{
//
// There is some strings before this format specifier
// we should move it to the buffer
//
UINT32 StringLen = Position - CurrentProcessedPositionFromStartOfFormat;
//
// Check final buffer capacity
//
if (CurrentPositionInFinalBuffer + StringLen < sizeof(FinalBuffer))
{
memcpy(&FinalBuffer[CurrentPositionInFinalBuffer],
&Format[CurrentProcessedPositionFromStartOfFormat],
StringLen);
CurrentProcessedPositionFromStartOfFormat += StringLen;
CurrentPositionInFinalBuffer += StringLen;
}
}
//
// Double check and apply
//
if (PercentageChar == '%')
{
//
// Set first character of specifier
//
CHAR FormatSpecifier[5] = {0};
FormatSpecifier[0] = '%';
//
// Read second char
//
CHAR IndicatorChar2 = Format[Position + 1];
//
// Check if IndicatorChar2 is 2 character long or more
//
if (IndicatorChar2 == 'l' || IndicatorChar2 == 'w' ||
IndicatorChar2 == 'h')
{
//
// Set second char in format specifier
//
FormatSpecifier[1] = IndicatorChar2;
if (IndicatorChar2 == 'l' && Format[Position + 2] == 'l')
{
//
// Set third character in format specifier "ll"
//
FormatSpecifier[2] = 'l';
//
// Set last character
//
FormatSpecifier[3] = Format[Position + 3];
}
else
{
//
// Set last character
//
FormatSpecifier[2] = Format[Position + 2];
}
}
else
{
//
// It's a one char specifier (Set last character)
//
FormatSpecifier[1] = IndicatorChar2;
}
//
// Apply the specifier
//
if (!strncmp(FormatSpecifier, "%s", 2))
{
//
// for string
//
if (!ApplyStringFormatSpecifier(
"%s",
FinalBuffer,
&CurrentProcessedPositionFromStartOfFormat,
&CurrentPositionInFinalBuffer,
Val,
FALSE,
sizeof(FinalBuffer)))
{
*HasError = TRUE;
return;
}
}
else if (!strncmp(FormatSpecifier, "%ls", 3) ||
!strncmp(FormatSpecifier, "%ws", 3))
{
//
// for wide string (not important if %ls or %ws , only the length is
// important)
//
if (!ApplyStringFormatSpecifier(
"%ws",
FinalBuffer,
&CurrentProcessedPositionFromStartOfFormat,
&CurrentPositionInFinalBuffer,
Val,
TRUE,
sizeof(FinalBuffer)))
{
*HasError = TRUE;
return;
}
}
else
{
ApplyFormatSpecifier(FormatSpecifier, FinalBuffer, &CurrentProcessedPositionFromStartOfFormat, &CurrentPositionInFinalBuffer, Val, sizeof(FinalBuffer));
}
}
}
if (WithoutAnyFormatSpecifier)
{
//
// Means that it's just a simple print without any format specifier
//
if (LenOfFormats < sizeof(FinalBuffer))
{
memcpy(FinalBuffer, Format, LenOfFormats);
}
}
else
{
//
// Check if there is anything after the last format specifier
//
if (LenOfFormats > CurrentProcessedPositionFromStartOfFormat)
{
UINT32 RemainedLen =
LenOfFormats - CurrentProcessedPositionFromStartOfFormat;
if (CurrentPositionInFinalBuffer + RemainedLen < sizeof(FinalBuffer))
{
memcpy(&FinalBuffer[CurrentPositionInFinalBuffer],
&Format[CurrentProcessedPositionFromStartOfFormat],
RemainedLen);
}
}
}
//
// Print final result
//
#ifdef SCRIPT_ENGINE_USER_MODE
printf("%s", FinalBuffer);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Prepare a buffer to bypass allocating a huge stack space for logging
//
LogSimpleWithTag((UINT32)Tag, ImmediateMessagePassing, FinalBuffer, (UINT32)strlen(FinalBuffer) + 1);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of event_inject function
*
* @param InterruptionType
* @param Vector
* @param HasError
* @return VOID
*/
VOID
ScriptEngineFunctionEventInject(UINT32 InterruptionType, UINT32 Vector, BOOL * HasError)
{
UNREFERENCED_PARAMETER(HasError);
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, event_inject is not supported in user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Validate the arguments
//
if (Vector >= 256 || InterruptionType >= 8)
{
LogInfo("Err, invalid event vector or interruption type is specified");
return;
}
else
{
VmFuncEventInjectInterruption(InterruptionType, Vector, FALSE, 0);
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of event_inject_error_code function
*
* @param InterruptionType
* @param Vector
* @param ErrorCode
* @param HasError
* @return VOID
*/
VOID
ScriptEngineFunctionEventInjectErrorCode(UINT32 InterruptionType, UINT32 Vector, UINT32 ErrorCode, BOOL * HasError)
{
UNREFERENCED_PARAMETER(HasError);
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, event_inject is not supported in user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Validate the arguments
//
if (Vector >= 256 || InterruptionType >= 8)
{
LogInfo("Err, invalid event vector or interruption type is specified");
return;
}
else
{
VmFuncEventInjectInterruption(InterruptionType, Vector, TRUE, ErrorCode);
}
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of strcmp function
*
* @param Address1
* @param Address2
*
* @return UINT64
*/
UINT64
ScriptEngineFunctionStrcmp(const char * Address1, const char * Address2)
{
UINT64 Result = 0;
#ifdef SCRIPT_ENGINE_USER_MODE
Result = strcmp(Address1, Address2);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
Result = VmFuncVmxCompatibleStrcmp(Address1, Address2);
#endif // SCRIPT_ENGINE_KERNEL_MODE
return Result;
}
/**
* @brief Implementation of strcmp function
*
* @param Address1
* @param Address2
* @param Num
*
* @return UINT64
*/
UINT64
ScriptEngineFunctionStrncmp(const char * Address1, const char * Address2, size_t Num)
{
UINT64 Result = 0;
#ifdef SCRIPT_ENGINE_USER_MODE
Result = strncmp(Address1, Address2, Num);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
Result = VmFuncVmxCompatibleStrncmp(Address1, Address2, Num);
#endif // SCRIPT_ENGINE_KERNEL_MODE
return Result;
}
/**
* @brief Implementation of wcscmp function
*
* @param Address1
* @param Address2
*
* @return UINT64
*/
UINT64
ScriptEngineFunctionWcscmp(const wchar_t * Address1, const wchar_t * Address2)
{
UINT64 Result = 0;
#ifdef SCRIPT_ENGINE_USER_MODE
Result = wcscmp(Address1, Address2);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
Result = VmFuncVmxCompatibleWcscmp(Address1, Address2);
#endif // SCRIPT_ENGINE_KERNEL_MODE
return Result;
}
/**
* @brief Implementation of wcsncmp function
*
* @param Address1
* @param Address2
* @param Num
*
* @return UINT64
*/
UINT64
ScriptEngineFunctionWcsncmp(const wchar_t * Address1, const wchar_t * Address2, size_t Num)
{
UINT64 Result = 0;
#ifdef SCRIPT_ENGINE_USER_MODE
Result = wcsncmp(Address1, Address2, Num);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
Result = VmFuncVmxCompatibleWcsncmp(Address1, Address2, Num);
#endif // SCRIPT_ENGINE_KERNEL_MODE
return Result;
}
/**
* @brief Implementation of memcmp function
*
* @param Address1
* @param Address2
* @param Count
* @return UINT64
*/
UINT64
ScriptEngineFunctionMemcmp(const char * Address1, const char * Address2, size_t Count)
{
UINT64 Result = 0;
#ifdef SCRIPT_ENGINE_USER_MODE
Result = memcmp(Address1, Address2, Count);
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
Result = VmFuncVmxCompatibleMemcmp(Address1, Address2, Count);
#endif // SCRIPT_ENGINE_KERNEL_MODE
return Result;
}
/**
* @brief Implementation of event_trace_instrumentation_step function
*
* @return VOID
*/
VOID
ScriptEngineFunctionEventTraceInstrumentationStep()
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, it's not possible to call event_trace_instrumentation_step function in the user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
//
// Call instrumentation step in
//
TracingPerformInstrumentationStepIn(&g_DbgState[CurrentCore]);
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of event_trace_step_in function
*
* @return VOID
*/
VOID
ScriptEngineFunctionEventTraceStepIn()
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, it's not possible to call event_trace_instrumentation_step function in the user-mode\n");
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Call instrumentation step in
//
TracingPerformRegularStepInInstruction();
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of lbr_save function
*
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionLbrSave()
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, it's not possible to call lbr_start function in the user-mode\n");
return FALSE;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Depending if we are in VMX-root then a VMCALL is issued by default instead, otherwise the VMCALL is ignored
//
return HyperTraceLbrSave(NULL, VmFuncVmxGetCurrentExecutionMode());
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
/**
* @brief Implementation of lbr_stop function
*
* @return BOOLEAN
*/
BOOLEAN
ScriptEngineFunctionLbrDump()
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, it's not possible to call lbr_stop function in the user-mode\n");
return FALSE;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
//
// Depending if we are in VMX-root then a VMCALL is issued by default instead, otherwise the VMCALL is ignored
//
return HyperTraceLbrDump(NULL, VmFuncVmxGetCurrentExecutionMode());
#endif // SCRIPT_ENGINE_KERNEL_MODE
}