Декомпильнул вручную, не до конца, код жесть Тут тоже не обошлось без чудо-конструкций Код (Text): if EDX EDX-- if EDX EDX-- if EDX EDX-- fi fi fi rdtsc - у rdtsc нет входных параметров и она переписывает edx. --- Сообщение объединено, 4 май 2025 --- Вот так вроде правильно. Как эта логика работает хз.
Код (Text): // Hypervisor Detection via Timing Variance Heuristic - Pseudocode // Initialize variables I = 0 // Sample counter X1 = 0 // Variance accumulator // Get initial performance counter F0 = PFC() // Initial performance counter value BeginMeasurement: // Take time stamp counter reading before operation T0 = TSC() // Small computation to measure timing variance EAX = I EDX = Sign(EAX) // Sign extend EAX into EDX (0 or -1) EDX:EAX = EDX:EAX / 4 // Division with remainder in EDX // Check remainder and perform conditional decrements // This creates predictable branch patterns if EDX != 0 EDX-- if EDX != 0 EDX-- if EDX != 0 EDX-- endif endif endif // Take time stamp counter reading after operation T = TSC() // Get current performance counter F = PFC() // Calculate and store TSC delta in buffer dTSC = T - T0 Bu[I*8] = dTSC // Store timing measurement // Increment sample counter I++ // Check if we have 1000 samples if I >= 1000 goto ProcessMeasurements endif // Check if enough time has elapsed (F - F0 >= 20) elapsed = F - F0 if elapsed >= 20 goto ProcessMeasurements endif // Continue measurement goto BeginMeasurement ProcessMeasurements: M = I // Total sample count // Initialize values for finding minimum min_value = Bu[0] // First sample as initial minimum min_index = 0 // Index of minimum X2 = 0 // Sum of all samples // Find minimum sample and calculate sum for J = 1 to M-1 current = Bu[J*8] // Check if current sample is smaller than minimum if current < min_value min_value = current min_index = J endif // Add to sum X2 = X2 + current next J // If we have more than one sample, replace minimum with last sample if M > 1 // Replace minimum with last sample Bu[min_index*8] = Bu[(M-1)*8] // Decrement sample count and adjust sum M-- X2 = X2 - min_value endif // Calculate mean X0 = X2 / M // Calculate variance (sum of squared differences) X1 = 0 for N = 0 to M-1 // Calculate (sample - mean)^2 diff = Bu[N*8] - X0 X1 = X1 + (diff * diff) next N // Calculate final variance value variance = (X1 / M) / X0 // Check if variance exceeds threshold (5000) if variance > 5000 return TRUE // Hypervisor detected else return FALSE // No hypervisor endif Так что ли?
galenkane, Во втором всё правильно. Это что то похожее на тему про серию call's. Ведётся таблица, в которую сохраняется дельта времени, что там дальше сходу не понять. Есть ещё холостая конструкция ECX = 1, врядле этот мусор компилер вставил. Для начала надо бы потестить, это вообще работает ? Есть ещё с cr3, но то ядерное. Что интересно опять же rdtsc с не используемым аргументом. INIT:00910EDC mov eax, cr3 INIT:00910EDF rdtsc wtf!?
galenkane, Варю я тестил на днях. Идея была в замере числа итераций 2-х циклов за одинаковый интервал и вычисление их отношения. Даже системные инструкции не меняют отношение таймингов как на хосте, что очень странно.
galenkane, ExpDetectHypervisorCpuId: Код (Text): INIT:00910F55 xor eax, eax INIT:00910F57 inc eax INIT:00910F58 xor ecx, ecx INIT:00910F5A cpuid INIT:00910F5C lea esi, [ebp-18h] INIT:00910F5F mov [esi], eax INIT:00910F61 mov [esi+4], ebx INIT:00910F64 mov [esi+8], ecx INIT:00910F67 mov [esi+0Ch], edx INIT:00910F6A test dword ptr [ebp-10h], 80000000h AMD SDM: Код (Text): Bits Field Name Description 31 — RAZ. Reserved for use by hypervisor to indicate guest status
Уровни привилегий: В нормальной системе без виртуализации приложения пользовательского режима (ring 3) не могут напрямую читать CR3 - это вызывает исключение защиты (#GP). Только код в режиме ядра (ring 0) имеет право читать/изменять регистры CR0-CR4. Если чтение не вызывает исключение защиты, это означает, что система виртуализирована Если происходит исключение, то система, скорее всего, работает на "голом железе"
galenkane, Я имею ввиду fetch_cr3 - rdtsc. --- Сообщение объединено, 4 май 2025 --- Наверно с этим связано:
В виртуализированной среде доступ к CR3 занимает значительно больше времени, чем в нативной --- Сообщение объединено, 4 май 2025 --- да,связано --- Сообщение объединено, 4 май 2025 --- Вот набросал идеи,может какие и зайдут. Нужно тестить.
galenkane, Если сравнить тайминг rdtsc VS iret, получается 4%5 на хосте и варе. Причём: Но это наверно не важно. rdtsc VS cpuid на хосте 2, на варе 40, не зависимо включен vmx или нет. Код (Text): Entry proc С xor esi,esi invoke GetTickCount lea ebx,D[eax+1000] .repeat inc esi xor eax,eax rdtsc invoke GetTickCount .until Eax >= Ebx push esi xor edi,edi invoke GetTickCount lea esi,D[eax+1000] .repeat inc edi xor eax,eax ; pushfd ; push cs ; push offset Lb ; iretd Lb: cpuid rdtsc invoke GetTickCount .until Eax >= Esi pop esi esi:edi. Отношение числа итераций соответственно равно отношению таймингов.
да, вроде работает. vmware - RDTSC vs CPUID timing ratio heuristic: Yes (RDTSC:CPUID ratio = 95:1, threshold = 10) windows host - RDTSC vs CPUID timing ratio heuristic: No (RDTSC:CPUID ratio = 5:1, threshold = 10)
Решил проверить исполнение - запись кода, но что то странное. Идея такая, есть две инструкции, которые исполняются на первом cpu, второй их изменяет одной инструкцией: Код (Text): ; 1st thread. P: mov eax,12345678 mov edx,87654321 ; 2st thread. mov eax,33BA8765h xchg D[P][3],eax --> mov eax,87655678 mov edx,87654333 По идеи проц должен выбрать первую инструкцию, затем измененную вторую, что привеёт к рассинхрону. На деле такого не происходит, получается бесконечный цикл. Как такое происходит, проц выбирает на исполнение две инструкции за раз ?? Код (Text): pThread proc p1:dword P:: mov eax,12345678h mov edx,87654321h .if ((Eax == 12345678h) && (Edx != 87654321h)) || ((Eax == 87655678h) && (Edx != 87654333h)) int 3 .endif ; Wait for end-of-quantum. mov ax,fs .if Ax == 53h ; WOW xor eax,eax mov fs,ax .repeat mov ax,fs .until Ax .else ; Native fwait .repeat smsw ax test ax,1000B .until !Zero? .endif jmp P pThread endp Entry proc Local Tid:ULONG invoke CreateThread, 0, 0, addr pThread, 0, 0, addr Tid invoke SetThreadAffinityMask, Eax, 10B invoke SetThreadAffinityMask, -2, 01B mov eax,33BA8765h @@: xchg D[P][3],eax jmp @b --- Сообщение объединено, 5 май 2025 --- Интересно получается. Это конвеер? Код (Text): Iter: ; xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax xor eax,eax P:: mov eax,12345678h mov edx,87654321h - так крутится, если добавить ещё одну из комента, возникает рассинхрон и останов На этом можно отличный детект построить. --- Сообщение объединено, 5 май 2025 --- На варе у конвеера длины нет похоже вовсе, на 300 инструкциях останова нет. --- Сообщение объединено, 5 май 2025 --- upd: У меня на варе крутится тк affinity = 1, хотя в настройках 2. Впрочем варя после бсодов немного повредилась, нужно на норм проверить. --- Сообщение объединено, 5 май 2025 --- Если в серию вставить jmp short, останов. Если вставить iret: Код (Text): pushfd push cs push offset Li iretd Li: - конвеер сбрасывается и останова нет. Короче забавная штука
galenkane, Не знаю пока, возможно нет. Это как то от выравнивания зависит на границу 64. Последнее время что не тема, то какое то гадание. Такое чувство что процессор живёт своей жизнью