OllyDbg - альтернатива SoftICE

 

Пособие расчитано на новичков, которые сталкиваются с OllyDbg впервые.

Сайт разработчиков OllyDbg
Форум для пользователей OllyDbg


Уверен, многие согласятся со мной в том, что SotfICE для нас - это стандарт de facto. Но сегодня я хотел бы познакомить вас с новым шедевром, популярность которого возрастает с каждым днем. За него не просят денег, его не нужно устанавливать. И он действительно хорош, хоть и требует доработки. Хорош настолько, что может заменить SoftICE. Пусть не во всем, но во многом...
А имя ему - OllyDbg. Или просто Olly.


 

1. Что такое Olly?
Olly - 32-битный отладчик для работы под Win9x, WinMe, WinNT, Win2k и WinXP. Он поддерживает все процессоры серии 80x86, Pentium, MMX, 3DNow!, включая расширения Athlon, SSE инструкции и соответствующие форматы данных. Возможно отображение данных в любом формате: HEX, ASCII, UNICODE, 16- и 32-битные знаковые/беззнаковые/шестнадцатиричные целые числа, 32/64/80-битные вещественные числа,
адреса, дизассемблирование на MASM, IDEAL или HLA. OllyDbg может подключаться к уже запущенному процессу или создавать новый. Одна из примечательных особенностей отладчика - анализатор, который распознает процедуры и количество входных аргументов, циклы, таблицы, константы и строки, вызовы API функций и многое другое. Анализатор не является компиляторо-зависимым и одинаково хорошо работает
со всеми РЕ-файлами. И это далеко не все...

2. Как работать с Olly?
Вообще, отладчик сопровождается хорошим хелпом, в котором можно найти полное описание всех свойств, настроек, режимов работы отладчика и много чего еще. Так что переписывать его, думаю, не стоит. Однако факт написания мануала на английском языке может затруднить его понимание русскоязычным населением. Поэтому кое-какие основные моменты я не могу оставить без внимания.

Пройдемся по панели инструментов...

Первая слева кнопка - открыть исполняемый файл. Горячая клавиша: [ F3 ]. Затем идут "Перезагрузить файл - [Ctrl + F2 ]" (загружает последний открывавшийся файл) и "Закрыть файл - [ Alt + F2 ]".

Следом - пара кнопок "Выполнить - [ F9 ]" и "Пауза - [ F12 ]". С ними все должно быть понятно.

Далее по списку режимы трассировки:

Step in - [ F7 ] - исполняет одну команду за раз.
При обработке вызова (call) передает управление (входит) в вызываемую подпрограмму, останавливаясь на первой команде в ней.
Step over - [ F8 ] - также исполняет одну команду за раз, но при обработке вызовов старается выполнить подпрограмму за один шаг, не передавая ей управление. Но! Управление все же передается в подпрограмму, если на вызов установлена точка останова, или в ней генерируются исключительные ситуации (прерывания).

Чтобы не нажимать F7 или F8 сотни раз подряд, Olly предусматривает режим "анимации" (Animate) [ Ctrl + F7 ] или [ Ctrl + F8 ]. Это режим автоматического пошагового выполнения, т. е. команды выполняются одна за
одной без необходимости тыкать на [ F7 ] или [ F8 ].
Анимация останавливается
* при нажатии [ Esc ]
* если встречается точка останова или исключение.

Trace into - [ Ctrl + F11 ] - режим похож на анимацию, только окна отладчика при этом не обновляются, и ведутся логи изменения регистров, памяти и т. п. Trace into выполняет процесс со входом в подпрограммы (как при step in) В окне Debugging Options -> Trace [ Alt + O ] можно изменить настройки
режима трассировки
Trace over - [ Ctrl + F12 ] - то же, что и trace into,
но подпрограммы выполняются за один шаг, как при step over.

Execute till RET - [ Ctrl + F9 ] - выполнять программу до инструкции RET.
В окне Debugging Options -> Trace [ Alt + O ] можно отметить пункт "After executing till RET, step over RET", чтобы останавливать выполнение программы на следующей за RET команде. Иначе останов будет осуществляться перед RET.

Далее идут кнопки, открывающие окошки с различной инфой (логи, подгружаемые модули, память процесса, ветви процесса, описатели, окна и т. д. и т. п.), с которыми мы будем знакомиться при появлении в этом необходимости. А сейчас перейдем к практической части.

 

Пример 1. Поиск регистрационного кода
В качестве примера будем использовать (ry0's Crackme #3

Итак, приступим.
Запускаем Olly, нажимаем [ F3 ] - открыть файл и открываем ccm_3.exe.
Отладчик тормозит на точке входа в программу (первый стоп можно поставить также на системную точку останова или вход в процедуру окна. Эти параметры можно изменить в Options -> Debugging options -> Events):

00401000 6A 00         push 0                                   ; pModule = NULL
00401002 E8 3D040000   call <jmp.&kernel32.GetModuleHandleA>    ; GetModuleHandleA
00401007 A3 00314000   mov dword ptr [403100], eax
0040100C 6A 00         push 0                                   ; lParam = NULL
0040100E 68 26104000   push 00401026                            ; DlgProc = ccm_3.00401026
00401013 6A 00         push 0                                   ; hOwner = NULL
00401015 68 E8030000   push 3E8                                 ; pTemplate = 3E8
0040101A 50            push eax                                 ; hInst
0040101B E8 D0030000   call <jmp.&user32.DialogBoxParamA>       ; DialogBoxParamA
00401020 50            push eax                                 ; ExitCode
00401021 E8 18040000   call <jmp.&kernel32.ExitProcess>         ; ExitProcess
00401026 55            push ebp


Теперь жмем [ F9 ] - выполнить. Далее как обычно - вводим имя юзера (PowerUser) и серийник (654321), но на "Регистрировать" не давим. Возвращаемся в Olly и зажимаем [ Ctrl + N ]. Нам откроется окно "Names" -
список всех импортируемых программой API функций. Ага, есть упоминание о GetDlgItemTextA. Ставим курсор на эту API функцию (клик левой), а затем вызываем popup-меню (клик правой). Устанавливаем точки останова (Set breakpoint on every reference). Точку останова также можно установить из командной строки (если установлен плагин CMDLINE.DLL). Для этого [ Alt + F1 ], а там уж как в SICE'е:

bpx GetDlgItemTextA [ввод]

Теперь в окне приложения (ccm_3.exe) клик по 'register'...


0040113A 6A 20         push 20                                  ; Count = 20 (32.)
0040113C 57            push edi                                 ; Buffer
0040113D 68 EC030000   push 3EC                                 ; ControlID = 3EC (1004.)
00401142 FF75 08       push [arg.1]                             ; hWnd
00401145 E8 DA020000   call <jmp.&user32.GetDlgItemTextA>       ; GetDlgItemTextA
0040114A 85C0          test eax, eax
0040114C 75 04         jnz short 00401152
0040114E B0 01         mov al, 1
00401150 EB 08         jmp short 0040115A
00401152 FF75 08       push [arg.1]                             ; Arg1
00401155 E8 96010000   call 004012F0                            ; ccm_3.004012F0
0040115A 50            push eax
0040115B FF75 08       push [arg.1]
0040115E E8 61020000   call 004013C4
00401163 EB 06         jmp short 0040116B
00401165 33C0          xor eax, eax
00401167 C9            leave
00401168 C2 1000       retn 10
0040116B B8 01000000   mov eax, 1
00401170 C9            leave
00401171 C2 1000       retn 10


Начинаем трассировку.
[ F8 ] - для пошаговой трассировки - по одной команде за раз. Но! При выполнении вызовов (call), в случае если на него установлена точка останова или подпрограмма генерирует исключения, будет осуществляться передача управления в подпрограмму. Чтобы этого избежать, можно попробовать комбинацию [ Shift + F8 ].
Итак, [ Shift + F8 ] для выполнения call GetDlgItemTextA, а затем [ F8 ] для пошагового выполнения.


0040114A 85C0          test eax, eax
0040114C 75 04         jnz short 00401152
0040114E B0 01         mov al, 1
00401150 EB 08         jmp short 0040115A
00401152 FF75 08       push [arg.1]                             ; Arg1
00401155 E8 96010000   call 004012F0                            ; ccm_3.004012F0



Буфер, адресуемый регистром EDI получает введенный юзером рег. код. Обратите внимание, что строка, на которую указывает регистр, отображается справа от его значения в окне регистров. Весьма удобно, согласитесь.
Далее идет проверка, ввел ли пользователь этот код. Если ввел - выполняем процедуру ccm_3.004012F0
Посмотрим, что она из себя представляет. Чтобы передать управление в подпрограмму, давим [ F7 ].


004012F0 55            push ebp
004012F1 8BEC          mov ebp, esp
004012F3 83C4 DC       add esp, -24
004012F6 53            push ebx
004012F7 56            push esi
004012F8 8D5D DF       lea ebx, dword ptr [ebp-21]
004012FB 6A 20         push 20                                  ; Count = 20 (32.)
004012FD 53            push ebx                                 ; Buffer
004012FE 68 EB030000   push 3EB                                 ; ControlID = 3EB (1003.)
00401303 FF75 08       push [arg.1]                             ; hWnd
00401306 E8 19010000   call <jmp.&user32.GetDlgItemTextA>       ; GetDlgItemTextA
0040130B 85C0          test eax, eax
0040130D 75 07         jnz short 00401316
0040130F B8 01000000   mov eax, 1
00401314 EB 47         jmp short 0040135D
00401316 66:813F 5245  cmp word ptr [edi], 4552
0040131B 75 08         jnz short 00401325
0040131D 8A57 02       mov dl, byte ptr [edi+2]
00401320 80F2 2D       xor dl, 2D
00401323 74 07         je short 0040132C


Так-так. Читаем имя юзера в буфер, адресуемый регистром EBX, и проверяем, введено ли это имя, или его впомине нет. А вот потом(!) проверяем, чтобы первые 3 символа ключа были не иначе как 'RE-'. Протрассировав до адреса :00401316 не торопитесь. Чтобы не повторять процесс заново, изменим серийник в памяти так, чтобы первыми символами были 'RE-', а не введенные нами. Для этого: 1. В окне регистров выделите значение регистра EDI (левым кликом), т. к. именно он указывает на введенный серийник. Затем правой кнопкой мыши и выберите 'Follow in Dump'. Или в окне кода выделите строку


00401316 66:813F 5245  cmp word ptr [edi], 4552


Потом правой кнопкой и выбирайте 'Follow in Dump -> Memory Address'. В окне данных покажется введенная строка:


0012FB13  36 35 34 33 32 31 00 D5 77 59 00 10 01 35 01 00  654321..wY...5..
0012FB23  00 D6 0C 01 E1 40 03 01 00 01 00 00 00 5F 3A D4  .....@......._:.


Выделите 3 первых байта (36h, 35h, 34h) и жмите [Ctrl + E] - откроется окно редактирования данных. Изменяем '654' на 'RE-' и продолжаем трассировку. В некоторых ситуациях можно просто изменить значение флага. Для этого необходимо дважды щелкнуть по цифре справа от нужного флага в окне регистров.


0040132C 33F6          xor esi, esi
0040132E BA 01000000   mov edx, 1
00401333 8BCB          mov ecx, ebx
00401335 0FB64C0A FF   movzx ecx, byte ptr [edx+ecx-1]
0040133A 8D3431        lea esi, dword ptr [ecx+esi]
0040133D 42            inc edx
0040133E 48            dec eax
0040133F 75 F2         jnz short 00401333
00401341 8BC6          mov eax, esi
00401343 69C0 66060000 imul eax, eax, 666
00401349 35 EFBEADDE   xor eax, DEADBEEF
0040134E C1C8 03       ror eax, 3


Это есть генерация серийника.


00401351 53            push ebx
00401352 50            push eax
00401353 E8 0B000000   call 00401363


А теперь переводим DWORD-число из EAX в ASCII-строку.


0040139A 57            push edi
0040139B 56            push esi
0040139C 53            push ebx
0040139D 8BF0          mov esi, eax
0040139F 8BD8          mov ebx, eax
004013A1 46            inc esi
004013A2 8A06          mov al, byte ptr [esi]
004013A4 3C 00         cmp al, 0
004013A6 75 F9         jnz short 004013A1
004013A8 B8 02000000   mov eax, 2
004013AD 8A57 03       mov dl, byte ptr [edi+3]
004013B0 8A4E FF       mov cl, byte ptr [esi-1]
004013B3 32D1          xor dl, cl
004013B5 75 09         jnz short 004013C0
004013B7 47            inc edi
004013B8 4E            dec esi
004013B9 3BF3          cmp esi, ebx
004013BB 7F F0         jg short 004013AD
004013BD 8D40 01       lea eax, dword ptr [eax+1]
004013C0 5B            pop ebx
004013C1 5E            pop esi
004013C2 5F            pop edi
004013C3 C3            retn


Здесь происходит проверка полученной строки с регистрационным кодом пользователя, начиная с четвертого символа. И проверка производится по диагонали, т. о. последний символ полученной строки будет четвертым символом серийника, предпоследний - пятым и т. д. В итоге мы имеем правильный ключ:
Name: PowerUser
Code: RE-C0857DBF


Пример 2. Пропатчивание
В качестве примера юзаем тот же (ry0's Crackme #3

Будем удалять nag-экран, который появляется при запуске ccm_3.exe.
Итак, открываем .EXE-шник в Olly. Затем в окне кода щелкаем правой кнопкой мыши. В появившемся popup-меню выберите Search for -> All referenced text strings
Ага, вот они, все строчечки:


00401082   push 0040311F                ASCII "Trial Version"
00401087   push 004030F9                ASCII "Register your copy of program, please"
00401192   push 00403000                ASCII "(ry0's Crackme #3"
004011A4   push 00403012                ASCII "Protection: Name - Serial...
00401234   push 004030C8                ASCII "http://www.cydem.org.ua"
00401239   push 004030C3                ASCII "open"
0040125B   push 004030E0                ASCII "mailto:cryo@cydem.org.ua"
00401260   push 004030C3                ASCII "open"
004013D2   mov edx, 00403067            ASCII "Try to enter Name and Code first"
004013DF   mov edx, 00403096            ASCII "Still unregistered."
004013EC   mov edx, 004030AA            ASCII "At last! Registered now."
004013FA   push 00403088                ASCII "Registration."


Теперь двойной щелк по нужной строке - и мы снова в окне кода, но уже на том месте, откуда к этой строке идет обращение:


00401066 68 80000000      push 80         
0040106B FF75 08          push [arg.1]  
0040106E E8 D5030000      call <jmp.&user32.SendMessageA> 
00401073 803D 2D314000 01 cmp byte ptr [40312D], 1
0040107A 0F84 EB000000    je 0040116B
00401080 6A 00            push 0     
00401082 68 1F314000      push 0040311F 
00401087 68 F9304000      push 004030F9 
0040108C FF75 08          push [arg.1]
0040108F E8 AE030000      call <jmp.&user32.MessageBoxA>
00401094 E9 D2000000      jmp 0040116B


Немного выше видим проверку истинности байта по адресу :40312D. Если ИСТИННО - перейти куда-то, если ЛОЖНО - показать MessageBox. Все предельно понятно. Нужно изменить 'je 0040116B' на 'jmp 0040116B'. Для этого - двойной клик по строке


0040107A 0F84 EB000000    je 0040116B


В появившемся окне меняем 'je' на 'jmp' и отмечаем "Fill with NOP's". Давим 'Assemble'. Все. Можно проверить работу, запустив ccm_3 на выполнение [ F9 ]. Работает! (Однако будьте осторожны и при пропатчивании следите за тем, чтобы длина новой команды не превышала длины изменяемой.)

Но мы пропатчили лишь память процесса, а не сам исполняемый файл. И внесенные изменения теперь надо сохранить. Правый клик мышой и выбираем "Copy to executable -> All modifications". Olly еще поспрашивает, действительно ли стоит сохранять все изменения и под каким именем писать новый файл. После этого можно закрыть отладчик и проверить, что мы намутили... Все идеально!!! И очень просто.


Автор: (ry0
12.10.2003


P.S. Большое спасибо (ry0 за отличную статью и разрешение разместить ее на нашем сайте.


Copyright © 2002-2004 hack4joy

 



Hosted by uCoz