Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #64, МАРТ 2006 г.

защита игр от взлома

КРИС КАСПЕРСКИ АКА МЫЩЪХ

Спецвыпуск: Хакер, номер #064, стр. 064-066-14


Листинг

пример программы, вызывающей функции по указателю

sub_sub_demo(int a, void *p, void *d)

{

// printf(«sub_sub_demo\n»);

if (--a) return ((int(*)(int, void*, void*))p)(a, p, d);

return 0;

}

sub_demo(int a, void *p, void *d)

{

// printf(«sub_demo\n»);

if (--a) return ((int(*)(int, void*, void*))d)(a, p, d);

return 0;

}

demo(int a, void *p, void *d)

{

// printf(«demo\n»);

((int(*)(int, void*, void *))p)(a, p, d);

}

main()

{

demo(0x69,sub_demo, sub_sub_demo);

}

В исходном тесте все понятно. Функция main вызывает функцию demo, передавая ей указатели на sub_demo и sub_demo, которые поочередно вызывают друг друга, каждый раз уменьшая счетчик на единицу. Короче, мы имеем цикл. Но какой! Ты оцени его дизассемблерный код.

Листинг

дизассемблерный листинг, демонстрирующий мощь косвенного вызова функций

.text:00401000 loc_401000: ; DATA XREF: _maino

.text:00401000 mov ecx, [esp+4]

.text:00401004 dec ecx

.text:00401005 jz short loc_401018

.text:00401007 mov eax, [esp+0Ch]

.text:0040100B push eax

.text:0040100C mov eax, [esp+0Ch]

.text:00401010 push eax

.text:00401011 push ecx

.text:00401012 call eax

.text:00401014 add esp, 0Ch

.text:00401017 retn

.text:00401020

.text:00401020 loc_401020: ; DATA XREF: _main+5o

.text:00401020 mov ecx, [esp+4]

.text:00401024 dec ecx

.text:00401025 jz short loc_401038

.text:00401027 mov eax, [esp+0Ch]

.text:0040102B mov edx, [esp+8]

.text:0040102F push eax

.text:00401030 push edx

.text:00401031 push ecx

.text:00401032 call eax

.text:00401034 add esp, 0Ch

.text:00401037 retn

.text:00401040

.text:00401060 _main proc near ; CODE XREF: start+AF p

.text:00401060 push offset loc_401000

.text:00401065 push offset loc_401020

.text:0040106A push 69h

.text:0040106C call sub_401040

.text:00401071 add esp, 0Ch

.text:00401074 retn

.text:00401074 _main endp

IDA Pro не смог распознать функции, хотя восстановил перекрестные ссылки на main — они еще ни о чем не говорят! Функции sub_demo и sub_sub_demo вызываются совсем не оттуда. Возьмем «функцию» loc_401000. Она принимает указатель в качестве аргумента и тут же вызывает его. А что это за указатель? Да хвост его знает! Перекрестной ссылки на материнскую функцию же нет. Единственный способ установить истину — проанализировать всю цепочку вызовов с самого начала программы, с функции main, но слишком трудоемко, так что даже не обсуждается (особенно если ломать реальную программу). Даже в таком случае приходится постоянно следить за указателями, которые пляшут как кони, причем, даже если развяжешь себе пупок, не сможешь понять, что находится в них в каждый конкретный момент...

Защита будет значительно усилена, если реализовать модель Маркова — функцию, возвращающую указатель на функцию. Такой прием программирования не слишком популярен, так как непривычен и лишен языковой поддержки. Язык С вообще не позволяет объявлять функции, возвращающие указатели на функции, поскольку такие определения рекурсивны и программисту приходится возиться с постоянным преобразованием типов, что не слишком украшает программу и является потенциальным рассадником ошибок. Тем не менее на автоматическое дизассемблирование моделей Маркова не способен ни один дизассемблер, в том числе IDA PRO.

Назад на стр. 064-066-13  Содержание  Вперед на стр. 064-066-15