Как можно вызвать функцию из одного сегмента кода в другом сегменте?

Я опишу задачу, с которой планирую работать. У меня есть лишь поверхностные знания по ассемблеру — изучал его для понимания работы в дебаге 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.
  • 20 ноября 2024 г. 11:23
Ответы на вопрос 2
Вы правильным образом подходите к задаче, рассматривая детали работы с ассемблером и структурой исполняемого файла. Давайте рассмотрим основные шаги для вызова одной функции из другого сегмента кода в ассемблере.

### 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 не возвращается.
Похожие вопросы