Брут паролей Сегодня я поведаю о том, как узнать пароль, не зная алгоритма генерации, вобщем о бруте. Скажу сразу, дело это долгое и весьма рисковое. Помните один из главных принципов - чем меньше изменений мы вносим в логику программы, тем лучше. Вдеь мы будем менять логику программы, внедрять свой код. [iNtr0] Перебор паролей происходит по средствам внедрения генератора и определения нескольких состояний полученной системы - правильный пароль, неправильный. Определяем куда поподает управление при правильном пароле и при неправильном. Если пароль правильный, то тормозимся и вызываем отладчик, а если нет, меняем (генерируем новый) и проверяем его и тд., получается, маленький такой, конечный автомат. [scripts] Эта часть статьи написана по принципу 'зацените изврат'. Брут через скрипты для Olly не самое быстрое занятие, но если вам так же как и мне нравится смотреть на бегущие буквы, то это для Вас. Долгое потому, что код сначала интерпритируется плагом OllyScript затем в игру вступает сама Olly и только потом прога. Так что мы успеваем и буквы увидеть. Начнём пожалуй. Сперва мне понадобилась программа с простейшим способом проверки. И я написал эти скромные строки. Code: invoke func_prov,offset str_pass,offset brutpass test eax,eax je @F invoke MessageBox,0,0,0,0 @@: push 0 call ExitProcess Где func_prov - функция, осуществлющая проверку, тупо, через cmp reg1,reg2. Она возвращает 0 если пароль неправильный, и 1 если правилный. Если мы выполняем перебор через скрипт, то внедрять в программу ничего не нужно, просто поставим бряки... Как бы это сказать?! Ну вот из чего состоит простейший автомат?... Сначала идёт проверка состояния, потом передача управления на нужный код (переход). Проверка состояния (switch в switch-технологии, извините за тавтологию =)) происходит с помощью Code: invoke func_prov,offset str_pass,offset brutpass test eax,eax je @F У нас два состояния 0 и 1. Если 0, то управление передаётся на Code: push 0 call ExitProcess если 1, то на Code: invoke MessageBox,0,0,0,0 Откроем прорамму в Olly. Code: 00401000 PUSH prog.00403006 00401005 PUSH prog.00403000 ; ASCII "ACBCA" 0040100A CALL <prog.func_prov> 0040100F TEST EAX,EAX 00401011 JE SHORT prog.00401021 00401013 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 00401015 PUSH 0 ; |Title = NULL 00401017 PUSH 0 ; |Text = NULL 00401019 PUSH 0 ; |hOwner = NULL 0040101B CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA 00401020 PUSH 0 ; /ExitCode = 0 00401022 CALL <JMP.&kernel32.ExitProcess> ; \ExitProcess Мы поставим бряки на 00401020 и 00401013. Если сработает бряк по адресу 00401020, то сгенерированный пароль не подходит, если по адресу 00401013, то всё круто можно выходить (из скрипта). Мной был написан следующий скрипт (не буду вдаваться в особенности генерации и несовершенности OllyScript, имхо не для этого он был написан). Code: // Name: Bruter 0.1 // Author: taha // Date: 18/02/07 //-- .data --------------------------------- var ot mov ot,41 var do mov do,43 //_ address ___________________ var start_addr mov start_addr,00401000 var bad_addr mov bad_addr,00401020 var good_addr mov good_addr,00401013 //__ string _________________ var str_addr mov str_addr,00403006 var y var count //__ backUp _____ var b_eax var b_ebx var b_ecx var b_edx var b_esi var b_edi var b_esp var b_ebp //-- .code --------------------------------- bphws bad_addr,"x" bphws good_addr,"x" mov b_eax,eax mov b_ebx,ebx mov b_edx,edx mov b_ecx,ecx mov b_edi,edi mov b_esi,esi mov b_esp,esp mov b_ebp,ebp mov count,str_addr mov y,str_addr mov [str_addr],41 genstr: cmp [y],do je gen_ra inc [y] jmp gen_ex gen_ra: fill y,1,ot cmp y,str_addr je add_s mov eax,y dec eax mov ecx,[eax] and ecx,FF cmp ecx,do je y_dec inc [eax] jmp gen_ex y_dec: dec y jmp gen_ra add_s: fill count,1,ot inc count fill count,1,ot gen_ex: mov y,count run cmp good_addr,eip je good mov eax,b_eax mov ebx,b_ebx mov ecx,b_ecx mov edx,b_edx mov edi,b_edi mov esi,b_esi mov esp,b_esp mov ebp,b_ebp mov eip,start_addr jmp genstr good: BPHWC good_addr BPHWC bad_addr msg "Всё гуд" ret Просто указываете адреса куда нужно попасть, а куда нет, адрес начала проверки и адрес буффера. Изначально строка, буффер, должна состоять из одного символа "A". Да, и не забудте указать с какого по какой символ. Code: var ot mov ot,41 var do mov do,43 Запускаем скрипт и... Code: 00403000 41 43 42 43 41 00 41 43 42 43 41 00 00 00 00 00 ACBCA.ACBCA..... Heppy end! [aSm] Тут всё сложнее, здесь нужно изменять не только логику, но и код. Однако смысл тот же. Я не стал ничего никуда внедрять, а сразу написал программу как будто внедрение было. Code: start: invoke func_prov,offset str_pass,offset brutpass test eax,eax je @F invoke MessageBox,0,0,0,0 int 3 @@: jmp Brute push 0 call ExitProcess Как видите, если пароль неверный, то происходит переход на наш код генерации, оттуда опять на start, а если верный то тормозится по int 3 и мы читаем пасс =)). Внедрять куда-либо мне было лень. [полиморфы] Я о простейших видах полиморфизма. Просто расшифровка какой-либо функции. Здесь тоже всё просто, но есть одна маленькая неприятность. Я пробовал брутить крямис ProTeuS'a. И прога упала при ключе 0BBh (187). Стек был забит всякой гадостью. Попробовал проанализировать код на котором она упала. Это был просто push [...]. Значит при предыдущих ключах вся область стека забилась мусором. Для того чтобы понять о чём я собствено сейчас пишу попробуйте испольнить следующие строки Code: xor eax,eax dec eax mov esp,eax А теперь попробуйте чтонить пропушить. Тото)). Большая неприятность. НО можно прогу перезапустить и начать брут с следующего ключа. Склоко раз предётся перезапускаться неизвестно... [ps] Врядли вам это пригодится. ИМХО брутить алго, смыс которого в расхоривании имени, нерационально. А если прога для собственного пользования, то проще перебить переход.