• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья "Посылаем сигналы пришельцам через radare2". Самая необходимая информация для использования этого фреймворка.

Mogen

Red Team
27.08.2019
316
614
BIT
27

Доброго времени суток, читатели Codeby! 👋

1639688446400.png


Будем честными. В большинстве случаев ревёрсеры используют IDA в качестве дизассемблера. Но что насчёт других дизассемблеров? Можно ли через терминальные отладчики отлаживать программы без проблем? Например, через radere2. В этой статье мы попытаемся ответить на этот вопрос. Также мы узнаем какая необходимая информация нужна для комфортного использования radare2. Всё рассматривать не будем, так как статья станет одеялом

Powerful_Crackme

Для обучения возьмём . Откроем его в radare2.

Проанализируем файл в radare2 через aaa. Это нужно для полного анализа программы. Мы будем использовать эту команду почти во всех случаях. Если нужно проанализировать что-то конкретное, можно обратиться к справке в radare2 (a?). Теперь перейдём к функции main, используя команду s main.

В IDA очень часто нужна информация из вкладки View. В radare2 тоже есть свои аналоги.

_attachments/Pasted image 20211211144112.png


Важные вкладки из ViewКоманды radare2
ExportsiE
Importsii
Namesis
Functionsafl или afll
Stringsiz или izz (Все строки)
SegmentsiS
SignaturesiT. Также можно использовать zg (генерация) z (просмотр)
Type Librariesil (Информация о библиотеках)
Structurets


Если вам нужен Hexdump, то используйте px или px количество символов для вывода.

_attachments/Pasted image 20211211144656.png

Графика!

В radare2 есть два основных способа получения информации.
  1. Через команды radare2.
  2. Через визуальный режим.
Умение вводить команды нам пригодится всегда, но сами команды можно узнать из , интернета или из графического режима. Да и статья станет слишком большой, поэтому я не буду писать о командах.

_attachments/Pasted image 20211215201333.png


Поэтому, мы будем рассматривать графический режим. Начнём с графов.

В IDA для активации режима графов нужно нажать пробел. В radare2 это делается через VV. В режиме графов можно перемещаться через hjkl или стрелочками. Можно использовать режим курсора (c) для редактирования частей графа. Переключение между блоками графа осуществляется через TAB или введением названия блока графа (od, ol и т.д.).

Если мы находимся в режиме курсора, то в левом верхнем углу это будет отображено.

Для выхода нужно нажать q. Эта клавиша работает везде одинаково.

_attachments/Pasted image 20211211212300.png



Переходим к другим частям визуального режима. Нажав V, мы попадаем в Hexdump. С помощью TAB мы можем менять информацию, выводимую на экране. Нажав Vp, мы попадаем в Hexdump, дизассемблированный код или в вывод другой команды. Сама команда отображается наверху.

_attachments/Pasted image 20211211213147.png



_attachments/Pasted image 20211211212639.png


Нажав v, мы попадаем в панель управления самолётом отладчик. Мы уделим этой части radare2 больше времени, так как она очень сильно может помочь. К этой панели прилагается очень хорошая справка (V?).

_attachments/Pasted image 20211211212802.png


Чтобы переключаться между окнами, нажимайте TAB. Чтобы переключаться между окнами и верхней панелью, нажимайте m. Можно переключаться между вкладками и
открывать их. Самое главное - это наличие игры 2048!

_attachments/Pasted image 20211211215306.png



В окнах можно менять вывод команд. Нажимаем правую кнопку мыши и выбираем нужное. Можно задать свои команды через e. Далее нужно будет ввести новую команду.


Мы можем переходить к разным функциям через браузер функций (_). Если браузер функций вам не нужен, то перемещаться между функциями можно в самом окне с дизассемблированным кодом. Клавиша n для перехода к следующей функции и N для перехода к предыдущей. Для перехода к конкретному адресу используйте g, а затем введите адрес или функцию. Если хочется поменять окна местами, то можно использовать p или P.
Если вы замечали надпись Tab, то поздравляю вас! Вы можете создавать/удалять новые вкладки через t. На значения из этих вкладок можно смотреть в увеличенном режиме, нажав Enter.


Вводить команды radare2 можно через :cmd. Через ) мы можем вывести дополнительную информацию на экран. O позволяет нам представлять код в дизассемблированном виде и в виде псевдо-кода си. А o даёт возможность переключаться между hexdump'ом, esil и другими режимами. Ну и самое важное - R Оно меняет тему radare2 на рандомную.
Если вы хотите посмотреть ссылки (refs) или перекрёстные ссылки (xrefs), то нажимайте x. Далее выбирайте то, что вам нужно, нажимая X или x. Самое главное - это не перепутать с клавишей X. Она закрывает окно.

В режиме курсора (c) мы можем менять значения байтов, нажимая i. Для записи изменений нужно указать флаг -w и -e bin.cache=true в командной строке, так как все изменения записываются в кеш. Через команду A мы можем вставлять произвольные ассемблерные инструкции вместо самой верхней инструкции. Мы можем посмотреть все изменения в программе через wc. Удалить конкретное изменение можно через wc- address. Также можно убирать изменения с какого-либо адреса по какой-либо через wc- from to. Ну или можно удалить все изменения через wcr. Их можно будет применить через wci или wc+ addr.

Через b мы можем просматривать и редактировать множество значений. Например: искать ROP-гаджеты, редактировать биты, смотреть импорты и т.д.
Часто приходится оставлять комментарии для себя в коде. В визуальном режиме это делается через ;. Комментарий будет добавлен к самой верхней инструкции.


Теперь перейдём в меню анализа и просмотра самой полезной информации. Нажмём Vv. Здесь мы можем просматривать xrefs (перекрёстные ссылки в самой программе), refs (ссылки в программе), переменные, определения и многое другое. Также мы можем не только просматривать их, но и редактировать! Почти всегда нужно менять какие-либо переменные в коде для удобства чтения.

Перейдём к отладке программы. В визуальном режиме точка останова ставиться через F2 на самой верхней инструкции. Начать выполнение программы до точки останова через F9. Выполнить шаг с заходом в функцию через F7, а без захода в функцию через F8.
Главная проблема отладки в визуальном режиме - это отсутствие вывода и ввода. Есть несколько способов решить это.

Первый - это выполнять функции вывода и ввода через команды radare2.
Второй - ввод данных через второе окно терминала.


Самые полезные команды для первого способа.

do - Заново открыть программу для отладки
db address - Установить точку останова по указанному адресу
ds - Выполнить инструкцию, заходя в функцию call
dss - Выполнить инструкцию, не заходя в функцию call
dc - Начать выполнение программы до точки останова. Если точек останова нет, то выполнять программу до самого конца.
Остальные команды можно узнать из справки d?.


Как выводить и вводить данные через второй терминал?

Создадим простой скрипт rarun2, где укажем ввод и вывод:
  1. Откроем новый терминал.
  2. Запустим команду tty и скопируем вывод. Введём команду sleep 999999999.
  3. Вставим значение после символа =.
Код:
#!/usr/bin/env rarun2
stdin=/dev/pts/3
stdout=/dev/pts/3

Теперь сохраняем этот скрипт в файл. Например, pty3. Вводим команду r2 -e dbg.profile=pty3 -d PowerFul_Crackme для запуска программы в radare2.


_attachments/Pasted image 20211212220354.png


Весь визуальный режим можно сравнить с главным окном в IDA. Давайте перейдём к решению самого crackme.


Решение crackme.

Код функции main в radare2:


В radare2 не указывается в квадратных скобках к какому регистру, что прибавляется. Эта информация указывается в начале функции!


IDA:

C-подобный:
.text:0000558FBDF1F248                 lea     rax, [rbp+inp_str]

radare2:

C-подобный:
0x560ba5a7f248 488d45de lea rax, [var_22h]

Фрагмент из начала функции main:

C-подобный:
; var int64_t var_22h @ rbp-0x22

Проанализируем дизассемблированный код этого crackme.

C-подобный:
```clike[/FONT]
 [FONT=verdana]; DATA XREF from entry0 @ 0x560ba5a7f08d
┌ 274: int main (int argc, char **argv, char **envp);
│ ; var int64_t var_2dh @ rbp-0x2d
│ ; var int64_t var_23h @ rbp-0x23
│ ; var int64_t var_22h @ rbp-0x22
│ ; var int64_t var_18h @ rbp-0x18
│ ; var int64_t var_17h @ rbp-0x17
│ ; var int64_t var_fh @ rbp-0xf
│ ; var int64_t var_dh @ rbp-0xd
│ ; var int64_t var_ch @ rbp-0xc
│ ; var int64_t var_8h @ rbp-0x8
│ ; var int64_t var_4h @ rbp-0x4
│ 0x560ba5a7f155 55 push rbp             \\ Пролог функции
│ 0x560ba5a7f156 4889e5 mov rbp, rsp     \\
│ 0x560ba5a7f159 4883ec30 sub rsp, 0x30
│ 0x560ba5a7f15d 48b862706661. movabs rax, 0x626f676a61667062 ; 'bpfajgob' | Перемещаем 'bpfajgob' в rax
│ 0x560ba5a7f167 488945e9 mov qword [var_17h], rax  | Перемещаем значение rax (строка выше) в память var_17
│ 0x560ba5a7f16b 66c745f16977 mov word [var_fh], 0x7769 ; 'iw' | Добавляем 'iw' в конец строки 'bpfajgob'
│ 0x560ba5a7f171 c645f300 mov byte [var_dh], 0
│ 0x560ba5a7f175 488d3d8c0e00. lea rdi, str.The_magic_string:_ ; 0x560ba5a80008 ; "The magic string: " \\ В rdi лежит адрес строки
│ 0x560ba5a7f17c b800000000 mov eax, 0
│ 0x560ba5a7f181 e8bafeffff call sym.imp.printf ; int printf(const char *format)  \\ printf("The magic string: ");

\\ strcpy(or_str, "bpfajgobiw");
\\ printf("The magic string: ");


│ 0x560ba5a7f186 c745fc000000. mov dword [var_4h], 0  \\ Здесь начнётся цикл for. var_4 - счётчик.
│ ┌─< 0x560ba5a7f18d eb24 jmp 0x560ba5a7f1b3  \\ Переходим по адресу 0x560ba5a7f1b3
│ ┌──> 0x560ba5a7f18f 488d55de lea rdx, [var_22h]  \\ В rdx лежит адрес значения var_22 (введённая строка)
│ ╎│ 0x560ba5a7f193 8b45fc mov eax, dword [var_4h] \\ В eax значение var_4
│ ╎│ 0x560ba5a7f196 4898 cdqe  \\ Выполняет преобразование dword в qword в rax
│ ╎│ 0x560ba5a7f198 4801d0 add rax, rdx \\ Добавляем к rax значение rdx. Таким образом мы записываем символы друг за другом, не перезаписывая ничего лишнего
│ ╎│ 0x560ba5a7f19b 4889c6 mov rsi, rax \\ В rsi лежит значение rax
│ ╎│ 0x560ba5a7f19e 488d3d760e00. lea rdi, [0x560ba5a8001b] ; " %c"  \\ В rdi адрес форматной строки для считывания символов
│ ╎│ 0x560ba5a7f1a5 b800000000 mov eax, 0
│ ╎│ 0x560ba5a7f1aa e8a1feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format) \\
│ ╎│ 0x560ba5a7f1af 8345fc01 add dword [var_4h], 1
│ ╎│ ; CODE XREF from main @ 0x560ba5a7f18d
│ ╎└─> 0x560ba5a7f1b3 837dfc09 cmp dword [var_4h], 9 \\ Сравниваем "Счётчик" со значением 9
│ └──< 0x560ba5a7f1b7 7ed6 jle 0x560ba5a7f18f  \\ Переходим в тело цикла, если "счётчик" >= 9[/FONT]
 
[FONT=verdana]\\ for ( i = 0; i <= 9; ++i )
\\    scanf(" %c", inp_str[i]);[/FONT]
 
[FONT=verdana]│ 0x560ba5a7f1b9 c745f8000000. mov dword [var_8h], 0 \\ "Счётчик"=0
│ ┌─< 0x560ba5a7f1c0 eb3a jmp 0x560ba5a7f1fc
│ ┌──> 0x560ba5a7f1c2 837df806 cmp dword [var_8h], 6 \\ Сравниваем "счётчик" с 6.
│ ┌───< 0x560ba5a7f1c6 7f19 jg 0x560ba5a7f1e1 \\ Если "счётчик" больше 6, то переходим к адресу 0x560ba5a7f1e1.
│ │╎│ 0x560ba5a7f1c8 8b45f8 mov eax, dword [var_8h] \\ Перемещаем значение из "счётчика" (var_8h) в eax.
│ │╎│ 0x560ba5a7f1cb 8d4803 lea ecx, [rax + 3] \\ Переносим адрес значения из rax+3 в ecx.
│ │╎│ 0x560ba5a7f1ce 8b45f8 mov eax, dword [var_8h] \\ Переносим значение из "счётчика" в eax.
│ │╎│ 0x560ba5a7f1d1 4898 cdqe  \\ Выполняет преобразование dword в qword в rax.
│ │╎│ 0x560ba5a7f1d3 0fb65405de movzx edx, byte [rbp + rax - 0x22] В edx лежит байт из введённой строки[eax] (var_22).
│ │╎│ 0x560ba5a7f1d8 4863c1 movsxd rax, ecx \\ Переносим значение, полученное в инструкции по адресу 0x560ba5a7f1cb в rax.
│ │╎│ 0x560ba5a7f1db 885405d3 mov byte [rbp + rax - 0x2d], dl \\ Переносим символ в финальную строку.
│ ┌────< 0x560ba5a7f1df eb17 jmp 0x560ba5a7f1f8 \\ Переходим к 0x560ba5a7f1f8
│ │└───> 0x560ba5a7f1e1 8b45f8 mov eax, dword [var_8h] \\ "Счётчик" > 6. Перемещаем значение из "счётчика" (var_8h) в eax.
│ │ ╎│ 0x560ba5a7f1e4 8d48f9 lea ecx, [rax - 7] \\ Переносим адрес значения из rax-7 в ecx.
│ │ ╎│ 0x560ba5a7f1e7 8b45f8 mov eax, dword [var_8h] Перемещаем значение из "счётчика" (var_8h) в eax.
│ │ ╎│ 0x560ba5a7f1ea 4898 cdqe  \\ Выполняет преобразование dword в qword в rax.
│ │ ╎│ 0x560ba5a7f1ec 0fb65405de movzx edx, byte [rbp + rax - 0x22] В edx лежит байт из введённой строки[eax] (var_22).
│ │ ╎│ 0x560ba5a7f1f1 4863c1 movsxd rax, ecx \\ Переносим значение, полученное в инструкции по адресу 0x560ba5a7f1e4 в rax.
│ │ ╎│ 0x560ba5a7f1f4 885405d3 mov byte [rbp + rax - 0x2d], dl \\ Переносим символ в финальную строку.
│ │ ╎│ ; CODE XREF from main @ 0x560ba5a7f1df
│ └────> 0x560ba5a7f1f8 8345f801 add dword [var_8h], 1 \\ "Счётчик" = "Счётчик" + 1
│ ╎│ ; CODE XREF from main @ 0x560ba5a7f1c0
│ ╎└─> 0x560ba5a7f1fc 837df809 cmp dword [var_8h], 9 \\ Сравниваем "счётчик" с 9.
│ └──< 0x560ba5a7f200 7ec0 jle 0x560ba5a7f1c2 \\ Если меньше или равно 9, то переходим в тело цикла.

\\for (i = 0; i <= 9; ++i ) {
\\    if ( i > 6 )
\\        j = i - 7;
\\    else
\\        j = i + 3;
\\    f_str[j] = inp_str[i];
}


│ 0x560ba5a7f202 c645e800 mov byte [var_18h], 0            |
│ 0x560ba5a7f206 c645dd00 mov byte [var_23h], 0            | Отделяем строки друг от друга через 0x00.

│ 0x560ba5a7f20a c745f4000000. mov dword [var_ch], 0   \\ "Счётчик" = 0
│ ┌─< 0x560ba5a7f211 eb2f jmp 0x560ba5a7f242 \\ Переходим к 0x560ba5a7f242
│ ┌──> 0x560ba5a7f213 8b45f4 mov eax, dword [var_ch] \\ В eax будет значение "счётчика"
│ ╎│ 0x560ba5a7f216 4898 cdqe \\ Выполняет преобразование dword в qword в rax.
│ ╎│ 0x560ba5a7f218 0fb65405d3 movzx edx, byte [rbp + rax - 0x2d] \\ Перемещаем в edx код символа из финальной строки[eax].
│ ╎│ 0x560ba5a7f21d 8b45f4 mov eax, dword [var_ch] \\ В eax будет значение "счётчика"
│ ╎│ 0x560ba5a7f220 4898 cdqe \\ Выполняет преобразование dword в qword в rax.
│ ╎│ 0x560ba5a7f222 0fb64405e9 movzx eax, byte [rbp + rax - 0x17] \\ Перемещаем в eax код символа из оригинальной строки[eax].
│ ╎│ 0x560ba5a7f227 38c2 cmp dl, al \\ Сравниваем символ из финальной строки с символом из оригинальной строки
│ ┌───< 0x560ba5a7f229 7413 je 0x560ba5a7f23e \\ Если символы равны, то переходим к 0x560ba5a7f23e
│ │╎│ 0x560ba5a7f22b 488d3ded0d00. lea rdi, str.Sorry__wrong_input_:_ ; 0x560ba5a8001f ; "Sorry, wrong input :(" \\ Символы не равны. Переносим адрес строки str.Sorry__wrong_input_ в rdi
│ │╎│ 0x560ba5a7f232 e8f9fdffff call sym.imp.puts ; int puts(const char *s) \\ puts("Sorry, wrong input :(");
│ │╎│ 0x560ba5a7f237 b800000000 mov eax, 0 \\ Переносим в eax 0 (Код выхода)
│ ┌────< 0x560ba5a7f23c eb27 jmp 0x560ba5a7f265 \\ Переходим к концу функции main
│ │└───> 0x560ba5a7f23e 8345f401 add dword [var_ch], 1 \\ "Счётчик" = "Счётчик" + 1
│ │ ╎│ ; CODE XREF from main @ 0x560ba5a7f211
│ │ ╎└─> 0x560ba5a7f242 837df409 cmp dword [var_ch], 9 \\ Сравниваем "счётчик" с 9
│ │ └──< 0x560ba5a7f246 7ecb jle 0x560ba5a7f213 \\ Если счётчик меньше или равен 9, то переходим к 0x560ba5a7f213
│ │ 0x560ba5a7f248 488d45de lea rax, [var_22h] \\ Переносим в rax адрес начала финальной строки
│ │ 0x560ba5a7f24c 4889c6 mov rsi, rax \\ Переносим адрес в rsi
│ │ 0x560ba5a7f24f 488d3de20d00. lea rdi, str.Congratulations__correct_flag__nThe_flag_is:_WatadCTF_s_n ; 0x560ba5a80038 ; "Congratulations, correct flag!\nThe flag is: WatadC
TF{%s}\n" \\ Переносим в rdi адрес str.Congratulations__correct_flag__nThe_flag_is
│ │ 0x560ba5a7f256 b800000000 mov eax, 0
│ │ 0x560ba5a7f25b e8e0fdffff call sym.imp.printf ; int printf(const char *format) \\ printf("Congratulations, correct flag!\nThe flag is: WatadCTF{%s}\n", inp_str);
│ │ 0x560ba5a7f260 b800000000 mov eax, 0 \\ Переносим в eax 0 (Код выхода)
│ │ ; CODE XREF from main @ 0x560ba5a7f23c
│ └────> 0x560ba5a7f265 c9 leave \\ Копирует содержимое RBP в RSP
└ 0x560ba5a7f266 c3 ret \\ Возвращаемся в функцию из RSP

\\ for (i = 0; i <=9; i++) {
\\    if ( f_str[i] != or_str[i] ) {
\\        puts("Sorry, wrong input :(");
          return 0;
\\    }
\\    else
\\        printf("Congratulations, correct flag!\nThe flag is: WatadCTF{%s}\n", inp_str);
\\        return 0;
\\}

Ассемблерный код можно перевести в код на си.

C:
#include <stdio.h>
#include <string.h>[/FONT]
 
[FONT=verdana]char or_str[11] = "";    //
char inp_str[11] = "";   // 11 символ - 0x00. Он означает конец строки.
char f_str[11] = "";     //
int i = 0;
int j = 0;[/FONT]
 
[FONT=verdana]int main() {[/FONT]
 
[FONT=verdana]   strcpy(or_str, "bpfajgobiw");
   printf("The magic string: ");
   
   for ( i = 0; i <= 9; ++i )
       scanf(" %c", &inp_str[i]);
   
   for (i = 0; i <= 9; ++i ) {
       if ( i > 6 )
           j = i - 7;
       else
           j = i + 3;
       f_str[j] = inp_str[i];
   }    
   
   for (i = 0; i <=9; i++) {
       if ( f_str[i] != or_str[i] ) {
           puts("Sorry, wrong input :(");
           return 0;
       }
   }
   
   printf("Congratulations, correct flag!\nThe flag is: WatadCTF{%s}\n", inp_str);
   return 0;
}

Эту программу можно скомпилировать в PowerFul_Crackme_my через команду gcc PowerFul_Crackme_my.c -o PowerFul_Crackme_my

Объяснение на русском языке.

В программе задумана строка bpfajgobiw. Пользователь вводит строку длиной 10 символов. Программа переносит последние три символа в начало строки. Таким образом создаётся финальная строка. Затем, финальная строка сравнивается со строкой bpfajgobiw. Если строки равны, выводится Congratulations, correct flag!.... Если строки не равны, то выводится Sorry, wrong input :(

Написанный выше текст можно проверить этим кодом:


C:
#include <stdio.h>
#include <string.h>[/FONT]
 
[FONT=verdana]char or_str[11] = "";
char inp_str[11] = "";
char f_str[11] = "";
int i = 0;
int j = 0;[/FONT]
 
[FONT=verdana]int main() {[/FONT]
 
[FONT=verdana]   strcpy(or_str, "bpfajgobiw");
   printf("The magic string: ");
   
   for ( i = 0; i <= 9; ++i )
       scanf(" %c", &inp_str[i]);
   
   for (i = 0; i <= 9; ++i ) {
       if ( i > 6 )
           j = i - 7;
       else
           j = i + 3;
       f_str[j] = inp_str[i];
   }    
   
   printf("f_str = %s\n", f_str);[/FONT]
 
[FONT=verdana]   for (i = 0; i <=9; i++) {
       if ( f_str[i] != or_str[i] ) {
           puts("Sorry, wrong input :(");
           return 0;
       }
   }
   
   printf("Congratulations, correct flag!\nThe flag is: WatadCTF{%s}\n", inp_str);
   return 0;
}

_attachments/Pasted image 20211213194612.png


Или через radare2 :)



Pasted image 20211213201314.png


Правильный ответ - ajgobiwbpf

Расширение и дополнительные утилиты из radare2.


Дополнительные утилиты.


  • rabin2. Эта утилита выводит нам информацию:
    • О файле: rabin2 -I PowerFul_Crackme
    • О секциях: rabin2 -S PowerFul_Crackme
    • О заголовках: rabin2 -H PowerFul_Crackme
    • и многом другом...
  • radiff2. Через него можно сравнивать два бинарных файла. radiff2 PowerFul_Crackme PowerFul_Crackme_my. radiff2 покажет различия в файлах.
  • rasm2. Это консольный ассемблер и дизассемблер, и он очень полезен! Сначала нам нужно определиться с архитектурой. Все архитектуры можно посмотреть через rasm2 -L. Возьмём архитектуру x86, а размер регистров (-b) установим в 64. Получится архитектура x86-64.
    • rasm2 -a x86 -b 64 "push eax" = 0x50
    • rasm2 -a x86 -b 64 -d 50 = push rax
    • rasm2 -w "push" -a x86 -b 64 - для получения информации об инструкции push.
  • rafind2. Эта утилита помогает искать информацию в файлах. Например, строку flagв PowerFul_Crackme_my.
    • rafind2 -s "flag" ./PowerFul_Crackme_my = 0x2051 или 0x205b.
  • rahash2. Эта утилита вычисляет хеш программы, кодирует/декодирует данные в base64 и некоторые функции шифрования.
    ПРЕДУПРЕЖДЕНИЕ - Не пытайтесь использовать rahash2 для большого файла, поскольку он сначала пытается загрузить весь файл в память.
    Для просмотра всех хеш-функций используйте флаг -L.
    • rahash2 -a md5 ./PowerFul_Crackme_my - узнать md5-хеш для PowerFul_Crackme_my.
    • rahash2 -a all ./PowerFul_Crackme_my - узнать все доступные хеш-функции для PowerFul_Crackme_my.
  • rarun2. Эта утилита позволяет запускать программу с различными параметрами среды, аргументами, правами и директориями. Вспомните скрипт, который написали ранее...
Код:
#!/usr/bin/env rarun2
stdin=/dev/pts/3
stdout=/dev/pts/3

Radare2 также можно расширять, как и IDA. Через свои скрипты или чужие. Раздел с расширением функций рассматривается бегло, так как для того же Cutter можно написать целую статью.

Декомпилятор.

Мы рассмотрели только малую часть возможностей radare2, которая поставляется "из коробки". Так эти возможности тоже можно расширить! Например, через пакетный менеджер r2pm.

В radare2 нет встроенного декомпилятора, но pdc может выдать псевдо-код. Через r2pm можно установить декомпилятор от Ghidra. Зайдите в radare2 и напишите:

Bash:
r2pm update
r2pm -ci r2ghidra

Дальше переходите в функцию main и вводите pdg.

_attachments/Pasted image 20211214213959.png


pdga тоже может пригодиться.

_attachments/Pasted image 20211214214201.png


pdg? показывает справку про r2ghidra.


Прокаченный псевдо-код.

Когда декомпилятор от Ghidra не помогает и pdc выдаёт что-то странное, можете попробовать использовать r2dec (GitHub - wargio/r2dec-js: radare2 plugin - converts asm to pseudo-C code.). Это переводчик с языка ассемблера на псевдо-C.

Bash:
r2pm init
r2pm install r2dec


Дальше переходите в функцию main и вводите pdd.

_attachments/Pasted image 20211214215115.png

pdd? показывает справку про r2dec.


Cutter

- это бесплатное приложение с открытым исходным кодом для реверс-инженеринга, основанное на Rizin.

- фреймворк для реверс-инженеринга (форк radare2), созданный и поддерживающийся частью основной команды radare2.

Cutter можно запустить на Linux, Windows и MacOs. Для Linux она поставляется в AppImage. Загрузите файл и назначьте ему права на исполнение (chmod +x Cutter-v2.0.4-x64.Linux.AppImage), а затем запускайте (./Cutter-v2.0.4-x64.Linux.AppImage).

В Cutter есть русский язык, возможности radare2 и встроенный декомпилятор от Ghidra.

_attachments/Pasted image 20211214221741.png


_attachments/Pasted image 20211214221830.png


_attachments/Pasted image 20211214221926.png

❄❄❄ Снег! ❄❄❄


Так как уже зима и скоро Новый Год, то посмотрите на снежок в radare2 :)


Предлагаю сделать небольшое задание. Попробуйте найти команду, которая вызывает его и отправьте её мне в личные сообщения на форуме вместе со скриншотом. Никнеймы первых 10 человек будут находиться в табличке. Удачи ^_^


Вывод.


Radare2 является хорошим инструментом для реверс-инжиниринга со множеством функций, но чтобы его освоить, нужно постараться. Особенно радует цена radare2, а точнее её отсутствие + open source. Не забывайте, что цена IDA PRO более 170 000 рублей!
_attachments/Pasted image 20211216203118.png


Также не следует забывать о расширяемости radare2! Для него написано множество дополнений. Итог: использовать radare2 можно.

Спасибо за то, что прочитали эту статью до конца! :)
 
Последнее редактирование:

Qulan

Red Team
06.12.2020
171
514
BIT
392
Прикольно ))) А я и не знал что ты реверсер )))
Хороший мануал. Давай ещё цикл, реверс для малышей)) мне прям интересно, но как-то не доступно. Не понимаю с какой стороны зайти.
 
  • Нравится
Реакции: Mogen

Mogen

Red Team
27.08.2019
316
614
BIT
27
Прикольно ))) А я и не знал что ты реверсер )))
Хороший мануал. Давай ещё цикл, реверс для малышей)) мне прям интересно, но как-то не доступно. Не понимаю с какой стороны зайти.
Для цикла статей нужно найти время. Может быть, сделаю :)
 

SearcherSlava

Red Team
10.06.2017
943
1 260
BIT
155
Для цикла статей нужно найти время. Может быть, сделаю :)
Здрав будь!

Семантический аспект
Знаешь Асм - тебе респект
Знаешь Си - и уважуха
И в делах и в жизни пруха
Радар знаешь стало быть
Можно рублик раздобыть
Можно два а можно три
В байте нолик подбери
Единичку не забудь
Отправляясь в дальний путь
Слева байт и справа байт
Между ними - полубайт
Там же рядом единица
Как же тут не соблазниться
Где же тьма а где же свет
Может бред а может нет
Все уходим в интернет
Время есть а денег нет
Всем даем один совет
Уходя гасите свет
Выключайте лампу
Может да а может нет
А в вопросе был ответ
 

Cubak777

One Level
06.11.2020
1
1
BIT
3

Доброго времени суток, читатели Codeby! 👋

Посмотреть вложение 55628

Будем честными. В большинстве случаев ревёрсеры используют IDA в качестве дизассемблера. Но что насчёт других дизассемблеров? Можно ли через терминальные отладчики отлаживать программы без проблем? Например, через radere2. В этой статье мы попытаемся ответить на этот вопрос. Также мы узнаем какая необходимая информация нужна для комфортного использования radare2. Всё рассматривать не будем, так как статья станет одеялом

Powerful_Crackme

Для обучения возьмём . Откроем его в radare2.

Проанализируем файл в radare2 через aaa. Это нужно для полного анализа программы. Мы будем использовать эту команду почти во всех случаях. Если нужно проанализировать что-то конкретное, можно обратиться к справке в radare2 (a?). Теперь перейдём к функции main, используя команду s main.

В IDA очень часто нужна информация из вкладки View. В radare2 тоже есть свои аналоги.

Посмотреть вложение 55605


Важные вкладки из ViewКоманды radare2
ExportsiE
Importsii
Namesis
Functionsafl или afll
Stringsiz или izz (Все строки)
SegmentsiS
SignaturesiT. Также можно использовать zg (генерация) z (просмотр)
Type Librariesil (Информация о библиотеках)
Structurets


Если вам нужен Hexdump, то используйте px или px количество символов для вывода.

Посмотреть вложение 55606

Графика!

В radare2 есть два основных способа получения информации.
  1. Через команды radare2.
  2. Через визуальный режим.
Умение вводить команды нам пригодится всегда, но сами команды можно узнать из , интернета или из графического режима. Да и статья станет слишком большой, поэтому я не буду писать о командах.

Посмотреть вложение 55607

Поэтому, мы будем рассматривать графический режим. Начнём с графов.

В IDA для активации режима графов нужно нажать пробел. В radare2 это делается через VV. В режиме графов можно перемещаться через hjkl или стрелочками. Можно использовать режим курсора (c) для редактирования частей графа. Переключение между блоками графа осуществляется через TAB или введением названия блока графа (od, ol и т.д.).

Если мы находимся в режиме курсора, то в левом верхнем углу это будет отображено.

Для выхода нужно нажать q. Эта клавиша работает везде одинаково.

Посмотреть вложение 55613


Переходим к другим частям визуального режима. Нажав V, мы попадаем в Hexdump. С помощью TAB мы можем менять информацию, выводимую на экране. Нажав Vp, мы попадаем в Hexdump, дизассемблированный код или в вывод другой команды. Сама команда отображается наверху.

Посмотреть вложение 55614


Посмотреть вложение 55615

Нажав v, мы попадаем в панель управления самолётом отладчик. Мы уделим этой части radare2 больше времени, так как она очень сильно может помочь. К этой панели прилагается очень хорошая справка (V?).

Посмотреть вложение 55616

Чтобы переключаться между окнами, нажимайте TAB. Чтобы переключаться между окнами и верхней панелью, нажимайте m. Можно переключаться между вкладками и
открывать их. Самое главное - это наличие игры 2048!

Посмотреть вложение 55617


В окнах можно менять вывод команд. Нажимаем правую кнопку мыши и выбираем нужное. Можно задать свои команды через e. Далее нужно будет ввести новую команду.


Мы можем переходить к разным функциям через браузер функций (_). Если браузер функций вам не нужен, то перемещаться между функциями можно в самом окне с дизассемблированным кодом. Клавиша n для перехода к следующей функции и N для перехода к предыдущей. Для перехода к конкретному адресу используйте g, а затем введите адрес или функцию. Если хочется поменять окна местами, то можно использовать p или P.
Если вы замечали надпись Tab, то поздравляю вас! Вы можете создавать/удалять новые вкладки через t. На значения из этих вкладок можно смотреть в увеличенном режиме, нажав Enter.


Вводить команды radare2 можно через :cmd. Через ) мы можем вывести дополнительную информацию на экран. O позволяет нам представлять код в дизассемблированном виде и в виде псевдо-кода си. А o даёт возможность переключаться между hexdump'ом, esil и другими режимами. Ну и самое важное - R Оно меняет тему radare2 на рандомную.
Если вы хотите посмотреть ссылки (refs) или перекрёстные ссылки (xrefs), то нажимайте x. Далее выбирайте то, что вам нужно, нажимая X или x. Самое главное - это не перепутать с клавишей X. Она закрывает окно.

В режиме курсора (c) мы можем менять значения байтов, нажимая i. Для записи изменений нужно указать флаг -w и -e bin.cache=true в командной строке, так как все изменения записываются в кеш. Через команду A мы можем вставлять произвольные ассемблерные инструкции вместо самой верхней инструкции. Мы можем посмотреть все изменения в программе через wc. Удалить конкретное изменение можно через wc- address. Также можно убирать изменения с какого-либо адреса по какой-либо через wc- from to. Ну или можно удалить все изменения через wcr. Их можно будет применить через wci или wc+ addr.

Через b мы можем просматривать и редактировать множество значений. Например: искать ROP-гаджеты, редактировать биты, смотреть импорты и т.д.
Часто приходится оставлять комментарии для себя в коде. В визуальном режиме это делается через ;. Комментарий будет добавлен к самой верхней инструкции.


Теперь перейдём в меню анализа и просмотра самой полезной информации. Нажмём Vv. Здесь мы можем просматривать xrefs (перекрёстные ссылки в самой программе), refs (ссылки в программе), переменные, определения и многое другое. Также мы можем не только просматривать их, но и редактировать! Почти всегда нужно менять какие-либо переменные в коде для удобства чтения.

Перейдём к отладке программы. В визуальном режиме точка останова ставиться через F2 на самой верхней инструкции. Начать выполнение программы до точки останова через F9. Выполнить шаг с заходом в функцию через F7, а без захода в функцию через F8.
Главная проблема отладки в визуальном режиме - это отсутствие вывода и ввода. Есть несколько способов решить это.

Первый - это выполнять функции вывода и ввода через команды radare2.
Второй - ввод данных через второе окно терминала.


Самые полезные команды для первого способа.

do - Заново открыть программу для отладки
db address - Установить точку останова по указанному адресу
ds - Выполнить инструкцию, заходя в функцию call
dss - Выполнить инструкцию, не заходя в функцию call
dc - Начать выполнение программы до точки останова. Если точек останова нет, то выполнять программу до самого конца.
Остальные команды можно узнать из справки d?.


Как выводить и вводить данные через второй терминал?

Создадим простой скрипт rarun2, где укажем ввод и вывод:
  1. Откроем новый терминал.
  2. Запустим команду tty и скопируем вывод. Введём команду sleep 999999999.
  3. Вставим значение после символа =.
Код:
#!/usr/bin/env rarun2
stdin=/dev/pts/3
stdout=/dev/pts/3

Теперь сохраняем этот скрипт в файл. Например, pty3. Вводим команду r2 -e dbg.profile=pty3 -d PowerFul_Crackme для запуска программы в radare2.


Посмотреть вложение 55618

Весь визуальный режим можно сравнить с главным окном в IDA. Давайте перейдём к решению самого crackme.


Решение crackme.

Код функции main в radare2:


В radare2 не указывается в квадратных скобках к какому регистру, что прибавляется. Эта информация указывается в начале функции!


IDA:

C-подобный:
.text:0000558FBDF1F248                 lea     rax, [rbp+inp_str]

radare2:

C-подобный:
0x560ba5a7f248 488d45de lea rax, [var_22h]

Фрагмент из начала функции main:

C-подобный:
; var int64_t var_22h @ rbp-0x22

Проанализируем дизассемблированный код этого crackme.

C-подобный:
```clike[/FONT][/FONT]
 [FONT=verdana][FONT=verdana]; DATA XREF from entry0 @ 0x560ba5a7f08d
┌ 274: int main (int argc, char **argv, char **envp);
│ ; var int64_t var_2dh @ rbp-0x2d
│ ; var int64_t var_23h @ rbp-0x23
│ ; var int64_t var_22h @ rbp-0x22
│ ; var int64_t var_18h @ rbp-0x18
│ ; var int64_t var_17h @ rbp-0x17
│ ; var int64_t var_fh @ rbp-0xf
│ ; var int64_t var_dh @ rbp-0xd
│ ; var int64_t var_ch @ rbp-0xc
│ ; var int64_t var_8h @ rbp-0x8
│ ; var int64_t var_4h @ rbp-0x4
│ 0x560ba5a7f155 55 push rbp             \\ Пролог функции
│ 0x560ba5a7f156 4889e5 mov rbp, rsp     \\
│ 0x560ba5a7f159 4883ec30 sub rsp, 0x30
│ 0x560ba5a7f15d 48b862706661. movabs rax, 0x626f676a61667062 ; 'bpfajgob' | Перемещаем 'bpfajgob' в rax
│ 0x560ba5a7f167 488945e9 mov qword [var_17h], rax  | Перемещаем значение rax (строка выше) в память var_17
│ 0x560ba5a7f16b 66c745f16977 mov word [var_fh], 0x7769 ; 'iw' | Добавляем 'iw' в конец строки 'bpfajgob'
│ 0x560ba5a7f171 c645f300 mov byte [var_dh], 0
│ 0x560ba5a7f175 488d3d8c0e00. lea rdi, str.The_magic_string:_ ; 0x560ba5a80008 ; "The magic string: " \\ В rdi лежит адрес строки
│ 0x560ba5a7f17c b800000000 mov eax, 0
│ 0x560ba5a7f181 e8bafeffff call sym.imp.printf ; int printf(const char *format)  \\ printf("The magic string: ");

\\ strcpy(or_str, "bpfajgobiw");
\\ printf("The magic string: ");


│ 0x560ba5a7f186 c745fc000000. mov dword [var_4h], 0  \\ Здесь начнётся цикл for. var_4 - счётчик.
│ ┌─< 0x560ba5a7f18d eb24 jmp 0x560ba5a7f1b3  \\ Переходим по адресу 0x560ba5a7f1b3
│ ┌──> 0x560ba5a7f18f 488d55de lea rdx, [var_22h]  \\ В rdx лежит адрес значения var_22 (введённая строка)
│ ╎│ 0x560ba5a7f193 8b45fc mov eax, dword [var_4h] \\ В eax значение var_4
│ ╎│ 0x560ba5a7f196 4898 cdqe  \\ Выполняет преобразование dword в qword в rax
│ ╎│ 0x560ba5a7f198 4801d0 add rax, rdx \\ Добавляем к rax значение rdx. Таким образом мы записываем символы друг за другом, не перезаписывая ничего лишнего
│ ╎│ 0x560ba5a7f19b 4889c6 mov rsi, rax \\ В rsi лежит значение rax
│ ╎│ 0x560ba5a7f19e 488d3d760e00. lea rdi, [0x560ba5a8001b] ; " %c"  \\ В rdi адрес форматной строки для считывания символов
│ ╎│ 0x560ba5a7f1a5 b800000000 mov eax, 0
│ ╎│ 0x560ba5a7f1aa e8a1feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format) \\
│ ╎│ 0x560ba5a7f1af 8345fc01 add dword [var_4h], 1
│ ╎│ ; CODE XREF from main @ 0x560ba5a7f18d
│ ╎└─> 0x560ba5a7f1b3 837dfc09 cmp dword [var_4h], 9 \\ Сравниваем "Счётчик" со значением 9
│ └──< 0x560ba5a7f1b7 7ed6 jle 0x560ba5a7f18f  \\ Переходим в тело цикла, если "счётчик" >= 9[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]\\ for ( i = 0; i <= 9; ++i )
\\    scanf(" %c", inp_str[i]);[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]│ 0x560ba5a7f1b9 c745f8000000. mov dword [var_8h], 0 \\ "Счётчик"=0
│ ┌─< 0x560ba5a7f1c0 eb3a jmp 0x560ba5a7f1fc
│ ┌──> 0x560ba5a7f1c2 837df806 cmp dword [var_8h], 6 \\ Сравниваем "счётчик" с 6.
│ ┌───< 0x560ba5a7f1c6 7f19 jg 0x560ba5a7f1e1 \\ Если "счётчик" больше 6, то переходим к адресу 0x560ba5a7f1e1.
│ │╎│ 0x560ba5a7f1c8 8b45f8 mov eax, dword [var_8h] \\ Перемещаем значение из "счётчика" (var_8h) в eax.
│ │╎│ 0x560ba5a7f1cb 8d4803 lea ecx, [rax + 3] \\ Переносим адрес значения из rax+3 в ecx.
│ │╎│ 0x560ba5a7f1ce 8b45f8 mov eax, dword [var_8h] \\ Переносим значение из "счётчика" в eax.
│ │╎│ 0x560ba5a7f1d1 4898 cdqe  \\ Выполняет преобразование dword в qword в rax.
│ │╎│ 0x560ba5a7f1d3 0fb65405de movzx edx, byte [rbp + rax - 0x22] В edx лежит байт из введённой строки[eax] (var_22).
│ │╎│ 0x560ba5a7f1d8 4863c1 movsxd rax, ecx \\ Переносим значение, полученное в инструкции по адресу 0x560ba5a7f1cb в rax.
│ │╎│ 0x560ba5a7f1db 885405d3 mov byte [rbp + rax - 0x2d], dl \\ Переносим символ в финальную строку.
│ ┌────< 0x560ba5a7f1df eb17 jmp 0x560ba5a7f1f8 \\ Переходим к 0x560ba5a7f1f8
│ │└───> 0x560ba5a7f1e1 8b45f8 mov eax, dword [var_8h] \\ "Счётчик" > 6. Перемещаем значение из "счётчика" (var_8h) в eax.
│ │ ╎│ 0x560ba5a7f1e4 8d48f9 lea ecx, [rax - 7] \\ Переносим адрес значения из rax-7 в ecx.
│ │ ╎│ 0x560ba5a7f1e7 8b45f8 mov eax, dword [var_8h] Перемещаем значение из "счётчика" (var_8h) в eax.
│ │ ╎│ 0x560ba5a7f1ea 4898 cdqe  \\ Выполняет преобразование dword в qword в rax.
│ │ ╎│ 0x560ba5a7f1ec 0fb65405de movzx edx, byte [rbp + rax - 0x22] В edx лежит байт из введённой строки[eax] (var_22).
│ │ ╎│ 0x560ba5a7f1f1 4863c1 movsxd rax, ecx \\ Переносим значение, полученное в инструкции по адресу 0x560ba5a7f1e4 в rax.
│ │ ╎│ 0x560ba5a7f1f4 885405d3 mov byte [rbp + rax - 0x2d], dl \\ Переносим символ в финальную строку.
│ │ ╎│ ; CODE XREF from main @ 0x560ba5a7f1df
│ └────> 0x560ba5a7f1f8 8345f801 add dword [var_8h], 1 \\ "Счётчик" = "Счётчик" + 1
│ ╎│ ; CODE XREF from main @ 0x560ba5a7f1c0
│ ╎└─> 0x560ba5a7f1fc 837df809 cmp dword [var_8h], 9 \\ Сравниваем "счётчик" с 9.
│ └──< 0x560ba5a7f200 7ec0 jle 0x560ba5a7f1c2 \\ Если меньше или равно 9, то переходим в тело цикла.

\\for (i = 0; i <= 9; ++i ) {
\\    if ( i > 6 )
\\        j = i - 7;
\\    else
\\        j = i + 3;
\\    f_str[j] = inp_str[i];
}


│ 0x560ba5a7f202 c645e800 mov byte [var_18h], 0            |
│ 0x560ba5a7f206 c645dd00 mov byte [var_23h], 0            | Отделяем строки друг от друга через 0x00.

│ 0x560ba5a7f20a c745f4000000. mov dword [var_ch], 0   \\ "Счётчик" = 0
│ ┌─< 0x560ba5a7f211 eb2f jmp 0x560ba5a7f242 \\ Переходим к 0x560ba5a7f242
│ ┌──> 0x560ba5a7f213 8b45f4 mov eax, dword [var_ch] \\ В eax будет значение "счётчика"
│ ╎│ 0x560ba5a7f216 4898 cdqe \\ Выполняет преобразование dword в qword в rax.
│ ╎│ 0x560ba5a7f218 0fb65405d3 movzx edx, byte [rbp + rax - 0x2d] \\ Перемещаем в edx код символа из финальной строки[eax].
│ ╎│ 0x560ba5a7f21d 8b45f4 mov eax, dword [var_ch] \\ В eax будет значение "счётчика"
│ ╎│ 0x560ba5a7f220 4898 cdqe \\ Выполняет преобразование dword в qword в rax.
│ ╎│ 0x560ba5a7f222 0fb64405e9 movzx eax, byte [rbp + rax - 0x17] \\ Перемещаем в eax код символа из оригинальной строки[eax].
│ ╎│ 0x560ba5a7f227 38c2 cmp dl, al \\ Сравниваем символ из финальной строки с символом из оригинальной строки
│ ┌───< 0x560ba5a7f229 7413 je 0x560ba5a7f23e \\ Если символы равны, то переходим к 0x560ba5a7f23e
│ │╎│ 0x560ba5a7f22b 488d3ded0d00. lea rdi, str.Sorry__wrong_input_:_ ; 0x560ba5a8001f ; "Sorry, wrong input :(" \\ Символы не равны. Переносим адрес строки str.Sorry__wrong_input_ в rdi
│ │╎│ 0x560ba5a7f232 e8f9fdffff call sym.imp.puts ; int puts(const char *s) \\ puts("Sorry, wrong input :(");
│ │╎│ 0x560ba5a7f237 b800000000 mov eax, 0 \\ Переносим в eax 0 (Код выхода)
│ ┌────< 0x560ba5a7f23c eb27 jmp 0x560ba5a7f265 \\ Переходим к концу функции main
│ │└───> 0x560ba5a7f23e 8345f401 add dword [var_ch], 1 \\ "Счётчик" = "Счётчик" + 1
│ │ ╎│ ; CODE XREF from main @ 0x560ba5a7f211
│ │ ╎└─> 0x560ba5a7f242 837df409 cmp dword [var_ch], 9 \\ Сравниваем "счётчик" с 9
│ │ └──< 0x560ba5a7f246 7ecb jle 0x560ba5a7f213 \\ Если счётчик меньше или равен 9, то переходим к 0x560ba5a7f213
│ │ 0x560ba5a7f248 488d45de lea rax, [var_22h] \\ Переносим в rax адрес начала финальной строки
│ │ 0x560ba5a7f24c 4889c6 mov rsi, rax \\ Переносим адрес в rsi
│ │ 0x560ba5a7f24f 488d3de20d00. lea rdi, str.Congratulations__correct_flag__nThe_flag_is:_WatadCTF_s_n ; 0x560ba5a80038 ; "Congratulations, correct flag!\nThe flag is: WatadC
TF{%s}\n" \\ Переносим в rdi адрес str.Congratulations__correct_flag__nThe_flag_is
│ │ 0x560ba5a7f256 b800000000 mov eax, 0
│ │ 0x560ba5a7f25b e8e0fdffff call sym.imp.printf ; int printf(const char *format) \\ printf("Congratulations, correct flag!\nThe flag is: WatadCTF{%s}\n", inp_str);
│ │ 0x560ba5a7f260 b800000000 mov eax, 0 \\ Переносим в eax 0 (Код выхода)
│ │ ; CODE XREF from main @ 0x560ba5a7f23c
│ └────> 0x560ba5a7f265 c9 leave \\ Копирует содержимое RBP в RSP
└ 0x560ba5a7f266 c3 ret \\ Возвращаемся в функцию из RSP

\\ for (i = 0; i <=9; i++) {
\\    if ( f_str[i] != or_str[i] ) {
\\        puts("Sorry, wrong input :(");
          return 0;
\\    }
\\    else
\\        printf("Congratulations, correct flag!\nThe flag is: WatadCTF{%s}\n", inp_str);
\\        return 0;
\\}

Ассемблерный код можно перевести в код на си.

C:
#include <stdio.h>
#include <string.h>[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]char or_str[11] = "";    //
char inp_str[11] = "";   // 11 символ - 0x00. Он означает конец строки.
char f_str[11] = "";     //
int i = 0;
int j = 0;[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]int main() {[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]   strcpy(or_str, "bpfajgobiw");
   printf("The magic string: ");
   
   for ( i = 0; i <= 9; ++i )
       scanf(" %c", &inp_str[i]);
   
   for (i = 0; i <= 9; ++i ) {
       if ( i > 6 )
           j = i - 7;
       else
           j = i + 3;
       f_str[j] = inp_str[i];
   }    
   
   for (i = 0; i <=9; i++) {
       if ( f_str[i] != or_str[i] ) {
           puts("Sorry, wrong input :(");
           return 0;
       }
   }
   
   printf("Congratulations, correct flag!\nThe flag is: WatadCTF{%s}\n", inp_str);
   return 0;
}

Эту программу можно скомпилировать в PowerFul_Crackme_my через команду gcc PowerFul_Crackme_my.c -o PowerFul_Crackme_my

Объяснение на русском языке.

В программе задумана строка bpfajgobiw. Пользователь вводит строку длиной 10 символов. Программа переносит последние три символа в начало строки. Таким образом создаётся финальная строка. Затем, финальная строка сравнивается со строкой bpfajgobiw. Если строки равны, выводится Congratulations, correct flag!.... Если строки не равны, то выводится Sorry, wrong input :(

Написанный выше текст можно проверить этим кодом:


C:
#include <stdio.h>
#include <string.h>[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]char or_str[11] = "";
char inp_str[11] = "";
char f_str[11] = "";
int i = 0;
int j = 0;[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]int main() {[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]   strcpy(or_str, "bpfajgobiw");
   printf("The magic string: ");
   
   for ( i = 0; i <= 9; ++i )
       scanf(" %c", &inp_str[i]);
   
   for (i = 0; i <= 9; ++i ) {
       if ( i > 6 )
           j = i - 7;
       else
           j = i + 3;
       f_str[j] = inp_str[i];
   }    
   
   printf("f_str = %s\n", f_str);[/FONT][/FONT]
 
[FONT=verdana][FONT=verdana]   for (i = 0; i <=9; i++) {
       if ( f_str[i] != or_str[i] ) {
           puts("Sorry, wrong input :(");
           return 0;
       }
   }
   
   printf("Congratulations, correct flag!\nThe flag is: WatadCTF{%s}\n", inp_str);
   return 0;
}

Посмотреть вложение 55619


Или через radare2 :)



Посмотреть вложение 55627

Правильный ответ - ajgobiwbpf

Расширение и дополнительные утилиты из radare2.


Дополнительные утилиты.


  • rabin2. Эта утилита выводит нам информацию:
    • О файле: rabin2 -I PowerFul_Crackme
    • О секциях: rabin2 -S PowerFul_Crackme
    • О заголовках: rabin2 -H PowerFul_Crackme
    • и многом другом...
  • radiff2. Через него можно сравнивать два бинарных файла. radiff2 PowerFul_Crackme PowerFul_Crackme_my. radiff2 покажет различия в файлах.
  • rasm2. Это консольный ассемблер и дизассемблер, и он очень полезен! Сначала нам нужно определиться с архитектурой. Все архитектуры можно посмотреть через rasm2 -L. Возьмём архитектуру x86, а размер регистров (-b) установим в 64. Получится архитектура x86-64.
    • rasm2 -a x86 -b 64 "push eax" = 0x50
    • rasm2 -a x86 -b 64 -d 50 = push rax
    • rasm2 -w "push" -a x86 -b 64 - для получения информации об инструкции push.
  • rafind2. Эта утилита помогает искать информацию в файлах. Например, строку flagв PowerFul_Crackme_my.
    • rafind2 -s "flag" ./PowerFul_Crackme_my = 0x2051 или 0x205b.
  • rahash2. Эта утилита вычисляет хеш программы, кодирует/декодирует данные в base64 и некоторые функции шифрования.
    ПРЕДУПРЕЖДЕНИЕ - Не пытайтесь использовать rahash2 для большого файла, поскольку он сначала пытается загрузить весь файл в память.
    Для просмотра всех хеш-функций используйте флаг -L.
    • rahash2 -a md5 ./PowerFul_Crackme_my - узнать md5-хеш для PowerFul_Crackme_my.
    • rahash2 -a all ./PowerFul_Crackme_my - узнать все доступные хеш-функции для PowerFul_Crackme_my.
  • rarun2. Эта утилита позволяет запускать программу с различными параметрами среды, аргументами, правами и директориями. Вспомните скрипт, который написали ранее...
Код:
#!/usr/bin/env rarun2
stdin=/dev/pts/3
stdout=/dev/pts/3

Radare2 также можно расширять, как и IDA. Через свои скрипты или чужие. Раздел с расширением функций рассматривается бегло, так как для того же Cutter можно написать целую статью.

Декомпилятор.

Мы рассмотрели только малую часть возможностей radare2, которая поставляется "из коробки". Так эти возможности тоже можно расширить! Например, через пакетный менеджер r2pm.

В radare2 нет встроенного декомпилятора, но pdc может выдать псевдо-код. Через r2pm можно установить декомпилятор от Ghidra. Зайдите в radare2 и напишите:

Bash:
r2pm update
r2pm -ci r2ghidra

Дальше переходите в функцию main и вводите pdg.

Посмотреть вложение 55620

pdga тоже может пригодиться.

Посмотреть вложение 55621

pdg? показывает справку про r2ghidra.


Прокаченный псевдо-код.

Когда декомпилятор от Ghidra не помогает и pdc выдаёт что-то странное, можете попробовать использовать r2dec (GitHub - wargio/r2dec-js: radare2 plugin - converts asm to pseudo-C code.). Это переводчик с языка ассемблера на псевдо-C.

Bash:
r2pm init
r2pm install r2dec


Дальше переходите в функцию main и вводите pdd.

Посмотреть вложение 55622
pdd? показывает справку про r2dec.


Cutter

- это бесплатное приложение с открытым исходным кодом для реверс-инженеринга, основанное на Rizin.

- фреймворк для реверс-инженеринга (форк radare2), созданный и поддерживающийся частью основной команды radare2.

Cutter можно запустить на Linux, Windows и MacOs. Для Linux она поставляется в AppImage. Загрузите файл и назначьте ему права на исполнение (chmod +x Cutter-v2.0.4-x64.Linux.AppImage), а затем запускайте (./Cutter-v2.0.4-x64.Linux.AppImage).

В Cutter есть русский язык, возможности radare2 и встроенный декомпилятор от Ghidra.

Посмотреть вложение 55623

Посмотреть вложение 55624

Посмотреть вложение 55625

❄❄❄ Снег! ❄❄❄


Так как уже зима и скоро Новый Год, то посмотрите на снежок в radare2 :)


Предлагаю сделать небольшое задание. Попробуйте найти команду, которая вызывает его и отправьте её мне в личные сообщения на форуме вместе со скриншотом. Никнеймы первых 10 человек будут находиться в табличке. Удачи ^_^


Вывод.


Radare2 является хорошим инструментом для реверс-инжиниринга со множеством функций, но чтобы его освоить, нужно постараться. Особенно радует цена radare2, а точнее её отсутствие + open source. Не забывайте, что цена IDA PRO более 170 000 рублей!
Посмотреть вложение 55626

Также не следует забывать о расширяемости radare2! Для него написано множество дополнений. Итог: использовать radare2 можно.

Спасибо за то, что прочитали эту статью до конца! :)
Парни, сделайте обзор qira плз
 
  • Нравится
Реакции: Mogen
09.11.2017
258
262
BIT
5
Стоп Медведь это ты мне посылал сигналы в космосе статья бомбическая) и не пинай Ты только Дядюшку Рика)
 
  • Нравится
Реакции: Mogen

fuzzz

Green Team
03.02.2019
249
468
BIT
2
@Mogen напиши админам пусть статью перенесут в тематический раздел по реверсу
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!