Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   Авторские статьи (https://forum.antichat.xyz/forumdisplay.php?f=31)
-   -   Распаковка PESpin 0.7 (https://forum.antichat.xyz/showthread.php?t=28832)

taha 10.12.2006 16:55

Распаковка PESpin 0.7
 
Распаковка PESpin 0.7

Содержание
Введени
Инструменты
Поиск OEP
Восстановление импорта
Умный в гору не пойдёт
Заключение

Введение

Сегодня я покажу как вручную распаковать протектор PESpin. Итак, подопытную программу вы можете скачать тут: http://www.tuts4you.com/blogs/download.php?view.338 Что такое? Там же тутор есть. - скажет читатель. Да есть и кое-где мы будем на него опираться. Просто я расскажу больше чем в туторе. Вы в этом убедитесь. Эта статья посвящена скорее тому, как обойти злобный протектор.

Инструменты
Ollydbg + plugins(OllyScript,OllyDump,CmdBar)
Imp Rec
И всё!!!

Поиск OEP
Грузим прогу в Olly. Давайте просто запустим программу, F9. Она тормозится на каком то исключении, нам первые исключения не интересны. Идём дальше.

Код:

004001C9  FFFF            ???                                      ; Unknown command
004001CB  FFFF            ???                                      ; Unknown command
004001CD  FFFF            ???                                      ; Unknown command
004001CF  FFFF            ???                                      ; Unknown command
004001D1  FFFF            ???                                      ; Unknown command
004001D3  FFFF            ???                                      ; Unknown command
004001D5  FFFF            ???                                      ; Unknown command
004001D7  FFFF            ???                                      ; Unknown command

Код:

00407F17  2BDB            SUB EBX,EBX
00407F19  64:8F03          POP DWORD PTR FS:[EBX]
00407F1C  58              POP EAX
00407F1D  5D              POP EBP

И программа запущена.
Скорее всего OEP будет идти после последнего или предпоследнего исключения (чаще после последнего).
Ставим бряк на esp-4.Через CmdBar, набрав hr esp-4. Или можно, пройдя pushad, выбрать в окне регистров esp, нажать на правую и выбрать Follow in dump.
В окне дампа, выделяем первые четыре байта, на правую Breakpoint > Hardware, on access > Dword.
F9, и идём до последнего исключения, ещё Shift-F9.
Ctrl-A - и Олька анализирует код.

Код:

00407087  61              POPAD
00407088  6A 00            PUSH 0 ; <----- Мы тут
0040708A  EB 01            JMP SHORT packed.0040708D
0040708C  E3 68            JECXZ SHORT packed.004070F6
0040708E  97              XCHG EAX,EDI
0040708F  70 40            JO SHORT packed.004070D1
00407091  00E9            ADD CL,CH

Дальше трейсим по F8. После прыжка попадаем на пару байт ниже.

Код:

0040708D  68 97704000      PUSH packed.00407097
00407092  -E9 7DA0FFFF      JMP packed.00401114

Мда странно. Зачем такие переходы? Лан идём дальше.

Код:

00401114  .-E9 04EF4600    JMP 0087001D
00401119    FF            DB FF
0040111A  $-E9 6BEF4600    JMP 0087008A
0040111F    FF            DB FF

Хм ничего не напоминает? Мне да!! Переходы на импортируемые функции. Но нефакт.
Дальше.

0087001D EB 01 JMP SHORT 00870020

Код:

00870020  8BFF            MOV EDI,EDI                              ; packed.00407B1D
00870022  55              PUSH EBP
00870023  8BEC            MOV EBP,ESP
00870025  837D 08 00      CMP DWORD PTR SS:[EBP+8],0
00870029  EB 07            JMP SHORT 00870032

Идём до прыжка, и f8.

00870032 ^EB F8 JMP SHORT 0087002C
Дальше.

0087002C -E9 01B5F97B JMP kernel32.7C80B532

Ещё =).

7C80B532 74 18 JE SHORT kernel32.7C80B54C

Мы в kernel32, а если взглянуть ниже иожно увидеть вызов GetModuleHandleW.

Посмотрим на пару байт выше.

Код:

7C80B529 > 8BFF            MOV EDI,EDI
7C80B52B  55              PUSH EBP
7C80B52C  8BEC            MOV EBP,ESP
7C80B52E  837D 08 00      CMP DWORD PTR SS:[EBP+8],0

Помоему я где то это уже видел. Смотри 00870020. Хех он что, у API байты ворует? Откуда всё началось?

Код:

00407088  6A 00            PUSH 0 ;
0040708A  EB 01            JMP SHORT packed.0040708D

Протектор возвращяет на место значения раегостров (popad). А дальше судя по всему идёт API. OEP? Надо проверить нашу догадку. Трейсим дальше.

Скажем, не далеко от вызова GetModuleHendleA, мы попадаем в USER32, посмотрев ниже, мы видим:

Код:

77D4891B  6A 02            PUSH 2
77D4891D  FF75 18          PUSH DWORD PTR SS:[EBP+18]
77D48920  FF75 14          PUSH DWORD PTR SS:[EBP+14]
77D48923  FF75 10          PUSH DWORD PTR SS:[EBP+10]
77D48926  50              PUSH EAX
77D48927  56              PUSH ESI
77D48928  E8 69DFFFFF      CALL USER32.DialogBoxIndirectParamAorW

Это скорее всего DialogBoxParamA. Из чего можно сделать вывод, что 00407088 - это искомый OEP. Удаляем бряк с esp.

Ну и снимаем дамп естественно, через OllyDump.

Т.к. до OEP, в процессе исследования, придётся доходить часто, напишем скрипт:

go_to_OEP.txt
Код:

        var real_OEP
        mov real_OEP,00407088        // найденый OEP
        var ex_OEP
        mov ex_OEP,00407F17        // последнее исключение
ff:
        eoe fOEP
        esto
fOEP:
        cmp eip,ex_OEP
        jne ff
        bp real_OEP
        esto
        bc real_OEP
        cmt eip," <------------- OEP"
        an real_OEP
        ret

ex_OEP - это то самое исключение, после которого идёт OEP. Сначала мы идём до последнего исключения. Это делается для того, что бы нам ничего не мешало в процессе прохода до OEP. Вобщем после того как доходим до последнего исключения, ставим бряк на OEP и esto (Shift-F9). Мы на OEP. Согласитесь, использовать скрипт очень удобно, он экономит время.

Восстановление импорта
Да, будет нелегко, но мы справимся.
Итак, перезапускаем программу, вызываем наш скрипт go_to_oep.
Т.к. протектор прыгает на пару байт дальше адреса функции, ImpRec нам не поможет. Придётся делать список функций, что бы составиь файл для ImpRec. Есть несколько способов решения данной проблемы.
Первый:
Нужно поставтить бряки на все вызовы функций (я имею ввиду на jump'ы начиная с 0040110E). И запустить программу (F9), дальше, когда сработают бряки, идти до функций и подниматься на пару байт вверх. F10 > Search for >Name in all modules.
Опять F10 > Sort by > Address (Это упростит поиск). Ищем полученный адрес.
Например:

Первый раз бряк сработает тут ( GetModuleHandleA, но мы этого пока не знаем =) )
00401114 .-E9 04EF4600 JMP 0087001D

F8 пока не попадём сюда:
7C80B532 74 18 JE SHORT kernel32.7C80B54C

Вверх на пару байт. Как мы знаем функция начинается c
7C80B529 > 8BFF MOV EDI,EDI

Следовательно в окне All names ищем 7C80B529.
7C80B529 .text Export GetModuleHandleA

И так с каждой функцией.

Втрой:
Мы всё ещё на OEP.
Откроем окно memory map (Alt-M), и посмотрим как в памяти рапсоложенна наша прога.

Код:

00400000  00001000  packed                PE header    Imag  RWE      RWE
00401000  00001000  packed    .petite    code          Imag  RWE      RWE
00402000  00001000  packed    .petite    data          Imag  RWE      RWE
00403000  00001000  packed    .petite                  Imag  RWE      RWE
00404000  00002000  packed    .rsrc      resources    Imag  RWE      RWE
00406000  00003000  packed    .petite    SFX,imports  Imag  RWE      RWE
00410000  00103000                                      Map    R        R
00520000  00129000                                      Map    R E      R E
00820000  00003000                                      Map    R        R
00830000  00008000                                      Priv  RW        RW
00840000  00001000                                      Priv  RW        RW
00850000  00001000                                      Priv  RW        RW
00860000  00004000                                      Priv  RW        RW
00870000  00001000                                      Priv  RWE      RWE
5D5B0000  00001000  COMCTL32              PE header    Imag  R        RWE
5D5B1000  00070000  COMCTL32  .text      code,imports  Imag  R        RWE

Мы знаем, что в процессе работы она гуляет по всем байтам до 5D5B0000.
Вернёмся назад.
Мы знаем, что код программы и протетора выполняется от 00400000 до 5DB0000. Давайте задаим параметры трассировки Debug > Set condition (Ctrl-T).
В первом и во втором полях EIP is outside the range пишем 00400000 и 5DB0000 соответственно. Ставим галочку напротив EIP is outside the range, OK.
Ctrl-F11 и мы тут:
7C80B532 74 18 JE SHORT kernel32.7C80B54C
Ну дальше опять поднимаемся на пару байт вверх. Ищем адрес функции в Name in all Modules.

И когда мы закончим у нас будет вот такой список:
Код:

KERNEL32----------------

40110E
All names, item 17785
 Address=7C81CAA2 kernel32
 Section=.text
 Type=Export  (Known)
 Name=ExitProcess

401114
All names, item 5136
 Address=7C80B529 kernel32
 Section=.text
 Type=Export  (Known)
 Name=GetModuleHandleA

USER32----------------


40111A
Names in USER32, item 15
 Address=77D3B4B1
 Section=.text
 Type=Export  (Known)
 Name=BeginPaint

401120
All names, item 1707
 Address=77D488E1 USER32
 Section=.text
 Type=Export  (Known)
 Name=DialogBoxParamA

401126
All names, item 9904
 Address=77D46CC9 USER32
 Section=.text
 Type=Export  (Known)
 Name=EndDialog

40112C
All names, item 9704
 Address=77D3B4C5 USER32
 Section=.text
 Type=Export  (Known)
 Name=EndPaint

401132
All names, item 9901
 Address=77D467A8 USER32
 Section=.text
 Type=Export  (Known)
 Name=LoadBitmapA

401138
Names in USER32, item 825
 Address=77D3E2AE
 Section=.text
 Type=Export  (Known)
 Name=SendMessageA


GDI32----------------

40113E
All names, item 12302
 Address=77F16DC0 GDI32
 Section=.text
 Type=Export  (Known)
 Name=BitBlt

401144
All names, item 12283
 Address=77F15E10 GDI32
 Section=.text
 Type=Export  (Known)
 Name=CreateCompatibleDC

40114A
All names, item 12301
 Address=77F16CA6 GDI32
 Section=.text
 Type=Export  (Known)
 Name=DeleteDC
       
401150
All names, item 12300
 Address=77F16A3B GDI32
 Section=.text
 Type=Export  (Known)
 Name=DeleteObject

401156
All names, item 12279
 Address=77F159A0 GDI32
 Section=.text
 Type=Export  (Known)
 Name=SelectObject

Дальше нам нужно составить файл импорта для ImpRec.

paced.txt
Код:

Target: C:\packed.exe
OEP: 00007088        IATRVA: 0000306C        IATSize: 00000100

FThunk: 00003070        NbFunc: 00000006
1        00003070        user32.dll        000E        BeginPaint
1        00003074        user32.dll        009F        DialogBoxParamA
1        00003078        user32.dll        00C7        EndDialog
1        0000307C        user32.dll        00C9        EndPaint
1        00003080        user32.dll        01B6        LoadBitmapA
1        00003084        user32.dll        023C        SendMessageA

FThunk: 0000308C        NbFunc: 00000002
1        0000308C        kernel32.dll        00B0        ExitProcess
1        00003090        kernel32.dll        016F        GetModuleHandleA

FThunk: 00003098        NbFunc: 00000005
1        00003098        gdi32.dll        0013        BitBlt
1        0000309C        gdi32.dll        002E        CreateCompatibleDC
1        000030A0        gdi32.dll        008D        DeleteDC
1        000030A4        gdi32.dll        0090        DeleteObject
1        000030A8        gdi32.dll        020F        SelectObject

Открывеам ImpRec вибираем процесс и жмём на Load tree, выбираем packed.txt. Fix'ируем на dumped.exe.

Запускаем наш dumped_.exe. Что такое? он не работает =(. Ну естественно надо ещё jump'ы подправить.

Открываем dumped_.exe. Ctrl-G > 0040110E. Мда гора мусора.
Код:

0040110E    E9            DB E9
0040110F    ED            DB ED
00401110    EE            DB EE
00401111    46            DB 46                                    ;  CHAR 'F'
00401112    00            DB 00

Ctrl-B,галочка с keep size убрана, пишем FF25, Ok. Появился jump.
Код:

0040110E    FF25 EE4600FF  JMP DWORD PTR DS:[FF0046EE]
Теперь откопируем его столько раз, сколько у нас функций.
Теперь исправляем адреса. Адреса функций храняться в .mackt. У меня это адрес 00409000. Там лежат адреса наших функций. Так вот исправляем наши джампы.
Вместо FF0046EE будет адрес адреса функции. Вот:
Код:

0040110E    -FF25 A2CA817C  JMP DWORD PTR DS:[kernel32.ExitProcess]
Все jump должны остаться на своиз местах, нльзя менять местами функции.
Как мне разобраться что есть что в окне дампа .mackt? - спросит читатель. Действительно трудно, но вспомнить адреса апи вам поможет плагин APIFinder.

Умный в гору не пойдёт
Как всё геморойно! Скажет чиатель и будет прав. Я тоже не люблю возиться с импортом. Главное найти OEP, а там.... Но этот протектор ворует байты у API, что очень затрудняет взлом. И тут вступаю в дело я =)).
А что если написать скрипт который сам восстановит IAT. Приступим.
Итак код прохода до OEP есть.
Вернёмся в packed.exe.
Что делать дальше? Идея очень проста. Поставим бряки на все джампы.
Код:

        var y // первый jump
        mov y,0040110E
f_IAT:
        bp y
        add y,6
        cmp y,0040115C
        jne f_IAT
        eob f_bpx
        run

Дальше по мере срабатывания бряков, мы будим их удалять. Когда сработает бряк, мы будем к примеру тут:
00401114 .-E9 04EF4600 JMP 0087001D
Введём переменную, в которую будем сохранять адрес jmp.
var otcuda
Проходим jmp'ы:
sto
sto
И мы тут:
00870020 8BFF MOV EDI,EDI ; packed.00407B1D
Нужно посчитать растояние до перехода к переходу на переход к функции =). Тобишь до сюда:
00870029 EB 07 JMP SHORT 00870032
Мы же должны знать сколько байт спёр протектор.
Код:

        findop eip,#EB07#
        mov count,$RESULT
        sub count,eip

Конечно перед этим вводим переменную count. Дальше идём до этого jump'а:
Код:

sol_byte:
        sti
        cmp eip,$RESULT
        jne sol_byte

Проходим джампы:
Код:

        sto
        sto
        sto

И мы в kernel32, ну или где там будем. Вычисляем адрес начала функции:
Код:

        mov x,eip
        sub x,count

и сохраняем его в какю-нибудь не нужную программе область. Я выбрал 0040115F.
Пишем туда адрес функции и снимаем бряк с джампа.
Код:

        mov [cuda],x       
        bc otcuda

Теперь на место старого пишем новый.
Код:

        mov [otcuda],25FF
        add otcuda,2
        mov [otcuda],cuda

Увеличиваем cuda на 4. И:
Код:

        run
        jmp f_bpx

Вот скрипт:
Код:

        var real_OEP
        mov real_OEP,00407088        // найденый OEP

        var ex_OEP
        mov ex_OEP,00407F17        // последнее исключение
ff:
        eoe fOEP
        esto
fOEP:
        cmp eip,ex_OEP
        jne ff
        bp real_OEP
        esto
        bc real_OEP
        cmt eip," <------------- OEP"
        an real_OEP

        var count
        var x
        var y
        mov y,0040110E
        var otcuda
        var cuda
        mov cuda,0040115F

f_IAT:
        bp y
        add y,6
        cmp y,0040115C
        jne f_IAT
        eob f_bpx
        run
f_bpx:       
        mov otcuda,eip
        sto
        sto
        findop eip,#EB07#
        mov count,$RESULT
        sub count,eip

sol_byte:
        sti
        cmp eip,$RESULT
        jne sol_byte

        sto
        sto
        sto
        mov x,eip
        sub x,count
        mov [cuda],x       
        bc otcuda
        mov [otcuda],25FF
        add otcuda,2
        mov [otcuda],cuda
        add cuda,4
        run
        jmp f_bpx

Запускаем его. После того как окно запустится и перестанет бегать строчка: Ctrl-G > 0040110E. И вот что там:
Код:


0040110E  .-E9 EDEE4600    JMP 00870000
00401113    FF            DB FF
00401114    -FF25 5F114000  JMP DWORD PTR DS:[40115F]                ;  kernel32.GetModuleHandleA
0040111A    -FF25 6B114000  JMP DWORD PTR DS:[40116B]                ;  USER32.BeginPaint
00401120    -FF25 63114000  JMP DWORD PTR DS:[401163]                ;  USER32.DialogBoxParamA
00401126  $-E9 21EF4600    JMP 0087004C
0040112B    FF            DB FF
0040112C    -FF25 7B114000  JMP DWORD PTR DS:[40117B]                ;  USER32.EndPaint
00401132    -FF25 67114000  JMP DWORD PTR DS:[401167]                ;  USER32.LoadBitmapA
00401138  $-E9 81EF4600    JMP 008700BE
0040113D    FF            DB FF
0040113E    -FF25 77114000  JMP DWORD PTR DS:[401177]                ;  GDI32.BitBlt
00401144    -FF25 6F114000  JMP DWORD PTR DS:[40116F]                ;  GDI32.CreateCompatibleDC
0040114A    -FF25 7F114000  JMP DWORD PTR DS:[40117F]                ;  GDI32.DeleteDC
00401150  $-E9 AAEF4600    JMP 008700FF
00401155    FF            DB FF
00401156    -FF25 73114000  JMP DWORD PTR DS:[401173]                ;  GDI32.SelectObject

Да определились не все функции, но ведь не все бряки сработали. Закрываем программу. И строчка опять побежала, после остановки: Ctrl-G > 0040110E.
Код:

0040110E  .-FF25 8F114000  JMP DWORD PTR DS:[40118F]                ;  kernel32.ExitProcess
00401114  .-FF25 5F114000  JMP DWORD PTR DS:[40115F]                ;  kernel32.GetModuleHandleA
0040111A  $-FF25 6B114000  JMP DWORD PTR DS:[40116B]                ;  USER32.BeginPaint
00401120  .-FF25 63114000  JMP DWORD PTR DS:[401163]                ;  USER32.DialogBoxParamA
00401126  $-FF25 8B114000  JMP DWORD PTR DS:[40118B]                ;  USER32.EndDialog
0040112C  $-FF25 7B114000  JMP DWORD PTR DS:[40117B]                ;  USER32.EndPaint
00401132  $-FF25 67114000  JMP DWORD PTR DS:[401167]                ;  USER32.LoadBitmapA
00401138  $-FF25 83114000  JMP DWORD PTR DS:[401183]                ;  USER32.SendMessageA
0040113E  $-FF25 77114000  JMP DWORD PTR DS:[401177]                ;  GDI32.BitBlt
00401144  $-FF25 6F114000  JMP DWORD PTR DS:[40116F]                ;  GDI32.CreateCompatibleDC
0040114A  $-FF25 7F114000  JMP DWORD PTR DS:[40117F]                ;  GDI32.DeleteDC
00401150  $-FF25 87114000  JMP DWORD PTR DS:[401187]                ;  GDI32.DeleteObject
00401156  $-FF25 73114000  JMP DWORD PTR DS:[401173]                ;  GDI32.SelectObject
0040115C    00            DB 00
0040115D    00            DB 00
0040115E    00            DB 00
0040115F  . 29B5807C      DD kernel32.GetModuleHandleA
00401163  . E188D477      DD USER32.DialogBoxParamA
00401167  . A867D477      DD USER32.LoadBitmapA
0040116B  . B1B4D377      DD USER32.BeginPaint
0040116F  . 105EF177      DD GDI32.CreateCompatibleDC
00401173  . A059F177      DD GDI32.SelectObject
00401177  . C06DF177      DD GDI32.BitBlt
0040117B  . C5B4D377      DD USER32.EndPaint
0040117F  . A66CF177      DD GDI32.DeleteDC
00401183  . AEE2D377      DD USER32.SendMessageA
00401187  . 3B6AF177      DD GDI32.DeleteObject
0040118B  . C96CD477      DD USER32.EndDialog
0040118F  . A2CA817C      DD kernel32.ExitProcess

Копируем всё это великолепие через binary copy.
Перезапускаем программу, идём до OEP, Ctrl-A, Ctrl-G > 0040110E, вставляем всё что накопровали.
Ctrl-A, поднимитесь выше!!
Код:

004010A5  |. 50            PUSH EAX                                ; /pPaintstruct
004010A6  |. FF75 08        PUSH DWORD PTR SS:[EBP+8]                ; |hWnd
004010A9  |. E8 6C000000    CALL packed.0040111A                    ; \BeginPaint
004010AE  |. 8945 BC        MOV DWORD PTR SS:[EBP-44],EAX
004010B1  |. FF75 BC        PUSH DWORD PTR SS:[EBP-44]              ; /hDC
004010B4  |. E8 8B000000    CALL packed.00401144                    ; \CreateCompatibleDC

Без комментариев!!

Заключение
Не парься %)!

taha 11.12.2006 01:10

Если немного изменить мой скрипт, может прокатить и с PESpin 1.304.


Время: 10:19