Только для образовательных целей! |
|
Автор: | bi0w0rM [AHTeam] |
Уровень: | Для опытных |
Программа: |
Тип защиты: |
Инструменты: |
[ iNTR0 ] Привет! Поначалу хочу сказать, что все рулез и поздравить всех с Новым 2004 годом! :) Как поздравил меня ViNCE: "Желаю всего наилучшего! Успехов в нашем нелёгком труде! :)) Чтобы все триалы становились длинной в жизнь, наги занопились :))), успешно находились OEP'ы, хорошо дампилось и прекрасно восстанавливался импорт! :))))))))))". Вот и вам того же! А я в Новый Год пытался разделаться с SVKP 1.3. Скачал с их сайта http://www.anticracking.sk . Хмм... Посмотрел я куда-то, уже не помню: Thanks to ELiCZ, ... И перечислена куча крутых кодеров и реверсеров :) Ну думаю, для меня все окончится плохо, я не скажу "Ура!" и вообще ... не получу удовлетворения от исследования, почувствую слабость и беспомощность. Но "...все не так на этот раз, она сказала мне..."
[ t00Lz ] Что нам надо в "нашем нелегком деле"? Как гладиаторы выбирают оружие для поединка, так и мы возьмем самое необходимое и нужное. OS: Ой не знаю... Я все проделал на WinXP, но думаю, что траблов у вас на 9x не возникнет:) PE Tools 1.5: у меня по сегодняшним меркам последний, Xmas Edition IDA Pro: без нее фик обойдешься. версия - чем больше, тем лучше. Я "юзал" 4.30 PELG (Predator's Extreme Loader Generator): он нам будет нужен для временных исследований. У меня версия 0.3 MASM32: ассемблер-компилятор. У меня версия 8.0
Все это можно скачать у DeMoNiX'а на сайте reversing.kulichki.ru, на www.wasm.ru, PE Tools свежий всегда есть на uINC.ru Если что-то не будет найдено, то есть еще protools.cjb.net и www.exetools.com.
[ RiPPiNG ] Следует помнить, если не победим - наш удел быть съеденными львами. Поэтому надо постараться вырвать победу, хоть из рук самого дьявола, пусть на это уйдут годы, но твой враг не станет столько ждать... :) Поэтому, чтоб потом не долбить меня лишними вопросами, прочтите внимательно эти страницы и может быть вам улыбнется удача! Хочу сказать, что RE-деятели делятся по своей направленности на несколько независимых ветвей. Первая - все-таки зависимая, это новички. Они пока еще может и не определились быть реверсерами - их тянет на vx,nethack(в стиле засунуть трояна соседу) и прочие направления хак-сцены. Вторая группа: середнячки. Они уже четко во всем определились, уже многое понимают и умеют, но в них еще есть новичковство и нет самостоятельности. Дальше идут крутые дядьки/парни-реверсеры, некоторых из них еще называют профи. Они в свою очередь делятся также на практиков и сухих практиков. Сухие практики - это обычно челы, входящие в какие-нибудь команды. Чтоб явнее почувствовать отличие, приведу пример: сухарю пофигу - ему не надо париться над распаковкой мудреного пакера/протектора и над восстановкой импорта - результату от этого ноль. Главное хоть как-нибудь забахать кряк/loader/кейген и положить это в инет или продать кому-нибудь. Другим же лишь бы распаковать, да вручную к тому же! Порой им важнее не получить полнофункционирующую и нетриальную(пожизненноживучую) прогу, а просто распаковать - получить рабочий дамп!! Обоих можно понять и поправу назвать маньяками. К чему такое догое тянучее вступление? Да не знаю, хочется просто поделиться своими убеждениями. Может кто сможет выделить еще одну категорию реверсеров - можете сообщить. Например я вижу еще supplier'ов, но они в прямом смысле не являются реверсерами. Итак, о проге... На форуме cr@acklab я поднял тему про SVKP - мне захотелось узнать, как распаковать это чудо. У кого-то оказался туториал, именно по этой проге. Но там была версия 2.5, а у меня оказалась 2.95, чего я не ожидал при скачивании - там же было написано, что 2.5... В общем по туториалу я распаковать не смог :( версия SVKP тоже оказалась другой. И тут я переключился на второй тип реверсеров-маньяков. Дальше мои действия записывайте под диктовку:) : Я запустил прогу и сдампил(Full Dump) этот процесс в PE Tools. (в настройках стояли галочки - Rebuild Image, fix header). Дамп сохранил в папке проги. Потом дизассемблировал его в IDA Pro. Пока ждал, врубил музыку и стал ждать... Когда IDA закончил(а) свое дело, смотрим Strings. развернем его(окно) для удобства. Ага, в меню About у проги стоит licensed to: <Unregistered>. Поэтому в IDA жмем Alt+T и пишем "licensed to:". Видим такие строки:
========-----------------<>-----------------======== seg000:004B1D8C aThisProductLic: ; DATA XREF: sub_4B1CDC+3Co seg000:004B1D8C unicode 0, <This product licensed to:> seg000:004B1D8C dw 3Ch seg000:004B1D8C unicode 0, <Unregistered> seg000:004B1D8C dw 3Eh seg000:004B1D8C unicode 0, <>,0 seg000:004B1DDC dd 0FFFFFFFFh, 19h seg000:004B1DE4 aThisProductL_0 db 'This product licensed to:',0 ; DATA XREF: sub_4B1CDC+5Bo ========-----------------<>-----------------======== То что надо! Двойным кликом по DATA XREF: sub_4B1CDC+3Co видим следующее:
========-----------------<>-----------------======== seg000:004B1CF4 mov eax, ds:dword_4FB7D4 seg000:004B1CF9 cmp byte ptr [eax], 0 seg000:004B1CFC jnz short loc_4B1D2C seg000:004B1CFE mov edx, 0FFFFFE00h seg000:004B1D03 mov eax, [ebx+310h] seg000:004B1D09 call sub_495AF4 seg000:004B1D0E mov edx, 0FFh seg000:004B1D13 call sub_41963C seg000:004B1D18 mov ecx, offset aThisProductLic ; "This product licensed to:<Unregistered>"... seg000:004B1D1D xor edx, edx seg000:004B1D1F mov eax, [ebx+310h] seg000:004B1D25 call sub_49686C seg000:004B1D2A jmp short loc_4B1D5C seg000:004B1D2C ; --------------------------------------------------------------------------- seg000:004B1D2C seg000:004B1D2C loc_4B1D2C: ; CODE XREF: sub_4B1CDC+20j seg000:004B1D2C mov ecx, ds:dword_4FB7FC seg000:004B1D32 mov ecx, [ecx] seg000:004B1D34 lea eax, [ebp+var_8] seg000:004B1D37 mov edx, offset aThisProductL_0 ; "This product licensed to:" ========-----------------<>-----------------======== Нам явно надо, чтобы jnz short loc_4B1D2C сработал. А его работа зависит от стоящей перед ним команды cmp, которая влияет на флаг нуля. Она сравнивает EAX с 0, а в EAX лежит байт dword_4FB7D4. Значит можно
сменить на
и тогда вместо <Unregistered> встанет наше имя, но об этом позже. Давайте состряпаем небольшой лоадер и посмотрим, правильно ли мы думаем. Запускаем PELG, указываем путь к проге, добавляем(Add) новый RVA. Команды CMP занимает три байта. Последний - это то, с чем сравнивать. Нам надо, чтоб было сравнение с 01. Значит RVA третьего байта будет... 4B1CF9+2, калькулятор от винды поможет сосчитать :)) А вообще такие вещи в уме считать надо :) 4B1CFB. Прописываем это в RVA, а дальше New Bytes - мы пишем 01. Пробуем - лоадер работает, но уже пишет не <Unregistered>, а какую-то муру. Непорядок! Надо зарегиться! Тогда и рег-инфа о нас возьмется :) Можно искать место проверки ее двумя путями: искать в Strings сообщение о неправильности рег-номера или поступить, как я. Даббл-кликаем по dword_4FB7D4 и попадаем в место объявления этой переменной. Скорее всего, когда писали эту прогу, это была что-то типа BOOL, то есть принимало значения true/false(у нас 1 или 0). Вот и подумаем, как бы мы поступили бы на месте разработчиков :) я бы так не поступил, но они... Сейчас мы вот здесь:
========-----------------<>-----------------======== seg001:004FB7D4 dword_4FB7D4 dd 4FC8C0h ; DATA XREF: sub_4B1CDC+18r seg001:004FB7D4 ; sub_4E1238+DCr ... ========-----------------<>-----------------======== Значит переменная юзается в двух местах. Первое - sub_4B1CDC+18, там мы уже были, а вот sub_4E1238+DC.. попадаем туда:
========-----------------<>-----------------======== seg000:004E1314 mov eax, ds:dword_4FB7D4 seg000:004E1319 cmp byte ptr [eax], 0 seg000:004E131C jz short loc_4E1343 seg000:004E131E mov eax, ds:dword_4FB858 seg000:004E1323 cmp dword ptr [eax], 0 seg000:004E1326 jz short loc_4E1334 seg000:004E1328 mov eax, ds:dword_4FB858 seg000:004E132D mov eax, [eax] seg000:004E132F call sub_4DE49C seg000:004E1334 seg000:004E1334 loc_4E1334: ; CODE XREF: sub_4E1238+EEj seg000:004E1334 lea eax, [ebp+var_14] seg000:004E1337 mov edx, offset aThankYouForReg ; "Thank you for registering Registry Medi"... seg000:004E133C call sub_403D40 seg000:004E1341 jmp short loc_4E1350 seg000:004E1343 ; --------------------------------------------------------------------------- seg000:004E1343 seg000:004E1343 loc_4E1343: ; CODE XREF: sub_4E1238+E4j seg000:004E1343 lea eax, [ebp+var_14] seg000:004E1346 mov edx, offset aRegistrationFa ; "Registration failed. Please try again!" seg000:004E134B call sub_403D40 seg000:004E1350 ========-----------------<>-----------------======== Вау! Да это же сообщения о регистрации! После умственного анализа команд приходим к выводу: несруки, если будет работать один из: Таким же образом, пробуем в PELG прописать, чтоб он менял оба
cmp byte ptr [eax], 0 на cmp byte ptr [eax], 1 Нифика не получается зарегиться, значит копаем дальше, а именно выше. Там есть еще одно похожее сообщение о том, что "Failed" вся наша регистрация:
========-----------------<>-----------------======== seg000:004E128C cmp eax, 6 seg000:004E128F jl loc_4E1385 seg000:004E1295 mov eax, [ebp+var_8] seg000:004E1298 call sub_403F28 seg000:004E129D cmp eax, 21h seg000:004E12A0 jl short loc_4E12BF seg000:004E12A2 mov eax, [ebp+var_4] seg000:004E12A5 call sub_4E1D78 seg000:004E12AA test al, al seg000:004E12AC jnz short loc_4E12BF seg000:004E12AE mov edx, [ebp+var_C] seg000:004E12B1 mov eax, offset dword_4E13E4 seg000:004E12B6 call sub_404214 seg000:004E12BB test eax, eax seg000:004E12BD jnz short loc_4E1304 seg000:004E12BF seg000:004E12BF loc_4E12BF: ; CODE XREF: sub_4E1238+68j seg000:004E12BF ; sub_4E1238+74j seg000:004E12BF lea eax, [ebp+var_14] seg000:004E12C2 mov edx, offset aRegistrationFa ; "Registration failed. Please try again!" ========-----------------<>-----------------======== После мозгового анализа видим: jl loc_4E1385 посылает нас на сообщение, что длина введенного регномера неверная, но нам это не грозит, ибо мы не мудаки :) jl short loc_4E12BF и jnz short loc_4E12BF ведут нас на сообщение "Registration failed.", а jnz short loc_4E1304, что все хорошо. Сами смотрите, что вам лучше. Как подтасовать данные? Да никак. Добавляем новые RVA в PELG - 4E12A0 и 4E12AC, по ним обоим надо сделать запись 9090. А еще сделайте 4E12BD - там пусть пишет EB(jmp), тогда он будет у нас безусловно прыгать на "Thanks", а не на "Failed". Попробовал - работает. ДалееЮ копаясь в Strings нашел еще словечко: "Unregistered". На кой оно? Нафик его! Вдруг где-то что-то из-за него портится :) seg000:004D91DC aUnregistered db 'Unregistered',0 ; DATA XREF: seg000:004D9135o Дабл-кликаем на seg000:004D9135 и попадаем в код, где эта aUnregistered присутствует:
========-----------------<>-----------------======== seg000:004D911A call sub_4E1498 seg000:004D911F test al, al seg000:004D9121 jnz short loc_4D9156 seg000:004D9123 lea edx, [ebp-14h] seg000:004D9126 mov eax, [ebp-4] seg000:004D9129 call sub_430050 seg000:004D912E lea eax, [ebp-14h] seg000:004D9131 push eax seg000:004D9132 lea ecx, [ebp-18h] seg000:004D9135 mov edx, offset aUnregistered ; "Unregistered" ========-----------------<>-----------------======== Возможно al модифицирует процедура sub_4E1498 и в зависимости от этого решается - ставить или нет эту тупую строку. Тогда чтоб убить причину заходим в sub_4E1498 и видим:
========-----------------<>-----------------======== seg000:004E1498 sub_4E1498 proc near ; CODE XREF: seg000:004D8E60p seg000:004E1498 ; seg000:004D911Ap ... seg000:004E1498 mov eax, ds:dword_4FB7D4 seg000:004E149D cmp byte ptr [eax], 0 seg000:004E14A0 jz short loc_4E14A5 seg000:004E14A2 mov al, 1 seg000:004E14A4 retn seg000:004E14A5 ; --------------------------------------------------------------------------- seg000:004E14A5 seg000:004E14A5 loc_4E14A5: ; CODE XREF: sub_4E1498+8j seg000:004E14A5 xor eax, eax seg000:004E14A7 retn seg000:004E14A7 sub_4E1498 endp ========-----------------<>-----------------======== Хорошо IDA дизасмит прямо как настоящий асм-код показывает - даж начало и конец процедуры :) Оказывается эта процедура еще кой-где вызывается - в 004D8E60 и в 4D911A => это какая-то процедура проверки. И опять знакомый байт dword_4FB7D4, который мы приблизительно булевым окрестили. Он здесь движется в EAX и EAX сравнивается с нолем. Ну раз он всюду сравнивается, почему-бы не поставить ему в начале загрузки 01h и не мучаться? Не получается :) не так все просто :) В общем 4E149D+2=4E149F -> по этому RVA надо прописать 01, тогда cmp byte ptr [eax], 0 примет вид: cmp byte ptr [eax], 1 Ладно. Теперь, что реально может нас обломать - триал! Когда он кончается(я часы вперед перевел на 2 месяца) показывается сообщение "Trial Expired,please registration!". Я нашел его в Strings и посмотрел, где оно объявляется:
========-----------------<>-----------------======== seg000:004E21E4 aExpired db 'Expired',0 ; DATA XREF: sub_4E2098+27o seg000:004E21EC aTrialExpiredPl db 'Trial Expired,please registration!',0 seg000:004E21EC ; DATA XREF: sub_4E2098+2Co ========-----------------<>-----------------======== Дабл-кликаем по sub_4E2098+2C и попадаем в код:
========-----------------<>-----------------======== seg000:004E2098 sub_4E2098 proc near ; CODE XREF: seg000:004E2224p seg000:004E2098 seg000:004E2098 var_24 = dword ptr -24h seg000:004E2098 var_20 = dword ptr -20h seg000:004E2098 var_1C = dword ptr -1Ch seg000:004E2098 var_18 = dword ptr -18h seg000:004E2098 var_14 = dword ptr -14h seg000:004E2098 var_10 = dword ptr -10h seg000:004E2098 var_C = dword ptr -0Ch seg000:004E2098 var_8 = dword ptr -8 seg000:004E2098 var_4 = dword ptr -4 seg000:004E2098 seg000:004E2098 push ebp seg000:004E2099 mov ebp, esp seg000:004E209B mov ecx, 4 seg000:004E20A0 seg000:004E20A0 loc_4E20A0: ; CODE XREF: sub_4E2098+Dj seg000:004E20A0 push 0 seg000:004E20A2 push 0 seg000:004E20A4 dec ecx seg000:004E20A5 jnz short loc_4E20A0 seg000:004E20A7 push ecx seg000:004E20A8 push ebx seg000:004E20A9 mov ebx, ds:dword_4FB5F8 seg000:004E20AF xor eax, eax seg000:004E20B1 push ebp seg000:004E20B2 push offset loc_4E21D8 seg000:004E20B7 push dword ptr fs:[eax] seg000:004E20BA mov fs:[eax], esp seg000:004E20BD push 30h seg000:004E20BF push offset aExpired ; "Expired" seg000:004E20C4 push offset aTrialExpiredPl ; "Trial Expired,please registration!" seg000:004E20C9 mov eax, ds:dword_4FB9D4 seg000:004E20CE mov eax, [eax] seg000:004E20D0 mov eax, [eax+24h] seg000:004E20D3 push eax seg000:004E20D4 call sub_407398 seg000:004E20D9 mov ecx, ds:dword_4FB9D4 ========-----------------<>-----------------======== Да-а-а-а... Тут блин сразу и не скажешь, что где. Явно это процедура(sub_4E2098). IDA показала, где она вызывается(seg000:004E2224). Кликаем по seg000:004E2224.
========-----------------<>-----------------======== seg000:004E2210 mov eax, ds:dword_4FB7D4 seg000:004E2215 cmp byte ptr [eax], 0 seg000:004E2218 jnz short loc_4E222A seg000:004E221A mov eax, ds:dword_4FB710 seg000:004E221F cmp byte ptr [eax], 0 seg000:004E2222 jz short loc_4E222A seg000:004E2224 call sub_4E2098 seg000:004E2229 retn seg000:004E222A ; --------------------------------------------------------------------------- seg000:004E222A seg000:004E222A loc_4E222A: ; CODE XREF: seg000:004E2218j seg000:004E222A ; seg000:004E2222j seg000:004E222A call sub_4E2038 ========-----------------<>-----------------======== Знакомый байт dword_4FB7D4. Вызов этой процедуры по адресу 4E2224. Но туда не дают идти джамп(ы) jnz short loc_4E222A. Чтобы он сработал, надо подставить в
нужную команду
Значит 4E2215h+2h=4E2217h! По этому RVA надо записать 01h. Но... То ли SVKP как-то ухитрился обмануть баги PELG, но этот байт "не хотел патчиться". То ли PELG не хочет, ибо уж много RVA мы ему скормили... Для этого я написал loader на ассемблере. Он похож на лоадер из прошлого туториала, но то был ASProtect. Разницы между ними не будет, только уберем Sleep(300), потому что SVKP не проверяет целостность кода. => SVKP хуже ASProtect ;) Вот исходник патчера:
========-----------------<>-----------------======== .486 .model flat, stdcall option casemap :none
include \masm32\include\windows.inc include \masm32\include\masm32.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc include \masm32\include\shell32.inc includelib \masm32\lib\masm32.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\shell32.lib
.data App db "Registry Medical",0 Err1 db "Program not found :(",0 prog db "REGMEDICAL.EXE",0 vastart DWORD 4E2217h
.data? bufr dw ? pinfo PROCESS_INFORMATION <> sinfo STARTUPINFO <> n DWORD ? .code
start:
JMP STARTUHA PATCHER PROC RVA:DWORD,WR:DWORD INVOKE ReadProcessMemory,pinfo.hProcess,RVA,addr bufr,1,n invoke WriteProcessMemory,pinfo.hProcess,RVA,ADDR WR,1,n RET PATCHER ENDP
STARTUHA: invoke CreateProcess,addr prog,NULL,NULL,NULL,FALSE, CREATE_NEW_CONSOLE OR NORMAL_PRIORITY_CLASS,NULL,NULL,addr sinfo,addr pinfo CMP EAX,0 JNZ COOL invoke MessageBox,NULL,addr Err1,addr App,MB_OK invoke ExitProcess,0 COOL:
INVOKE ReadProcessMemory,pinfo.hProcess,vastart,addr bufr,1,n CMP EAX,0 JZ COOL CMP bufr,00h JNZ COOL
;invoke Sleep,300 invoke SuspendThread,addr pinfo.hThread
INVOKE PATCHER,4E2217h,01h INVOKE PATCHER,4B1CFBh,01h INVOKE PATCHER,4E12A0h,90h INVOKE PATCHER,4E12A1h,90h INVOKE PATCHER,4E12ACh,90h INVOKE PATCHER,4E12ADh,90h INVOKE PATCHER,4E12BDh,0EBh INVOKE PATCHER,4E131Ch,90h INVOKE PATCHER,4E131Dh,90h INVOKE PATCHER,4E1326h,0EBh INVOKE PATCHER,4E149Fh,01h invoke ResumeThread,addr pinfo.hThread invoke CloseHandle,pinfo.hThread invoke ExitProcess,0 RET
end start ========-----------------<>-----------------======== Комментарии не помещаю, ибо если понять комментарии_в_исходнике из прошлой статьи, то это понять будет легче. Как видите, даже снимать SVKP не надо. Все оказалось легко. Я не вдаюсь в подробности SVKP-регфункций, но если один лишь этот байт 4FB7D4 решает ВСЕ и его возвращает именно протектор, то это полный LOL! ;) Я пишу туториал, потому что меня уже давно трясут: "Знаешь что-нибудь про SVKP?", "Про SVKP вообще ничего нигде не написано!". Вот дошли до него руки. Оказалось, против лома нет приема :)
[ 0uTR0 ] // Вместо заключения Кому интересно попробовать распаковать, я могу выслать перевод статьи по именно_распаковке Registry Medical. Кстати, сам протектор я скачал с сайта SVKP. Кто хочет - защитите им вот эту прогу на асме и попробуйте распаковать. Это будет легко, потому что вам дадут только demo-защиту, но все же:
========-----------------<>-----------------======== .486 .model flat, stdcall option casemap :none
include \masm32\include\windows.inc include \masm32\include\masm32.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc
includelib \masm32\lib\masm32.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib
.data
FUCK DB "Fuck you!",0
.code start: invoke MessageBox,NULL,ADDR FUCK,ADDR FUCK,MB_OK ret end start ========-----------------<>-----------------======== Скомпилируйте в MASM и защитите SVKP. Теперь, прерываемся на EP при помощи Break'n'Enter или через Sumbol Loader у SoftICE. Ставим bpm esp-4 и нажимаем F5 пока не покажется OEP, а будет он на 401000. Добраться легко... Дальше сдампить, восстановить импорт(всего-то один MessageBox :)) в ImpREC и все... На этом прощаюсь...
[ REVERSER: bi0w0rM [AHTeam] ] [ EMAIL : bioworm@mail.ru ] [ bioworm.narod.ru ]
|