Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей.
Здесь обсуждаются безопасность, программирование, технологии и многое другое.
Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
 |

10.12.2006, 16:55
|
|
Постоянный
Регистрация: 20.08.2006
Сообщений: 327
Провел на форуме: 2472378
Репутация:
1077
|
|
Распаковка 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
Проходим джампы:
И мы в kernel32, ну или где там будем. Вычисляем адрес начала функции:
Код:
mov x,eip
sub x,count
и сохраняем его в какю-нибудь не нужную программе область. Я выбрал 0040115F.
Пишем туда адрес функции и снимаем бряк с джампа.
Код:
mov [cuda],x
bc otcuda
Теперь на место старого пишем новый.
Код:
mov [otcuda],25FF
add otcuda,2
mov [otcuda],cuda
Увеличиваем cuda на 4. И:
Вот скрипт:
Код:
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
Без комментариев!!
Заключение
Не парься %)!
|
|
|

11.12.2006, 01:10
|
|
Постоянный
Регистрация: 20.08.2006
Сообщений: 327
Провел на форуме: 2472378
Репутация:
1077
|
|
Если немного изменить мой скрипт, может прокатить и с PESpin 1.304.
|
|
|
|
 |
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|