Статьи: 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 пока не дойдём до такого места: 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 |