Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

Видеокурс программиста и крэкера 5D 2O17
(актуальность: декабрь 2O17)
Свежие инструменты, новые видеоуроки!

  • 400+ видеоуроков
  • 800 инструментов
  • 100+ свежих книг и статей

УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь


Распаковка протектора SafeDisk 4.6, часть 1




Хорошая подборка видеоуроков, инструментов крэкера, книг и статей - здесь.

Распаковка SafeDisk 4.6 на примере

Launch Sid Meier's Civilization 4


AntiDebug, нахождение OEP


VaZeR



ИНСТРУМЕНТЫ: SoftIce v4.3.2+IceExt v0.67, OllyDbg+plugun Olly advanced v1.26 beta 9, PETools v1.5, ImpREC v1.6.


ЧАСТЬ I. AntiDebug, нахождение OEP


SafeDisk достаточно распространённый протектор для игр. Он обеспечивает достаточную надёжность, а самое главное неплохое быстродействие приложения. Для примера распаковки я взял игру CIVILIZATION IV, потому что именно на ней я встретил всё защиты SafeDisk в одном месте: наномиты, порча импорта и указателей к нему, эмулированные опкоды, SDAPI второй версии. До этого времени я распаковал из продуктов Macrovision только SafeCast 2.4 версии и в целом можно сказать, что защита выросла на порядок. AntiDebug не сильно сложный у этого протектора и его вполне можно обойти путём патча нескольких байт в коде, которые находятся довольно просто. Так как разработчики не сильно хорошо защитили процедуры проверки и сделали всё это в одном месте программы. Только проверка на присутствие SoftIce имеется ещё в другом месте программы, где весь код с обфускацией. Но появляющиеся строки в стеке говорят сами за себя.

При запуске защищенного приложения во временную директорию (Temp) распаковываются несколько файлов такие как ~e5.0001 (отладчик) и папка с соответствующим названием ~e5.0001.dir.0000, где имеются ещё четыре файла ~deff16.tmp(библиотека участвующая в проверке диска и расшифровке секции кода), ~df394b.tmp(библиотека в которой находится вся защита файла), ~efe2.tmp, PfdRun.pfd.

Чтобы определить версию протектора можно посмотреть в hex - редакторе строку в секции заголовка файла, которая начинается с BoG, где после Yy> номер версии, у меня здесь 04 3С (4.60):

AntiDebug, нахождение OEP

Иногда эта строчка затёрта (нет проверки целостности CRC) и тогда можно посмотреть с помощью Restorator те файлы, которые находятся во временной директории. В разделе про версию файла можно получить исчерпывающею информацию:

AntiDebug, нахождение OEP

Файл ~e5.0001 - это отладчик для защищенного приложения. Видимо поэтому OllyDbg при запуске файла уходит в бесконечный цикл, так как программа ждет ответа от своего отладчика. Я не стал изучать верно ли моё предположение или нет. Я просто решил использовать SoftIce, а для этого придётся разобраться с antidebug’ом. И здесь OllyDbg может помочь нам, так как с плагином Olly advanced 1.26 beta 9, он проходит все проверки и распаковывает секцию кода. Сначала я выяснил, какие именно проверки использует SafeDisk для этого я убрал все галочки в настройках плагина Olly advanced и запустил приложение, появилось окно, что обнаружен отладчик:

AntiDebug, нахождение OEP

Далее будем ставить по одной галочке и смотреть, когда же мы пройдём проверки. Галочку IsDebuggerPresent нужно поставить сразу, так как эта проверка в большинстве случаев присутствует во всех протекторах. Поэкспериментировав с настройками можно понять, что приложение запускается, если есть обход проверок ZwQueryInformationProcess и ZwQuerySystemInformation. В принципе можно и не находить какие существуют проверки. А ограничится только лишь IsDebuggerPresent. Но тогда будет не совсем понятно, из-за чего нас обнаруживают.

Загрузив в OllyDbg наше приложение нужно поставить брекпоинт на функцию IsDebuggerPresent, только нужно ставить брекпоинт не на начало, так как первый байт проверяется на присутствие точки останова. А куда то ниже. Хотя в моём случае эта проверка происходит после вызова IsDebuggerPresent, но это возможно не всегда так. Запустив программу, остановимся на нашем брекпоинте:


AntiDebug, нахождение OEP




Выходим из этой функции и попадаем на код проверки полученных данных:

AntiDebug, нахождение OEP

Из этого кода видно, что если отладчик есть, то возвращаемое значение в AX 1, если нет то 0. Опять выходим из этой процедуры и попадаем сюда:

AntiDebug, нахождение OEP

Это и есть главная ветка программы ответственная за обнаружение отладчика. В общем можно сказать, что она состоит из CALL …TEST… JNZ(JBE). Где в CALL есть какая-нибудь проверка. И именно эти условные переходы отвечают, проходим мы antidebug или нет. Если отладчик замечен, то мы переходим по адресу 667070F8.

Здесь можно исследовать эти CALL. Например, по адресу 66707013 есть проверка CreateFileA, запушен ли . Если он запушен, то в EAX возвращается в моём случае 84. Если нет то FFFFFFFF. По адресу 6670702D есть следующая проверка:

AntiDebug, нахождение OEP

Из справочника по API можно узнать, что если InfoClass = 7, то мы получаем сведения о присутствие отладчика. После выполнения, которой по адресу ESP+C будет находится число, если это 0 то отладчика нет, если FFFFFFFF то он присутствует.

По адресу 6670708B осуществляется проверка API (kernel32.dll) на присутствие брекпоинта:

AntiDebug, нахождение OEP


По адресу 667070F0 тоже имеется проверка наличия отладчика:

AntiDebug, нахождение OEP


Исследуя эти CALL можно встретить ещё и проверку времени выполнения кода:

AntiDebug, нахождение OEP

Если в EAX число больше чем 190, то наше присутствие обнаружено. Поэтому нужно следить и за такими проверками. Далее установим в самом начале нашей ветки (66706FD0) брекпоинт - Hardware, on execution.

Теперь попробуем запустить SoftIce c IceExt (!Protect ON). И обойти все эти проверки. Опять открываем в OllyDbg нашу программу и останавливаемся на нашем брекпоинте. Далее начинаем трассировать код, попутно смотря, на каком условном переходе мы переходим по адресу 667070F8, если переходим, то возвращаемся назад «-» и New Origin here. Запоминаем адрес условного перехода, изменяем флаг нуля (Z) на противоположный и двигаемся дальше. Можно сначала и по трассировать этот код в OllyDbg без SoftIce и со всеми опциями в плагине Olly advanced и запомнить правильный порядок. И понять из-за чего нас обнаруживают. Но есть ещё более легкий способ обхода первой проверки. Если мы выйдем через RET в конце этой ветки программы, то попадём на следующее место:

AntiDebug, нахождение OEP

По трассировав этот код, можно заметить, что если мы выходим из нашёй процедуры с нулём в EAX, то проходим первую проверку, если там, что-то другое то нет. Также если у нас ноль в EAX, то в последствии мы кладём туда 10000, а когда обнаружены то 4000, также в некоторых версиях протектора присутствует ещё и третье число 2000. Можно попробовать положить и нам 2000 и посмотреть, на следующее сообщение:

AntiDebug, нахождение OEP

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

Вот мы и разобрали первую проверку присутствия отладчика. Теперь при запуске окно с сообщением об отладчике исчезнет, но и приложение так же закрывается, что в SoftIce, что в OllyDbg (с условием, что запущен SoftIce без него всё нормально). Это всё происходит из-за того, что существует ещё одна проверка присутствия SoftIce. Которая осуществляется из ring 0. При помощи драйвера SafeDisk SecDrv.sys (…system32\drivers). Эта проверка, не выводит не каких окон, а просто тихо завершает работу приложения, в случае обнаружения отладчика. Её найти уже сложнее. Я решил её искать довольно простым методом, просто трассировать код в OllyDbg, начиная с адреса 6670149С. Сначала не входя в не какие процедуры (F8). А когда, пройдя какой-нибудь CALL в котором происходит завершение приложения, запомнить его адрес и в следующий раз уже входить в него (F7) и так далее. Двигаясь как бы по слоям, можно в конце концов, выйти на проверку. Но трассировать придётся довольно много. Поэтому лучше использовать самотрассировку - Animate over (Ctrl+F8). Появляется начальная заставка игры и программа закрывается, пройдя CALL по адресу 66704A55. Ставим на него брекпоинт (Hardware, on execution) и перезапускаем программу, когда остановимся, входим в него. И начинаем трассировать код дальше. Теперь мы закрываемся по адресу - 667018F8 => 6676142D (на этот адрес мы попадаем 18 раз, прежде чем закроется программа) => после чего мы входим внутрь и начинаем изучать код, кода здесь много, но большая его часть это просто мусор. Поэтому очистим этот код от него и постараемся понять, как же он работает. По исследовав код можно сказать, что это цикл который перебирает следующие значения (полный листинг ПРИЛОЖЕНИЕ 1 в конце статьи):

 "SoftICE at address";  
  "Hooking IOAPIC";  
  "I3HERE [ON";  
  "BPM, BPMB, BPMW";  
 "WINICE: Int41 Get".
  

Причём перебирает несколько раз сначала 4 раза каждую, потом 2 раза каждую, и в конце 1 раз каждую. И именно когда он перебирает 1 раз каждую после "I3HERE [ON" мы закрываемся. Глядя на этот код (ПРИЛОЖЕНИЕ 1) можно понять, что проверка осуществляется по адресу 6670AEC9. Я нашёл этот адрес путём сравнения работы с SoftIce и без него.

Теперь заходим в этот CALL и посмотрим, как работают условные переходы при определённых условиях. И тогда уже будет видно, где мы идём по неправильному пути:

AntiDebug, нахождение OEP

Вот это и есть та самая проверка, если число в ESP+8 равно 587С1194 то мы выходим. Причем SafeDisk завершает работу приложения только со второго раза, т.е. если мы два раза имеем значение в ESP+8 равное 587C1194. Это, видимо, сделано, чтобы снизить вероятность ложного срабатывания защиты. Также если нет отладчика, то по адресу ESP+8 в большинстве случаев находится число 587С1284. Теперь нам надо понять, откуда берётся это число. Это можно выяснить трассировкой этого цикла со значениями. По трассировав, можно сказать, что запись происходит после выполнения API функции DeviceIoControl. А эта API связывает наше приложение со своим драйвером. Теперь нам надо изучить код драйвера. Чтобы понять, откуда берётся у нас значение 587С1194. Здесь можно использовать только SoftIce или ещё какой-нибудь ring 0 отладчик. Запускаем в SoftIce нашу программу, сначала обходим первую проверку (bpx 6670147F, после срабатывания обнуляем EAX) и ставим брекпоинт на адрес 6670E80B. Когда сработает, перейдём к API DeviceIoControl (u DeviceIoControl, поставить указатель на начало функции и F7). Теперь мы стоим в самом начале функции и отсюда нам нужно начать трассировать код до самого драйвера. Лучше всего трассировать код, входя во все процедуры. Чтобы не пропустить не чего интересного. Сначала мы должны попасть в ядро Windows, через вызов native API NtDeviceIoControlFile:

AntiDebug, нахождение OEP

Сам переход в ring 0 выглядит следующим образом:

AntiDebug, нахождение OEP

Далее нам нужно найти в ядре Windows переход к нашему драйверу SecDrv.sys:

AntiDebug, нахождение OEP

Зайдя в этот CALL, мы попадём на код нашего драйвера. Код драйвера не такой уж большой, поэтому его нужно просто внимательно трассировать и смотреть, когда у нас появится значение 587С1194 или 587С1284. Вот таким образом можно и выйти на следующий код:

AntiDebug, нахождение OEP

Отсюда видно, что значение 587С1194, является константой в драйвере.

Примечание: В принципе можно было вместо отладчика воспользоваться и дисассемблером и найти по константе это место, но это возможно не всегда так есть случаи, когда могут использоваться и другие константы, например 58803194. Их можно найти в драйвере аналогичным образом.

И чтобы она не была использована, отвечает условный переход по адресу A884FAC7. Поэтому нам нужно в любом hex редакторе исправить байт 75 на EB (JMP). После чего обязательно нужно пересчитать контрольную сумму драйвера, иначе Windows не загрузит его. Это можно сделать с помощью PETools:

AntiDebug, нахождение OEP

Проделав это, мы обошли проверку на присутствие отладчика из ring 0.


Примечание: Чтобы окно SoftIce выглядело нормально с запущенной игрой, без искажений, нужно установить разрешение игры такое же, как и в Windows.


Теперь мы можем запускать свободно игру со SoftIce даже без IceExt (!Protect ON). Что очень удобно в исследовании.


ОЕР

Мы обошли анти отладку SafeDisk и теперь можно начать изучать код дальше. Попробуем найти OEP. Применим старый способ поиска. Открыв в отладчике программу и посмотрим переход в секцию кода программы (Примечание: он находится ниже EP). И такой тут имеется:

AntiDebug, нахождение OEP

Он единственный здесь, который ведёт в секцию кода программы других нет. То, что он ведёт в секцию кода, я узнал, посмотрев в OllyDbg (ALT+M) на секции файла (их адреса):

AntiDebug, нахождение OEP

Но нужно проверить, правы ли мы или нет. Поставим на него брекпоинт в SoftIce и когда остановимся, то перейдём по адресу 99B988, где видим следующее:

AntiDebug, нахождение OEP

Это OEP программы написанной седьмой версией C++. Теперь можно и сдампить программу для этого нужно зациклить программу, т.е. вместо первых байт 6A74 вписать EBFE. После чего их в дампе нужно восстановить обратно.




ПРИЛОЖЕНИЕ 1

 			 			...
 			 			6670AE2B   PUSH EDI
 			 			6670AE2C   CALL 			~df394b.66710920
 			 			6670AE31   ADD ESP,4
 			 			6670AE34   MOV EBX,EAX
 			 			6670AE52   TEST EBX,EBX
 			 			6670AE54   JE ~df394b.6670B008
 			 			6670AE5A   MOV EAX,DWORD PTR 			SS:[ESP+14]
 			 			6670AE5E   TEST EAX,EAX
 			 			6670AE60   MOV DWORD PTR 			SS:[ESP+10],0
 			 			6670AE68   JBE 			~df394b.6670AF46
 			 			
=> 6670AF0D
6670AEB8 MOV EAX,DWORD PTR DS:[EDI] 6670AEBA MOV ECX,DWORD PTR DS:[ESI+4] 6670AEBD LEA EDX,DWORD PTR SS:[ESP+28] 6670AEC1 PUSH EDX 6670AEC2 MOV EDX,DWORD PTR DS:[ESI] 6670AEC4 PUSH EAX 6670AEC5 PUSH EBX 6670AEC6 PUSH ECX 6670AEC7 PUSH EDX 6670AEC8 PUSH EBP 6670AEC9 CALL DWORD PTR SS:[ESP+38] 6670AECD ADD ESP,18 6670AED0 TEST AX,AX 6670AED3 JE ~df394b.6670B05C 6670AEF1 CMP DWORD PTR SS:[ESP+28],458061FE 6670AEF9 JE SHORT ~df394b.6670AF15 ;прыгаем если есть отладчик … 6670AF15 MOV EAX,DWORD PTR SS:[ESP+18] 6670AF19 INC EAX 6670AF1A MOV DWORD PTR SS:[ESP+18],EAX 6670AF32 MOV ECX,DWORD PTR SS:[ESP+2C] 6670AF36 CMP EAX,DWORD PTR DS:[ECX+C68] 6670AF3C JNB ~df394b.6670B0C6 ;завершение приложения
=> 6670AF13
6670AF42 MOV ESI,DWORD PTR SS:[ESP+2C] 6670AF46 MOV EDX,DWORD PTR DS:[EDI] 6670AF48 INC EDX 6670AF49 PUSH EDX 6670AF4A PUSH EBX 6670AF4B CALL ~df394b.66710980 6670AF50 MOV EAX,DWORD PTR SS:[ESP+24] 6670AF54 MOV ECX,DWORD PTR DS:[ESI+7A8] 6670AF5A ADD ESP,8 6670AF5D INC EAX 6670AF5E ADD EDI,65 6670AF61 CMP EAX,ECX 6670AF63 MOV DWORD PTR SS:[ESP+1C],EAX 6670AF67 JB ~df394b.6670ADC3; повторяем значение 6670AF6D JBE SHORT ~df394b.6670AF76 ; на ret
{ ;Попадаем суда если нет SoftIce 6670AEFB MOV EAX,DWORD PTR SS:[ESP+10] 6670AEFF MOV ECX,DWORD PTR SS:[ESP+14] 6670AF03 INC EAX 6670AF04 ADD ESI,8 6670AF07 CMP EAX,ECX 6670AF09 MOV DWORD PTR SS:[ESP+10],EAX 6670AF0D JB ~df394b.6670AE74 ; если повтор 6670AF13 JMP SHORT ~df394b.6670AF42 ;новое значение }





Скачать статью "Распаковка протектора SafeDisk 4.6, часть 1" в авторском оформление + файлы.



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS