mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-10 01:29:59 +00:00
252 lines
5.7 KiB
C
252 lines
5.7 KiB
C
/**
|
|
* @file Common.c
|
|
* @author Sina Karvandi (sina@hyperdbg.org)
|
|
* @brief Common functions that needs to be used in all source code files
|
|
* @details
|
|
* @version 0.1
|
|
* @date 2020-04-10
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
|
|
/**
|
|
* @brief Broadcast a function to all logical cores
|
|
* @details This function is deprecated as we want to supporrt more than 32 processors
|
|
*
|
|
* @param ProcessorNumber The logical core number to execute routine on it
|
|
* @param Routine The function that should be executed on the target core
|
|
* @return BOOLEAN Returns true if it was successful
|
|
*/
|
|
_Use_decl_annotations_
|
|
BOOLEAN
|
|
CommonAffinityBroadcastToProcessors(ULONG ProcessorNumber, RunOnLogicalCoreFunc Routine)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
KeSetSystemAffinityThread((KAFFINITY)(1ULL << ProcessorNumber));
|
|
|
|
OldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
Routine(ProcessorNumber);
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
KeRevertToUserAffinityThread();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Get process name by eprocess
|
|
*
|
|
* @param Eprocess Process eprocess
|
|
* @return PCHAR Returns a pointer to the process name
|
|
*/
|
|
PCHAR
|
|
CommonGetProcessNameFromProcessControlBlock(PEPROCESS Eprocess)
|
|
{
|
|
PCHAR Result = 0;
|
|
|
|
//
|
|
// We can't use PsLookupProcessByProcessId as in pageable and not
|
|
// work on vmx-root
|
|
//
|
|
Result = (CHAR *)PsGetProcessImageFileName(Eprocess);
|
|
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* @brief Detects whether the string starts with another string
|
|
*
|
|
* @param pre
|
|
* @param str
|
|
* @return BOOLEAN Returns true if it starts with and false if not strats with
|
|
*/
|
|
BOOLEAN
|
|
CommonIsStringStartsWith(const CHAR * pre, const CHAR * str)
|
|
{
|
|
SIZE_T LenPre = strlen(pre),
|
|
LenStr = strlen(str);
|
|
return LenStr < LenPre ? FALSE : memcmp(pre, str, LenPre) == 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Get cpuid results
|
|
*
|
|
* @param Func
|
|
* @param SubFunc
|
|
* @param CpuInfo
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, INT * CpuInfo)
|
|
{
|
|
CpuCpuIdEx(CpuInfo, Func, SubFunc);
|
|
}
|
|
|
|
/**
|
|
* @brief determines if the guest was in 32-bit user-mode or 64-bit (long mode)
|
|
* @details this function should be called from vmx-root
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
CommonIsGuestOnUsermode32Bit()
|
|
{
|
|
//
|
|
// Only 16 bit is needed however, VMWRITE might write on other bits
|
|
// and corrupt other variables, that's why we get 64bit
|
|
//
|
|
UINT64 CsSel = NULL64_ZERO;
|
|
|
|
//
|
|
// Read guest's cs selector
|
|
//
|
|
CsSel = HvGetCsSelector();
|
|
|
|
if (CsSel == KGDT64_R0_CODE)
|
|
{
|
|
//
|
|
// 64-bit kernel-mode
|
|
//
|
|
return FALSE;
|
|
}
|
|
else if ((CsSel & ~3) == KGDT64_R3_CODE)
|
|
{
|
|
//
|
|
// 64-bit user-mode
|
|
//
|
|
return FALSE;
|
|
}
|
|
else if ((CsSel & ~3) == KGDT64_R3_CMCODE)
|
|
{
|
|
//
|
|
// 32-bit user-mode
|
|
//
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
LogError("Err, unknown value for cs, cannot determine wow64 mode");
|
|
}
|
|
|
|
//
|
|
// By default, 64-bit
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief Produce debug information from unrecoverable bugs
|
|
* @param VCpu The virtual processor's state
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
CommonWriteDebugInformation(VIRTUAL_MACHINE_STATE * VCpu)
|
|
{
|
|
LogError("HyperDbg cannot recover from this error, please provide the following information through the Git issues");
|
|
|
|
LogInfo("Target RIP: %llx\n", VCpu->LastVmexitRip);
|
|
|
|
CHAR Instruction[MAXIMUM_INSTR_SIZE] = {0};
|
|
|
|
MemoryMapperReadMemorySafeOnTargetProcess(VCpu->LastVmexitRip, Instruction, MAXIMUM_INSTR_SIZE);
|
|
|
|
for (SIZE_T i = 0; i < MAXIMUM_INSTR_SIZE; i++)
|
|
{
|
|
Log("%02X ", Instruction[i] & 0xffU);
|
|
}
|
|
|
|
Log("\n");
|
|
DisassemblerShowOneInstructionInVmxRootMode((PVOID)VCpu->LastVmexitRip,
|
|
CommonIsGuestOnUsermode32Bit());
|
|
Log("\n");
|
|
|
|
Log(
|
|
"RAX=%016llx RBX=%016llx RCX=%016llx\n"
|
|
"RDX=%016llx RSI=% 016llx RDI=%016llx\n"
|
|
"RIP=%016llx RSP=%016llx RBP=%016llx\n"
|
|
"R8 =%016llx R9 =%016llx R10=%016llx\n"
|
|
"R11=%016llx R12=%016llx R13=%016llx\n"
|
|
"R14=%016llx R15=%016llx\n",
|
|
VCpu->Regs->rax,
|
|
VCpu->Regs->rbx,
|
|
VCpu->Regs->rcx,
|
|
VCpu->Regs->rdx,
|
|
VCpu->Regs->rsi,
|
|
VCpu->Regs->rdi,
|
|
VCpu->LastVmexitRip,
|
|
VCpu->Regs->rsp,
|
|
VCpu->Regs->rbp,
|
|
VCpu->Regs->r8,
|
|
VCpu->Regs->r9,
|
|
VCpu->Regs->r10,
|
|
VCpu->Regs->r11,
|
|
VCpu->Regs->r12,
|
|
VCpu->Regs->r13,
|
|
VCpu->Regs->r14,
|
|
VCpu->Regs->r15);
|
|
}
|
|
|
|
/**
|
|
* @brief Check correctness of the XCR0 register value.
|
|
* @param XCr0 The XCR0 register value.
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
CommonIsXCr0Valid(XCR0 XCr0)
|
|
{
|
|
CPUID_EAX_0D_ECX_00 XCr0CpuidInfo;
|
|
UINT64 UnsupportedXCr0Bits;
|
|
|
|
//
|
|
// SDM Vol.3A 2.6 EXTENDED CONTROL REGISTERS (INCLUDING XCR0) - describes the invalid
|
|
// states of the XCR0 register.
|
|
//
|
|
|
|
CommonCpuidInstruction(CPUID_EXTENDED_STATE_INFORMATION, 0, (INT32 *)&XCr0CpuidInfo);
|
|
UnsupportedXCr0Bits = ~(XCr0CpuidInfo.Eax.AsUInt | (UINT64)XCr0CpuidInfo.Edx.AsUInt << 32);
|
|
|
|
if ((XCr0.AsUInt & UnsupportedXCr0Bits) != 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (XCr0.X87 != 1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (XCr0.Sse == 0 && XCr0.Avx == 1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (XCr0.Avx == 0)
|
|
{
|
|
if ((XCr0.Opmask | XCr0.ZmmHi256 | XCr0.ZmmHi16) == 1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (XCr0.Bndcsr != XCr0.Bndreg)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ((XCr0.Opmask | XCr0.ZmmHi256 | XCr0.ZmmHi16) == 1)
|
|
{
|
|
if ((XCr0.Opmask & XCr0.ZmmHi256 & XCr0.ZmmHi16) != 1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|