Out-Of-Context Execution

Тема в разделе "WASM.A&O", создана пользователем Ahimov, 18 окт 2025.

  1. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    372
    Привет.

    Нашлась публикация по детекту кода через шедулер.

    Closing the Execution Gap:
    Hardware-Backed Telemetry for Detecting Out-Of-Context
    Execution

    Метод древний, интересно другое. Была тема про обход таких детектов.

    Системный профайлер такой код не видит, с контекстом тоже не выйдет. Дальше поверх хайд контекста в ntcallbackreturn.

    Такой буфер шедулер не видит.

    Как дополнить детектор, что бы работал ?
     

    Вложения:

    Mikl___ нравится это.
  2. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    410
    Ну вот нейронка помыслила. Мб поможет.

    Через markdown viewer открывать

    через https://github.com/Wasdubya/x64dbgMCP можно посмотреть позже) мб тула позволит)
     

    Вложения:

    Последнее редактирование: 23 окт 2025
    Mikl___ и Ahimov нравится это.
  3. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    372
    На анализ берется текущий контекст. Нагрузка выполняется после завершения контекстного переключения и прерываний, что бы вероятность свапконтекста была минимальной.

    Детектор должен каким то образом выйти на ветвь с нагрузкой, симулировать или транслировать. В emet был simexecflow что бы ловить подобное.
     
  4. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    410
    execution hiding через timing attack на context switch ?
     
  5. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    372
    На то исполнение внеконтекстное", потому что шедулер себя выдает.

    Странные тексты выше, чепуха ботов многословная :)

    Профайлер устроен крайне просто - частота прерываний повышается(перестройка таймера апик вроде), из них профайлер сохраняет в лог context.ip
    Разумеется он не получит управления сразу как отдал его.

    i-cet это простейший хард cfi. Можно закрутить последовательности, где будет баланс call-ret. Простая цепь rop что бы метод обкатать профайлерами, не суть важно что там крутится.
    --- Сообщение объединено, 23 окт 2025 ---
    Тут можно много интереснлго найти.

    Тут картировалось, тем по шедулеру навалом.
     
  6. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    410
    Когда окно переднего плана активно (перетаскивание мыши), Windows автоматически повышает частоту системного таймера для обеспечения плавности GUI. Это не квантование потоков, а именно частота clock interrupt.

    Код (C++):
    1. #include <windows.h>
    2. #include <winternl.h>
    3. #include <iostream>
    4. #include <iomanip>
    5. #include <vector>
    6. #include <cmath>
    7.  
    8. #pragma comment(lib, "ntdll.lib")
    9.  
    10. typedef LONG NTSTATUS;
    11.  
    12. typedef NTSTATUS(NTAPI* pNtQueryTimerResolution)(
    13.   PULONG MinimumResolution,
    14.   PULONG MaximumResolution,
    15.   PULONG CurrentResolution
    16. );
    17.  
    18. typedef NTSTATUS(NTAPI* pNtQuerySystemInformation)(
    19.   ULONG SystemInformationClass,
    20.   PVOID SystemInformation,
    21.   ULONG SystemInformationLength,
    22.   PULONG ReturnLength
    23. );
    24.  
    25. #define SystemInterruptInformation 23
    26.  
    27. class TimerMonitor {
    28. private:
    29.   pNtQueryTimerResolution NtQueryTimerResolution;
    30.   pNtQuerySystemInformation NtQuerySystemInformation;
    31.   LARGE_INTEGER perfFreq;
    32.  
    33.   struct Snapshot {
    34.     ULONG resolution;
    35.     ULONG dpcCount;
    36.     LARGE_INTEGER perfCounter;
    37.     double estimatedIPS;
    38.   };
    39.  
    40.   Snapshot lastSnapshot;
    41.  
    42. public:
    43.   TimerMonitor() {
    44.     HMODULE ntdll = GetModuleHandleA("ntdll.dll");
    45.     NtQueryTimerResolution = (pNtQueryTimerResolution)GetProcAddress(ntdll,
    46.         "NtQueryTimerResolution");
    47.     NtQuerySystemInformation = (pNtQuerySystemInformation)GetProcAddress(ntdll,
    48.         "NtQuerySystemInformation");
    49.     QueryPerformanceFrequency(&perfFreq);
    50.     QueryPerformanceCounter(&lastSnapshot.perfCounter);
    51.     ULONG min, max, cur;
    52.     NtQueryTimerResolution(&min, &max, &cur);
    53.     lastSnapshot.resolution = cur;
    54.     lastSnapshot.dpcCount = 0;
    55.     lastSnapshot.estimatedIPS = 0;
    56.   }
    57.  
    58.   void PrintHeader() {
    59.     ULONG minRes, maxRes, curRes;
    60.     NtQueryTimerResolution(&minRes, &maxRes, &curRes);
    61.     std::cout <<
    62.       "=== System Timer Frequency Monitor ==="
    63.       << std::endl;
    64.     std::cout << "Range: " << maxRes / 10000.0 << " - " << minRes /
    65.       10000.0 << " ms" << std::endl;
    66.     std::cout << "Frequencies: " << (int)(10000000.0 / minRes) << " - " << (int)(
    67.         10000000.0 / maxRes) << " Hz" << std::endl;
    68.     std::cout << std::endl;
    69.     std::cout << "INSTRUCTIONS:" << std::endl;
    70.     std::cout << "1. Run the program" << std::endl;
    71.     std::cout <<
    72.       "2. Drag another application's window (for example, File Explorer)"
    73.       << std::endl;
    74.     std::cout <<
    75.       "3. Observe changes in Resolution and Frequency"
    76.       << std::endl;
    77.     std::cout << std::endl;
    78.     std::cout << std::setw(10) << "Time(s)"
    79.       << std::setw(18) << "Resolution(ms)"
    80.       << std::setw(15) << "Frequency(Hz)"
    81.       << std::setw(18) << "Change"
    82.       << std::endl;
    83.     std::cout << std::string(65, '-') << std::endl;
    84.   }
    85.  
    86.   void Update() {
    87.     ULONG minRes, maxRes, curRes;
    88.     NtQueryTimerResolution(&minRes, &maxRes, &curRes);
    89.     LARGE_INTEGER now;
    90.     QueryPerformanceCounter(&now);
    91.     double elapsed = (double)(now.QuadPart - lastSnapshot.perfCounter.QuadPart) /
    92.       perfFreq.QuadPart;
    93.     double currentFreq = 10000000.0 / curRes;
    94.     // Detect if resolution changed
    95.     std::string change = "";
    96.  
    97.     if (curRes < lastSnapshot.resolution) {
    98.       change = "↑ INCREASE!";
    99.     } else if (curRes > lastSnapshot.resolution) {
    100.       change = "↓ decrease";
    101.     }
    102.  
    103.     static DWORD startTime = GetTickCount();
    104.     double runTime = (GetTickCount() - startTime) / 1000.0;
    105.     std::cout << std::fixed << std::setprecision(1)
    106.       << std::setw(10) << runTime
    107.       << std::setw(18) << curRes / 10000.0
    108.       << std::setw(15) << (int)currentFreq
    109.       << std::setw(18) << change
    110.       << std::endl;
    111.     lastSnapshot.resolution = curRes;
    112.     lastSnapshot.perfCounter = now;
    113.   }
    114. };
    115.  
    116. int main() {
    117.   TimerMonitor monitor;
    118.   monitor.PrintHeader();
    119.  
    120.   // Monitor for 5 minutes
    121.   for (int i = 0; i < 300; i++) {
    122.     Sleep(1000);
    123.     monitor.Update();
    124.   }
    125.  
    126.   std::cout << "\nMonitoring finished." << std::endl;
    127.   std::cout <<
    128.     "\nAnalysis: If the Resolution decreased during window dragging"
    129.     << std::endl;
    130.   std::cout <<
    131.     "(and Frequency increased), then the hypothesis is confirmed!"
    132.     << std::endl;
    133.   return 0;
    134. }
    135.  
    Код (C++):
    1. #include <windows.h>
    2. #include <winternl.h>
    3. #include <psapi.h>
    4. #include <tlhelp32.h>
    5. #include <iostream>
    6. #include <iomanip>
    7. #include <vector>
    8. #include <string>
    9. #include <map>
    10. #include <set>
    11. #include <algorithm>
    12.  
    13. #pragma comment(lib, "ntdll.lib")
    14. #pragma comment(lib, "psapi.lib")
    15.  
    16. typedef LONG NTSTATUS;
    17.  
    18. typedef NTSTATUS(NTAPI* pNtQueryTimerResolution)(
    19.   PULONG MinimumResolution,
    20.   PULONG MaximumResolution,
    21.   PULONG CurrentResolution
    22. );
    23.  
    24. typedef NTSTATUS(NTAPI* pNtQuerySystemInformation)(
    25.   ULONG SystemInformationClass,
    26.   PVOID SystemInformation,
    27.   ULONG SystemInformationLength,
    28.   PULONG ReturnLength
    29. );
    30.  
    31. // Структуры для получения информации о процессах
    32. // SYSTEM_PROCESS_INFORMATION is already defined in winternl.h
    33.  
    34. #define SystemProcessInformation 5
    35.  
    36. class ProcessMonitor {
    37. private:
    38.   struct ProcessInfo {
    39.     DWORD pid;
    40.     std::string name;
    41.     DWORD lastSeen;
    42.   };
    43.  
    44.   std::map<DWORD, ProcessInfo> activeProcesses;
    45.   std::set<DWORD> suspiciousProcesses;
    46.  
    47. public:
    48.   std::string GetProcessName(DWORD processID) {
    49.     char processName[MAX_PATH] = "<unknown>";
    50.     HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
    51.         FALSE, processID);
    52.  
    53.     if (hProcess != NULL) {
    54.       HMODULE hMod;
    55.       DWORD cbNeeded;
    56.  
    57.       if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
    58.         GetModuleBaseNameA(hProcess, hMod, processName, sizeof(processName));
    59.       }
    60.  
    61.       CloseHandle(hProcess);
    62.     }
    63.  
    64.     return std::string(processName);
    65.   }
    66.  
    67.   void ScanActiveProcesses() {
    68.     HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    69.  
    70.     if (hSnapshot == INVALID_HANDLE_VALUE) {
    71.       return;
    72.     }
    73.  
    74.     PROCESSENTRY32 pe32;
    75.     pe32.dwSize = sizeof(PROCESSENTRY32);
    76.     DWORD currentTime = GetTickCount();
    77.  
    78.     if (Process32First(hSnapshot, &pe32)) {
    79.       do {
    80.         ProcessInfo info;
    81.         info.pid = pe32.th32ProcessID;
    82.         // Convert WCHAR to std::string
    83.         char processName[MAX_PATH];
    84.         WideCharToMultiByte(CP_UTF8, 0, pe32.szExeFile, -1, processName, MAX_PATH, NULL, NULL);
    85.         info.name = processName;
    86.         info.lastSeen = currentTime;
    87.         activeProcesses[pe32.th32ProcessID] = info;
    88.       } while (Process32Next(hSnapshot, &pe32));
    89.     }
    90.  
    91.     CloseHandle(hSnapshot);
    92.   }
    93.  
    94.   void MarkSuspicious(DWORD pid) {
    95.     suspiciousProcesses.insert(pid);
    96.   }
    97.  
    98.   std::vector<ProcessInfo> GetRecentlyActive(DWORD withinMs = 2000) {
    99.     std::vector<ProcessInfo> result;
    100.     DWORD currentTime = GetTickCount();
    101.  
    102.     for (const auto& pair : activeProcesses) {
    103.       if (currentTime - pair.second.lastSeen <= withinMs) {
    104.         result.push_back(pair.second);
    105.       }
    106.     }
    107.  
    108.     return result;
    109.   }
    110.  
    111.   void PrintSuspiciousProcesses() {
    112.     if (suspiciousProcesses.empty()) {
    113.       std::cout << "\nNo suspicious processes detected." << std::endl;
    114.       return;
    115.     }
    116.  
    117.     std::cout << "\n=== Processes that likely changed timer resolution ===" <<
    118.       std::endl;
    119.     std::cout << std::setw(10) << "PID" << "  " << "Process Name" << std::endl;
    120.     std::cout << std::string(50, '-') << std::endl;
    121.  
    122.     for (DWORD pid : suspiciousProcesses) {
    123.       auto it = activeProcesses.find(pid);
    124.  
    125.       if (it != activeProcesses.end()) {
    126.         std::cout << std::setw(10) << pid << "  " << it->second.name << std::endl;
    127.       }
    128.     }
    129.   }
    130. };
    131.  
    132. class TimerMonitor {
    133. private:
    134.   pNtQueryTimerResolution NtQueryTimerResolution;
    135.   LARGE_INTEGER perfFreq;
    136.   ProcessMonitor processMonitor;
    137.  
    138.   struct Snapshot {
    139.     ULONG resolution;
    140.     LARGE_INTEGER perfCounter;
    141.     std::vector<DWORD> activePIDs;
    142.   };
    143.  
    144.   Snapshot lastSnapshot;
    145.   std::map<ULONG, std::set<DWORD>> resolutionChanges; // resolution -> PIDs
    146.  
    147. public:
    148.   TimerMonitor() {
    149.     HMODULE ntdll = GetModuleHandleA("ntdll.dll");
    150.     NtQueryTimerResolution = (pNtQueryTimerResolution)GetProcAddress(ntdll,
    151.         "NtQueryTimerResolution");
    152.     QueryPerformanceFrequency(&perfFreq);
    153.     QueryPerformanceCounter(&lastSnapshot.perfCounter);
    154.     ULONG min, max, cur;
    155.     NtQueryTimerResolution(&min, &max, &cur);
    156.     lastSnapshot.resolution = cur;
    157.   }
    158.  
    159.   void PrintHeader() {
    160.     ULONG minRes, maxRes, curRes;
    161.     NtQueryTimerResolution(&minRes, &maxRes, &curRes);
    162.     std::cout << "=== System Timer Resolution Monitor with Process Tracking ===" <<
    163.       std::endl;
    164.     std::cout << "Range: " << maxRes / 10000.0 << " - " << minRes / 10000.0 << " ms"
    165.       << std::endl;
    166.     std::cout << "Frequencies: " << (int)(10000000.0 / minRes) << " - "
    167.       << (int)(10000000.0 / maxRes) << " Hz" << std::endl;
    168.     std::cout << std::endl;
    169.     std::cout << "INSTRUCTIONS:" << std::endl;
    170.     std::cout << "1. Run the program" << std::endl;
    171.     std::cout << "2. Drag another application's window" << std::endl;
    172.     std::cout << "3. Watch for Resolution changes and suspect processes" <<
    173.       std::endl;
    174.     std::cout << "4. Press Ctrl+C to exit and see summary" << std::endl;
    175.     std::cout << std::endl;
    176.     std::cout << std::setw(10) << "Time(s)"
    177.       << std::setw(15) << "Res(ms)"
    178.       << std::setw(12) << "Freq(Hz)"
    179.       << std::setw(15) << "Status"
    180.       << "  Suspect Processes"
    181.       << std::endl;
    182.     std::cout << std::string(80, '=') << std::endl;
    183.   }
    184.  
    185.   void Update() {
    186.     // Scan processes before checking resolution
    187.     processMonitor.ScanActiveProcesses();
    188.     ULONG minRes, maxRes, curRes;
    189.     NtQueryTimerResolution(&minRes, &maxRes, &curRes);
    190.     LARGE_INTEGER now;
    191.     QueryPerformanceCounter(&now);
    192.     double currentFreq = 10000000.0 / curRes;
    193.     // Detect if resolution changed
    194.     std::string status = "";
    195.     std::string suspectInfo = "";
    196.  
    197.     if (curRes < lastSnapshot.resolution) {
    198.       status = "** INCREASED **";
    199.       // Get recently active processes
    200.       auto suspects = processMonitor.GetRecentlyActive(1500);
    201.  
    202.       // Build suspect list
    203.       if (!suspects.empty()) {
    204.         suspectInfo = "PIDs: ";
    205.         size_t maxSuspects = (std::min)(suspects.size(), size_t(3));
    206.  
    207.         for (size_t i = 0; i < maxSuspects; i++) {
    208.           suspectInfo += std::to_string(suspects[i].pid) + "(" +
    209.             suspects[i].name + ")";
    210.  
    211.           if (i < maxSuspects - 1) {
    212.             suspectInfo += ", ";
    213.           }
    214.  
    215.           processMonitor.MarkSuspicious(suspects[i].pid);
    216.           resolutionChanges[curRes].insert(suspects[i].pid);
    217.         }
    218.       }
    219.     } else if (curRes > lastSnapshot.resolution) {
    220.       status = "decreased";
    221.     } else {
    222.       status = "-";
    223.     }
    224.  
    225.     static DWORD startTime = GetTickCount();
    226.     double runTime = (GetTickCount() - startTime) / 1000.0;
    227.     std::cout << std::fixed << std::setprecision(1)
    228.       << std::setw(10) << runTime
    229.       << std::setw(15) << curRes / 10000.0
    230.       << std::setw(12) << (int)currentFreq
    231.       << std::setw(15) << status;
    232.  
    233.     if (!suspectInfo.empty()) {
    234.       std::cout << "  " << suspectInfo;
    235.     }
    236.  
    237.     std::cout << std::endl;
    238.     lastSnapshot.resolution = curRes;
    239.     lastSnapshot.perfCounter = now;
    240.   }
    241.  
    242.   void PrintSummary() {
    243.     std::cout << "\n" << std::string(80, '=') << std::endl;
    244.     std::cout << "=== MONITORING SUMMARY ===" << std::endl;
    245.     std::cout << std::string(80, '=') << std::endl;
    246.     processMonitor.PrintSuspiciousProcesses();
    247.  
    248.     if (!resolutionChanges.empty()) {
    249.       std::cout << "\n=== Resolution Changes Log ===" << std::endl;
    250.  
    251.       for (const auto& pair : resolutionChanges) {
    252.         std::cout << "\nResolution changed to " << pair.first / 10000.0
    253.           << " ms (" << (int)(10000000.0 / pair.first) << " Hz)"
    254.           << std::endl;
    255.         std::cout << "Suspect PIDs: ";
    256.  
    257.         for (DWORD pid : pair.second) {
    258.           std::cout << pid << " ";
    259.         }
    260.  
    261.         std::cout << std::endl;
    262.       }
    263.     }
    264.  
    265.     std::cout << "\n=== Analysis ===" << std::endl;
    266.     std::cout << "Common processes that change timer resolution:" << std::endl;
    267.     std::cout << "- dwm.exe (Desktop Window Manager - during window dragging)" <<
    268.       std::endl;
    269.     std::cout << "- audiodg.exe (Audio Engine - during audio playback)" <<
    270.       std::endl;
    271.     std::cout << "- chrome.exe / firefox.exe (Browsers - for smooth animations)" <<
    272.       std::endl;
    273.     std::cout << "- Discord.exe, Spotify.exe (Media apps)" << std::endl;
    274.     std::cout << "- explorer.exe (File Explorer - during drag operations)" <<
    275.       std::endl;
    276.   }
    277. };
    278.  
    279. int main() {
    280.   TimerMonitor monitor;
    281.   monitor.PrintHeader();
    282.   // Monitor for 5 minutes (or until Ctrl+C)
    283.   std::cout << "Monitoring started... (will run for 5 minutes)\n" << std::endl;
    284.  
    285.   for (int i = 0; i < 300; i++) {
    286.     Sleep(1000);
    287.     monitor.Update();
    288.   }
    289.  
    290.   monitor.PrintSummary();
    291.   std::cout << "\n=== Hypothesis Check ===" << std::endl;
    292.   std::cout << "If you saw resolution decrease (frequency increase) during window"
    293.     << std::endl;
    294.   std::cout <<
    295.     "dragging, and the suspect processes include dwm.exe or explorer.exe," <<
    296.     std::endl;
    297.   std::cout << "then the hypothesis is CONFIRMED!" << std::endl;
    298.   std::cout <<
    299.     "\nWindows automatically increases timer frequency for GUI responsiveness." <<
    300.     std::endl;
    301.   return 0;
    302. }
     
    Последнее редактирование: 7 ноя 2025
    Ahimov нравится это.
  7. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    372
    galenkane

    Предполагалось что железные таймеры не перестраиваются.

    Там на скрине 2&3 столбцы - isr/s без изменений. Эффект пропадает когда апик на макс частоте(последние столбцы).

    Откуда еще прерываниям взяться не известно, только если они генерятся софтверно.
     
  8. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    410
    паузы
    --- Сообщение объединено, 7 ноя 2025 ---
    или DPC
     
  9. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    372
    Подсчет числа прерываний, секунда абсолютна. Такие частоты только профайлер может поднять, но никак не окна.
    Вы измеряете переменные ядра, а не характеристики железных таймеров :preved:

    Откуда они сыпались не знаю, в то время ядерный монитор этого дела собирать не хотелось, чесно говоря от синих экранов какой то рефлекс не хороший. Как начнет что то падать и при этом инфу с дампов не получить и не разобрать, такое желательно избегать :skull:
     
    Последнее редактирование: 7 ноя 2025