Lazar Posted November 17, 2004 Report Share Posted November 17, 2004 Введение - Цель данной статьи изучение защиты ARPR и применение "brute-force inside". Цель - Advanced RAR Password Recovery v1.50 Программу можно найти: http://www.elcomsoft.com/arpr.html Инструментарий: HIEW - no comment IDA Pro - no comment WinDBG - Windows Debugger Stripper Все начилось как всегда банально - с просьбы приятеля расковырять RAR-архив . . . Изучение проблемы выявило две потенциально интересных программы: RAR Password Cracker v4.12 (31-Aug-2003) Copyright © 1998-2003 Dmitry Nikitin и Advanced RAR Password Recovery v1.50 Обе используют для поиска и brute-force, и поиск по словарям. Скорости работы - примерно одинаковы с той только разницей, что RPC сканирует от максимального значения через вычитание, а ARPR - от минимального через сложение. Начну со сравниния этих утилит: пока не будем отвлекаться на защитные приемы, и обратим внимание на триальные возможности. Ограничение при поиске кода в три разряда является общим и по сути единственным. RAR Password Cracker мне не понравился интерфейсом и глюком : при длине поиска в три разряда + "только цифры" несколько раз оповещал о количестве вариантов - 100! Что в дальнейшем стоит ожидать от зарегистрированной утилиты?! или автор - супер и это некий защитный ход?! - и после регистрации глюк будет устаранен, или . . . мысль дальше останавливается . . . Кстати, попытки найти А где, собственно, в утилите нам предстоит регистрироваться тоже успехом не увенчались. . . Цитата из авторского readme.txt: "Don’t try to use cracks, serials and so on at all. The integrity validation routines are built into the password recovery routines, so any crack’s code or unauthorized serial may cause the password recovery system to work incorrectly. You even will never know whether it has occured or not!" Сильно сказано! Ну а то, что автор использовал ASProtect 1.23 RC4 - 1.3.08.24 -> Alexey Solodovnikov, контроль кода на модификацию и обильно навтыкал терминаторов процесса - не обрадовало, но и особо не впечатлило. . . Вывод: третий сорт - еще не брак. ARPR - заслуженно получил при сравнении более высокие оценки: удобный интерфейс, разумный алгоритм действий при не нахождении кода, закладка Registration и прочие мелочи. Глюков в триале не отмечено. Поиск в коротких тестовых архивах в разумное время дал положительные результаты. Протекционные меры примерно такие же как и в RPC. В общем и целом, было принято решение уделить "внимание" именно ARPR. Еще одно прочесываение сети выявило кучу крэков для ранних версий и несколько реализации для версии 1.50: от команды NiTROUS (crack) и от команды HTB (loader) и еще один крэкнутый exe-ник от какой-то "нашей" (русскоговорящей) команды (не сохранил название). Все кривые: крэк от NiTROUS не работает при поиске ключа более 3 символов - просто умирает. Даже не интересно почему, на 99,99% уверен: TerminateProcess из-за контроля модификации программы (модификацией считается распаковка). Лоадер выдал "protection error - error 1" и тоже умер. "Наш" exe-шник - тоже не панацея. Он позволяет пройти регистрацию, но сложность защиты в том, что этого не достаточно для полноценного функционирования. Но об этом чуть позже. В сети можно найти и некоторое количество SN . . . попробуйте использовать - ничего не получится. Любопытство распалено до невозможности. Следовательно, беремся за дело. Глава первая. Итак : PEiD показывает, что мы имеем дело с ASProtect 1.22 - 1.23 Beta 21 -> Alexey Solodovnikov. Распаковке посвящено много достойных статей и туториалов от Профи и Гуру от распаковке что и позволяет эту преграду преодолеть не задумываясь. Можете попрактиковаться в ручном unpack`е или использовать автоматический распаковщик. Я пользовал Stripper. К сожалению, Wdsm10K при попытке загрузить распакованный exe-ник мгновенно умирает, поэтому будем пользовать IDA. Поищем в листинге "Elcom" и в результате мы знаем о ветке реестра HKEY_LOCAL_MACHINESOFTWAREElcomAdvanced RAR Password RecoveryRegistration, и о текстовом параметре "Code". Давайте создадим такую ветку и параметр. И что-нибудть внесем в параметр. Наш путь в отладчик. "BP RegQueryValueExA" и мы остановились на .text:0040928B call cs:RegQueryValueExA. делаем несколько "StepOut" и всплываем в .text:00404C24 call sub_4092EC .text:00404C29 test eax, eax Обязан привести sub_4092ec полностью: .text:004092EC .text:004092EC ; --------------- S U B R O U T I N E --------------------------------------- .text:004092EC .text:004092EC ; Attributes: bp-based frame .text:004092EC .text:004092EC sub_4092EC proc near ; CODE XREF: sub_4047A9+47Bp .text:004092EC ; sub_4047A9+4CFp ... .text:004092EC .text:004092EC var_40 = dword ptr -40h .text:004092EC .text:004092EC enter 40h, 0 .text:004092F0 lea eax, [ebp+var_40] .text:004092F3 call sub_40922C .text:004092F8 lea eax, [ebp+var_40] .text:004092FB call sub_40916B .text:00409300 leave .text:00409301 retn .text:00409301 sub_4092EC endp .text:00409301 Вот собственно и вся защита при запуске программы: читаем из знакомой нам ветви реестра "Code" и проверяем его в sub_40916b и все. Наш путь теперь в sub_40916b. .text:0040916B .text:0040916B ; --------------- S U B R O U T I N E --------------------------------------- .text:0040916B .text:0040916B ; Attributes: bp-based frame .text:0040916B .text:0040916B sub_40916B proc near ; CODE XREF: sub_4092EC+Fp .text:0040916B ; sub_409385+E7p ... .text:0040916B .text:0040916B var_6C = dword ptr -6Ch .text:0040916B var_10 = dword ptr -10h .text:0040916B .text:0040916B push ebx .text:0040916C push ecx .text:0040916D push edx .text:0040916E push esi .text:0040916F push edi .text:00409170 enter 6Ch, 0 .text:00409174 mov esi, eax .text:00409176 call sub_416A30 .text:0040917B mov ecx, eax .text:0040917D cmp eax, 6 .text:00409180 jge short loc_409189 .text:00409182 .text:00409182 loc_409182: ; CODE XREF: sub_40916B+28j .text:00409182 ; sub_40916B+66j .text:00409182 xor eax, eax .text:00409184 jmp locret_409225 .text:00409189 ; --------------------------------------------------------------------------- .text:00409189 .text:00409189 loc_409189: ; CODE XREF: sub_40916B+15j .text:00409189 mov ebx, 2 .text:0040918E cdq .text:0040918F idiv ebx .text:00409191 test edx, edx .text:00409193 jnz short loc_409182 .text:00409195 mov eax, ecx .text:00409197 cdq .text:00409198 idiv ebx .text:0040919A lea ebx, [eax-2] .text:0040919D lea eax, [ebp+var_6C] .text:004091A0 call sub_40962E .text:004091A5 lea edi, [esi+4] .text:004091A8 mov edx, edi .text:004091AA lea eax, [ebp+var_6C] .text:004091AD call sub_40967F .text:004091B2 lea edx, [ebp+var_6C] .text:004091B5 lea eax, [ebp+var_10] .text:004091B8 call sub_40A5D0 .text:004091BD mov ebx, 10h .text:004091C2 mov edx, offset unk_43BA30 .text:004091C7 lea eax, [ebp+var_10] .text:004091CA call sub_416CB0 .text:004091CF test eax, eax .text:004091D1 jnz short loc_409182 .text:004091D3 lea eax, [ebp+var_6C] .text:004091D6 call sub_40962E .text:004091DB mov ebx, ecx .text:004091DD mov edx, esi .text:004091DF lea eax, [ebp+var_6C] .text:004091E2 call sub_40967F .text:004091E7 lea edx, [ebp+var_6C] .text:004091EA lea eax, [ebp+var_10] .text:004091ED call sub_40A5D0 .text:004091F2 lea eax, [ebp+var_10] .text:004091F5 call sub_40911A .text:004091FA test eax, eax .text:004091FC jz short locret_409225 .text:004091FE cmp ds:dword_44A2B0, 0 .text:00409205 jnz short loc_409220 .text:00409207 push 10h .text:00409209 push edi .text:0040920A call ds:off_43BA48 .text:00409210 call ds:off_43BA40 .text:00409216 mov ds:dword_44A2B0, 1 .text:00409220 .text:00409220 loc_409220: ; CODE XREF: sub_40916B+9Aj .text:00409220 mov eax, 1 .text:00409225 .text:00409225 locret_409225: ; CODE XREF: sub_40916B+19j .text:00409225 ; sub_40916B+91j .text:00409225 leave .text:00409226 pop edi .text:00409227 pop esi .text:00409228 pop edx .text:00409229 pop ecx .text:0040922A pop ebx .text:0040922B retn .text:0040922B sub_40916B endp .text:0040922B Краткий анализ приведенной процедуры показывает, что в EAX возвращается "0" - если все плохо, и "1" если мы зарегистрированы. Я обещал упомянуть крэк от "нашей" команды : так вот, его творцы просто заNOP`или :00409182 xor eax,eax. Т.е процедура никогда не возвращает "0". Но для анализа полной функциональности используются данные промежуточных итераций по проверке SN. А в этом случае они некорректны - как следствие ограничение при поиске в три символа, а при большей длинне кода - получим call cs:TerminateThread из-за распаковки, которую утилита считает своей модификацией. Итак, еще раз повторюсь: организовать возврат в EAX "1" недостаточно. Дело в том, что процедура чтения SN вызывается один раз, а вот процедура его проверки вызывается многократно, при любых измениниях каких-либо настроек программы и, естественно, при попытке указать длину ключа для поиска больше 3. И при этом не однократно, те. я насчитал (если не путаю) min ТРИ! вызова проверки SN между указанием rar-архива в настройке, длины ключа и сообщением что это "unregisterd version". Программер проверяется на каждом шагу! Круто. Давайте внимательно изучим процедуру. Единственный входящий параметр - содержимое EAX - адрес, куда записываются данные из реестра, т.е адрес SN. call sub_416A30 - > вычисляет длинну SN. Если меньше "6" - все плохо. За этим следует проверка длины SN на четность. Нечет - тоже плохо. Таким образом, длина SN должна быть четной и быть больше 6. Собственно защита начинается с вычисления некой константы (длина_SN/2-2) и формирования 7-ми dword`ов из которых три - "0" и используются для результатов промежуточных итераций. Вы, пожалуй, уже заметили, что проверка SN состоит из двух блоков, которые начинаются одинаково - с формирования 7-ми dword`ов (call sub_40962E) и различаются только процедурами контроля : sub_416CB0 и sub_40911A. Процедура sub_40967F вычленяет из SN некую часть начиная со второго dword`а в количестве = SAR{(длина_SN/2-2)},2. Процедуры sub_40A5D0 формируют четыре кэша и занимаются совершенно иррациональными манипуляциями. Я честно предпринял попытку (и не одну - времени пока brute-force (забегаю немного вперед))трудился было достаточно) разобраться в происходящем, но потерпел полное фиаско. . . Сложность еще и в том, что из самой процедуры проверки вызывается весьма и весьма много прочих процедур и так далее,т.е. алгоритм не прямолинейный. и что самое неприятное - защита построена на принципе неявной проверки. Принцип заключается в том, что явного анализа и явных действий просто нет. Если все параметры указаны правильно - все хорошо, а если - нет, для анализа используются данные промежуточных итераций, а они невалидны => дело - труба. И еще одно: поскольку программа после распаковки считает себя модифицированной, кроме собственно защиты придется разбираться и с этим приемом тоже. Это означает весьма существенные затраты времени и мозгов. Были нужны свежие мысли и они пришли. Первой была статья Godness`а о Advanced PDF Password Recovery (получил удовольствие от прочтения и подчерпнул некоторые полезные моменты). Кстати, защита совершенно отличается от описанной Godness`ом. Компания одна, а правая рука не знает что творит левая или так было задумано: просто работают разные группы творцов? Второй и самой интересной была мысль: а не попробовать ли заставить саму защиту найти SN? Расшифровываю - можно ли использовать метод brute-force для нахождения SN? Так сказать, из нутри. Предположение, что разработчики защиты не очень работают в команде и что регистрация не использует какие-либо персональные данные пользователя, т.е не зависит от рег.имен, было основано на том, что, в принципе, у всех пользователей регистрируется скачанная с сайта единственная "исходная" версия. Да и компания, что торгует лиценциями к утилите, подтвердила это в ответе на вопрос: Будет ли зарегистрирована последняя версия с сайта разработчиков? "Да, будет." Таков был ответ. . . Они даже были не знали какая версия лежит на сайте! Во как! Возникало только одно препятствие: огромные временные затраты на brute-force "в лоб". . . И еще одна мысль, круто изменившая направление в этом исследовании, была почти авантюрной попытка проверить найденные в сети SN на корректность. И не просто пропробовать (а мы уже знаем, что они не валидны), а пройти по защите в отладчике. В целом, все найденные SN НЕ валидны. Подчеркиваю, "в целом". НО... Великие Регистры! Найденные SN ПРОШЛИ первую часть контроля защиты ! .text:004091CF test eax, eax .text:004091D1 jnz short loc_409182 Такого удара я не ожидал ! И некоторое время пытался усмирить ураган мыслей и догадок. Профессионального интереса ради, я решил проверить себя и попробовал "отыскать" цифровую часть SN, использовав внутренний brute-force. На это ушло с перерывами ХХХ дней. С учетом параллельных вычислений. Осталось преодолеть вторую часть проверки. И мы уже знаем структуру SN! Смутные догадки о длине SN продтвердились: четыре dword-константы из sub_40962E, четыре cases. . . Первая часть SN (напоминаю, не считая первых четырех символов!) - 4 х 4 = 16 символов, и вторая часть еще 4 х 4 = 16 символов. Плюс первые четыре символа. Итого - 36 символа. Еще одно этому подтверждение: четыре константы из sub_40962E, соответственно 16 символов из SN. это означит, что константа количества символов передаваемое из SN для анализа и равное SAR{(длина_SN/2-2)},2 должна быть равна 4, а это значит, что длина SN равна 0х24, т.е 36 символов. Итак, будем brute-forc`ить ! Глава вторая. Итак, будем brute-forc`ить ! Для этого в распакованный exe-шник "внедрим" приведенный ниже код: -------------------------------------------- 409300: test eax,eax 409302: jne 409353 409304: lea eax,[ebp-40] ; eax - addr SN (0x0006f59c) 409307: mov ebx,eax 409309: mov esi,eax 40930b: call 416a30 ; size SN ? size SN -> eax 409310: mov dl,[ebx][eax]-1 ; lower bit SN 409314: add dl,1 ; dl + 1 409317: cmp dl,5b ; ending of posible letter? 40931a: je 409322 ; to creative 2 next code bit SN 40931c: mov [ebx][eax]-1,dl ; + 1 to current code bit SN 409320: jmps 4092f8 ; jmp to next test 409322: mov dl, 41 ; ebx - addr SN, eax - size SN 409324: mov [ebx][eax-01],dl ; reset current bit SN "A" 409328: sub eax,1 ; index to next bit SN 40932b: cmp eax,14 ; high byte of letters part SN ? 40932e: je 409332 409330: jmps 409310 409332: mov eax,ebx 409334: mov esi,eax 409336: call 416a30 ; size SN ? eax - size SN 40933b: add eax,2 ; size SN + 2 : even only ! 40933e: cmp eax,34 ; max size SN ? 409341: je 409341 ; STOP - code not found 409343: add ebx,eax 409345: mov dl,00 409347: mov [ebx],dl 409349: mov dl,41 40934b: mov [ebx-01],dl ; reset two new bit SN 40934e: mov [ebx-02],dl 409351: jmp 4092f8 ; jmp to next test 409353: jmps 409353 ; ! ! ! WE`RE GOT SN ! ! ! SEE [0006f59c] -------------------------------------------- Комментарии вполне достаточны, но можете опробовать и собственные алгоритмы. Обращаю ваше внимание на важный момент: Первый вопрос был: Куда внедрять код? с последующей проверкой Не "зацепим" ли другие процедуры, что используются в начале выполнения программы, чтения из реестра и собственно в проверке SN. Как видите, код небольшой, а последующая процедура (sub_409302) была невостребованной. Осталость записать в реестр в параметр "Code" "ARPR-XXXXXXXXXXXXXX-AA" или "ARPR-XXXXXXXXXXXXXX-AAAAAAAAAAAAAAAA". ("ххх" - цифровая часть SN, "AA" или "AAAAAAAAAAAAAAAA" - реальные символы "А"). С точки зрения алгоритма работы защиты предпочтителен укороченный вариант, но наша процедура будет корректно работать/искать в обоих случаях. Разумеется, для параллельных вычислений необходимо использовать второй (полный) вариант. Запускаем модифицированную утилиту через отладчик, ВР 409353 и . . . запасаемся терпением... Не думайте что процесс займет 5 минут - у меня ушло ХХХ суток с перерывами. С учетом того, что у меня была возможность задействовать несколько машин и параллелить вычисления, применив метод деления попалам: одна машина сканировала с первого символа"А" т.е с начала, а вторая с символа "Z" т.е с конца. Затем "В" и "Y". И так далее. Я использовал WinDBG и ожидал всплытия на 409353 и порой наблюдал изменение содержимого памяти по адресу 0x0006f59c. Через какое-то время отладчик всплыл в 409353, а это означало, что SN в наших руках. Мы реализовали brute-force для нахождения SN изнутри самой программы! В данном случаем нас совершенно не волнует добавочные защитные приемы против модификации программы - мы находимся на маленьком пятачке, а все навороты - ниже по течению. Впрочем, запуск распакованной программы даже с правильным SN обречен на TerminateProcess. Пальма первенства применения "brute-force inside" принадлежит другим - но все равно, красиво получилось! Согласны? Успехов в Ваших делах! Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.