Всем привет! Написал код для проверки запуска под вирт.машиной и песочницей Sandboxie, но не могу проверить его работу именно под VMware, т.к. у меня только VirtualBox. Если у кого есть варя с Win, буду благодарен за тест. Интересует, какое железо обнаружится. В скрепке asm и exe - вот что дампит код на моей машине VBox:
VMware 17.6.1 build-24319023 Код (Text): CPU name string.....: AMD Ryzen 5 7500F 6-Core Processor CPU cores...........: 2 CPU frequency.......: 3527.0 MHz Physical memory.....: 2046.5 Mb Check 1 sec delay...: 1000.0 msec Computer name.......: DESKTOP-VALL98E Display device......: VMware SVGA 3D. 1718 x 928 Bios Version........: CD/DVDROM name.....: NECVMWar VMware SATA CD01 Hard drive name.....: VMware Virtual NVMe Disk Hard drive size.....: 60.0 Gb NIC MAC address.....: 00:0c:29:87:26:a4 -------- 08:00:27: <----- VBox v5.2 00:21:f6: v3.3 52:54:00: Vagrant or QEMU -------- 00:50:56: <----- VMware Workstation 00:0c:29: ESXi Host 00:05:69: ESXi,GSX 00:1c:14: VMware VBox \System32 dll..: Sandboxie dll test..: Sandboxie Desktop...:
shanya0xff, и ещё.. в папке Win\system32 вирт.машины должны быть её библиотеки например в VBox все они начинаются с префикса VBox***.dll (см.мой скрин выше) на VMware так-же или нет? по какому префиксу можно их найти и перечислить?
Думаю гонять овер 100 тестов не имеет смысла - вполне хватит и парочки. Например как выяснилось, Sleep() на вирт.машине возвращает точно переданный нами параметр (у меня это 1000=1 сек), хотя на реальной машине по любому будет погрешность +/- 1%.
> хотя на реальной машине по любому будет погрешность +/- 1%. Разрешение GTC не менее 50ms. Причем оно нелинейно. Используйте ntqueryperformancecounter для точных замеров времени.
так в данном случае наоборот точный qpc не нужен - в этом и суть. вм перехватывает Sleep() и возвращает всегда значение параметра, а не реальное.
Код (C++): #include <iostream> #include <windows.h> #include <winternl.h> #include <chrono> #include <thread> // Definition of NtQueryPerformanceCounter function type typedef NTSTATUS(NTAPI* PFN_NT_QUERY_PERFORMANCE_COUNTER)( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency OPTIONAL ); int main() { // Load ntdll.dll library HMODULE ntdllModule = GetModuleHandleA("ntdll.dll"); if (!ntdllModule) { std::cerr << "Failed to load ntdll.dll" << std::endl; return 1; } // Get NtQueryPerformanceCounter function address PFN_NT_QUERY_PERFORMANCE_COUNTER NtQueryPerformanceCounter = (PFN_NT_QUERY_PERFORMANCE_COUNTER)GetProcAddress(ntdllModule, "NtQueryPerformanceCounter"); if (!NtQueryPerformanceCounter) { std::cerr << "Failed to find NtQueryPerformanceCounter function" << std::endl; return 1; } // Get performance counter frequency LARGE_INTEGER frequency = { 0 }; LARGE_INTEGER dummy = { 0 }; NTSTATUS status = NtQueryPerformanceCounter(&dummy, &frequency); if (!NT_SUCCESS(status)) { std::cerr << "Error getting counter frequency. Status: 0x" << std::hex << status << std::endl; // Try fallback to QueryPerformanceFrequency if (!QueryPerformanceFrequency(&frequency)) { std::cerr << "QueryPerformanceFrequency also failed. Error: " << GetLastError() << std::endl; return 1; } std::cout << "Using QueryPerformanceFrequency instead." << std::endl; } std::cout << "Counter frequency: " << frequency.QuadPart << " Hz" << std::endl; // Time measurement example LARGE_INTEGER startCounter, endCounter; // Start time status = NtQueryPerformanceCounter(&startCounter, NULL); if (!NT_SUCCESS(status)) { std::cerr << "Error getting initial counter value. Status: 0x" << std::hex << status << std::endl; return 1; } // Execution of operation to be measured // In this case, just wait for 100 ms std::this_thread::sleep_for(std::chrono::milliseconds(100)); // End time status = NtQueryPerformanceCounter(&endCounter, NULL); if (!NT_SUCCESS(status)) { std::cerr << "Error getting final counter value. Status: 0x" << std::hex << status << std::endl; return 1; } // Calculate time in milliseconds double elapsedMilliseconds = static_cast<double>(endCounter.QuadPart - startCounter.QuadPart) * 1000.0 / static_cast<double>(frequency.QuadPart); std::cout << "Time elapsed: " << elapsedMilliseconds << " ms" << std::endl; // Demonstration of non-linear measurements std::cout << "Demonstration of non-linear time intervals:" << std::endl; for (int i = 0; i < 5; i++) { LARGE_INTEGER start, end; status = NtQueryPerformanceCounter(&start, NULL); if (!NT_SUCCESS(status)) { std::cerr << "Error in iteration " << i << ". Status: 0x" << std::hex << status << std::endl; continue; } // Increase sleep interval with each iteration std::this_thread::sleep_for(std::chrono::milliseconds(50 + i * 25)); status = NtQueryPerformanceCounter(&end, NULL); if (!NT_SUCCESS(status)) { std::cerr << "Error in iteration " << i << ". Status: 0x" << std::hex << status << std::endl; continue; } double elapsed = static_cast<double>(end.QuadPart - start.QuadPart) * 1000.0 / static_cast<double>(frequency.QuadPart); std::cout << "Interval " << i + 1 << ": requested " << (50 + i * 25) << " ms, measured " << elapsed << " ms" << std::endl; } return 0; } Код (C++): #include <iostream> #include <windows.h> #include <winternl.h> #include <vector> #include <algorithm> #include <cmath> #include <iomanip> // Definition of NtQueryPerformanceCounter function type typedef NTSTATUS(NTAPI* PFN_NT_QUERY_PERFORMANCE_COUNTER)( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency OPTIONAL ); // Structure to hold measurement statistics struct MeasurementStats { double min; double max; double avg; double stdDev; }; // Function to calculate statistics from a vector of measurements MeasurementStats calculateStats(const std::vector<double>& measurements) { MeasurementStats stats = {0}; if (measurements.empty()) { return stats; } stats.min = *std::min_element(measurements.begin(), measurements.end()); stats.max = *std::max_element(measurements.begin(), measurements.end()); // Calculate average double sum = 0.0; for (const auto& val : measurements) { sum += val; } stats.avg = sum / measurements.size(); // Calculate standard deviation double sumSquaredDiff = 0.0; for (const auto& val : measurements) { double diff = val - stats.avg; sumSquaredDiff += diff * diff; } stats.stdDev = std::sqrt(sumSquaredDiff / measurements.size()); return stats; } // Precise busy-wait function for short durations void preciseSleep(double milliseconds, PFN_NT_QUERY_PERFORMANCE_COUNTER ntQueryPerfCounter, const LARGE_INTEGER& frequency) { LARGE_INTEGER start, current; ntQueryPerfCounter(&start, NULL); double elapsedMs = 0.0; while (elapsedMs < milliseconds) { ntQueryPerfCounter(¤t, NULL); elapsedMs = static_cast<double>(current.QuadPart - start.QuadPart) * 1000.0 / static_cast<double>(frequency.QuadPart); // For longer waits, yield to avoid CPU hogging if (milliseconds > 10.0 && elapsedMs < milliseconds - 5.0) { Sleep(1); } else { // Short yield for very precise timing YieldProcessor(); } } } int main() { // Raise process priority for more accurate timing SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); // Set thread priority to highest SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); // Load ntdll.dll library HMODULE ntdllModule = GetModuleHandleA("ntdll.dll"); if (!ntdllModule) { std::cerr << "Failed to load ntdll.dll" << std::endl; return 1; } // Get NtQueryPerformanceCounter function address PFN_NT_QUERY_PERFORMANCE_COUNTER NtQueryPerformanceCounter = (PFN_NT_QUERY_PERFORMANCE_COUNTER)GetProcAddress(ntdllModule, "NtQueryPerformanceCounter"); if (!NtQueryPerformanceCounter) { std::cerr << "Failed to find NtQueryPerformanceCounter function" << std::endl; return 1; } // Get performance counter frequency LARGE_INTEGER frequency = {0}; LARGE_INTEGER dummy = {0}; NTSTATUS status = NtQueryPerformanceCounter(&dummy, &frequency); if (!NT_SUCCESS(status)) { std::cerr << "Error getting counter frequency. Status: 0x" << std::hex << status << std::endl; // Try fallback to QueryPerformanceFrequency if (!QueryPerformanceFrequency(&frequency)) { std::cerr << "QueryPerformanceFrequency also failed. Error: " << GetLastError() << std::endl; return 1; } std::cout << "Using QueryPerformanceFrequency instead." << std::endl; } std::cout << "Counter frequency: " << frequency.QuadPart << " Hz" << std::endl; // Warmup phase to stabilize CPU state std::cout << "Performing warmup..." << std::endl; for (int i = 0; i < 10; i++) { LARGE_INTEGER start, end; NtQueryPerformanceCounter(&start, NULL); preciseSleep(20, NtQueryPerformanceCounter, frequency); NtQueryPerformanceCounter(&end, NULL); } // Test intervals in milliseconds const int numIntervals = 10; const int intervalsMs[numIntervals] = {10, 20, 30, 40, 50, 75, 100, 125, 150, 200}; // Number of iterations per interval for statistical significance const int iterations = 20; std::cout << "\nPrecise timing measurements:\n" << std::endl; std::cout << std::left << std::setw(12) << "Requested" << std::setw(12) << "Min" << std::setw(12) << "Max" << std::setw(12) << "Average" << std::setw(12) << "StdDev" << std::setw(12) << "Error %" << std::endl; std::cout << std::string(72, '-') << std::endl; for (int i = 0; i < numIntervals; i++) { int targetMs = intervalsMs[i]; std::vector<double> measurements; for (int j = 0; j < iterations; j++) { LARGE_INTEGER start, end; status = NtQueryPerformanceCounter(&start, NULL); if (!NT_SUCCESS(status)) { std::cerr << "Error getting start time. Status: 0x" << std::hex << status << std::endl; continue; } // Use precise busy-wait for timing preciseSleep(targetMs, NtQueryPerformanceCounter, frequency); status = NtQueryPerformanceCounter(&end, NULL); if (!NT_SUCCESS(status)) { std::cerr << "Error getting end time. Status: 0x" << std::hex << status << std::endl; continue; } double elapsed = static_cast<double>(end.QuadPart - start.QuadPart) * 1000.0 / static_cast<double>(frequency.QuadPart); measurements.push_back(elapsed); } // Calculate statistics MeasurementStats stats = calculateStats(measurements); double errorPercent = ((stats.avg - targetMs) / targetMs) * 100.0; // Print results with proper formatting std::cout << std::fixed << std::setprecision(3); std::cout << std::left << std::setw(12) << targetMs << std::setw(12) << stats.min << std::setw(12) << stats.max << std::setw(12) << stats.avg << std::setw(12) << stats.stdDev << std::setw(12) << errorPercent << "%" << std::endl; } return 0; } рил Counter frequency: 10000000 Hz Time elapsed: 108.429 ms Demonstration of non-linear time intervals: Interval 1: requested 50 ms, measured 61.0943 ms Interval 2: requested 75 ms, measured 79.2942 ms Interval 3: requested 100 ms, measured 108.687 ms Interval 4: requested 125 ms, measured 134.471 ms Interval 5: requested 150 ms, measured 151.704 ms
galenkane Эти периоды порядка планирования( те свапконтексты). Можно поднять частоту, либо нужно большее число итераций.)