Как сделать инжектор dll

Обновлено: 21.11.2024

Соавторы Simple Injector — увлеченные разработчики программного обеспечения, и наша библиотека DI поддерживает наш подход к разработке программного обеспечения

Мы продвигаем передовой опыт и разработали Simple Injector, чтобы направить разработчика к успеху

Мы любим простоту и разработали API, с которым легко начать работу и который достаточно мощен для работы с крупными корпоративными приложениями

Simple Injector можно использовать бесплатно и всегда будет бесплатным

Simple Injector оптимизирован для производительности и одновременного использования

Simple Injector имеет самую продвинутую поддержку общей типизации среди всех DI-библиотек

Simple Injector позволяет расширять и улучшать конвейер создания объектов с помощью собственных пользовательских функций

Подробная документация Simple Injector объясняет, как реализовать DI с принципами проектирования SOLID

Мы верим в хороший дизайн и лучшие практики и любим говорить об этом

Простой
Общие
Люди
Диаграммы

Простой

Простой инжектор — это просто

Простой инжектор бесплатен

Намного быстрее не бывает

Дополнительно
Общие

Расширенная поддержка универсального ввода

Мощная
диагностика

Мощные службы диагностики

Центр разработчиков

Хотите узнать больше?

Простой инжектор — это просто

В базовой библиотеке Simple Injector есть тщательно подобранный набор функций, поддерживающих множество расширенных сценариев. Simple Injector поддерживает настройку на основе кода и поставляется со встроенными службами диагностики для выявления многих распространенных проблем с конфигурацией.

Простой инжектор бесплатен

Simple Injector имеет открытый исходный код и распространяется под разрешающей лицензией MIT. Simple Injector есть и всегда будет бесплатным. Бесплатное использование. Бесплатно копировать. Бесплатно изменить. Бесплатно.

Все вклады в Simple Injector подпадают под действие всеобъемлющего лицензионного соглашения с участниками, чтобы гарантировать, что весь код, внесенный в проект Simple Injector, не может быть впоследствии заявлен как принадлежащий какому-либо лицу или группе.

Это не намного быстрее, чем это

Simple Injector оптимизирован для обеспечения производительности и одновременного использования. Simple Injector является потокобезопасным, а его конструкция без блокировок позволяет линейно масштабировать его с количеством доступных процессоров и потоков. Вы обнаружите, что скорость разрешения графа объектов сравнима с аппаратным созданием объектов.

Это означает, что вы, разработчик, можете сосредоточиться на важных вещах: модульном тестировании, исправлении ошибок, новых функциях и т. д. Вам никогда не придется беспокоиться о времени, которое требуется для построения графа объектов. Вам никогда не потребуется контролировать производительность библиотеки или вносить специальные коррективы в конфигурацию, чтобы повысить ее производительность.

Но не верьте нам — взгляните на независимые тесты в Интернете.

Самая продвинутая поддержка универсального программирования среди всех DI-библиотек

Аспектно-ориентированное программирование упрощается благодаря расширенной поддержке универсальных типов в Simple Injector. Универсальные декораторы с ограничениями универсального типа могут быть зарегистрированы с помощью одной строки кода и могут применяться условно с использованием предикатов. Simple Injector может работать с открытыми универсальными типами, закрытыми универсальными типами и частично закрытыми открытыми универсальными типами.

Simple Injector имеет мощную систему диагностики

Система диагностики Simple Injector может помочь выявить ошибки конфигурации. Эту систему можно запрашивать визуально в отладчике или программно во время выполнения.

Службы диагностики работают, анализируя всю информацию, которая может быть статически определена библиотекой.

Мы верим в хороший дизайн и лучшие практики и любим говорить об этом

Простой инжектор был разработан с использованием современных проверенных методов и принципов разработки, таких как TDD и SOLID. Simple Injector имеет обширный набор модульных тестов, обеспечивающих высокий уровень достоверности новых выпусков.

Мы проводим много времени на дискуссионном форуме Simple Injector и на Stack Overflow, отвечая на вопросы, предоставляя помощь и отзывы нашим пользователям и коллегам.

Обычно проблемы решаются в течение 24 часов с момента их появления на сайте, и всегда предоставляется обратная связь — проблемы не остаются без внимания в течение длительного периода времени.

Внедрение зависимостей с помощью Simple Injector с использованием принципов проектирования SOLID

Simple Injector имеет исчерпывающую и актуальную документацию: в документации описаны начало работы, управление временем жизни объектов, руководства по интеграции, общая типизация, расширенные сценарии, диагностический API и конвейер Simple Injector. Все, что явно не описано в документации, скорее всего, зависит от реализации, и в этих случаях наше сообщество готово помочь.

Многие разработчики хвалят Simple Injector за исчерпывающую документацию, в которой объясняется, как реализовать внедрение зависимостей с помощью Simple Injector с использованием принципов проектирования SOLID.

Возможность контролировать и управлять поведением системы и вызовами API — полезный навык для любого разработчика Windows. Он позволяет исследовать внутренние процессы и обнаруживать подозрительный и вредоносный код. Ранее мы описали простой способ установить глобальную перехватчик API, манипулируя разделом реестра AppInit_DLLs и делая процесс calc.exe невидимым в списке запущенных процессов.

На этот раз мы углубимся в методы внедрения динамических библиотек (DLL). Мы демонстрируем, как сделать любой процесс Windows бессмертным, чтобы никакой другой процесс не мог его завершить. Этот учебник по внедрению DLL будет полезен разработчикам Windows, которые хотят узнать больше о различных способах изменения потока и поведения вызовов API в приложениях Windows.

Команда восстановления данных

Основы подключения API

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

Что такое перехват API? Перехват API — это метод, который разработчики используют для управления поведением системы или приложения. С помощью перехвата API вы можете перехватывать вызовы в приложении Windows или собирать информацию, связанную с вызовами API. Кроме того, перехват API — это один из методов, которые антивирусы и решения Endpoint Detection and Response используют для выявления вредоносного кода.

  • Внедрение DLL: позволяет запускать код внутри процесса Windows для выполнения различных задач.
  • Внедрение кода — реализуется с помощью API WriteProcessMemory, используемого для вставки пользовательского кода в другой набор инструментов процесса. Предоставляет вам полный контроль над отлаживаемым приложением, упрощая манипулирование памятью отлаживаемого процесса.

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

Существует три широко используемых метода внедрения DLL, основанных на использовании:

  • функция SetWindowsHookEx. Этот метод применим только к приложениям, использующим графический интерфейс пользователя (GUI).
  • функция CreateRemoteThread. Этот метод можно использовать для перехвата любого процесса, но он требует много кода.
  • исправление контекста удаленного потока. Этот метод эффективен, но довольно сложен, поэтому его лучше использовать только в том случае, если два других метода по каким-то причинам не работают.

Далее в этой статье мы объясним, как реализовать каждый из этих методов, и предоставим практический пример установки перехватчиков API с помощью одного из них. Наше путешествие начинается с обзора первой техники в этом списке — использования функции SetWindowsHookEx.

Внедрение DLL с помощью функции SetWindowsHookEx

Первый метод внедрения DLL, который мы рассмотрим в этом посте, основан на функции SetWindowsHookEx. Используя хук WH_GETMESSAGE, мы устанавливаем процесс, который будет следить за сообщениями, обрабатываемыми системными окнами. Чтобы установить хук, мы вызываем функцию SetWindowsHookEx:

Аргумент WH_GETMESSAGE определяет тип ловушки, а параметр functionAddress определяет адрес функции (в адресном пространстве вашего процесса), которую система должна вызывать всякий раз, когда окно собирается обработать сообщение.

Параметр dllToBeInjected определяет библиотеку DLL, содержащую функцию functionAddress. Последний аргумент, 0, указывает поток, для которого предназначен крючок. Передавая 0, мы сообщаем системе, что устанавливаем ловушку для всех существующих в ней потоков графического интерфейса. Таким образом, этот метод можно применять для подключения определенного процесса или всех процессов в системе.

Давайте посмотрим, как все это работает:

  1. Поток Some_application.exe собирается отправить сообщение какому-то окну.
    1. Система проверяет, установлен ли хук WH_GETMESSAGE для этого потока.
      1. Затем система выясняет, сопоставляется ли Inject.dll, библиотека DLL, содержащая обратный вызов для сообщения, с адресным пространством процесса Some_application.exe.
        1. Если Inject.dll еще не сопоставлена, система сопоставляет ее с адресным пространством приложения Some_application.exe и увеличивает счетчик блокировок библиотеки DLL в этом процессе.
          1. Функция DllMain Inject.dll вызывается с параметром DLL_PROCESS_ATTACH.
            1. Затем вызывается обратный вызов в адресном пространстве процесса Some_application.exe.
              1. После возврата из обратного вызова счетчик блокировки DLL в адресном пространстве процесса уменьшается на 1.

              Теперь давайте посмотрим, как мы можем внедрить DLL вторым методом — с помощью функции CreateRemoteThread.

              Внедрение DLL с помощью функции CreateRemoteThread

              Теперь мы рассмотрим наиболее гибкий способ внедрения DLL — использование функции CreateRemoteThread. Общий поток выглядит следующим образом:

              Внедрение библиотеки DLL включает вызов функции LoadLibrary в потоке целевого процесса для загрузки нужной библиотеки DLL. Поскольку управлять потоками другого процесса крайне сложно, лучше создать в нем свой собственный поток. К счастью, функция CreateRemoteThread упрощает эту задачу:

              Эта функция очень похожа на функцию CreateThread, но имеет дополнительный параметр hProcess, определяющий процесс, которому будет принадлежать новый поток.

              Начнем с того, что получим дескриптор процесса, который собираемся перехватить:

              Затем мы должны выделить часть памяти в целевом процессе, чтобы передать путь DLL, поскольку целевой процесс может получить доступ только к своей частной памяти:

              С помощью функции WriteProcessMemory мы можем поместить путь DLL в адресное пространство нашего целевого процесса:

              Тогда мы можем начать новую тему. С помощью этого потока наша DLL будет загружена в целевой процесс.

              Наконец, мы можем перейти к третьему методу внедрения DLL, основанному на исправлении контекста потока.

              Внедрение DLL с исправлением контекста удаленного потока

              Этот метод внедрения DLL нелегко обнаружить, так как в основном он выглядит как обычная активность потока. Чтобы добиться успеха, нам нужно манипулировать контекстом существующего удаленного потока и убедиться, что поток не знает об этих манипуляциях. Указатель инструкций целевого потока сначала устанавливается на пользовательский фрагмент кода. Когда код выполняется, указатель перенаправляется в исходное положение.

              Вот как выглядит весь процесс:

              Давайте посмотрим, как мы можем реализовать этот метод внедрения DLL в системе x64.

              Во-первых, нам нужно найти целевой процесс и выбрать поток внутри него. Лучше выбрать поток, который уже запущен или может быть запущен, чтобы наша DLL могла быть загружена как можно раньше. Выбор ожидающего потока — не лучшая идея, так как такой поток не запустит код, если он не готов к запуску.

              Сначала мы используем функцию OpenThread, чтобы открыть дескриптор удаленного потока:

              Затем нам нужно выделить память в удаленном процессе для хранения внедренного кода и пути к DLL:

              Затем мы записываем путь к DLL в середине удаленного выделенного буфера:

              Затем мы приостанавливаем удаленный поток и получаем его контекст:

              Теперь компилируем ассемблерный код и сохраняем его в буфере:

              Мы устанавливаем регистр удаленного IP (RIP) нашего удаленного потока в буфер:

              Наконец, мы устанавливаем новый контекст и возобновляем поток:

              Теперь, когда вы лучше понимаете различные методы внедрения DLL, пришло время посмотреть, как эти методы работают на практике.

              Настройка перехватчиков API с внедрением DLL на практике

              Хотя использование функции CreateRemoteThread является наиболее универсальным способом установки обработчиков API с внедрением DLL, этот метод требует большого объема предварительного кодирования. Вот почему мы проиллюстрируем, как устанавливать перехватчики API с помощью внедрения DLL, используя функцию SetWindowsHookEx, которая требует меньше времени.

              Этот пример основан на базовой DLL пользовательского режима, написанной на C++. Чтобы иметь возможность отслеживать ваши действия, убедитесь, что в ваш проект добавлена ​​последняя версия исходного кода Mhook.

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

              1. Мы внедряем нашу DLL с помощью функции SetWindowsHookEx:
              1. Чтобы убедиться, что мы можем восстановить исходную функцию после удаления нашего хука, нам нужно сохранить его адрес.

              Чтобы завершить процесс, нам нужно вызвать функцию TerminateProcess из kernel32.dll. Благодаря созданию и инициализации глобальной переменной теперь мы можем хранить исходный адрес функции:

              1. Мы подключили функцию HookedTerminateProcess вместо оригинальной функции TerminateProcess.Подключенная функция сначала вызывает функцию QueryFullProcessImageNameW из kernel32.dll и получает полное имя исполняемого образа для процесса.

              Теперь нам нужно проверить имя процесса. Если у него есть суффикс «_immortal», мы не должны допускать завершения этого процесса.

              Примечание. Обе функции, исходная и перехваченная, должны иметь одинаковые подписи.

              1. Здесь мы наконец можем внедрить нашу DLL в код целевого процесса, чтобы установить ловушку.

              После загрузки в целевой процесс функция DllMain получит параметр DLL_PROCESS_ATTACH. Теперь мы можем манипулировать этим процессом и перехватывать выбранную функцию с помощью библиотеки Mhook:

              1. После выгрузки библиотеки DLL из адресного пространства целевого процесса функция DllMain получает параметр DLL_PROCESS_DETACH. После этого мы удаляем хук и восстанавливаем исходную функцию.

              Теперь у нас есть весь код, необходимый для установки перехватчиков API с внедрением Windows DLL. Пришло время проверить, действительно ли этот код работает.

              Выполнение нашего примера кода перехвата API

              Для практической иллюстрации мы использовали утилиту просмотра структурированных хранилищ и превратили ее в бессмертный процесс, внедрив DLL с функцией SetWindowsHookEx. В результате этого процесса мы получили исполняемый файл с именем SSView_immortal.exe. Давайте запустим этот исполняемый файл и посмотрим на него в диспетчере задач. Нам также понадобится установленная утилита Process Explorer, чтобы проверить, действительно ли наша DLL внедрена в процесс Taskmgr.exe:

              В диспетчере задач мы видим процесс SSView_immortal.exe. Попробуем завершить его:

              Когда мы нажимаем Завершить задачу , мы получаем окно сообщения с ошибкой (та же ошибка, которую мы показываем в нашей перехваченной функции):

              Затем мы также получаем сообщение «Отказано в доступе». Это ответ ERROR_ACCESS_DENIED, который мы установили ранее с помощью функции SetLastError при реализации нашей перехваченной функции:

              Как видите, мы успешно перехватили системный процесс и сделали невозможным его завершение любым другим процессом Windows, что мы и собирались сделать.

              Заключение

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

              Существует множество способов перехвата функции с помощью внедрения DLL — путем установки перехватчиков в определенных функциях или манипулирования контекстом удаленного потока. Исходя из нашего опыта, мы можем сказать, что установка хуков с помощью функции CreateRemoteThread является наиболее эффективным подходом. Поскольку эта функция поддерживается операционной системой Windows, при работе с ней не нужно использовать какие-то дополнительные хитрости, сложные структуры исполняемых файлов или внутренности операционной системы. Однако, если вы работаете с приложением с графическим интерфейсом, вы можете использовать самый простой вариант — функцию SetWindowsHookEx.

              Мы в Apriorit уже установили тысячи крючков и знаем, как ориентироваться в различных операционных системах и процессах. Станьте на шаг ближе к реализации проекта своей мечты — свяжитесь с нами и расскажите об этом!

              Вы ищете инструмент для инжектора DLL для Windows? Есть много инструментов, хотя все они могут не подходить для вашей цели. В этой статье вы можете найти список лучших программ для инжектора DLL. Но прежде чем перейти к списку инструментов, вы должны знать несколько важных вещей о инжекторах DLL.

              В компьютерном программировании внедрение DLL известно как метод запуска внешних кодов для изменения поведения компьютерной программы. С помощью внешнего кодирования вы можете указать компьютеру выполнять определенную задачу с помощью инструмента ввода DLL.

              Оглавление

              8 лучших программ для инжектора DLL для Windows

              Для Windows доступно множество инструментов внедрения DLL. Выбор правильного программного обеспечения зависит от нескольких важных параметров. Этими параметрами являются пользовательский интерфейс, функции, размер, эффективность, удобство использования и т. д. Список инструментов можно найти в следующем разделе этой статьи.

              1. Удаленная DLL

              Сегодня удаленная библиотека DLL стала одним из самых надежных инструментов для внедрения DLL. Программное обеспечение поставляется с бесшовным и привлекательным интерфейсом. Пользователи могут легко найти различные функции и параметры удобного интерфейса на панели инструментов. Эффективность инструмента также высока, поскольку он предлагает пользователям несколько методов внедрения DLL.

              Некоторыми из методов DLL, предлагаемых программным обеспечением, являются Queue Use APC, Create a Remote Tread и NT Create Thread. Благодаря интерфейсу и удобству использования этот инструмент понравится новичкам. В то же время профессиональные программисты найдут это программное обеспечение очень многофункциональным.

              2. Инжектор DLL

              DLL Injector — это бесплатный инструмент для пользователей Windows. Программное обеспечение имеет простой и удобный интерфейс. Использование этого программного обеспечения упрощает выполнение инъекции DLL. С помощью этого инструмента программисты могут отслеживать запущенные процессы. Например, вы можете отслеживать путь процесса, PID и имя процесса.

              Чтобы выбрать DLL-файл, который вы хотите внедрить в компьютер Windows, нажмите кнопку «Выбрать DLL». При нажатии на кнопку откроется окно просмотра, в котором можно найти файл DLL для внедрения в компьютер.

              3. Экстремальный инжектор

              Среди лучших инжекторов DLL Extreme Injector должен найти свое место. Вы можете развернуть этот инжектор DLL для операционной системы Windows. Инжекторный софт подойдет для заядлых геймеров. Лучше всего использовать этот инструмент, чтобы попробовать игровые хаки.

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

              4. Автоматический инжектор DLL

              Как следует из названия, этот инструмент помогает автоматизировать процесс внедрения DLL. Если вам нужен эффективный и безупречный инжектор DLL, это идеальный инструмент для вас.

              Хотя этот инструмент работает автоматически, он также вводит DLL в систему вручную. По этой причине инструмент очень удобен для всех пользователей.

              Пока вы используете компьютер Windows, программа будет работать в фоновом режиме для автоматического внедрения DLL. Программное обеспечение имеет бесшовный пользовательский интерфейс. Кроме того, он имеет множество удобных функций и опций.

              5. DLL-вакцина

              DLL-вакцина — еще один эффективный и надежный инструмент для внедрения DLL. Простой интерфейс является наиболее яркой особенностью инструмента. Подобно Auto DLL, этот инструмент также имеет две опции. С помощью этого инструмента вы можете выполнять внедрение DLL как вручную, так и автоматически. С помощью этого инструмента пользователи также могут выбрать несколько файлов DLL.

              6. Инжектор

              Источник: Softpedia

              Инжектор также является популярным программным обеспечением для инжектора DLL, в котором предусмотрена ручная и автоматическая инъекция DLL. Для внедрения файла DLL вам нужно нажать на опцию обзора. Вам нужно выбрать и ввести DLL-файл на панель инструментов из окна браузера. Нажатие на кнопку «Загрузить» поможет вам внедрить выбранную DLL в систему.

              7. DLL удаленного инжектора

              DLL Remote Injector — это идеальный инструмент для внедрения DLL-файлов в компьютеры Windows. Программное обеспечение имеет простой пользовательский интерфейс. Тем не менее, вы можете использовать доступные команды для выполнения процесса внедрения DLL с помощью этого инструмента.

              8. Инжекторный гаджет

              Injector Gadget — еще один бесплатный инструмент для инжектора DLL для Windows. Программное обеспечение отображает DLL вместе с PID. Нажатие кнопки инъекции в программном обеспечении начнет процесс инъекции DLL. Инструмент имеет простой и удобный пользовательский интерфейс.

              Вердикт

              В этом блоге вы рассмотрели восемь отличных программ для инжектора DLL для Windows. Вы можете использовать любой из этих инструментов, чтобы изменить поведение любой программы Windows, выполнив внешний код. Моими любимыми инжекторами DLL являются Remote DLL, DLL Injector и DLL Vaccine.

              Я начал этот проект главным образом потому, что мне нужен был правильный трекер XP, за который мне не нужно было доплачивать, поскольку цена казалась мне совершенно неоправданной.

              На этой странице объясняется, как я использовал Visual C++ для написания инструмента инжектора DLL для NXT-клиента RuneScape вместе с DLL, которая подключается к вызовам отрисовки OpenGL RuneScape для рендеринга дорогого оверлея ImGui поверх него.

              Внедрение DLL

              Для инжектора DLL я использовал базовое консольное приложение C++ из Visual Studio. Для этого PoC нам не нужно ничего особенного.

              Принцип внедрения DLL следующий:

              В коде это выглядит следующим образом:

              Поиск PID

              В этом коде используется API Windows, указанный в заголовке Windows.h, чтобы сначала создать моментальный снимок всех запущенных процессов с помощью CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0), а затем итерировать его, непрерывно вызывая Process32Next(hSnap, &procEntry) для получения следующей записи. в списке. Это делается до тех пор, пока имя текущего процесса не совпадет с переданным именем, в нашем случае rs2client.exe .

              Получение дескриптора процесса

              Это очень просто и понятно. Мы можем просто снова использовать Windows API.

              Это даст нам дескриптор на основе PID с полным доступом к этому процессу. Так мы взаимодействуем с клиентом RuneScape.

              Выделить память в целевом процессе

              Эта часть выполняется для подготовки к следующему шагу. Он выделяет память в удаленном процессе и помещает в него строку DLL. Это необходимо, так как нам нужно вызвать функцию LoadLibrary, которая принимает путь к загружаемой DLL.

              Начало обсуждения

              Теперь мы собираем все воедино. Запуск потока в процессе RuneScape с использованием CreateRemoteThread(.) с LoadLibraryA в качестве подпрограммы потока. На самом деле это работает только из-за приятного совпадения, что подпись LPTHREAD_START_ROUTINE очень похожа на подпись LoadLibraryA. Обе функции имеют указатель в качестве аргумента и целое число в качестве возвращаемого значения. Если бы у этой функции было больше параметров, было бы намного сложнее выполнять внедрение DLL.

              Если CreateRemoteThread , теперь мы можем выполнять наш код в контексте целевого процесса, что позволяет нам напрямую считывать его память, исправлять код и вставлять перехватчики. Теперь нам нужно создать DLL, которая обрабатывает перехват.

              Сборка библиотеки DLL

              Библиотеку DLL можно создать, создав проект библиотеки динамической компоновки (DLL) в Visual Studio, который правильно устанавливает всю конфигурацию сборки и включает базовый шаблон, содержащий функцию точки входа DllMain(.) библиотеки DLL.

              Выполняемый код

              Чтобы действительно запустить наш код в игре, нам нужно запустить еще один поток. Как правило, это плохая идея, поскольку во время работы DllMain блокировка загрузчика Windows удерживается. Это означает, что многие вызовы Windows, использующие загрузчик, вызовут блокировку приложения. Мы не используем здесь ни одну из этих функций, поэтому по большей части мы в безопасности. В нашем случае поток определенно необходим, так как DllMain блокирует как наш инжектор, так и вызовы API в другом месте целевого приложения. Поэтому он должен запускаться и заканчиваться быстро, не блокируя нас.

              Наша DLL просто создает новый поток, который запускает наш код при загрузке.

              Получение выходных данных консоли из библиотеки DLL

              Для целей отладки обычно полезно вести журнал в нашем приложении. К счастью, Windows API снова помог нам. Использование функции AllocConsole позволяет нам создать новое окно консоли в текущей программе. Не закрывайте это окно, так как его закрытие будет действовать как исключение SIGINT, что может привести к сбою игры, если исключения не будут обработаны должным образом.

              Подключение OpenGL

              Секрет рисования наложения в любом процессе заключается в подключении функции графической библиотеки "Конец кадра". В случае OpenGL эта функция называется wglSwapBuffers, в случае DirectX — d3dEndScene. Мы просто позволяем игре отрисовывать все свое содержимое, а когда она вызывает функцию для завершения текущего кадра, мы рисуем оверлей поверх перед вызовом фактической функции завершения кадра.

              Примечание: простой способ узнать, что использует игра, которую вы хотите перехватить, — это загрузить исполняемый файл игры в Ghidra и проверить его импорт в дереве символов.

              (RuneScape импортирует здесь как opengl32.dll, так и d3d9.dll, но, согласно вики, он использует Direct3D только в том случае, если OpenGL не работает)

              Но как вообще работает перехват?

              Перехватчик работает, перезаписывая некоторые инструкции в коде функций инструкцией jmp.

              Перед исправлением

              После исправления

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

              Теперь, когда у нас есть место для перехода к нашему хуку, нам нужно вставить его в функцию, которую мы хотим перехватить. Следующие функции позаботятся об удалении ограничений на запись кодовой страницы, вставке ловушки и повторном восстановлении исходных ограничений.

              С его помощью крючок можно вставить следующим образом:

              Рисование наложения

              Наконец, после всей этой работы мы можем приступить к рисованию оверлея imgui. Для этого мы просто загружаем исходный код imgui и компилируем его вместе с остальным кодом DLL. Imgui также нуждается в оболочке opengl для компиляции, я использовал для этого glew. Чтобы он скомпилировался, opengl32.lib и glew32s.lib должны быть связаны с DLL. opengl32.lib получает динамическую компоновку, поскольку она уже была загружена RuneScape, но glew ДОЛЖЕН быть связан статически, поскольку мы не можем загрузить другую DLL внутри внедренной DLL, не рискуя тупиковой блокировкой.

              Используя impl-файлы imgui для win32 и opengl3, найденные в папке примеров репозитория, можно создать простое наложение. Я использовал imgui_impl_win32.h и imgui_impl_opengl3.h для RuneScape, но это сильно зависит от того, что использует ваша игра.

              Во время инициализации нашего графического материала мы также перехватываем обратный вызов игры wndProc. Мы используем его для захвата событий клавиатуры и мыши и направления их в imgui. Это также позволяет нам переключать оверлей и отвлекать внимание от игры, когда оверлей присутствует.

              Заключение

              Несмотря на то, что внедрить DLL довольно просто, есть много вещей, которые могут пойти не так. Вот некоторые проблемы, с которыми я столкнулся при написании этой статьи, и способы их решения:

              Сбой LoadLibraryA с отказом в доступе

              Это произошло после добавления glew в DLL. Я попытался динамически связать glew.dll, загрузив его в свою собственную DLL. Это не работает, так как моя DLL теперь зависит от уже загруженного glew. Я исправил это, просто статически связав glew.

              Вызов любой функции в хуке вызывает segfault

              Это произошло потому, что я забыл нажать/вытолкнуть один регистр в батуте, что привело к искажению контекста при возврате к исходной функции. Я также изначально не реплицировал инструкцию, которую я перезаписал переходом, который привел к повреждению стека, когда перехваченная функция пыталась вернуться

              Imgui не получает никаких данных от мыши

              StackOverflow предложил использовать SetWindowLong для перезаписи функции wndProc. Это не сработало, и мой хук так и не был вызван. Переключение на SetWindowLongPtr вместо этого устранило проблемы.

              Читайте также: