Я опишу задачу, с которой планирую работать. У меня есть лишь поверхностные знания по ассемблеру — изучал его для понимания работы в дебаге IDA, и, хотя в целом логика мне ясна, я хотел бы решить свою проблему именно с помощью ассемблера. <b>Поэтому инъекцию dll рассматривать не стоит!</b> В наличии имеется исполняемый файл игры, который содержит функции для импорта и экспорта текстур. Я хотел бы научить игру использовать эти функции. Для анализа exe файла я использовал IDA PRO 9 и планировал изменять ассемблерный код там. Если есть более удобные альтернативы для работы с ассемблером, то буду признателен за рекомендации. Изучив структуру exe файла, я пришел к следующему выводу: игра использует собственный аналог препроцессора C/C++, созданный разработчиками. Это не настоящие препроцессорные команды! В папке с игрой есть файл name.ini, в котором заданы константы для ботов, уровней сложности и других параметров, используя синтаксис препроцессора, такой как #define, #include, #if и тому подобное. Например: <pre><code class="cpp">// file.ini // Cars #define OFFROAD 0 #define HIGHWAY 1 // и т.д. // Game difficulty #define EASY 1 #define NORMAL 2 // и т.д.</code></pre> Чтением этих файлов занимается "функция-парсер-компилятор" под названием gameHandlePreproc. Она проверяет ключевые слова (#define, #include и пр.), сверяет их с допустимыми значениями и определяет, какую функцию нужно вызвать. Я хотел бы добавить в этот шаблон своё собственное ключевое слово (например, #skinconverter?), чтобы запускать функции импорта и экспорта. Если я правильно понял, внедрить свою функцию в середину существующих функций невозможно, так как все адреса сегмента уже заняты, а сдвиг стека приведет к поломке. Я предполагаю, что решение заключается в создании нового сегмента, где я смогу записать свои команды. Для этого я ознакомился с таблицей сегментов в IDA.
Вы правильным образом подходите к задаче, рассматривая детали работы с ассемблером и структурой исполняемого файла. Давайте рассмотрим основные шаги для вызова одной функции из другого сегмента кода в ассемблере. ### 1. Определение функции Прежде всего, вам нужно будет определить вашу новую функцию. Например, вы можете использовать следующий шаблон: ```asm section .text global myFunction myFunction: ; Ваш код здесь ret ``` ### 2. Добавление нового сегмента Как вы упомянули, возможно создание нового сегмента для вашей функции. В IDA это можно сделать путем: 1. Перейдите в окно сегментов и создайте новый сегмент. 2. Задайте ему имя (например, `.myseg`) и укажите его адрес. 3. В этом новом сегменте разместите вашу функцию. ### 3. Вызов функции из другого сегмента После того как ваша функция будет создана и готова к вызову, вам нужно будет обеспечить корректный переход к ней. В Асемблере это можно сделать с помощью инструкции `call`. Пример вызова функции может выглядеть так: ```asm section .text extern myFunction ; Объявляем функцию как внешнюю someFunction: ; Предварительные действия call myFunction ; Вызов вашей функции ; Остальной код ret ``` ### 4. Обработка переходов и стека При вызове функции важно правильно обрабатывать стек. Если ваша функция использует какие-либо параметры, не забудьте правильно их передать через стек или регистры, в зависимости от используемого соглашения о вызовах (calling convention). ### 5. Изменение кода парсера `gameHandlePreproc` Теперь вам нужно найти и модифицировать функцию `gameHandlePreproc`, чтобы она распознавала ваше новое ключевое слово (`#skinconverter`) и вызывала вашу функцию. Примерно это может выглядеть так: ```asm gameHandlePreproc: ; Предыдущий код cmp eax, #skinconverter_key ; Сравниваем ключевое слово je call_myFunction ; Если найдено, переходим к вызову вашей функции ; Остальной код ret call_myFunction: call myFunction ; Вызов вашей функции ret ``` ### 6. Компиляция и тестирование После внесения всех изменений скомпилируйте и протестируйте ваш исполняемый файл. Убедитесь, что новая функция корректно вызывается при обработке нового ключевого слова. ### Важные заметки: - Обязательно сделайте резервную копию оригинального файла, прежде чем вносить изменения. - В зависимости от архитектуры и платформы разные моменты могут иметь разное поведение, поэтому убедитесь, что вы хорошо понимаете контекст выполнения (например, 32-бит или 64-битная архитектура). - Если у вас есть доступ к отладчику (например, GDB), это будет полезно для проверки правильности выполнения вашего кода. ### Инструменты для работы с ассемблером: - **IDA Pro** - вы уже используете это мощное средство для статического анализа и редактирования кода. - **Radare2** - это более доступное свободное ПО для анализа и редактирования, поддерживающее множество форматов. - **Ghidra** - еще один инструмент для реверс-инжиниринга, который стал популярным за свои функции и гибкость. С учетом всех этих аспектов вы сможете успешно реализовать вашу идею. Удачи в ваших исследованиях!
// Получаю ошибку:
7FFF0000: The instruction at 0x7FFF0000 referenced memory at 0x7FFF0000. The memory could not be executed -> 7FFF0000 (exc.code c0000005, tid 6332)
В чем проблема?
По видимому в том, что вызвать функцию получилось, но память по адресу7FFF0000
-- не исполняемая.
Как починить?
Начать с того, что сделать память по адресу7FFF0000
исполняемой. После этого вывод в лог должен заработать, но будет падать после него, потому что функцияmySuperFunction
не возвращается.