Перейти к содержанию

Статья: Вызов API-функций через Code-injection.


Рекомендуемые сообщения

Date: 30.11.2011

Author: keng

Tools needed: Cheat Engine 6.1, Microsoft Notepad

Не знаю точно, куда запостить, если что - пните в нужную сторону.

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

1. Читаем статью на вики. Вдумчиво.

2. Понимаем, что это, говоря по-человечески, функция (а точнее, их набор), при помощи которой все Windows-приложения (и игры в том числе) контактируют между собой и взаимодействуют с системой. Простые примеры:

1. CreateFile. Создаёт файл. Удобно? Да. И из любой программы можно вызвать - создастся файл.

2. MessageBox. Показывает окошко с некоторой информацией и кнопками "Ok", "Cancel" и так далее, на выбор. Позволяет добиться какой-то реакции от пользователя. Тоже крутая штука.

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

Тэк-с, теорией немного пропитались, пойдём дальше. Тренироваться будем на всеми любимом Блокноте.

Открываем блокнот (Пуск -> Выполнить -> notepad.exe):

25uthn4.jpg

Открываем Cheat Engine (надеюсь, не нужно показывать, как она выглядит). Присоединяемся к процессу notepad.exe и начинаем думать. В программе есть меню. В меню "Файл" есть пункт "Сохранить как", который вызывает диалоговое окошко, позволяющее сохранить (!) текущий документ. В выполнение этой-то функции мы и внедрим свой замечательный код. Делаем поиск текстового значения, вот так:

1o3e3k.jpg

Находим один-единственный адрес, хранящий эту текстовую строку. Добавляем его в таблицу адресов, жмём правой кнопкой и выбираем опцию "Find out what accessess this address" (Найти, что обращается к этому адресу). Выскакивает окошко отладчика, возвращаемся в блокнот и пробуем сохранить наш документ. В отладчике видим примерно вот такую картину:

14kilc2.jpg

Первая функция вызвалась обратилась к нашему адресу аж 8 раз, а вот остальные - по одному. Выбираем одну из них (на свой вкус, я взял вторую), жмём кнопку "Show disassembler" (Показать дизассемблер). Открывается окно дизассемблера, в нём ничего не трогаем и идём в меню Tools - Auto Assembler (Инструменты - Автоассемблер), или жмём Ctrl+A. В окне автоассемблера набиваем следующий код:

Ага, как же. Ещё немного теории!

В ассемблере API-функции вызываются вот таким вот образом:

push arg2
push arg1
push arg0
call func

Командами push мы запихиваем в стек аргументы функции (если нужны), так как это стек - запихиваем их с конца (справа налево), после чего командой call func вызываем функцию, где func - имя или адрес (в 16-й системе счисления, ибо компьютер - глуп и не понимает привычных нам арабских цифр).

Попробуем вызвать функцию Beep. Кликом по названию идём в MSDN и читаем о ней статью, а кто не знает английского или не любит читать (:(), для тех поясняю - эта функция заставляет встроенный в компьютер динамик пищать, а в качестве аргументов принимает частоту и длительность сигнала. Итак, нам остаётся выяснить адрес функции, чтобы вызвать её из блокнота, так как все эти функции хранятся во внешних dll-библиотеках и адреса вызова для разных программ могут быть разные, ибо библиотеки эти подгружаются динамически.

Идём в отладчик и выбираем меню View - Enumerate DLL's and Symbols (Вид - Пронумеровать ДЛЛ'ки и Символы). Получаем вот такое окно:

350o1fn.jpg

Жмём правой кнопкой - Find (Найти) - вводим слово Beep и в выделенной строчке получаем адрес вызова:

2rc4tbs.jpg

Возвращаемся в Авто ассемблер и нашему коду! В меню выбираем Template - Code Injection (Шаблон - Инъекция кода) и пишем вот так:

alloc(newmem,2048) //2kb should be enough
label(returnhere)
label(originalcode)
label(exit)

newmem: //this is allocated memory, you have read,write,execute access
//place your code here

originalcode:
mov eax,[esi+ecx*4-1C]
mov [edi+ecx*4-1C],eax
//наш код
pushad
push 10
push ff
call 75A76DF3
popad

exit:
jmp returnhere

"msvcrt.dll"+9CCA:
jmp newmem
nop
nop
nop
returnhere:

Разберу поподробней то, что мы написали. Вот этот кусочек:

pushad
push 10
push ff
call 75A76DF3
popad

Pushad - сохраняет текущие значения всех регистров, чтобы мы чего лишнего не поломали нашим хитрым кодом.

push 10 и push ff - толкаем в стек длительность (16 мсек) и частоту (255 Гц) в качестве аргументов нашей функции. Напомню прототип функции:

Beep(Frequency, Duration)

где Frequency - это частота, а Duration - это длительность.

Командой call мы вызваем, собственно, нашу пищалку-пищалочку, а затем popad-ом возвращаем значения регистров на свои места.

Всё дописали, перепроверили, жмём Execute (Выполнить), пробуем сохранить файл - слышим пищание. Круто!

...но зачем это может быть нужно?

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

На этом всё. :)

UP: Прилепил к шапке статью в виде PDF:

WinApiInjection_by_keng.zip

  • Плюс 4
Ссылка на комментарий
Поделиться на другие сайты

Это все круто, за исключением пары моментов, о которых не было упомянуто - Dll-ка с необходимой функцией может отсутствовать в таблице импорта игры (да, случается и такое) и, как следствие, игрой не подгружаться. В этом случае инъекцией надо подгружать библиотеку в пространство игры, затем находить в ней необходимую функцию, и затем только вызывать ее.

Ссылка на комментарий
Поделиться на другие сайты

Это все круто, за исключением пары моментов, о которых не было упомянуто - Dll-ка с необходимой функцией может отсутствовать в таблице импорта игры (да, случается и такое) и, как следствие, игрой не подгружаться. В этом случае инъекцией надо подгружать библиотеку в пространство игры, затем находить в ней необходимую функцию, и затем только вызывать ее.

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

Ссылка на комментарий
Поделиться на другие сайты

  • 8 месяцев спустя...

Так как создать строку в CE?

В дизассемблере ASCII "TEST",0

Запиши в память, побайтно, а потом адрес первого байта и запихивай в стек. :D

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.