Reverse Engineering для самых маленьких. Часть вторая.

В первой части мы познакомились немного с теорией. Теперь перейдем сразу к практике на простых программках. Качаем первый CrackMe и запускаем его.

Все в целом понятно без слов, введите правильный код . Берем IDA Pro и открываем программу.

IDA Pro один из мощнейших отладчиков \ дизассемблеров . Ну просто чудо комбайн с плагином HexRays (превращает ассемблер в псевдо код на С ), поддерживает xrefs (перекрестные ссылки) и т.д.

С лева окно функций, которые смог распознать отладчик. В центре листинг самой программы. В этой программе все достаточно скучно, по этому просто листаем программу. В блоке данных мы достаточно быстро находим строку :

aTheSerialYouHa_0:
                  text "UTF-16LE", 'The serial you have entered is invalid. Try again!!

С помощью xrefs ( горячая кнопка -> X ) находим участок кода где используется эта переменная.

Мы попадаем на кусок кода где вызывается окно с надписью, но нас больше интересует метка loc_402456. Если конкретней откуда мы попадаем на нее.

Попадаем на очередною локальную функцию. Первое что бросается в глаза : .text:004023BC push offset aRmth2hm89t21 ; — кладем в стеке строчку . Скорей всего это и есть наш ключ. Дальше идет сравнение регистров : .text:004023EC cmp si, di. И условный переход на loc_402456 : .text:004023FB jz short loc_402456. Дальше идет код вывод таблички о удачном вводе ключа.

JE/JZJump Equal (равно) или Jump Zero (ноль)
JNE/JNZJump Not Equal (не равно) или Jump Not Zero (не ноль)

По сути мы уже решили задачу, нашли ключ в коде программы. Но думаю это слишком скучно. Предлагаю пропатчить ее, что бы на любой введенный текст она говорила что все хорошо.Для этого нам строчку с условным переходом ( jz short loc_402456 ) надо заменить на команду Nop.

NOP — это однобайтовая команда, которая ничего не выполняет, а только занимает место и время. Машинный код команды NOP фактически соответствует команде XCHG AL, AL

Что бы пропатчить строчку кода выделяем ее, затем идем в меню Edit -> Patch Program -> Assemble . Обратите внимание что команда JZ занимает в коде два байта, а NOP один. Нам надо вставить две команды что бы не поломать адресацию программы.

Теперь применяем изменения (Edit -> Patch Program -> Apply … ) и запускаем программу.

Второй заход…

Следующий файл уже повеселей немного, качаем

Тут нам предлагается вести Имя и Пароль, в задание написано найдите пароль. Открываем файл в IDA , удачно. Программа сразу нам находит main функцию )))

В принципе работа программы уже вполне понятна. Если у вас не открылся просмотр в режиме графов нажмите Пробел (Space) . Нас будут интересовать три функции _prompt_user , _check_password и _get_pwd . Что бы постареть псевдо код нажмите F5 .

Давайте обратим внимание на строчки :

call    _check_password
cmp     eax, 1

По идее функция _check_password возвращает один или ноль в регистр eax по результату проверки пароля . Идем туда и смотрим ) Псевдо код не ассемблер, более менее понятно : первый символ пароля сравнивается с символом полученным в _get_pwd

Дальше идет просто зубодробительная функция (get_pws). Про ассемблер я вообще молчу, тут и в псевдокод жесть какая-то ( надо еще и С++ подучить ). Я решил пойти немного другим путем и поставил брекпоинт (клавиша F2 ) на строчку :

cmp     dl, al

И посмотреть в отладчике какие значения .

Поигравшись я выяснил что первая буква должна быть ASCII Code = 77 или «w».

Третий, контрольный в голову…

Качаем третий экземпляр, там все уже привычно. Находим функцию проверки ключа и смотрим ее в псевдокоде ( F5 )

Для удобства я переименовал переменные ( правой кнопкой на переменной или клавиша N ), а также оставил комментарии ( клавиша / ). Что бы код был принят переменная mr_x должна быть ровна 7. В принципе уже понятно что пароль 7 символов, но мать вашу : где этот X увеличивается ???

Я точно не гений, решение этой проблемы у меня заняло определенное время. Пришлось лезть в ассемблер , ставить брекпоинты и ковырять отличником алгоритм работы. Собственно я нашел как проходит проверка ключа. Он по символьной сравнивается с Secret_key db 'phahh`b',0 . Алгоритм работы такой :

mr_x ^ Secret_key[mr_x]) == key[mr_x]
.text:0040109B                 movsx   edx, byte ptr Secret_key[esi] ; "phahh`b"
.text:004010A2                 movsx   eax, key[esi]
.text:004010A9                 xor     edx, esi
.text:004010AB                 cmp     edx, eax
.text:004010AD                 jnz     loc_4011CB
.text:004010B3                 mov     eax, offset key
.text:004010B8                 lea     edx, [eax+1]
.text:004010BB                 jmp     short loc_4010C0

Оператор XOR приемник , источник — выполняет побитную операцию ИЛИ .

Ну а пароль высчитывается так :

0x70 ^ 0  ->  " p "
0x68 ^ 1  ->  " i "
0x61 ^ 2  ->  " c "
0x68 ^ 3  ->  " k "
0x68 ^ 4  ->  " l "
0x60 ^ 5  ->  " e "
0x62 ^ 6  ->  " d "