Есть ли способ определить, использует ли программа определенные функции API c Windows? - PullRequest
2 голосов
/ 09 марта 2020

Хорошо, это может быть немного сложно объяснить:

Предположим, кто-то создает приложение Windows (используя C# или любой другой язык), которое использует функцию GetDesktopWindow() в user32.dll сделать снимок экрана и затем отправить это изображение в любой онлайн-сервис.

Поскольку это специальное приложение, никакое антивирусное программное обеспечение не сможет определить, является ли он вирусом, потому что оно все еще неизвестно для него. Кроме того, для такого API есть законное применение, так что это не обязательно вирус, это может быть безобидный инструмент для захвата окон или какой-либо инструмент шпионажа.

Я хочу знать следующее: есть ли способ Посмотрите, что конкретный файл c EXE делает с функциями Windows? Могу ли я узнать, использует ли "myapp.exe" GetDesktopWindow() из user32.dll?

Это только один пример. Есть много других Windows конечных точек, которые я хотел бы знать, когда они используются какими-либо приложениями.

Есть ли способ сделать это?

1 Ответ

4 голосов
/ 09 марта 2020

Это зависит от того, какую длину вы хотите 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, который является трассировщиком вызовов библиотеки.

...