• Новые темы в этом разделе публикуются автоматически при добавлении файла в менеджер ресурсов.
    Ручное создание новых тем невозможно.
Иконка ресурса

Мануал Любая версия Ограничиваем debug для GM

Красная Королева

Путник
Модератор
Сообщения
461
Розыгрыши
0
Репутация
141
Реакции
28
Баллы
0
Мне потребовалось: IDA + Hex Rays, хекс редактор, Cheat Engine и немного знаний асма.
Ахтунг! Все числа в статье - в 16-ричной системе счисления. Где-то есть 0x, где-то нет.

Статья будет состоять из трёх частей:

1. Анализ/поиск функций
Итак, нужно запретить доступ к дебаг командам всем, кроме ГМов. Как?
У меня не было опыта редактирования ядра, но я предположил, что нужно глянуть функции, которые отвечают за управление Debug командами (лвл ап - d 2000 и подобные) и GM командами (телепорт гма - d 19 1 1 1 и подобные). Открываем ядро IDA'ой, ждём полного анализа. Слева список функций:
xqM3pHB.png

Жмём Alt-T, вбиваем в поиск Debug. С помощью Ctrl-T можно переключать на следующий результат поиска.
Через минуту я нашёл интересные функции (они были рядом):
b2pFcTF.png

Название говорит за себя. Выбираем GMCommandHandler, F5 (генерация псевдокода). Видим (у меня переименованы некоторые переменные):
AQ2UJDn.png
Строчка
PHP:
if ( (param1  222) && param1 != 19 )
палит всю функцию. Я вспомнил, что для гма доступны как раз команды d 19, d 201, d 202, .., d 222. Видно, что идёт запись в лог, если параметр неверный. Значит мы на верном пути.
Смотрим дальше. Должна быть проверка на то, ГМ ли это вызывает. Тут одно из двух: либо проверка идёт перед вызовом функции (где-то в дебрях кода), либо внутри функции.
Я безуспешно проверил все функции CheckGMPrivilege, HasGMPrivilege, которых оказалось полно в ядре, но ни одна не вызывалась при использовании этих команд. (Десктопная убунту + IDA, приаттаченная к процессу. Спасибо Максимиану за подсказку).
Всё оказалось проще. Сразу после записи в лог идёт строчка
PHP:
if ( *(a1 + 0x48) )
Очевидно, что a1 - указатель на структуру перса, который юзает команду d num, а +0x48 - это смещение до GM флага или структуры с информацией о GM правах. В любом случае, если это значение 0, то идёт выход из функции.
В асм коде эта проверка выглядит так:
WwLQ1j0.png
Если 0, то прыжок не идёт (jnz - jump if not zero). Записали, назовём это IsCharGM() (просто для себя)

Переходим к функции DebugCommandHandler, F5. Начало у неё такое:
JGGpWWG.png
Опять же, переменные переименованы, так как я вводил свои структуры. Красным выделена строчка, которая вызывает функцию GLog::log(), которая записывает куда-то что-то. Вроде и полезная.. Но нам ведь надо всунуть нашу найденную проверку IsCharGM(), а для неё еще место нужно. Поэтому я принял решение стереть эту функцию нафиг (ВОТ ЭТО ДЫРА!!1)
Смотрим асм код:
tGMi0Wa.png
Зеленое - махинации с указателями на локальный/глобальный стек, трогать нельзя ни в коем случае. Красным - функция GLog::log(). Смотрим адрес начала этой функции: 0x812527E и конец: 0x812529C минус один == 812529B.
Аргументы функции DebugCommandHandler:
JT8oUc1.png
По счастливой случайности, первый параметр оказался как раз тем самым указателем на структуру перса, вызывающего команду (поверьте на слово, проверил бряками в иде). Это очень сильно упрощает задачу. Почему? Об этом во второй части.

2. Пишем код Что мы знаем?
а) У нас есть 0x1E (30 штук) байт для проверки гм прав у перса (0x1E - вместо затёртой, в будущем, функции)
б) В функцию DebugCommandHandler передаётся указатель на структуру перса

Как должен примерно выглядеть код проверки? На си:
PHP:
if (*(a1+0x48)) return 0;
На асме:
mov eax, [ebp+8h] ; в регистр eax суём наш указатель на структуру. Он находится в [ebp+8], потому что cmp [eax+48h], 00 ; сравниваем значение по адресу eax+48 с нулём
jz %адрес выхода с функции%

(jz %адрес% можно заменить на mov eax, %адрес% / jz eax, но мой "генератор" опкода отказался работать с "jz %регистр%")

Теперь поэтапно:
а) Адрес выхода с функции? Листаем функцию в самый низ, видим там:
ZauxcPF.png
Зеленое - адрес выхода с функции. 0x812B8D1
б) Теперь нужно этот асм-код преобразовать в опкод. Я делал это с помощью Cheat Engine. На первый взгляд нет проблем, просто преобразовать 3 команды в байт-код. Ан нет!
Команда jz %ptr% на самом деле опознаётся компьютером, как jz +N, где N - разность между адресом назначения и адресом команды, следующей сразу за прыжком. Вот такая хитрая относительная адресная арифметика.
Поэтому:
I) Переводим первые две команды в опкод:
6Bg6OEc.png
8B 45 08 83 78 48 00 - 7 байт в сумме
II) Возвращаемся к записанным ранее адресам: 0x812527E (адрес начала функции, которая будет стёрта). Прибавляем 7 байт. 0x812527E+7 == 0x8125285. Значит по адресу 0x8125285 будет лежать команда jz +N. Она занимает 6 байт (опкод самого jz + 4 байта на N). Значит 0x8125285 + 6 == 0x812528B.
III) Теперь вычитаем из конечного адрес (выхода с функции 0x812B8D1) полученный адрес (0x812528B) == 0x6646.
Вот и всё. Теперь спокойно переводим команду jz +6646 в байты: 0F 84 46 66 00 00
Весь код: 8B 45 08 83 78 48 00 0F 84 46 66 00 00

3. Замена кода
Открываем ядро в хекс редакторе (мой любимый - 010 Editor). В файле все адреса смещены на 0x8048000 относительно того, что в памяти, поэтому берём адрес функции для затирания: 812527E и вычитаем 8048000, получаем DD27E.
Переходим по этому адресу (Ctrl-G), видим
YvPUJk8.png
Затираем 0x1E (30 в десятичной) байт. Не нулями, а байтами по 90 (nop - no operation). Вообще, код лучше не затирать нулями никогда.
EgrZEfS.png
Затёрли, теперь вбиваем наш код:
ePNH8M7.png
Сохраняем.
Поздравляю, вы великолепны.

Дополнения
1. Скорее всего (это никак не меняет сути гайда), там не указатель на структуру персонажа, а указатель на объект. И функции - это просто методы класса, которые выполняют действия над этим объектом. С другой стороны, обычно указатель на объект передаётся в ecx, поэтому могу и ошибаться.
2. Дыр быть не может. Если вы прочитали гайд полностью, это должно быть очевидно. Если игрок не может использовать ГМ команды, то он не может использовать дебаг команды.
3. Минус - не будет функции, которая что-то там логгирует.
4. Возможно, я индус, и можно было сделать всё проще, но я привык редактировать код, а не копаться в каких-нибудь xml и искать нужные параметры.
5. Я не описал (и не буду) моменты, как я добывал значения переменных с помощью бряков в ИДЕ, иначе это не влезет в одно сообщение. Да и в гугле полно информации на эту тему.
Запрещено копировать материал/лепить патчи без разрешения автора. (c) int 3

Если есть вопросы - задавайте, с радостью отвечу.
 

Назад
Сверху Снизу