Гайд Дневник разработчика: проблемы при разработке экстернал читов

Разработчик
Статус
Оффлайн
Регистрация
1 Сен 2018
Сообщения
1,597
Реакции[?]
881
Поинты[?]
116K
Более форматированная версия -
Пожалуйста, авторизуйтесь для просмотра ссылки.


Всем привет! Уже около шести месяцев я занимаюсь разработкой своего экстернал чита Spurdo как хобби в свободное от работы время. Хочу поделиться с вами проблемами, с которыми я столкнулся, и размышлениями о том, как их решить.

Это мой личный опыт, который, скорее всего, применим к большинству масс-маркета. Всё это можно было бы разделить на три статьи и рассказать о каждом более подробно, но мне кажется, что этот формат более подходящий.

Case №1: Проблема поддержки полноэкранного режима
Первый способ
В большинстве масс-маркет читов для Counter-Strike 2 существует проблема поддержки полноэкранного режима. Например, X1 утверждает, что эта проблема подвластна всем внешним читам и предлагает использовать масштабирование с помощью видеокарты.



В целом, это был первый вариант решения проблемы, но есть некоторые "но":
  • Он требует специфических действий со стороны пользователя. Вы ведь не думаете, что ему интересно что-то дополнительно исправлять при покупке p2c?
  • Конкретно этот способ подходит только для обладателей видеокарты от Nvidia.
Чужой оверлей
Второй способ решения этой проблемы - это просто перехватить оверлей легитимной компании, которая уже исправила за вас эти проблемы =). Фактически, этот способ является стандартом индустрии и практикуется в большинстве читов (в основном в играх, защищенных EAC / BE).

Перехватить можно как минимум двумя способами:
  • Выполнить так называемый “hijacking” окна игры и рисовать там свой оверлей. При этом подходе вы полностью можете контролировать атрибуты этого окна.
    Пожалуйста, авторизуйтесь для просмотра ссылки.
  • Записывать в IPC (inter-process communication) буфер оверлея, чтобы он позже отрисовал кадр. Плюсы этого подхода в большей стабильности происходящего. Для неразбирающегося в теме человека может показаться, что задержка при использовании оверлея по сравнению с первым подходом уменьшается до минимального, и возникает полная синхронизация ESP с моделью в игре. Мы обсудим это позже. Минусы: придется реверсить(((, вы ограничены функционалом, заложенным разработчиками, структуры могут разниться от версии ПО, и нужно будет заставлять пользователей скачивать новую версию оверлея.
Этот способ имеет похожий минус с предыдущим вариантом - пользователю нужно дополнительно что-то делать и устанавливать.

Злоупотребление DWM
В названии указана страшная аббревиатура DWM. Что же это такое? Desktop Window Manager (DWM) - это часть операционных систем Windows. Он отвечает за управление окнами на рабочем столе. Раньше его функция состояла только в том, чтобы обеспечить сглаживание окон и прочие визуальные эффекты, такие как Aero Glass.

С выходом Windows 8, DWM стал обязательным компонентом Windows, в тот же период времени они добавили полную поддержку глубины окон, т.е. сделали условные слои, как в фотошопе, которые позволяли полноценно накладывать одни окна на другие. Слои поделены на группы по порядку отрисовки на экране.

Вот вам enum с названиями этих групп, они, кстати, называются ZBID:
C++:
/*

from the lowest to the highest z-order:

    ZBID_DESKTOP

    ZBID_IMMERSIVE_BACKGROUND

    ZBID_IMMERSIVE_APPCHROME

    ZBID_IMMERSIVE_MOGO

    ZBID_IMMERSIVE_INACTIVEMOBODY

    ZBID_IMMERSIVE_NOTIFICATION

    ZBID_IMMERSIVE_EDGY

    ZBID_SYSTEM_TOOLS

    ZBID_LOCK (Windows 10 only)

    ZBID_ABOVELOCK_UX (Windows 10 only)

    ZBID_IMMERSIVE_IHM

    ZBID_GENUINE_WINDOWS

    ZBID_UIACCESS

*/


// @author: <https://blog.adeltax.com/window-z-order-in-windows-10/>

enum ZBID

{

     ZBID_DEFAULT = 0,

     ZBID_DESKTOP = 1,

     ZBID_UIACCESS = 2,

     ZBID_IMMERSIVE_IHM = 3,

     ZBID_IMMERSIVE_NOTIFICATION = 4,

     ZBID_IMMERSIVE_APPCHROME = 5,

     ZBID_IMMERSIVE_MOGO = 6,

     ZBID_IMMERSIVE_EDGY = 7,

     ZBID_IMMERSIVE_INACTIVEMOBODY = 8,

     ZBID_IMMERSIVE_INACTIVEDOCK = 9,

     ZBID_IMMERSIVE_ACTIVEMOBODY = 10,

     ZBID_IMMERSIVE_ACTIVEDOCK = 11,

     ZBID_IMMERSIVE_BACKGROUND = 12,

     ZBID_IMMERSIVE_SEARCH = 13,

     ZBID_GENUINE_WINDOWS = 14,

     ZBID_IMMERSIVE_RESTRICTED = 15,

     ZBID_SYSTEM_TOOLS = 16,


     //Windows 10+

     ZBID_LOCK = 17,

     ZBID_ABOVELOCK_UX = 18

};
ZBID_DESKTOP - самая первая группа глубины окон, именно в ней рисуются все окна!
1715838190316.png
Вы могли заметить, что я к коду приложил порядок отрисовки на экране, и последним на нём рисуется ZBID_UIACCESS. Если мы создадим окно с этим атрибутом, то мы сможем просто взять и нарисовать наш оверлей поверх экрана как системный. Но как же его создать?

Вы можете воспользоваться недокументированной функцией CreateWindowInBand из user32.dll, которая подозрительно сильно похожа на CreateWindowEx, вот её прототип:
C++:
HWND WINAPI CreateWindowInBand(

     DWORD dwExStyle,

     LPCWSTR lpClassName,

     LPCWSTR lpWindowName,

     DWORD dwStyle,

     int x,

     int y,

     int nWidth,

     int nHeight,

     HWND hWndParent,

     HMENU hMenu,

     HINSTANCE hInstance,

     LPVOID lpParam,

     DWORD dwBand);
При разработке я не заметил никаких минусов этого подхода, но в теории их всего 2:
  1. Поддержка только Windows 8+
  2. Чтобы это работало в полноэкранном режиме, нужно пользоваться “оптимизацией полноэкранного режима”, что в целом логично.
Case №2: Оптимизация. Да зачем она вообще нужна?
В какой-то момент вы столкнетесь с проблемой: ваш чит может начать лагать у пользователей. И эти 15 миллиардов кадров, которые вы видите на своем i9-15900k 400w, ваши пользователи могут не увидеть на своем Core 2 Duo. Что же делать? Конечно, оптимизировать. Я ведь не просто так это написал в заголовке кейса. Но нам нужно ознакомиться с мемом про оптимизацию, прежде чем приступить.
1715838245574.png
Теперь можно.

Побольше swap context
У вас же есть свой драйвер, верно??? А может быть, и гипервизор?? Хипстеры. Даже если вы ответили "нет", в любом случае операция изменения памяти (независимо от того, чтение это или запись) занимает очень много процессорного времени. Но знаете что?

Если вы прочтете не 2 байта за один вызов, а 50 тысяч, то операция займет столько же времени. И вот на этом основан простой метод оптимизации. Почему бы нам не объединить чтение каждого оффсета в чтение одного большого класса? В своем чите я использовал преимущества схемы в Counter-Strike 2, написал короткий подсчет размера всех нетворк-классов и написал кодген под них.

В итоге удалось сократить количество вызовов чтения памяти с 60+ до 10-13. А что по цифрам?
До оптимизации: 1300000-1600000ns
После: 70000-110000
Разница: 1454.54% - 1857.14%

И самое главное, что при необходимости взять что-то из класса игрока количество вызовов чтения памяти не будет расти, что очень важно для большого экстернал-чита

Таймеры, часы, где же суть?
Читатель, погружаемся в лор. Представь: ты создаешь свою OC, уже сделал потоки, процессы, но появилась проблема - они все время работают и нагружают систему, даже когда не активны. Тебе нужно добавить механизм, который бы контролировал их состояние. Хорошо, придумали: в процессоре есть прерывания, будем вызывать их через каждый n-интервал и будить потоки, которые находились в спящем режиме. Но возникает проблема: что, если один поток требует одного интервала, а другой - другого? Например, чтобы включать музыку, нужно быстро обрабатывать все и минимальное время на сон, а в автозаварке кофе можно поставить больший таймер.


Если тебе пришло в голову поставить для всей системы самый низкий интервал среди приложений, поздравляю с прохождением теста - ты индус из Microsoft. Подход, казалось бы, работает, но нагружает систему, когда это не нужно.
1715838289146.png
В Windows получить текущий интервал можно с помощью утилиты clockres с System Internals:

Причем здесь вообще экстерналы и оптимизация? Чтобы процессор не нагружался и правильно ограничивать FPS, вы используете Sleep или std::this_thread::sleep_for - не имеет значения. Так вот, когда ваш поток засыпает на n ms, он может проснуться ровно по таймеру, а может и позже, ведь планировщик вызывается интервалами. Если ваш сон дольше, чем один интервал, то он будет перенесен на другой, то есть:
C++:
if( currentSleep <= 0.f)
       Resume();

// else ignore. Even with 100 nanoseconds left.
// so it will actually take currentSleep + currentTImer
С этим можно бороться следующими способами:
  • Установить минимальный интервал с помощью timeBeginPeriod, но в большинстве случаев ваш сон не будет соответствовать желаемому.
  • Использовать прерывания, для этого есть метод _mm_pause. Проверять, прошло ли нужное время, можно с помощью QueryPerformanceCounter, или посчитать руками заранее. При этом подходе вы будете ужасным человеком, вы будете мешать планировщику Windows.
  • Вызывать NtDelayExecution с -1, чтобы спать на минимальное количество времени, но для этого нужно просчитывать нужное количество циклов для сна, ну или костыль с QueryPerformanceCounter =)
Case №3: Мой оверлей лагает. Что же не так?
Буду честен, над этой проблемой мы в проекте провели не одну неделю, перепробовали всё: начиная со сменой движка отрисовки, заканчивая переписыванием полностью кодовой базы. В один момент, спустя месяцы, я снова решил попробовать свои силы в этой проблеме. При диалоге и рассуждении с моим хорошо знакомым seniusz, ко мне пришло озарение, что это Windows мне что-то портит. Спустя пару минут гугления обновлений Windows, я нашёл то самое! Чтобы исправить маленький FPS в оверлее, вам нужно сделать две вещи:
  • Отключить Game Mode, он доступен с Windows 10 1809
  • Отключить планирование графического процессора с аппаратным ускорением

К сожалению, проблема до сих пор остается частично. Что-то в Windows обрезает FPS ровно в два раза, выделяя больше ресурсов на игру. Если вы знаете, как это решить - отпишите мне, буду благодарен!

Case №4: Защищайтесь сударь
В этом кейсе нет конкретики. В большинстве внешних читов, которые мне довелось протестировать, я замечал много проблем с безопасностью от анти-чита (например, X1, Pellix, PUSSYCAT, AIMSTAR и т.д.).

Основная проблема: мало кому нужен чит, который не способен обеспечить защиту от анти-чита.


Вывод
В разработке экстернал читов есть множество проблем, но все они решаемы. Главное думать головой, и пытаться понять что делаешь.
До скорой встречи, Make cheats, not war!

Мой блог ( зачем он здесь?? ) -
Пожалуйста, авторизуйтесь для просмотра ссылки.


Источники:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.
( фраза Make cheats, not war! )
 
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
241
Реакции[?]
83
Поинты[?]
12K
Более форматированная версия -
Пожалуйста, авторизуйтесь для просмотра ссылки.


Всем привет! Уже около шести месяцев я занимаюсь разработкой своего экстернал чита Spurdo как хобби в свободное от работы время. Хочу поделиться с вами проблемами, с которыми я столкнулся, и размышлениями о том, как их решить.

Это мой личный опыт, который, скорее всего, применим к большинству масс-маркета. Всё это можно было бы разделить на три статьи и рассказать о каждом более подробно, но мне кажется, что этот формат более подходящий.

Case №1: Проблема поддержки полноэкранного режима
Первый способ
В большинстве масс-маркет читов для Counter-Strike 2 существует проблема поддержки полноэкранного режима. Например, X1 утверждает, что эта проблема подвластна всем внешним читам и предлагает использовать масштабирование с помощью видеокарты.



В целом, это был первый вариант решения проблемы, но есть некоторые "но":
  • Он требует специфических действий со стороны пользователя. Вы ведь не думаете, что ему интересно что-то дополнительно исправлять при покупке p2c?
  • Конкретно этот способ подходит только для обладателей видеокарты от Nvidia.
Чужой оверлей
Второй способ решения этой проблемы - это просто перехватить оверлей легитимной компании, которая уже исправила за вас эти проблемы =). Фактически, этот способ является стандартом индустрии и практикуется в большинстве читов (в основном в играх, защищенных EAC / BE).

Перехватить можно как минимум двумя способами:
  • Выполнить так называемый “hijacking” окна игры и рисовать там свой оверлей. При этом подходе вы полностью можете контролировать атрибуты этого окна.
    Пожалуйста, авторизуйтесь для просмотра ссылки.
  • Записывать в IPC (inter-process communication) буфер оверлея, чтобы он позже отрисовал кадр. Плюсы этого подхода в большей стабильности происходящего. Для неразбирающегося в теме человека может показаться, что задержка при использовании оверлея по сравнению с первым подходом уменьшается до минимального, и возникает полная синхронизация ESP с моделью в игре. Мы обсудим это позже. Минусы: придется реверсить(((, вы ограничены функционалом, заложенным разработчиками, структуры могут разниться от версии ПО, и нужно будет заставлять пользователей скачивать новую версию оверлея.
Этот способ имеет похожий минус с предыдущим вариантом - пользователю нужно дополнительно что-то делать и устанавливать.

Злоупотребление DWM
В названии указана страшная аббревиатура DWM. Что же это такое? Desktop Window Manager (DWM) - это часть операционных систем Windows. Он отвечает за управление окнами на рабочем столе. Раньше его функция состояла только в том, чтобы обеспечить сглаживание окон и прочие визуальные эффекты, такие как Aero Glass.

С выходом Windows 8, DWM стал обязательным компонентом Windows, в тот же период времени они добавили полную поддержку глубины окон, т.е. сделали условные слои, как в фотошопе, которые позволяли полноценно накладывать одни окна на другие. Слои поделены на группы по порядку отрисовки на экране.

Вот вам enum с названиями этих групп, они, кстати, называются ZBID:
C++:
/*

from the lowest to the highest z-order:

    ZBID_DESKTOP

    ZBID_IMMERSIVE_BACKGROUND

    ZBID_IMMERSIVE_APPCHROME

    ZBID_IMMERSIVE_MOGO

    ZBID_IMMERSIVE_INACTIVEMOBODY

    ZBID_IMMERSIVE_NOTIFICATION

    ZBID_IMMERSIVE_EDGY

    ZBID_SYSTEM_TOOLS

    ZBID_LOCK (Windows 10 only)

    ZBID_ABOVELOCK_UX (Windows 10 only)

    ZBID_IMMERSIVE_IHM

    ZBID_GENUINE_WINDOWS

    ZBID_UIACCESS

*/


// @author: <https://blog.adeltax.com/window-z-order-in-windows-10/>

enum ZBID

{

     ZBID_DEFAULT = 0,

     ZBID_DESKTOP = 1,

     ZBID_UIACCESS = 2,

     ZBID_IMMERSIVE_IHM = 3,

     ZBID_IMMERSIVE_NOTIFICATION = 4,

     ZBID_IMMERSIVE_APPCHROME = 5,

     ZBID_IMMERSIVE_MOGO = 6,

     ZBID_IMMERSIVE_EDGY = 7,

     ZBID_IMMERSIVE_INACTIVEMOBODY = 8,

     ZBID_IMMERSIVE_INACTIVEDOCK = 9,

     ZBID_IMMERSIVE_ACTIVEMOBODY = 10,

     ZBID_IMMERSIVE_ACTIVEDOCK = 11,

     ZBID_IMMERSIVE_BACKGROUND = 12,

     ZBID_IMMERSIVE_SEARCH = 13,

     ZBID_GENUINE_WINDOWS = 14,

     ZBID_IMMERSIVE_RESTRICTED = 15,

     ZBID_SYSTEM_TOOLS = 16,


     //Windows 10+

     ZBID_LOCK = 17,

     ZBID_ABOVELOCK_UX = 18

};
ZBID_DESKTOP - самая первая группа глубины окон, именно в ней рисуются все окна!
Посмотреть вложение 276995
Вы могли заметить, что я к коду приложил порядок отрисовки на экране, и последним на нём рисуется ZBID_UIACCESS. Если мы создадим окно с этим атрибутом, то мы сможем просто взять и нарисовать наш оверлей поверх экрана как системный. Но как же его создать?

Вы можете воспользоваться недокументированной функцией CreateWindowInBand из user32.dll, которая подозрительно сильно похожа на CreateWindowEx, вот её прототип:
C++:
HWND WINAPI CreateWindowInBand(

     DWORD dwExStyle,

     LPCWSTR lpClassName,

     LPCWSTR lpWindowName,

     DWORD dwStyle,

     int x,

     int y,

     int nWidth,

     int nHeight,

     HWND hWndParent,

     HMENU hMenu,

     HINSTANCE hInstance,

     LPVOID lpParam,

     DWORD dwBand);
При разработке я не заметил никаких минусов этого подхода, но в теории их всего 2:
  1. Поддержка только Windows 8+
  2. Чтобы это работало в полноэкранном режиме, нужно пользоваться “оптимизацией полноэкранного режима”, что в целом логично.
Case №2: Оптимизация. Да зачем она вообще нужна?
В какой-то момент вы столкнетесь с проблемой: ваш чит может начать лагать у пользователей. И эти 15 миллиардов кадров, которые вы видите на своем i9-15900k 400w, ваши пользователи могут не увидеть на своем Core 2 Duo. Что же делать? Конечно, оптимизировать. Я ведь не просто так это написал в заголовке кейса. Но нам нужно ознакомиться с мемом про оптимизацию, прежде чем приступить.
Посмотреть вложение 276996
Теперь можно.

Побольше swap context
У вас же есть свой драйвер, верно??? А может быть, и гипервизор?? Хипстеры. Даже если вы ответили "нет", в любом случае операция изменения памяти (независимо от того, чтение это или запись) занимает очень много процессорного времени. Но знаете что?

Если вы прочтете не 2 байта за один вызов, а 50 тысяч, то операция займет столько же времени. И вот на этом основан простой метод оптимизации. Почему бы нам не объединить чтение каждого оффсета в чтение одного большого класса? В своем чите я использовал преимущества схемы в Counter-Strike 2, написал короткий подсчет размера всех нетворк-классов и написал кодген под них.

В итоге удалось сократить количество вызовов чтения памяти с 60+ до 10-13. А что по цифрам?
До оптимизации: 1300000-1600000ns
После: 70000-110000
Разница: 1454.54% - 1857.14%

И самое главное, что при необходимости взять что-то из класса игрока количество вызовов чтения памяти не будет расти, что очень важно для большого экстернал-чита

Таймеры, часы, где же суть?
Читатель, погружаемся в лор. Представь: ты создаешь свою OC, уже сделал потоки, процессы, но появилась проблема - они все время работают и нагружают систему, даже когда не активны. Тебе нужно добавить механизм, который бы контролировал их состояние. Хорошо, придумали: в процессоре есть прерывания, будем вызывать их через каждый n-интервал и будить потоки, которые находились в спящем режиме. Но возникает проблема: что, если один поток требует одного интервала, а другой - другого? Например, чтобы включать музыку, нужно быстро обрабатывать все и минимальное время на сон, а в автозаварке кофе можно поставить больший таймер.


Если тебе пришло в голову поставить для всей системы самый низкий интервал среди приложений, поздравляю с прохождением теста - ты индус из Microsoft. Подход, казалось бы, работает, но нагружает систему, когда это не нужно.
Посмотреть вложение 276997
В Windows получить текущий интервал можно с помощью утилиты clockres с System Internals:

Причем здесь вообще экстерналы и оптимизация? Чтобы процессор не нагружался и правильно ограничивать FPS, вы используете Sleep или std::this_thread::sleep_for - не имеет значения. Так вот, когда ваш поток засыпает на n ms, он может проснуться ровно по таймеру, а может и позже, ведь планировщик вызывается интервалами. Если ваш сон дольше, чем один интервал, то он будет перенесен на другой, то есть:
C++:
if( currentSleep <= 0.f)
       Resume();

// else ignore. Even with 100 nanoseconds left.
// so it will actually take currentSleep + currentTImer
С этим можно бороться следующими способами:
  • Установить минимальный интервал с помощью timeBeginPeriod, но в большинстве случаев ваш сон не будет соответствовать желаемому.
  • Использовать прерывания, для этого есть метод _mm_pause. Проверять, прошло ли нужное время, можно с помощью QueryPerformanceCounter, или посчитать руками заранее. При этом подходе вы будете ужасным человеком, вы будете мешать планировщику Windows.
  • Вызывать NtDelayExecution с -1, чтобы спать на минимальное количество времени, но для этого нужно просчитывать нужное количество циклов для сна, ну или костыль с QueryPerformanceCounter =)
Case №3: Мой оверлей лагает. Что же не так?
Буду честен, над этой проблемой мы в проекте провели не одну неделю, перепробовали всё: начиная со сменой движка отрисовки, заканчивая переписыванием полностью кодовой базы. В один момент, спустя месяцы, я снова решил попробовать свои силы в этой проблеме. При диалоге и рассуждении с моим хорошо знакомым seniusz, ко мне пришло озарение, что это Windows мне что-то портит. Спустя пару минут гугления обновлений Windows, я нашёл то самое! Чтобы исправить маленький FPS в оверлее, вам нужно сделать две вещи:
  • Отключить Game Mode, он доступен с Windows 10 1809
  • Отключить планирование графического процессора с аппаратным ускорением

К сожалению, проблема до сих пор остается частично. Что-то в Windows обрезает FPS ровно в два раза, выделяя больше ресурсов на игру. Если вы знаете, как это решить - отпишите мне, буду благодарен!

Case №4: Защищайтесь сударь
В этом кейсе нет конкретики. В большинстве внешних читов, которые мне довелось протестировать, я замечал много проблем с безопасностью от анти-чита (например, X1, Pellix, PUSSYCAT, AIMSTAR и т.д.).

Основная проблема: мало кому нужен чит, который не способен обеспечить защиту от анти-чита.


Вывод
В разработке экстернал читов есть множество проблем, но все они решаемы. Главное думать головой, и пытаться понять что делаешь.
До скорой встречи, Make cheats, not war!

Мой блог ( зачем он здесь?? ) -
Пожалуйста, авторизуйтесь для просмотра ссылки.


Источники:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.
( фраза Make cheats, not war! )
Что касается уиаксеса с ним есть один забавный прикол: если делать его так как ты показал в посте, у тебя в процессе висит флаг который можно получить даже при QUERY_LIMITED_INFORMATION :)

Что касается пелликса, мы буквально сделали минимум защиты не особо заморачиваясь, если ты про ксго версию то там вообще беда была, в кс2 лучше но мы всё ещё не занимаемся вещами по типу скрытия процесса от итерации. Чит делается под банку пива вечерами, и мы больше занимаемся добавлением прикольного функционала (по типу экстернал аволла) чем защитой. Хочу отметить что при всём при этом за 2 года у чита ни разу не было банвейва (хотя и по причине того что валве пофигу)

А так пост хороший, сталкивался буквально со всем из вышеперечисленного.
P.S. Что касается точного времени для слипа можно заюзать NtSetTimerResolution после чего вызывать NtDelayExecution в стиле

Sleep:
LARGE_INTEGER interval;
interval.QuadPart = -1ll * (int)(flMilliseconds * 10000.0f);
NtDelayExecution(true, &interval);
 
Последнее редактирование:
Разработчик
Статус
Оффлайн
Регистрация
1 Сен 2018
Сообщения
1,597
Реакции[?]
881
Поинты[?]
116K
P.S. Что касается точного времени для слипа можно заюзать NtSetTimerResolution после чего вызывать NtDelayExecution в стиле

Sleep:
LARGE_INTEGER interval;
interval.QuadPart = -1ll * (int)(flMilliseconds * 10000.0f);
NtDelayExecution(true, &interval);
Он не точный, по факту NtDelayExecution это просто более низкий уровень для Sleep, проблема с пропуском на следующий интервал будет присутствовать
 
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
241
Реакции[?]
83
Поинты[?]
12K
Он не точный, по факту NtDelayExecution это просто более низкий уровень для Sleep, проблема с пропуском на следующий интервал будет присутствовать
Он будет по 0.5мс клоку при этом не сжирая цпу на цикл с _mm_pause.
_mm_pause подходит в случае если ты делаешь условный спинлок но для слипов он как по мне слишком много цпу жрёт.

Например вот я сделал бесконечный цикл с _mm_pause() на своём ноуте с Ryzen 7 6800h
1715841628227.png
Да, там будет идеальная точность но как правило это не нужно. Теперь пример с "точным" NtDelayExection на 0.5 мс клоке:

1715841708930.png
Даже при том что он может пропустить пол миллисекунды, мы выигрываем в нагрузке на цпу в (?) раз. Не могу представить ситуацию где прийдётся делать более 1500 циклов с слипом впринципе. К слову я замерял по приколу и получилось что если сравнивать мёртвый цикл с _mm_pause и без каких бы то слипов вообще, нагрузка на цпу отличается аж на целых 3%(!), так что если тебе действительно нужно сделать эти 360к циклов в секунду (что странным образом соответствует частоте процессора) то _mm_pause погоды не делает (с ним происходит в среднем 349к циклов в секунду при соответственно 3% выигрыше в проценте загруженности ядра)
 
Последнее редактирование:
Тьомчик
Участник
Статус
Оффлайн
Регистрация
30 Июн 2020
Сообщения
751
Реакции[?]
153
Поинты[?]
61K
читать лень, но надосуге я это прочту, респект за целый конспект
 
Разработчик
Статус
Оффлайн
Регистрация
1 Сен 2018
Сообщения
1,597
Реакции[?]
881
Поинты[?]
116K
Он будет по 0.5мс клоку при этом не сжирая цпу на цикл с _mm_pause.
_mm_pause подходит в случае если ты делаешь условный спинлок но для слипов он как по мне слишком много цпу жрёт.

Например вот я сделал бесконечный цикл с _mm_pause() на своём ноуте с Ryzen 7 6800h
Посмотреть вложение 276999
Да, там будет идеальная точность но как правило это не нужно. Теперь пример с "точным" NtDelayExection на 0.5 мс клоке:

Посмотреть вложение 277000
Даже при том что он может пропустить пол миллисекунды, мы выигрываем в нагрузке на цпу в (?) раз. Не могу представить ситуацию где прийдётся делать более 1500 циклов с слипом впринципе. К слову я замерял по приколу и получилось что если сравнивать мёртвый цикл с _mm_pause и без каких бы то слипов вообще, нагрузка на цпу отличается аж на целых 3%(!), так что если тебе действительно нужно сделать эти 360к циклов в секунду (что странным образом соответствует частоте процессора) то _mm_pause погоды не делает (с ним происходит в среднем 349к циклов в секунду при соответственно 3% выигрыше в проценте загруженности ядра)
Да, ты прав, да и в статье в целом я так и сказал, что этот метод будет нарушать идею планировщика WIndows. Но этот вариант показан как путь к стабильному решению, самым правильным в целом будут прерывания с -1 через системный вызов NtDelayExecution, и расчётом количества нужных циклов ( если конечно же нужна точность более 1ms )
 
Продавец
Статус
Оффлайн
Регистрация
12 Сен 2016
Сообщения
868
Реакции[?]
263
Поинты[?]
5K
на сколько я помню простым смертным запрещено вызывать данную функцию.
Это не задукоментированная функция, её нет в sdk, ты её сможешь её можешь получить через getprocaddress и использовать, но твой процесс должен иметь ui контекст, иначе не запашет
 
Разработчик
Статус
Оффлайн
Регистрация
1 Сен 2018
Сообщения
1,597
Реакции[?]
881
Поинты[?]
116K
на сколько я помню простым смертным запрещено вызывать данную функцию.
Да, спасибо за примечание, хотел, но забыл упомянуть.
Для этого способа нужно иметь права TokenUIAccess в токене пользователе. Для этого можно просто скопировать права токена с winlogon, и после этого свободно можно будет создать новый процесс с правами использования CreateWindowInBand.
Примерный PoC:
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
241
Реакции[?]
83
Поинты[?]
12K
Да, ты прав, да и в статье в целом я так и сказал, что этот метод будет нарушать идею планировщика WIndows. Но этот вариант показан как путь к стабильному решению, самым правильным в целом будут прерывания с -1 через системный вызов NtDelayExecution, и расчётом количества нужных циклов ( если конечно же нужна точность более 1ms )
Тогда сорян, зря быканул.
Это не задукоментированная функция, её нет в sdk, ты её сможешь её можешь получить через getprocaddress и использовать, но твой процесс должен иметь ui контекст, иначе не запашет
В качестве альтернативы можно установить этот флаг в кернеле, тогда он не будет палиться в флагах процесса. Он прям в EPROCESS лежит.
 
Сверху Снизу