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

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

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

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


глобальные инициализированные переменные

Предлагаю альтернативный путь — не препятствовать снятию дампа, а сделать полученный образ бесполезным, для чего достаточно использовать глобальные инициализированные переменные, «перебивая» их новыми значениями.

Листинг

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

char *p = 0; // глобальная переменная 1

DWORD my_icon = MY_ICON_ID; // глобальная переменная 2

if (!p) p = (char*) malloc(MEM_SIZE);

my_icon = (DWORD) LoadIcon (hInstance, my_icon);

Задумайся, что произойдет, если сбросить дамп с работающей программы. В переменной p окажется указатель на когда-то выделенный блок памяти, условие (!p) обломится и новая память не будет (!) выделена, а при обращении по старому указателю произойдет исключение. Другими словами, хакер уже не сможет изготовить исполняемый файл из дампа! Как минимум, придется восстановить значения всех глобальных переменных — геморрой :(. Ладно, изготовить исполняемый файл из дампа нельзя, но, может, дизассемблировать его? А вот и нельзя...

После выполнения функции LoadIcon переменная my_icon будет содержать не идентификатор иконки, а ее обработчик. Хакер не сможет установить, что это за иконка (строка, битмап или другой ресурс), и ему придется обращаться к отладчику, противостоять которому намного проще, чем дизассемблеру. Кстати, такой прием экономит память и широко используется во многих программах. Например, в стандартном «Блокноте» — попробуй снять с него дамп и обломайся :).

стартовый код

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

Листинг

типичный представитель стартового кода (в случае с Microsoft Visual C++ MFC)

.text:00402A82 push ebp

.text:00402A83 mov ebp, esp

.text:00402A85 push 0FFFFFFFFh

.text:00402A87 push offset unk_403748

.text:00402A8C push offset loc_402C06

.text:00402A91 mov eax, large fs:0

.text:00402A97 push eax

.text:00402A98 mov large fs:0, esp

.text:00402A9F sub esp, 68h

...

.text:00402BAA call ds:GetModuleHandleA

.text:00402BB0 push eax

.text:00402BB1 call _WinMain@16 ; WinMain(x,x,x,x)

точка останова на GetModuleHandleA

Вызов API-функции GetModuleHandleA сразу же бросается в глаза. Если хакер установит сюда точку останова, отладчик/дампер «всплывет» в start-up-коде еще до передачи управления WinMain (также можно поставить точки останова на GetVesion/GetVersionEx, GetCommandLine, GetStartupInfo и т.д.). Если точка останова программная, распаковщик может обнаружить ее по наличию ССh в начале API-функции и, с некоторой долей риска, снять ее. Если второй байт функции равен 8Bh, то перед нами, очевидно, предстает стандартный пролог, первый (оригинальный) байт которого равен 55h. Получаешь права на запись через VirtualAlloc, меняешь CCh на 8Bh и продолжаешь распаковку в обычном режиме. Пусть хакер крякнет! Правда, в последующих версиях Windows пролог API-функций может быть модифицирован, и тогда этот трюк не сработает.

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