Исследование программы Aurora MPEG To DVD Burner! Инструменты: +-----------------------------------------+ | 1) Отладчик - OllyDebuger | 2) Хексер - Hiew | 3) Borland Delphi7 - для написания патча | 4) Анализатор - PEID +-----------------------------------------+ | • Защита : [++-----]легко (для новичков) | • Версия : [1.0.0.1] | • Ссылка : [http://www.xxxxxx.ru/] +-----------------------------------------+ Программа Aurora MPEG To DVD Burner, предназначена для перекодировки MPEG в DVD -формат с последующёй записью на диск. Короче прога нужная! Итак, начальная информация дана. Приступим. Для начала скормим наш бинарник, а именно файл "Aurora MPEG To DVD.exe" анализатору PEID. Он покажет, что файл не запакован и написанн на "Microsoft Visual C++ 6.0". Вообще на будущее новичкам, старайтесь сразу анализировать файл PEID'ом, в будущем это сэкономит вам массу времени (матёрые кракеры меня поддержат). Сначала запустим программу, просто так, без отладчика и попробуем ввести "левые" данные в поля для регистрации, для этого найдите наверху такой большой замочек с надписью "Register". Кликаем и вводим: User Name: I'll_crack_you! Registration: 1234567890 Нажимаем "OK" и видим, что нас посылают с нашими замашкими супер-кракера вот таким сообщением: Invalid Username or Registration code. И сразу мы понимаем, что мы можем отыскать это сообщение в строках в отладчике! Так и делаем для этого в Olly: В окне кода кликаем правую кнопку мыши --> Serach For --> All referenced Text Strings В окне строк кликаем правую кнопку мыши --> Search For Text --> Вводим строку которую нам показала программа, а именно "Invalid Username or Registration code", незабудте поставить галочку на поиск скопом (Entire Scope), а Case Sensitive - выключить, вдруг вы ошибётесь в наборе текста и напишите например вместо "Username" - "username", тогда отладчик просто не найдёт строку! Нажимаем на сообщение 2 раза и попадаем в окно кода, как раз на эту сроку. Видим такую картину: PHP: 004233BD . E8 9EF9FFFF CALL Aurora_M.00422D60 004233C2 . 83C4 08 ADD ESP,8 004233C5 . 85C0 TEST EAX,EAX 004233C7 . 75 18 JNZ SHORT Aurora_M.004233E1 ; <-- Переход (перепрыг =)) 004233C9 . 6A 40 PUSH 40 004233CB . 68 ACFB4800 PUSH Aurora_M.0048FBAC ; ASCII "Sorry" 004233D0 . 68 80FB4800 PUSH Aurora_M.0048FB80 ; ASCII "Invalid username" 004233D5 . 8BCE MOV ECX,ESI 004233D7 . E8 F5B20300 CALL Aurora_M.0045E6D1 ; <-- Вызов функции 004233DC . E9 A0000000 JMP Aurora_M.00423481 004233E1 > 8B4E 5C MOV ECX,DWORD PTR DS:[ESI+5C] 004233E4 . 8D5424 04 LEA EDX,DWORD PTR SS:[ESP+4] 004233E8 . 51 PUSH ECX 004233E9 . 68 64FB4800 PUSH Aurora_M.0048FB64 ; ASCII "License To:%s 004233EE . 52 PUSH EDX 004233EF . E8 20520300 CALL Aurora_M.00458614 004233F4 . 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+10] 004233F8 . 83C4 0C ADD ESP,0C 004233FB . 8BCE MOV ECX,ESI 004233FD . 6A 40 PUSH 40 004233FF . 68 58FB4800 PUSH Aurora_M.0048FB58 ; ASCII "Thank you" 00423404 . 50 PUSH EAX 00423405 . E8 C7B20300 CALL Aurora_M.0045E6D1 ; <-- Вызов функции Смотрим на смещение "004233C7", там стоит условный переход на адрес "004233E1", но он сработает только тогда когда мы введём правильное соотношение "Имя-код"! Но как вы понимаете мы не знаем правильного кода и когда выполнение дойдёт до места перехода, он не сработает и в стек перададуться строки сначала "Sorry", затем "Invalid username..." и затем вызовется функция MessageBox c переданными строками! Лицезреть вы это могли тогда, когда нас "посылали". Но! Так как нам это сообщение не нужно мы попробуем его перескочить заменив оператор "JNZ" на "JMP"! Итак меняем прямо в отладчике. Для этого: На операторе 2 раза мышкой и меняем JNZ на JMP (остальное не трогаем!). Запускаем, вводим любые данные и радуемся что прога нам сказала, что она "ТИПА" зарегана! Но не спешите радоваться! Попробуйте перезапустить прогу без отладчика и вы снова увидите, что прога "UNREGISTERED". Не отчаивайтесь и слушайте меня: Этот способ с JMP - безусловным переходом, прокатывает но не всегда! Дело в том что осуществляются дополнительные проверки, при старте проги! Другое дело пойти 100% путём! И замутить по другому! Как по другому я уже писал в другой статье (ищите на античате). Но для тех кто не читал я повторюсь, так что читаем и вникаем: Посмотрим ещё раз на кусок кода: PHP: 004233BD . E8 9EF9FFFF CALL Aurora_M.00422D60 004233C2 . 83C4 08 ADD ESP,8 004233C5 . 85C0 TEST EAX,EAX 004233C7 . 75 18 JNZ SHORT Aurora_M.004233E1 ; <-- Переход (перепрыг =)) 004233C9 . 6A 40 PUSH 40 004233CB . 68 ACFB4800 PUSH Aurora_M.0048FBAC ; ASCII "Sorry" 004233D0 . 68 80FB4800 PUSH Aurora_M.0048FB80 ; ASCII "Invalid username" 004233D5 . 8BCE MOV ECX,ESI 004233D7 . E8 F5B20300 CALL Aurora_M.0045E6D1 ; <-- Вызов функции 004233DC . E9 A0000000 JMP Aurora_M.00423481 004233E1 > 8B4E 5C MOV ECX,DWORD PTR DS:[ESI+5C] Видите по адресу 004233C5 EAX, сравнивается грубо говоря с единицей! А ниже стоит переход с условием JNZ (Jump Not Zero - перейти если не нуль). Вы поняли? Нам нужно сделать так, чтобы в EAX было бы значение 1 (еденица). Можно конечно перед проверкой (TEST EAX,EAX), а именно по адресу 004233C2 заменить ADD ESP,8 на INC EAX (INC - увеличивает аккамулятор на 1), но при выполнении программе просто сорвёт башню и она может вылететь! А можно сделать так, чтобы функция, которая вызывается перед сравнением (CALL Aurora_M.00422D60), всегда возвращала в регистр EAX - еденицу! Так и делаем: Встаёим по адресу функции (004233BD), нажимаем ENTER, чтобы перейти в эту функцию и меняем три первых оператора на: XOR EAX,EAX INC EAX RETN Первая строка обнулит EAX, если там что-то было. Вторая строка увеличит EAX на еденицу. Ну а третья строка просто вернёт выполнение программы на то место откуда была вызванна функция + 1 оператор (то есть на адрес 004233C2). После всех этих нехитрых манипуляций в регистре EAX будет содержаться значение 1, и мы успешно перескочим сообщение об не правильном Рег-Коде, ну а дальше дело техники: 1) В стек толкнётся сообщение об правильном коде 2) Сработает API - MessageBox c этим сообщением Вот и всё! Можете открыть HIEW и пропатчить все изменённые байты, а именно: 00422D60 33C0 00422D62 40 00422D63 C3 00422D64 90 00422D65 90 00422D66 90 Открываем HIEW, грузим "Aurora MPEG To DVD.exe", жмём F5, вводим смещение (вводить нужно с точкой, напимер: .00422D60), становимся на нужный байт, жмём F3 и меняем на изменённые значения всё байты по порядку! Нажимаем F9, для того чтобы изменения вступили в силу, закрываем HIEW, запускаем прогу, нажимаем Register и пишем своё имя или ник, нажимаем OK! Теперь прога взломана на 100%. Проверим? Закройте программу и откройте её заново, в заголовке окна вы должны видеть: Aurora MPEG To DVD Buirner (License To:ВАШ_НИК), где ВАШ_НИК - имя которое вы ввели в окне регистрации. Если вы видите ваш ник, то всё впоряде! Вот теперь точно всё! Кому и этого хватит, может дальше не читать, а кому нет, то сейчас мы напишем кряк на Delphi7: Пишем в блокноте: PHP: {$D-} program crack; uses Windows; var iByteWrt:Cardinal; hFile:THandle; const pB1:integer=$33C0; pB2:integer=$40; pB3:integer=$C3; pB4:integer=$90; pB5:integer=$90; pB6:integer=$90; begin MessageBoxa(0,'Crack for MPEG2DVD - 1.0.0.1 by KindEcstasy','Crack',64); hFile:=CreateFile('Aurora MPEG To DVD.exe',GENERIC_WRITE,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0); if hFile<>INVALID_HANDLE_VALUE then begin CopyFile('MPEG2DVD','backup.exx',true); SetFilePointer(hFile,$00422D60,nil,0); WriteFile(hFile,pB1,1,iByteWrt,nil); SetFilePointer(hFile,$00422D62,nil,0); WriteFile(hFile,pB2,1,iByteWrt,nil); SetFilePointer(hFile,$00422D63,nil,0); WriteFile(hFile,pB3,1,iByteWrt,nil); SetFilePointer(hFile,$00422D64,nil,0); WriteFile(hFile,pB4,1,iByteWrt,nil); SetFilePointer(hFile,$00422D65,nil,0); WriteFile(hFile,pB5,1,iByteWrt,nil); SetFilePointer(hFile,$00422D66,nil,0); WriteFile(hFile,pB6,1,iByteWrt,nil); CloseHandle(hFile); MessageBoxa(0,'File cracked successuflly!!!','Good',64); Exit; end else begin MessageBoxA(0,'Unable to patch file!!!','Bad',MB_ICONERROR); end; end. Заменяем инфу (ник и т.д.) на свои, сохраняем как crack.dpr и компилим! Всё кряк готов можно выкладывать в сети =)) Всё! На этом я заканчиваю свои долгие обьяснения. До скорых встреч! (c) KindEcstasy
Да защита простенькая, вот только зря не привёл что идёт перед вызовом функции, т.к. если ей передаются параметры через стек, то такой способ может привести к не коректному завершению программы. Я заметил ты немножко путаешь, хоть и результат правельный, а путаница вот в чём, в джамповых инструкциях есть синонимы, пишутся по разному, но после компиляции результат одинаков, это "e" и "z". Тоесть "je" = "jz" и "jne" = "jnz" тогда "test eax, eax" скорее сравнивает eax не с "1", а с "0" и в этом можно убедиться на примере. Code: je @f @@: jz @f @@: jne @f @@: jnz @f @@: Можешь скомпилить и посмотреть опкоды этих пар инструкций. Думаю это кому нибудь пригодиться, я как-то скомпилил свою прогу и когда отлаживал увидел что там другие инструкции, тогда полез в мануал за опкодами, там я это и нашел.