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

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


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

Распаковка FSG 2.0 - развеивание мифов

Обсудить статью на форуме

Очень удобно, когда все крэкерские инструменты, книги и статьи в одном месте. Используйте сборник от EXELAB - вот тут.

Автор: ARCHANGEL <crazyangel88@mail.ru>

Начало

Однажды после тяжёлого студенческого учебного дня отправился я на форум Cracklab себя показать
и на других посмотреть. Долго я бродил по лабиринтам нашего любимого cracklab, как вдруг на
горизонте замаячил топик с названием "Распаковка FSG 2.0" (ну, или что-то вроде этого). Я до
этого вторую версию данного пакера не распаковывал - как-то не попадалась. Но зато мне попадалась
версия 1.33, которую я успешно снимал не один раз. Так что я решил помочь человеку советом.
Жаль только, не помню ник автора форума, а то бы он сразу понял, что этот тьютор именно для
него, ну да ладно, дело ведь совсем не в этом. А дело в том, что до меня там уже велась активная
дискуссия про снятие данного пакера. Вкратце расскажу для тех, кто не в курсе - проблема заключалась
в том, что после нахождения ОЕР ImpRec неправильно определял таблицу импорта, вследствие чего
полученный дамп не работал. Тогда в Imprec просто вбили фактическое расположение и длину таблицы,
но результат не изменился. "Советчики" напредлагали автору форума для решения его проблемы
такое, что я чуть со стула не рухнул:) Некоторые даже стали ругать бедолагу за его кривые
руки (Pe_Kill, как не стыдно?:) Я же просто не поверил, что такое возможно, но через некоторое
время совесть меня заела, и я решил проверить всё на практике.

Практика

Для начала подготовим инструметы, с помощью которых будем осуществлять распаковку:

1. PeID v 0.94 - обнаружение FSG 2.0
2. OllyDebug v 1.10 - просто отличный отладчик
3. LordPe Deluxe by Yoda - dumper & Pe editor & Rebuilder
4. ImpRec v 1.6 final - как ни странно, но он не так уж безнадёжен:)
5. ResHacker 3.4.0.79 - редактор ресурсов
6. Microsoft Visual C++ 6.0 (его редактор ресурсов) - что-то типа граббера ресурсов:)

Как видите, стандартный набор, конечно, за исключением последних двух инструментов, но
если вам не нужны ресурсы распаковываемой проги, то и они вам тоже ни к чему, т.к. с их
помощью мы будем только ресурсы выдирать. Ну, что ж, приступим...
Для начала (как обычно:) натравим наш PeID на цель (целью у меня был опять какой-то keygen)
и увидим вот что:
FSG 2.0 -> bart/xt
Далее давайте спланируем стратегию распаковки. В принципе, она будет выглядеть очень даже
стандартно:

1. Нахождение ОЕР.
2. Снятие дампа.
3. Восстановление ресурсов.
4. Нахождение таблицы импорта.
5. Правка РЕ и Rebuild.

Теперь перейдём к практике. Итак, пункт первый - нахождение ОЕР(+пункт второй - вместе навсегда:)
Грузим запакованную прогу в отладчик. Далее жмём вверху по кнопочке Show Modules window и
в появившемся списке ищем библиотеку kernel32.dll. Дальше кликаем по ней два раза, и мы
внутри нашей библы. Теперь жмём правую мышу, а далее так:
Search for -> Name (label) in current module
Нашему взору открывается таблица экспорта. Теперь ищем функцию, которая при распаковке
всегда интересует нас больше всего, а именно GetModuleHandleA. Нашли? Теперь выделим её и
нажмём Enter. Так мы оказались в самом начале нашей функции, что нам и нужно. Теперь ставим
Hardware бряк on execution на начало GetModuleHandleA и жмём по кнопочке Show CPU (она
недалеко от Show Modules window). Запомните этот метод - он может пригодиться при борьбе
даже со многими протекторами (если не со всеми:), хотя его применение против FSG, в общем,
не обязательно. Да что-то мы отвлеклись, вернёмся к нашей проге. Мы сейчас стоим на ЕР, но
это не надолго. Жмём могучей рукой F9 и прерываемся на нашем бряке внутри GetModuleHandleA.
Сама функция нас глубоко не волнует, поэтому жмём Ctrl+F9 (execute till return), так мы
попадаем на retn нашей GetModuleHandleA, теперь один раз жмём F8 и возвращаемся в прогу, а
там такое!:

004013D2     A3             DB A3
004013D3     70             DB 70                                    ;  CHAR 'p'
004013D4     70             DB 70                                    ;  CHAR 'p'
004013D5     40             DB 40                                    ;  CHAR '@'
004013D6     00             DB 00
004013D7     E8             DB E8
004013D8     50             DB 50                                    ;  CHAR 'P'
004013D9     17             DB 17
004013DA     00             DB 00
004013DB     00             DB 00
004013DC     A3             DB A3
004013DD     68             DB 68                                    ;  CHAR 'h'
004013DE     70             DB 70                                    ;  CHAR 'p'
004013DF     40             DB 40                                    ;  CHAR '@'
004013E0     00             DB 00
004013E1     6A             DB 6A                                    ;  CHAR 'j'

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

004013CB   . 6A 00          PUSH 0                                   ; /pModule = NULL
004013CD   . E8 60170000    CALL Nero_Bur.00402B32                   ; \GetModuleHandleA
004013D2   . A3 70704000    MOV DWORD PTR DS:[407070],EAX            МЫ ЗДЕСЬ!
004013D7   . E8 50170000    CALL Nero_Bur.00402B2C                   ; [GetCommandLineA
004013DC   . A3 68704000    MOV DWORD PTR DS:[407068],EAX
004013E1   . 6A 0A          PUSH 0A                                  ; /Arg4 = 0000000A
004013E3   . FF35 68704000  PUSH DWORD PTR DS:[407068]               ; |Arg3 = 00000000
004013E9   . 6A 00          PUSH 0                                   ; |Arg2 = 00000000
004013EB   . FF35 70704000  PUSH DWORD PTR DS:[407070]               ; |Arg1 = 00000000
004013F1   . E8 06000000    CALL Nero_Bur.004013FC                   ; \Nero_Bur.004013FC
004013F6   . 50             PUSH EAX                                 ; /ExitCode
004013F7   . E8 24170000    CALL Nero_Bur.00402B20                   ; \ExitProcess

Теперь прокрутим немного вверх в поисках ОЕР. Мне крутить пришлось недолго, т.к. кейген
наш оказался написан на асме, поэтому ОЕР располанается на пару инструкций выше, т.е.
VA OEP = 004013CB. Ставим на нашу ОЕР второй аппаратный бряк, удаляем первый, т.к. он нам
более не понадобиться и перезапускаем прогу под отладчиком. Далее тупо жмём F9 (можете жать
умно:) и, стоя на нашем втором бряке, снимаем дамп с помощью LordPe. Также попутно с помощью
LordPe определяем значение ImageBase, которое в моём случае составило 00400000. Теперь по
известной формуле, которую я не буду здесь в сотый раз повторять, определим RVA OEP. Оно
составит 000013CB. Запомним это значение - оно нам ещё пригодится.
Так мы только что выполнили первые два пункта распаковки - нашли ОЕР и получили дамп.
Перейдём к восстановлению ресурсов.
Восстановление ресурсов - самая лёгкая и приятная часть всего тьютора. Здесь не будет ни
единой строчки кода, даже ни единой консольной команды, т.к. я не очень люблю программы для
перестраивания ресурсов типа ResFixer и иже с ним. Мы просто запустим Microsoft Visual
C++ 6.0, окроем с его помощью наш дамп (в строке Open as выберем значение Resources), далее
сохраним появившееся дерево ресурсов в отдельном файле с расширением res и закроем наш
Microsoft Visual C++ 6.0. Он нам больше не понадобится. Теперь открываем наш дамп при помощи
ResHacker'a. Как видите, при попытке отредактировать ресурсы нашего дампа у нас ничего не
выйдет, поэтому в меню Action выберем Update all resources и укажем наше сохранённое в
Microsoft Visual C++ 6.0 дерево ресурсов. Теперь ресурсы обновились и стали доступными для
редактирования. Сохраняем изменения в ResHacker'e и выходим из него. Ресурсы восстановлены,
а мы переходим к четвёртому пункту. Впереди - восстановление импорта.
Казалось бы - такая простая задача это восстановление импорта, а из-за него, собственно, и
весь гемор. Но давайте поближе познакомимся с проблемой. Если мы тупо запустим ImpRec и
в поле ОЕР впишем наше ОЕР, а дальше нажмём IAT AutoSearch, то ImpRec что-то, конечно, найдёт,
но это будет далеко не вся таблица, и, как следствие, наш дамп с такой таблицей не заработает.
Но есть способ, как нам с вами самим извлечь подлую таблицу на поверхность:). Для этого опять
воспользуемся помощью отладчика. Стоя на ОЕР, один раз нажмём F8, если мы ещё раз нажмём F8,
то выполниться функция GetModuleHandleA, но нам нужно другое. Вместо этого посмотрим на
процесс выполнения данной функции, т.е. нажмём F7 и окажемся в таком месте, где, как говорят,
никогда не светит солнце:):

00402B32   $-FF25 7C604000  JMP DWORD PTR DS:[40607C]                ;  kernel32.GetModuleHandleA
00402B38   $-FF25 78604000  JMP DWORD PTR DS:[406078]                ;  kernel32.GetTickCount
00402B3E   $-FF25 74604000  JMP DWORD PTR DS:[406074]                ;  kernel32.GlobalAlloc
00402B44   $-FF25 70604000  JMP DWORD PTR DS:[406070]                ;  kernel32.GlobalLock
00402B4A   $-FF25 6C604000  JMP DWORD PTR DS:[40606C]                ;  kernel32.GlobalUnlock
00402B50   $-FF25 68604000  JMP DWORD PTR DS:[406068]                ;  kernel32.LoadResource
00402B56   $-FF25 64604000  JMP DWORD PTR DS:[406064]                ;  kernel32.SetHandleCount
00402B5C   $-FF25 60604000  JMP DWORD PTR DS:[406060]                ;  ntdll.RtlZeroMemory
00402B62   $-FF25 5C604000  JMP DWORD PTR DS:[40605C]                ;  kernel32.SizeofResource
00402B68   $-FF25 58604000  JMP DWORD PTR DS:[406058]                ;  kernel32.lstrcatA
00402B6E   $-FF25 54604000  JMP DWORD PTR DS:[406054]                ;  kernel32.lstrcpyA
00402B74   $-FF25 50604000  JMP DWORD PTR DS:[406050]                ;  kernel32.lstrlenA
00402B7A   $-FF25 00604000  JMP DWORD PTR DS:[406000]                ;  advapi32.GetUserNameA

(Мы в самом верху). Это так называемые переходники, но обратите внимание, что из переходников
следует, будто прога использует функции из трёх разных библиотек, в то время, как AutoSearch
ImpRec'a показал только функции из kernel32.dll, значит коварный ImpRec точно хотел нас
кинуть с импортом. Хотя нас это не волнует, идём дальше.
Присмотритесь к переходнику. Что это? Это не что иное, как прыг по адресу, значение которого
расположено по адресу 0040607C. А давайте перейдём в окно дампа и посмотрим, что же за
значение по адресу 0040607C расположено. И вот что мы там можем увидеть:
0040607C 29 B5 80 7C )µ.|
Там, конечно, дальше есть ещё много чего, точнее вся таблица импорта, но нас интересуют
только эти 4 байта. Это, как вы уже поняли, адрес нашей функции GetModuleHandleA. Т.е.,
отсюда следует, что мы сейчас в окне дампа видим где-то середину таблицы импорта. Середина -
это хорошо, но хотелось бы увидеть начало и конец. Ну, это можно!:) Для этого нам нужно
просто проследить, как значение наших 4-х байт попадает на этот адрес. Чтоб это узнать, мы
поступим так - поставим бряк на эти 4 байта:
Breakpoint->Hardware, on write->DWORD
И перезапустим прогу под отладчиком. Теперь жмём F9, несколько раз прервёмся в местах,
которые нас не особо интересуют и в конце-концов попадём на джамп:

004001C4   AD               LODS DWORD PTR DS:[ESI]
004001C5   50               PUSH EAX
004001C6   FF53 10          CALL DWORD PTR DS:[EBX+10]
004001C9   95               XCHG EAX,EBP
004001CA   8B07             MOV EAX,DWORD PTR DS:[EDI]
004001CC   40               INC EAX
004001CD  ^78 F3            JS SHORT Nero_Bur.004001C2
004001CF   75 03            JNZ SHORT Nero_Bur.004001D4
004001D1   FF63 0C          JMP DWORD PTR DS:[EBX+C]
004001D4   50               PUSH EAX
004001D5   55               PUSH EBP
004001D6   FF53 14          CALL DWORD PTR DS:[EBX+14]
004001D9   AB               STOS DWORD PTR ES:[EDI]
004001DA  ^EB EE            JMP SHORT Nero_Bur.004001CA         Интересное место!

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

004001D6   FF53 14          CALL DWORD PTR DS:[EBX+14]   вызов GetProcAddress
004001D9   AB               STOS DWORD PTR ES:[EDI]      запись значения из ЕАХ по адресу EDI

Короче говоря, перед вызовом GetProcAddress в стек заталкивается строка с именем функции,
после чего GetProcAddress возвращает её адрес в системе, а следующая инструкция записывает
этот адрес куда надо. А куда надо? Да посмотрите, что в этот момент в EDI, теперь в окне
дампа перейдите на это значение и увидите там часть таблицы. С каждым очередным проходом
по циклу в том районе будет появляться новое значение, и так до запуска самой проги. Наша
задача состоит в том, чтоб определить, где начинается и заканчивается таблица, причём это
нужно сделать как можно точнее. Такая точность требуется для того, чтоб избежать
нежелательных "подарков" со стороны ImpRec'a. Давайте начнём пока с более простого - найдём
начало таблицы. Для этого скопируем текущее значение EDI и перейдём на него в окне дампа.
Далее прокрутим чуть вверх до такого места:

00406000  C3 67 40 00 FF FF FF 7F D5 5F F1 77 3B 6A F1 77  Гg@.....Х_сw;jсw
00406010  3B AC F1 77 F1 5F F1 77 D2 B4 F1 77 0B 5D F1 77  ;.сwс_сwТ.сw.]сw
00406020  A7 5B F1 77 49 C4 F1 77 80 AD F3 77 A0 59 F1 77  §[сwIДсw..уw.Yсw
00406030  FF FF FF 7F 2A E9 81 7C 2F FE 80 7C A9 CC 80 7C  ....*й.|/ю.|©М.|
00406040  2F 08 81 7C 77 9B 80 7C 67 CC 80 7C 42 24 80 7C  /..|w..|gМ.|B$.|
00406050  E0 C6 80 7C 29 C7 80 7C B9 8F 83 7C F1 BA 80 7C  аЖ.|)З.|№Џ.|сє.|
00406060  1B 31 90 7C CF C6 80 7C 65 A0 80 7C 82 00 81 7C  .1.|ПЖ.|e..|...|
00406070  19 01 81 7C 2D FF 80 7C AC 92 80 7C 29 B5 80 7C  ...|-..|...|)µ.|
00406080  ED 66 40 00 DD 66 40 00 CF 66 40 00 47 68 40 00  нf@.Эf@.Пf@.Gh@.
00406090  FF FF FF 7F A4 C9 D3 77 AE E2 D3 77 88 C9 D3 77  .....ЙУw®вУw.ЙУw

Ниже продолжается наша таблица, а вот выше - нули, значит VA начала таблицы - 00406000, а
RVA - 00006000. Теперь определим конец таблицы. Вообще-то, нам нужен не конец таблицы,
а её размер, т.е. Size, но мы, вычтя от адреса конца таблицы адрес начала, получим эту
искомую величину. Для этого применим (мой любимый:) метод "тупого трейса". А именно, зажмём
F8 и будем смотреть, какое значение последним поменяется перед запуском проги. У меня это
было значение 0040616B. А его RVA - 0000616B. Теперь с помощью калькулятора (или кто хочет,
может в уме, т.к. тут вычитать нечего) вычтем из конца начало. Получим Size 0000016B.
Теперь можем смело запускать ImpRec, в процессах выбирать нашу прогу, стоящую всё ещё под
отладчиком, и вбивать полученную инфу в поле RVA - 00006000 и Size - 0000016B. Далее жмём
Get Imports и видим ветку с надписью NO напротив. Но это уже почти конец. Далее просто
жмём Show Invalid и видим, что их там очень мало таких, и они какие-то без смысла - эти
невосстановленные функции, поэтому смело жмём Cut thunk(s) и получаем пять (заметьте, не одну:)
валидных веток с функциями. Теперь жмём Fix dump и выбираем наш дамп, тот, который уже с
восстановленными ресурсами. Таблица импорта успешно восстановлена. Переходим к финалу.
Несмотря на все наши старания, наш дамп до сих пор неработоспособен! Прямо как на форуме,
но давайте попробуем разобраться, в чём же дело. Грузим дамп в отладчик и... и мне всё
ясно. Дело в том, что мы забыли поправить ОЕР, ведь указывая параметры импорта вручную, мы
обошлись без ОЕР, поэтому ImpRec и не поправил её значение. Но мы можем это сделать сами.
Открываем наш дамп в Pe Editor'e из LordPe, в поле OEP вписываем значение, которое мы
определили ещё вначале, а именно - 000013CB. Далее жмём Save и ОК. Теперь делаем Rebuild Pe
и на этой мажорной ноте заканчивается распаковка, т.к. дамп полностью работоспособен:)

Заключение

Надеюсь, после изучения данного тьютора все вопросы по FSG 2.0 отпадут и больше никогда не
возникнут. Жаль только, что на все вопросы форумов не накатаешь по тьютору. Удачи вам в
дальнейшем реверсинге!:)Да, к слову, на распаковку у меня ушло приблизительно 15 минут:)

Благодарности

Спасибо cracklab за размещение данного материала и поддержку сотен крэкеров, спасибо моим
друзьям за поддержку одного крэкера, т.е. меня:) И вам, ребята с форума, которые обсуждали
вышеизложенную проблему, тоже спасибо, и тебе, читатель.




Обсуждение статьи: Распаковка FSG 2.0 - развеивание мифов >>>


Комментарии к статье: Распаковка FSG 2.0 - развеивание мифов

DrFits 29.09.2006 01:31:55
Теперь с помощью калькулятора (или кто хочет,
может в уме, т.к. тут вычитать нечего) вычтем из конца начало - в олли можно с левой стороны нажать на адреса мышкой, и увидишь смещение от начала таблицы до конца, типа
$ ==> >00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
$ 10 >00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
$ 20 >00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

вот 10, 20 и т.д. это размер, и никакого калькулятора ненадо (типа оптимизация) ;)
---

Материалы находятся на сайте https://exelab.ru



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


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