Это зависит от того, какую длину вы хотите go сделать это. По сути, это игра в кошки-мышки - плохие актеры будут пытаться найти новые способы обойти ваше обнаружение, перепрыгивая через некоторые неясные обручи, вы добавите более сложные методы обнаружения для этих уловок, они будут думать о новых уловках и так далее.
Кроме того, это зависит от того, хотите ли вы статически и динамически определить это, и действительно ли вы хотите знать, вызывается ли GetDesktopWindow
или если «программа получает дескриптор окна рабочего стола» (который может быть достигнутым и другими способами).
Вот неисчерпывающий список идей:
- Вы можете статически определить, импортируется ли функция, посмотрев каталог импорта. Исследуйте структуру файлов PE, чтобы узнать больше. Эта статья может помочь.
- Этот метод обнаружения может быть легко обойден путем динамического импорта функции с использованием
LoadLibrary
и GetProcAddress
.
- Вы можете отсканировать файл на наличие строки
GetDesktopWindow
, чтобы обнаружить возможное использование для динамического c импорта. - Этот метод обнаружения можно легко обойти, упаковав, зашифровав или иным образом запутав имя динамически импортируемой функции.
- Вы можете динамически наблюдать, будет ли
GetDesktopWindow
Функция вызывается путем регистрации AppInit_DLL
или глобальной ловушки, которая внедряется в каждый новый процесс, и перехватывает функцию GetDesktopWindow
изнутри процесса, перезаписывая свои первые байты с помощью перехода к вашему собственному коду, как-то уведомляя ваш компонент обнаружения, выполнение оригинальных байтов и отскок назад. ( Microsoft Detours может помочь в этом.) - Этот метод обнаружения можно обойти, если цель замечает ловушку и удаляет ее перед вызовом, поскольку она находится в своем собственном пространстве процесса. (Вы также можете проделать некоторые трюки, действуя как отладчик и установив аппаратную точку останова в первой инструкции
GetDesktopWindow
, но опять же будут способы обнаружить или обойти это, поскольку цель также может изменять регистры отладки.) - Вы можете создать драйвер, который делает это из режима ядра, но теперь мы углубляемся.
Обратите внимание, что до сих пор мы фокусировались на актуальная функция GetDesktopWindow
от user32.dll
. Но что, если цель просто будет использовать другой способ для достижения своей цели получения дескриптора окна рабочего стола?
- Дескриптор окна рабочего стола для текущего потока хранится в TIB (блок информации о потоке), который доступен через
fs:[18]
в режиме пользователя. Вы можете увидеть это в GetDesktopWindow
исходном коде ReactOS , который довольно точен по сравнению с реальной реализацией Microsoft (которую вы можете проверить, посмотрев на нее в отладчике). Следовательно, цель может просто получить доступ к TIB и извлечь это значение, даже не вызывая GetDesktopWindow
. - Цель может просто взять известное окно верхнего уровня, такое как скрытое окно совместимости оболочки, которое вы получить через
GetShellWindow()
или - чтобы избежать обнаружения GetShellWindow
тоже - например, FindWindow(NULL, "Program Manager")
(или даже недавно созданное окно!) и вызвать GetAncestor(hWnd, GA_PARENT)
, чтобы получить дескриптор окна рабочего стола. - Я уверен, что с некоторой креативностью ваши противники предложат более умные идеи, чем эта.
Кроме того, если мы сделаем еще один шаг вперед и взглянем на конечную цель - на скриншоте, существуют и другие способы достижения этого. Первый пример, который приходит на ум: они могут использовать keybd_event
, чтобы эмулировать нажатие клавиши PrnS c, а затем читать скриншот из данных буфера обмена.
Так что все зависит от того, как далеко вы хотите пройти. this.
Кстати, вас может заинтересовать проект drltrace
, который является трассировщиком вызовов библиотеки.