Главная | Программы | Статьи | Заработай 100$ и более

Гостевая книга

 
Статьи: Securom 7 на F.E.A.R. или Мы ожидали большего 15.01.2006

Доброго времени суток всем читающим. Надеюсь, все знакомы с игрой F.E.A.R. Если всё же кто-то не в курсе, очень ожидаемая игра, одна из единиц, в которые мне хотелось играть. Графика хороша(большего не позволяет мой Celeron:), геймплэй страшноватый-затягивающий (ночью без света со звуком лучше все-таки не играть) вобщем у кого машина посильнее очень рекомендую. Теперь по поводу используемой защиты: в папочке лежит программа с названием “SR7Stop.exe”, а одна из секций называется securom, что наталкивает нас на мысль о присутствии защиты от Sony: Securom, и похоже 7 версии. В прошлой моей статье про игру Emire Earth 2 я рассматривал Securom 4-ой версии. Чудно, посмотрим, как изменилась эта защита.

Ну что, для начала смотрим, что нам говорит PeiD, а говорит он “nothing found”, ну и ладно, не очень-то и надо было. Теперь пробуем открыть fear.exe в Olly. Точка входа незнакома. Ладно, в прошлый раз мы ловили апи CreateEvent, попробуем и в этот раз, вдруг прокатит, ставим бряку и отпускаем прогу и... очень странно, в статус баре видим access violation when reading XXXXXXXX. Жмём паузу и смотрим, снимаем в опциях отладчика все флажки по поводу исключений и продолжаем гаму. Исключение происходит здесь:

007AEB58 66:813E 4D5A CMP WORD PTR DS:[ESI],5A4D
007AEB5D 75 3E JNZ SHORT FEARR.007AEB9D
007AEB5F 8B46 3C MOV EAX,DWORD PTR DS:[ESI+3C]
007AEB62 03C6 ADD EAX,ESI
007AEB64 8138 50450000 CMP DWORD PTR DS:[EAX],4550
007AEB6A 75 31 JNZ SHORT FEARR.007AEB9D
007AEB6C 0FB758 16 MOVZX EBX,WORD PTR DS:[EAX+16]
007AEB70 33C9 XOR ECX,ECX
007AEB72 F7C3 00200000 TEST EBX,2000
007AEB78 74 20 JE SHORT FEARR.007AEB9A
007AEB7A 8378 78 00 CMP DWORD PTR DS:[EAX+78],0
007AEB7E 74 1A JE SHORT FEARR.007AEB9A
007AEB80 8B58 78 MOV EBX,DWORD PTR DS:[EAX+78]
007AEB83 03DE ADD EBX,ESI
007AEB85 8B4B 0C MOV ECX,DWORD PTR DS:[EBX+C]

(справка: 5A4D - MZ, 4550 – PE :). Смотрим в стек и видим:

00210E04 0022FFB0 Pointer to next SEH record
00210E08 007AEBC3 SE handler

Теперь топаем сюда - 007AEBC3. Это обработчик исключений, заданный самим секуромом. Ставим туда бряку и жмём Shift+F9.

007AEBC3 55 PUSH EBP
007AEBC4 8BEC MOV EBP,ESP
007AEBC6 53 PUSH EBX
007AEBC7 8B5D 10 MOV EBX,DWORD PTR SS:[EBP+10]
007AEBCA 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
007AEBCD A1 A024C400 MOV EAX,DWORD PTR DS:[C424A0]
007AEBD2 8983 B8000000 MOV DWORD PTR DS:[EBX+B8],EAX
007AEBD8 33C0 XOR EAX,EAX
007AEBDA 5B POP EBX
007AEBDB 8BE5 MOV ESP,EBP
007AEBDD 5D POP EBP
007AEBDE C3 RETN


Немного потрейсим и обратим внимание на строки:

007AEBCD A1 A024C400 MOV EAX,DWORD PTR DS:[C424A0]
007AEBD2 8983 B8000000 MOV DWORD PTR DS:[EBX+B8],EAX

Как можно заметить число по адресу DWORD PTR DS:[C424A0] лежит в диапазоне адресов кода секурома. Смотрим, куда он указывает - 007AEB9D:

007AEB9D 81E6 0000FFFF AND ESI,FFFF0000
007AEBA3 81C6 00000100 ADD ESI,10000 007AEBA9 81FE 000000C0 CMP ESI,C0000000
007AEBAF ^ 72 A7 JB SHORT FEARR.007AEB58
007AEBB1 64:8F05 00000000 POP DWORD PTR FS:[0]

То есть обнуляет 2 младших байта, затем прибавляет 10000, если это меньше C0000000, тогда переходит туда, где обычно происходит исключение, иначе восстанавливаем SEH и валим. В этом блоке, кто ещё не догадался, защита ищет загруженные библиотеки и их адреса загрузки (MZ и PE – для проверки, исполняемый файл или нет, то бишь библиотека). Без апи, плюс к этому в Olly это занимает много времени, поэтому, когда мы дождёмся конца этой функции, нас пошлют. Можно подменять адреса нужными, глядя на меморимап, но нас всё равно обломают. Есть идея получше – мы запускаем гаму отдельно, после запуска с максимальной скоростью аттачимся к ней (чтобы было проще и быстрее я в PEExplorer’e немного увеличил размеры окна аттача в Olly, чтобы не тратить время на прокрутку). Теперь ставим бряки на доступ на все секции и жмём Shift+F9 пока не дойдём до такого места:

00535EEA 8B3D 78405400 MOV EDI,DWORD PTR DS:[544078] ; kernel32.GetModuleHandleA
00535EF0 FFD7 CALL NEAR EDI
00535EF2 66:8138 4D5A CMP WORD PTR DS:[EAX],5A4D
00535EF7 75 1F JNZ SHORT FEARR.00535F18
00535EF9 8B48 3C MOV ECX,DWORD PTR DS:[EAX+3C]
00535EFC 03C8 ADD ECX,EAX


Прокрутив немного выше можно узнать стандартное начало программ на С++.

00535ED8 6A 74 PUSH 74
00535EDA 68 30965500 PUSH FEARR.00559630
00535EDF E8 F0040000 CALL FEARR.005363D4
00535EE4 33DB XOR EBX,EBX
00535EE6 895D E0 MOV DWORD PTR SS:[EBP-20],EBX
00535EE9 53 PUSH EBX
00535EEA 8B3D 78405400 MOV EDI,DWORD PTR DS:[544078] ; kernel32.GetModuleHandleA
00535EF0 FFD7 CALL NEAR EDI
00535EF2 66:8138 4D5A CMP WORD PTR DS:[EAX],5A4D

Мы остановились на несколько команд позже, чем надо было, поэтому не забудем поправить OEP на 135ED8. Теперь надо сдампить нашу почти уже распакованную игруху. Если дампим в Olly, не забываем убрать галочку “Rebuild Import”, жмём Dump и видим фигу. Ещё один финт протектора. Пробуем в PETools. Tools’ы говорят ОК, но глядя на дамп этого не скажешь (2 Мб – код протектора конечно занимает место, но не 2.4 же метра, да и куда иконка делась). Тогда пробуем дампить по частям. По адресу 00561000 сдампить не можем. Значит некоторые страницы заблокированы (PAGE_GUARD, вещают нам Tools). Опять открываем отладчик с нашей гамой и в memorymap в свойствах всех секций выбираем Set access->Full Access. Теперь дампится всё и без ошибок. У дампа импорт перестраивать не надо, как и раньше секция импорта на месте и без повреждений. Дамп готов поехали дальше...

Пробуем запустить наш свеженький дамп и, ожидаемо, получаем ошибку, не может быть всё так просто, это ж всё таки протектор. Теперь пробуем запустить дамп под отладчиком:

007C89E6 8B12 MOV EDX,DWORD PTR DS:[EDX]
007C89E8 891424 MOV DWORD PTR SS:[ESP],EDX
007C89EB 85D5 TEST EBP,EDX


Исключение в первой строке. Надо найти, откуда оно берётся, и что из себя собсно представляет этот механизм защиты. Можно дойти по шагам, а можно посмотреть в стеке, по шагам надёжнее, но я уже знаю, что и откуда вызывалось, по этому пойду через стек:

0012FEE8 018809D8
0012FEEC 00000202
0012FEF0 77E7AD86 kernel32.GetModuleHandleA
0012FEF4 005610A8 Копия_Ко.005610A8
0012FEF8 0012FFC0
0012FEFC 0012FF10
0012FF00 00000000
0012FF04 7C38B1D8 MSVCR71.7C38B1D8
0012FF08 00562298 Копия_Ко.00562298
0012FF0C 00537D20 Копия_Ко.00537D20
0012FF10 00D9608E RETURN to Копия_Ко.00D9608E from Копия_Ко.007C86D0
0012FF14 0040A495 Копия_Ко.0040A495
0012FF18 00537D30 RETURN to Копия_Ко.00537D30 from Копия_Ко.0040D940
0012FF1C 7C341CD6 RETURN to MSVCR71.7C341CD6
0012FF20 0012B998
0012FF24 00536007 RETURN to Копия_Ко.00536007 from <JMP.&MSVCR71._initterm>

Последняя строчка (<JMP.&MSVCR71._initterm>) показывает, что вызвалась функция _initterm. Она вызывается обычно в самом начале работы программы.

0012FF18 00537D30 RETURN to Копия_Ко.00537D30 from

Последней вызов из секции кода игры. Идем туда и заходим в вышерасположенный call. Что мы видим там, прыжок в секцию секурома:

0040D940 $- E9 3F879800 JMP Копия_Ко.00D96084
0040D945 1750D700 DD Копия_Ко.00D75017
0040D949 9F51D700 DD Копия_Ко.00D7519F
0040D94D FF52D700 DD Копия_Ко.00D752FF
0040D951 9F54D700 DD Копия_Ко.00D7549F
0040D955 F755D700 DD Копия_Ко.00D755F7
.
поскипано
.
0040DA7F . /EB 08 JMP SHORT Копия_Ко.0040DA89
0040DA81 . |EB 06 JMP SHORT Копия_Ко.0040DA89
0040DA83 . |EB 04 JMP SHORT Копия_Ко.0040DA89
0040DA85 |EB DB EB
0040DA86 |00 DB 00
0040DA87 |00 DB 00
0040DA88 |00 DB 00
0040DA89 > \C3 RETN


Теперь посмотрим, что же там, в секции секурома:

00D96084 68 95A44000 PUSH Копия_Ко.0040A495
00D96089 E8 4226A3FF CALL Копия_Ко.007C86D0
00D9608E - E9 F67967FF JMP Копия_Ко.0040DA89

Посмотрите внимательно, куда ведёт прыжок из секции секурома... на ret в коде игры, то есть на конец процедуры. Это очень похоже на антидмпы или code splising в Armadillo, только здесь убрана процедура целиком и прыжок идёт в пределы программы, а не в аллоченную память. Но ошибка где-то глубже, значит, копаем дальше. Можно посмотреть громадную функцию секурома (где исключение), а можно посмотреть причину, что по-моему логичнее. Итак, прот обращается к памяти, которая недоступна. Обращение у меня идёт по адресу 018809D8. Значит мне нужен участок памяти, начиная с 01880000. Адрес начала участка в открытом виде не используется, в EDX кладётся число, к нему прибавляется другое, далее для доступа будет использоваться и регистр EAX. Следить за всеми превращения мне влом, тем более и тут видимо есть проверка, т.к. нераспакованный FEAR после тщательных неторопливых исследований вылетел с неизвестной ошибкой. Это нужно было для разбора принципа работы этой функции относительно выделенного куска памяти, то есть откуда берутся его адреса и как они обрабатываются, чтобы потом припаять его к новой последней секции и перенаправить указатели у секурома. Раз уж это не работает, тогда делаем ещё проще:

1) Дампим участок памяти по адресу 01880000
2) В PEEditore грузим секцию с диска, увеличиваем виртуальный размер секции .securom (то есть перед добавленной) так, чтобы она заканчивалось на адресе 01880000, то есть к VS += 01880000 – (VO+VS)
3) У новой секции ставим Virtual Offset 01880000
4) Я не учёл ImageBase, поэтому после проверки уменьшил Virtual Offset новой секции на 400000 и стало это 01480000


Не надеясь на рабочее состояние игры я после проверки работоспособности добавления отпустил гаму в поисках других ошибок. Каково же было моё удивление, когда всё заработало. Правда выход осуществился в разрешение 800Х600 и винда благородно разместила все значки, которые я расставлял несколько дней в поисках абсолютного удобства, в зоне видимости, смешав всё в фарш. Ещё была замечена фишка, что если после нескольких разов попытаться прицепиться к игре и выйти через F4 секуром после F9 не продолжал выполнение, с этим можно бороться запуская FearRun.exe, правда если у вас именно тот DVD, который и у меня.

Предвкушая новые извращения над импортом и увидев их отсутствие я был сильно обломан. Но может это и к лучшему, игра работает без них быстрее, а с её требования и моими возможностями это ой как важно. За сим разрешите откланяться.

Все претензии и прочее шлите мылом: rascalspb dog mail dot ru