Skip to content

Commit 8dff22a

Browse files
author
Requiem
committed
remove: LBR virtualization checks
1 parent 17ff619 commit 8dff22a

2 files changed

Lines changed: 0 additions & 203 deletions

File tree

src/cli.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,6 @@ static void general() {
828828
checker(VM::EDID, "EDID");
829829
checker(VM::CPU_HEURISTIC, "CPU heuristics");
830830
checker(VM::CLOCK, "system timers");
831-
checker(VM::LBR, "LBR virtualization");
832831
// ADD NEW TECHNIQUE CHECKER HERE
833832

834833
const auto t2 = std::chrono::high_resolution_clock::now();

src/vmaware.hpp

Lines changed: 0 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,6 @@ struct VM {
570570
EDID,
571571
CPU_HEURISTIC,
572572
CLOCK,
573-
LBR,
574573

575574
// Linux and Windows
576575
SIDT,
@@ -10169,205 +10168,6 @@ struct VM {
1016910168
SetupDiDestroyDeviceInfoList(devs);
1017010169
return !found;
1017110170
}
10172-
10173-
10174-
/**
10175-
* @brief Check if Last Branch Record MSRs are correctly virtualized
10176-
* @category Windows
10177-
* @implements VM::LBR
10178-
* @note Currently investigating possible false flags with this
10179-
*/
10180-
[[nodiscard]] static bool lbr() {
10181-
#if (x86)
10182-
const HMODULE ntdll = util::get_ntdll();
10183-
if (!ntdll) return false;
10184-
10185-
const char* names[] = {
10186-
"NtAllocateVirtualMemory",
10187-
"NtFreeVirtualMemory",
10188-
"NtFlushInstructionCache",
10189-
"RtlAddVectoredExceptionHandler",
10190-
"RtlRemoveVectoredExceptionHandler",
10191-
"NtCreateThreadEx",
10192-
"NtGetContextThread",
10193-
"NtSetContextThread",
10194-
"NtResumeThread",
10195-
"NtWaitForSingleObject",
10196-
"NtClose",
10197-
"NtProtectVirtualMemory"
10198-
};
10199-
void* funcs[ARRAYSIZE(names)] = {};
10200-
util::get_function_address(ntdll, names, funcs, ARRAYSIZE(names));
10201-
10202-
using NtAllocateVirtualMemory_t = NTSTATUS(__stdcall*)(HANDLE, PVOID*, ULONG_PTR, PSIZE_T, ULONG, ULONG);
10203-
using NtFreeVirtualMemory_t = NTSTATUS(__stdcall*)(HANDLE, PVOID*, PSIZE_T, ULONG);
10204-
using NtFlushInstructionCache_t = NTSTATUS(__stdcall*)(HANDLE, PVOID, SIZE_T);
10205-
using RtlAddVectoredExceptionHandler_t = PVOID(__stdcall*)(ULONG, PVECTORED_EXCEPTION_HANDLER);
10206-
using RtlRemoveVectoredExceptionHandler_t = ULONG(__stdcall*)(PVOID);
10207-
using NtCreateThreadEx_t = NTSTATUS(__stdcall*)(PHANDLE, ACCESS_MASK, PVOID, HANDLE, PVOID, PVOID, BOOLEAN, ULONG_PTR, SIZE_T, SIZE_T, PVOID);
10208-
using NtGetContextThread_t = NTSTATUS(__stdcall*)(HANDLE, PCONTEXT);
10209-
using NtSetContextThread_t = NTSTATUS(__stdcall*)(HANDLE, PCONTEXT);
10210-
using NtResumeThread_t = NTSTATUS(__stdcall*)(HANDLE, PULONG);
10211-
using NtWaitForSingleObject_t = NTSTATUS(__stdcall*)(HANDLE, BOOLEAN, PLARGE_INTEGER);
10212-
using NtClose_t = NTSTATUS(__stdcall*)(HANDLE);
10213-
using NtProtectVirtualMemory_t = NTSTATUS(__stdcall*)(HANDLE, PVOID*, PSIZE_T, ULONG, PULONG);
10214-
10215-
const auto pNtAllocateVirtualMemory = reinterpret_cast<NtAllocateVirtualMemory_t>(funcs[0]);
10216-
const auto pNtFreeVirtualMemory = reinterpret_cast<NtFreeVirtualMemory_t>(funcs[1]);
10217-
const auto pNtFlushInstructionCache = reinterpret_cast<NtFlushInstructionCache_t>(funcs[2]);
10218-
const auto pRtlAddVectoredExceptionHandler = reinterpret_cast<RtlAddVectoredExceptionHandler_t>(funcs[3]);
10219-
const auto pRtlRemoveVectoredExceptionHandler = reinterpret_cast<RtlRemoveVectoredExceptionHandler_t>(funcs[4]);
10220-
const auto pNtCreateThreadEx = reinterpret_cast<NtCreateThreadEx_t>(funcs[5]);
10221-
const auto pNtGetContextThread = reinterpret_cast<NtGetContextThread_t>(funcs[6]);
10222-
const auto pNtSetContextThread = reinterpret_cast<NtSetContextThread_t>(funcs[7]);
10223-
const auto pNtResumeThread = reinterpret_cast<NtResumeThread_t>(funcs[8]);
10224-
const auto pNtWaitForSingleObject = reinterpret_cast<NtWaitForSingleObject_t>(funcs[9]);
10225-
const auto pNtClose = reinterpret_cast<NtClose_t>(funcs[10]);
10226-
const auto pNtProtectVirtualMemory = reinterpret_cast<NtProtectVirtualMemory_t>(funcs[11]);
10227-
10228-
if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory || !pNtFlushInstructionCache ||
10229-
!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler ||
10230-
!pNtCreateThreadEx || !pNtGetContextThread || !pNtSetContextThread ||
10231-
!pNtResumeThread || !pNtWaitForSingleObject || !pNtClose || !pNtProtectVirtualMemory) {
10232-
return false;
10233-
}
10234-
10235-
// ICEBP because the kernel interrupt handler that inserts the LastBranchFromIp into EXCEPTION_RECORD->ExceptionInformation[0] is the INT 01 handler
10236-
constexpr unsigned char codeBytes[] = { 0xE8,0x00,0x00,0x00,0x00, 0xF1, 0xC3 }; // CALL next ; ICEBP ; RET
10237-
const SIZE_T codeSize = sizeof(codeBytes);
10238-
const HANDLE hCurrentProcess = reinterpret_cast<HANDLE>(-1LL);
10239-
10240-
PVOID controlBase = nullptr;
10241-
SIZE_T controlSize = sizeof(PVOID);
10242-
NTSTATUS st = pNtAllocateVirtualMemory(hCurrentProcess, &controlBase, 0, &controlSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
10243-
if (st != 0 || !controlBase) return false;
10244-
*reinterpret_cast<PVOID*>(controlBase) = nullptr;
10245-
10246-
PVOID execBase = nullptr;
10247-
SIZE_T allocSize = codeSize;
10248-
st = pNtAllocateVirtualMemory(hCurrentProcess, &execBase, 0, &allocSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
10249-
if (st != 0 || !execBase) {
10250-
SIZE_T tmp = controlSize;
10251-
pNtFreeVirtualMemory(hCurrentProcess, &controlBase, &tmp, MEM_RELEASE);
10252-
return false;
10253-
}
10254-
10255-
unsigned char* dst = reinterpret_cast<unsigned char*>(execBase);
10256-
for (SIZE_T i = 0; i < codeSize; ++i) dst[i] = codeBytes[i];
10257-
10258-
ULONG oldProtect = 0;
10259-
SIZE_T protectSize = allocSize;
10260-
PVOID protectBase = execBase;
10261-
st = pNtProtectVirtualMemory(hCurrentProcess, &protectBase, &protectSize, PAGE_EXECUTE_READ, &oldProtect);
10262-
if (st != 0) {
10263-
SIZE_T tmpExec = allocSize;
10264-
pNtFreeVirtualMemory(hCurrentProcess, &execBase, &tmpExec, MEM_RELEASE);
10265-
SIZE_T tmpControl = controlSize;
10266-
pNtFreeVirtualMemory(hCurrentProcess, &controlBase, &tmpControl, MEM_RELEASE);
10267-
return false;
10268-
}
10269-
10270-
pNtFlushInstructionCache(hCurrentProcess, execBase, codeSize);
10271-
10272-
// local static pointer to control slot so lambda can access a stable address
10273-
static PVOID g_control_slot = nullptr;
10274-
g_control_slot = controlBase;
10275-
10276-
auto veh_lambda = [](PEXCEPTION_POINTERS ep) -> LONG {
10277-
if (!ep || !ep->ExceptionRecord) return EXCEPTION_CONTINUE_SEARCH;
10278-
if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH;
10279-
10280-
ULONG_PTR info0 = 0;
10281-
if (ep->ExceptionRecord->NumberParameters > 0) info0 = ep->ExceptionRecord->ExceptionInformation[0];
10282-
if (info0 && g_control_slot) {
10283-
PVOID expected = nullptr;
10284-
_InterlockedCompareExchangePointer(reinterpret_cast<PVOID*>(g_control_slot), reinterpret_cast<PVOID*>(info0), expected);
10285-
}
10286-
return EXCEPTION_CONTINUE_EXECUTION;
10287-
};
10288-
10289-
// Register VEH
10290-
const PVECTORED_EXCEPTION_HANDLER veh_fn = static_cast<PVECTORED_EXCEPTION_HANDLER>(veh_lambda);
10291-
const PVOID vehHandle = pRtlAddVectoredExceptionHandler(1, veh_fn);
10292-
if (!vehHandle) {
10293-
SIZE_T tmp = allocSize;
10294-
pNtFreeVirtualMemory(hCurrentProcess, &execBase, &tmp, MEM_RELEASE);
10295-
tmp = controlSize;
10296-
pNtFreeVirtualMemory(hCurrentProcess, &controlBase, &tmp, MEM_RELEASE);
10297-
return false;
10298-
}
10299-
10300-
// create suspended thread
10301-
HANDLE hThread = nullptr;
10302-
NTSTATUS ntres = pNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, nullptr, hCurrentProcess, execBase, nullptr, TRUE, 0, 0, 0, nullptr);
10303-
if (ntres != 0 || !hThread) {
10304-
pRtlRemoveVectoredExceptionHandler(vehHandle);
10305-
SIZE_T tmp = allocSize;
10306-
pNtFreeVirtualMemory(hCurrentProcess, &execBase, &tmp, MEM_RELEASE);
10307-
tmp = controlSize;
10308-
pNtFreeVirtualMemory(hCurrentProcess, &controlBase, &tmp, MEM_RELEASE);
10309-
return false;
10310-
}
10311-
10312-
// set debug bits + TF on suspended thread
10313-
CONTEXT ctx;
10314-
ZeroMemory(&ctx, sizeof(ctx));
10315-
ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS;
10316-
ntres = pNtGetContextThread(hThread, &ctx);
10317-
if (ntres != 0) {
10318-
pNtClose(hThread);
10319-
pRtlRemoveVectoredExceptionHandler(vehHandle);
10320-
SIZE_T tmp = allocSize;
10321-
pNtFreeVirtualMemory(hCurrentProcess, &execBase, &tmp, MEM_RELEASE);
10322-
tmp = controlSize;
10323-
pNtFreeVirtualMemory(hCurrentProcess, &controlBase, &tmp, MEM_RELEASE);
10324-
return false;
10325-
}
10326-
ctx.Dr7 |= (1ull << 8) | (1ull << 9); // LBR only would be enough
10327-
ctx.EFlags |= 0x100;
10328-
ntres = pNtSetContextThread(hThread, &ctx);
10329-
if (ntres != 0) {
10330-
pNtClose(hThread);
10331-
pRtlRemoveVectoredExceptionHandler(vehHandle);
10332-
SIZE_T tmp = allocSize;
10333-
pNtFreeVirtualMemory(hCurrentProcess, &execBase, &tmp, MEM_RELEASE);
10334-
tmp = controlSize;
10335-
pNtFreeVirtualMemory(hCurrentProcess, &controlBase, &tmp, MEM_RELEASE);
10336-
return false;
10337-
}
10338-
10339-
// resume and wait
10340-
ULONG suspendCount = 0;
10341-
ntres = pNtResumeThread(hThread, &suspendCount);
10342-
if (ntres != 0) {
10343-
pNtClose(hThread);
10344-
pRtlRemoveVectoredExceptionHandler(vehHandle);
10345-
SIZE_T tmp = allocSize;
10346-
pNtFreeVirtualMemory(hCurrentProcess, &execBase, &tmp, MEM_RELEASE);
10347-
tmp = controlSize;
10348-
pNtFreeVirtualMemory(hCurrentProcess, &controlBase, &tmp, MEM_RELEASE);
10349-
return false;
10350-
}
10351-
ntres = pNtWaitForSingleObject(hThread, FALSE, nullptr);
10352-
10353-
// read slot (pointer-sized) so if null then no LBR observed
10354-
const PVOID slot_val = *reinterpret_cast<PVOID*>(controlBase);
10355-
10356-
// cleanup
10357-
pRtlRemoveVectoredExceptionHandler(vehHandle);
10358-
pNtClose(hThread);
10359-
SIZE_T tmpSize = allocSize;
10360-
pNtFreeVirtualMemory(hCurrentProcess, &execBase, &tmpSize, MEM_RELEASE);
10361-
tmpSize = controlSize;
10362-
pNtFreeVirtualMemory(hCurrentProcess, &controlBase, &tmpSize, MEM_RELEASE);
10363-
g_control_slot = nullptr;
10364-
10365-
// a breakpoint set anywhere in this function before slot_val is read will cause the kernel to not deliver any LBR info, thereby returning true
10366-
return (slot_val == nullptr);
10367-
#else
10368-
return false;
10369-
#endif
10370-
}
1037110171
// ADD NEW TECHNIQUE FUNCTION HERE
1037210172
#endif
1037310173

@@ -11457,7 +11257,6 @@ struct VM {
1145711257
case EDID: return "EDID";
1145811258
case CPU_HEURISTIC: return "CPU_HEURISTIC";
1145911259
case CLOCK: return "CLOCK";
11460-
case LBR: return "LBR";
1146111260
// END OF TECHNIQUE LIST
1146211261
case DEFAULT: return "setting flag, error";
1146311262
case ALL: return "setting flag, error";
@@ -11996,7 +11795,6 @@ std::pair<VM::enum_flags, VM::core::technique> VM::core::technique_list[] = {
1199611795
std::make_pair(VM::CLOCK, VM::core::technique(100, VM::clock)),
1199711796
std::make_pair(VM::POWER_CAPABILITIES, VM::core::technique(45, VM::power_capabilities)),
1199811797
std::make_pair(VM::CPU_HEURISTIC, VM::core::technique(90, VM::cpu_heuristic)),
11999-
std::make_pair(VM::LBR, VM::core::technique(95, VM::lbr)),
1200011798
std::make_pair(VM::EDID, VM::core::technique(100, VM::edid)),
1200111799
std::make_pair(VM::BOOT_LOGO, VM::core::technique(100, VM::boot_logo)),
1200211800
std::make_pair(VM::GPU_CAPABILITIES, VM::core::technique(45, VM::gpu_capabilities)),

0 commit comments

Comments
 (0)