/** * @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 }