Русское сообщество по скриптингу

Сигнатуры функций

Статьи или фрагменты кода для новичков и уже опытных скриптеров по Metamod.
Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

В данном разделе форума разрешено создавать темы, касающие только обучающему материалу по Metamod.

Сигнатуры функций

Сообщение 6a6kin » 01 фев 2012, 03:50

Автор: 6a6kin

Содержание:
  • I. Основы
  • II. Создание шаблона сигнатуры функции
  • Приложение А. Поиск необходимой функции

I. Основы
Знаете ли вы, во что превращается код программы на C++ или ассемблере после компиляции? Тот, кто когда-нибудь открывал исполняемые файлы текстовым редактором, видел там только кучу непонятных символов. На самом деле, это последовательность байт, в которую превратилась ваша программа. Все дело в том, что процессор ничего знает о С++, классах, объектах, он даже не видит разницы между положительными и отрицательными числами. Процессор умеет выполнять только микрокоманды, вроде сложения или деления. Эти микрокоманды представляют собой небольшие последовательности байт, из которых и состоит программа. Считывая байты, процессор распознает микрокоманды и выполняет их.

Однако исполняемые файлы состоят не только из микрокоманд. Как в Windows, так и в GNU\Linux программа и данные, с которыми она работает, содержаться в специальной оболочке, которая определяет формат файла. В Windows это PE формат, а в GNU\Linux - ELF формат. Каждый файл содержит заголовок, которые сообщает о том, какой формат у этого файла.

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

Процессор не знает, где конец функции, где текстовые данные, а где микрокоманды. Управление работой процессора выполняется с помощью самих микрокоманд. Например, прямо посреди кода можно разместить текст "Hello, brah", но при этом добавить микрокоманды, указывающие процессору, что данную последовательность байт считывать не нужно. Это означает, что функции сами регулируют, где они заканчиваются и никаких разделителей между ними нет. Микрокоманды функций идут друг за другом.

Так что же представляют из себя микрокоманды? Условно разделим последовательность байт микрокоманды на следующие части: опкод, операнды. На самом деле, строение микрокоманд более сложное, но для понимания хватит и такого представления. Опкод микрокоманды - её уникальное имя, причем чаще всего, одна асемблерная команда может соответствовать нескольким машинным, что сделано для удобства. Операнды могут быть представлены в виде непосредственных значений, адресов, регистров. Иногда операнд в виде регистра может формировать микрокоманду с другим опкодом. Адрес представляет собой смещение относительно начала файла, в котором содержится функция.

И вот мы подошли к теме нашей статьи. Что такое сигнатура функции? Общепринято сигнатурой функции считать уникальное имя функции, позволяющее транслятороу распознать её среди других функций. В GNU\Linux данные имена называются символами. И вроде бы все хорошо, но вот иногда эти имена исключают из программы и найти функцию по этому имени невозможно.
Поэтому в контексте наших статей, сигнатура функции - это любая уникальная последовательность байт(которые представляют собой набор микрокоманд функции), существующая только в пределах этой функции. Причем вся последовательность микрокоманд функции также является её сигнатурой. Возникает вопрос: почему бы просто не искать последовательность микрокоманд функции целиком? Во-первых, размер функции может быть очень большим. А во-вторых, как уже обсуждалось ранее, в качестве операндов микрокоманд могут использоваться адреса. И эти адреса могут быть изменены массой различных причин. Именно поэтому необходимо создать шаблон сигнатуры функции, который можно будет использовать для поиска функции в "изменчивой среде".

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

II. Создание шаблона сигнатуры функции
Шаблон состоит из двух частей: сигнатуры и маски. Сигнатурой является та самая уникальная последовательность байт. Маска указывает на то, какие части сигнатуры могут изменятся, чтобы игнорировать их при поиске.

Для получения нужной нам информации будем использовать Interactive Disassemler(IDA). После открытия исследуемой библиотеки, необходимо включить показ кодов микрокоманд. В меню Options->General... во вкладке Disassembly в поле Number of opcode bytes поставьте 10. После чего слева от ассемблерных микрокоманд появятся их машинное представление.

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

Сигнатурой функции является та самая уникальная последовательность байт. Просто скопируйте их из дизассемблера. Главное условие - эта последовательность должна быть уникальна в пределах программы. Я использую 32 байта в качестве сигнатуры, но размер никак не ограничен. Сразу следует отметить, что это должны быть именно ПЕРВЫЕ n байт, так как адресом является точка входа функции, а это и есть её начало. Это упрощает поиск.

Далее нужно составить маску сигнатуры, тем самым исключив динамические части. Адреса, как операнды микрокоманд, изменяются всегда. На самом деле, только их исключать из поиска и имеет смысл. Обычно это микрокоманды:
  • jmp
  • call
  • условные переходы jXX(jc, jnz, jbne etc.)
  • lea
  • mov
Определимть использование адреса легко - размер микрокоманды от 5 байт и выше(в 32-разрядных системах размер адреса равен 4 байтам, с этим связано ограничение на 4 ГиБ ОЗУ). Микрокоманды, работающие с непосредственными значениями и\или регистрами, могут быть больше, чем 5 байт, однако не нуждаются в исключении. Маска представляет собой строку, в которой байты, содержащие динамические значения отмечены знаками вопроса('?'), а все остальные 'x' или любым другим.

Рассмотрим небольшой пример. После кода идут символы маски, которые соответствуют кодам микрокоманд.
Код: Выделить всё
; пролог функции не нуждающийся в исключении
.text:01D6C2F0 55                      push    ebp
.text:01D6C2F1 8B EC                   mov     ebp, esp
.text:01D6C2F3 56                      push    esi
x
xx
x

;обычные операции с регистрами
.text:01D6C2F4 8B 75 08                mov     esi, [ebp+arg_0]
.text:01D6C2F7 56                      push    esi
xxx
x

;вызов функции, первый байт - опкод, остальные 4 - адрес, его мы помечаем знаками вопроса
.text:01D6C2F8 E8 B3 08 00 00          call    sub_1D6CBB0
x????

;обычные операции с регистрами
.text:01D6C2FD 83 C4 04                add     esp, 4
.text:01D6C300 83 F8 01                cmp     eax, 1
xxx
xxx

;короткий переход не использует адрес, лишь смещение относительно текущего адреса
.text:01D6C303 7C 38                   jl      short loc_1D6C33D
xx

;сравнение регистра eax с адресом
;первый байт - опкод, второй - регистр eax, остальные - адрес
.text:01D6C305 3B 05 28 6F 13 02       cmp     eax, dword_2136F28
xx????

;опять короткий переход
.text:01D6C30B 7F 30                   jg      short loc_1D6C33D
xx

;перемещение в регистр адреса
;первый байт - опкод, второй - регистр edx, остальные - адрес
.text:01D6C30D 8B 15 24 6F 13 02       mov     edx, dword_2136F24
xx????

;обычные операции с регистрами и непосредственными значениями
.text:01D6C313 8D 0C 80                lea     ecx, [eax+eax*4]
.text:01D6C316 C1 E1 09                shl     ecx, 9
.text:01D6C319 03 C8                   add     ecx, eax
.text:01D6C31B 6A 39                   push    39h
xxx
xxx
xx
xx

;обратите внимание, код микрокоманды занимает 7 байт, но не использует адреса
;это значит что исключать из поиска ничего не нужно
.text:01D6C31D 8D 84 CA F8 AF FF FF    lea     eax, [edx+ecx*8-5008h]
xxxxxxx

;опять опычные операции
.text:01D6C324 8D 70 7C                lea     esi, [eax+7Ch]
.text:01D6C327 56                      push    esi
xxx
x

;вызов функции, первый байт - опкод, остальные - адрес
.text:01D6C328 E8 F3 9E FC FF          call    sub_1D36220
x????

В итоге мы получим:
Код: Выделить всё
сигнатура: "55 8B EC 56 8B 75 08 56 E8 B3 08 00 00 83 C4 04 83 F8 01 7C 38 3B 05 28 6F 13 02 7F 30 8B 15 24 6F 13 02 8D 0C 80 C1 E1 09 03 C8 6A 39 8D 84 CA F8 AF FF FF 8D 70 7C 56 E8 F3 9E FC FF"
маска: "xxxxxxxxx????xxxxxxxxxx????xxxx????xxxxxxxxxxxxxxxxxxxxxx????"

Чем больше тренируетесь, тем проще. У меня на поиск и создание шаблона уходит не более, чем 3 минуты.

В дополнение о символах. В GNU\Linux библиотеках hlds присутствуют символы функций, с помощью которых можно искать функции. Рекомендуется именно так и делать, так как изменение функции не повлечет за собой изменение символа(исключая случаи, когда изменяются аргументы - обычно символы включают имя функции и её аргументы). В Windows библиотеках символы отсутствуют.

Приложение А. Поиск необходимой функции
Еще одно узкое место - найти дизассемблированный код функции в IDA. Вот несколько советов:
  • Ищите сначала в GNU\Linux библиотеках. Большинство функций можно найти по названию, так как ч библиотеках присутствуют символические имена.
  • Если вы не знаете имя функции, ищите ближайшие названия, относящиеся к этой функции, строки, названия кваров, переменных.
  • Найденное название функции является символом, который можно использовать для поиска в GNU\Linux библиотеках.
  • Чтобы найти эквивалентную функцию в Windows библиотеке, придется постараться. В Windows библиотеках отсутствуют символы, поэтому нужно искать обходные пути. Тут так же можно найти функцию по используемой строковой константе, кварам.
  • Есть интересный способ: если функция использует необычный размер локальных переменных, можно найти все вхождения опкода выделения места в стеке для локальных переменных - sub esp, xx. Далее ищите наиболее правдоподобный размер выделенного места и проверяете, нужная ли это вам функция.
  • Бывают случаи, что функция в GNU\Linux библиотеке обычная, а в Windows - подставляемая. Это значит, что код функции подставляется в место вызова и отдельной функции не существует.
  • Если вы переводите дизассемблированный код в Сишный, ориентироваться стоит на Windows библиотеки. Я не знаю точной причины, возможно gcc так хорошо оптимизирует, а может, HEX-Rays плохо расшифровывает, но Windows функции расшифровываются лучше, более структурированный выходит код. Расшифруйте обе версии функции, Windows версия покажет структуру, а GNU\Linux - название используемых функций.

Вы должны зарегистрироваться, чтобы видеть ссылки.
This work is licensed under a Вы должны зарегистрироваться, чтобы видеть ссылки..
Последний раз редактировалось 6a6kin 07 окт 2013, 14:57, всего редактировалось 2 раз(а).
На заказ не пишу.
Аватара пользователя
6a6kin
Скриптер
 
Сообщения: 332
Зарегистрирован: 09 мар 2010, 16:40
Благодарил (а): 38 раз.
Поблагодарили: 278 раз.

Re: Сигнатуры функций

Сообщение KORD_12.7 » 01 фев 2012, 04:28

А можно пример хука/вызова функции по сигнатуре?

_http://aghl.ru/ - Half-Life и Adrenaline Gamer: за пределами возможного
Аватара пользователя
KORD_12.7
Скриптер
 
Сообщения: 298
Зарегистрирован: 28 сен 2009, 10:14
Откуда: Владивосток
Благодарил (а): 142 раз.
Поблагодарили: 257 раз.
Опыт программирования: Больше трех лет
Языки программирования: Half-Life
Opposing Force
Adrenaline Gamer
Counter-Strike

Re: Сигнатуры функций

Сообщение 6a6kin » 01 фев 2012, 11:56

Это в следующих статьях.
На заказ не пишу.
Аватара пользователя
6a6kin
Скриптер
 
Сообщения: 332
Зарегистрирован: 09 мар 2010, 16:40
Благодарил (а): 38 раз.
Поблагодарили: 278 раз.

Re: Сигнатуры функций

Сообщение 6a6kin » 01 фев 2012, 16:51

И еще кое-что: те, кто изучает swds - в IDA можно редактировать названия функций, констант, интерпретировать память как структуры и все это сохранять в базе. Если вы этим занимаетесь - пишите мне через ЛС.
На заказ не пишу.
Аватара пользователя
6a6kin
Скриптер
 
Сообщения: 332
Зарегистрирован: 09 мар 2010, 16:40
Благодарил (а): 38 раз.
Поблагодарили: 278 раз.

Re: Сигнатуры функций

Сообщение Arwel » 01 фев 2012, 20:02

Спасибо. Я так понял если в этом разобратся, то можно, например, изменить максимальное количество слотов? Или не правильно понял ...
[spoiler]Чувак ты крут![/spoiler]
Аватара пользователя
Arwel
 
Сообщения: 34
Зарегистрирован: 09 сен 2011, 14:13
Благодарил (а): 5 раз.
Поблагодарили: 4 раз.
Опыт программирования: Около 6 месяцев
Языки программирования: Counter-Strike 1.6

Re: Сигнатуры функций

Сообщение 6a6kin » 01 фев 2012, 22:02

Сделать можно все, что угодно. Важно то, сколько усилий придется потратить.
На заказ не пишу.
Аватара пользователя
6a6kin
Скриптер
 
Сообщения: 332
Зарегистрирован: 09 мар 2010, 16:40
Благодарил (а): 38 раз.
Поблагодарили: 278 раз.

Re: Сигнатуры функций

Сообщение noo00oob » 02 фев 2012, 20:38

Arwel писал(а):Спасибо. Я так понял если в этом разобратся, то можно, например, изменить максимальное количество слотов? Или не правильно понял ...

Даже если и извратится, максимальное колличество слотов редактированием одного лишь сервера не изменить.
Один фрукт, страдающий недостачей времени, нашел его ради меня любимого и писал(а):
noo00oob, зачем родился на свет вообще? срать на форумах это понятно.. больше изъеба не найти как бэ? а то, что ты недоношенная скотина, сдерживайся, детка.
noo00oob
 
Сообщения: 1061
Зарегистрирован: 09 янв 2010, 21:52
Благодарил (а): 258 раз.
Поблагодарили: 394 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Half-Life

Re: Сигнатуры функций

Сообщение 6a6kin » 02 фев 2012, 20:57

noo00oob, почему?
На заказ не пишу.
Аватара пользователя
6a6kin
Скриптер
 
Сообщения: 332
Зарегистрирован: 09 мар 2010, 16:40
Благодарил (а): 38 раз.
Поблагодарили: 278 раз.

Re: Сигнатуры функций

Сообщение Fedcomp » 02 фев 2012, 21:03

потому что еще есть клиент.
Не помогаю в ЛС - есть форум.
Плагины тоже не пишу, на форуме достаточно хороших скриптеров.


"я ставлю зависимости потому что мне приятно" - subb98 @ 2017
Аватара пользователя
Fedcomp
Администратор
 
Сообщения: 4936
Зарегистрирован: 28 авг 2009, 20:47
Благодарил (а): 813 раз.
Поблагодарили: 1317 раз.
Языки программирования: =>
pawn / php / python / ruby
javascript / rust

Re: Сигнатуры функций

Сообщение noo00oob » 02 фев 2012, 21:38

6a6kin писал(а):noo00oob, почему?

Даже если не лезть в сам движок - в одном только client_dll куча ограничений. Вот к примеру:
Код: Выделить всё
extern hud_player_info_t   g_PlayerInfoList[MAX_PLAYERS+1];      // player info from the engine
extern extra_player_info_t  g_PlayerExtraInfo[MAX_PLAYERS+1];   // additional player info sent directly to the client dll
extern team_info_t         g_TeamInfo[MAX_TEAMS+1];
extern int               g_IsSpectator[MAX_PLAYERS+1];

Эти данные используются в любом месте, где надо узнать ник игрока, цвет его команды и тд( чат, сообщение о смерти ). Но самое для нас обидное это то, что таблица очков не может отображать > 32 игроков.
Один фрукт, страдающий недостачей времени, нашел его ради меня любимого и писал(а):
noo00oob, зачем родился на свет вообще? срать на форумах это понятно.. больше изъеба не найти как бэ? а то, что ты недоношенная скотина, сдерживайся, детка.
noo00oob
 
Сообщения: 1061
Зарегистрирован: 09 янв 2010, 21:52
Благодарил (а): 258 раз.
Поблагодарили: 394 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Half-Life

След.

Вернуться в Статьи / фрагменты кода

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 8