Intro

Небольшой экскурс в историю. Проект radare начал разрабатывать хакер с ником pancake в 2006 году и долгое время по сути он был единственным разработчиком. Созданный фреймворк обладал простым консольным интерфейсом для работы как шестнадцатеричный редактор, поддерживающий 64-битную архитектуру. Это позволяло находить и восстанавливать данные с жестких дисков. Поэтому его еще называли инструментом для компьютерной криминалистической экспертизы. Но в 2010 год произошел “редизайн” фреймворка и после чего проект стал разрастаться и пополняться новым функционалом, что позволяет его использовать не только как редактор, но и дизассемблер, анализатор как кода, так и шеллкодов. На данный момент этот фреймворк используют как знаменитые CTF-команды (Dragon Sector), так и вирусные аналитики (MalwareMustDie и AlienVault), причем последние представляют его на своем воркшопе на Black Hat. Достаточно большой список тех кто использует radare2 с примерами представлен в блоге проекта.

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

Начнем с поддержки большого количества архитектур, есть даже для Gameboy, видео по анализу популярной игры Pokemon для этого устройства опубликовал на канале youtube один из исследователей, правда на немецком языке.

Одна из особенностей поддержка многих различных скриптовых языков. Помимо популярных Python с Perl, которые поддерживаются в других дизассмблерах, есть так же Vala, Go, Guile, Ruby, Lua (о его плюсах и минусах я писал ранее), Java, JavaScript (nodejs и ducktape), sh и многие другие.

Так же многим пригодится поддержка типов, особенно при анализе C++ программ. Достаточно создать *.h файл с описанием и подключить его. Ниже я привел пример от автора фреймворка. Содержимое файла с описанием структуры:

[0x00000000]> cat test.h
#define uint32_t unsigned int
typedef struct addr {  
        char street[127];
        char city[40];
        uint32_t zip;
} addr_t;

Подключаем файл и помечаем область со структурой:

[0x00000000]> to test.h
[0x00000000]> tl addr 0x4000
[0x00000000]> tf 0x4000
struct addr {  
street : 0x00004000 = "Wallaby Way"  
  city : 0x00004000 = "Sydney"
   zip : 0x00004008 = 2000
}

Существует поддержка отладки. Причём ты можешь проводить как прямую отладку, так и работу с протоколами gdb, winedbg.

Благодаря тому, что фреймворком заинтересовались вирусные аналитики, появилась поддержка утилиты yara о которой мы писали ранее. Помимо поддержки самой утилиты было встроено большое количество правил. Некоторые из них, например, позволяют определить большое количество упаковщиков. Ниже я привёл такой пример для одного из сэмплов вредоносной программы:

[0x0040324d]> yara scan
dUP_v2_x_Patcher
Nullsoft_PiMP_Stub

Установка

Так как на данный момент radare2 не является версией 1.0 (на момент написания статьи она была 0.9.8), разработчики советуют использовать свой фреймворк, скачав и собрав его из исходников с github ( заодно вспомним как работать с git =) ):

$ git clone https://github.com/radare/radare2.git

Если же у тебя исходники были уже скачены, то нужно их обновить следующей командой:

$ git pull

Для автоматической компиляции можешь воспользоваться встроенный скрипт:

$ sys/install.sh

Если же он выдал ошибку, то попробуй сделать вручную:

$ ./configure --prefix=/usr
$ gmake
$ sudo gmake install

Или вместо gmake используй утилиту make. Например, для Mac OS X мне так и пришлось сделать. А после перезагрузки я увидел долгожданное окно:

Так же ты можешь поставить radare2 из macports или использовать утилиту homebrew, но там версии периодически отстают. По этой же причины, если используешь Kali Linux, то советую удалить встроенный radare2 через утилиту apt-get и поставить фреймворк из исходников, как я описал выше.

Для Windows бинарный файл можно скомпилировать с помощью какой-либо *nix платформы или воспользоваться mingw-компилятором.

Android-версия доступна в google play, причем права root не требуется. Так как с помощью фреймворка можно анализировать и java-файлы, об этом есть неплохая статья с примерами, то легко добавили поддержку apk-файлов. Ниже я покажу как выглядят интерфейс программы и дизассемблерированый код.

Хотя в некоторых случаях можно обойтись и без компиляции. Благодаря сервису СI есть возможность скачивать уже скомпилированные файлы под различные платформы, в том числе и для Windows. Например, именно поэтому android-версия идет рука об руку с основной.

Теперь немного остановимся на доработке функционала. Чтобы отменить свои модификации исходников, вернемся к нормальной версией:

$ git reset --hard HEAD

Если же твои доработки наоборот исправили какую-то проблему, то помимо обычного commit, можно сделать патч и отправить его разработчику:

$ git diff > radare-foo.patch

Теперь рассмотрим саму работу с фреймворком.

Обзор утилит

Помимо основной утилиты radare2 к которой мы вернемся позже, рассмотрим набор программ, который входит в фреймворк на примере простых операций, которые могут пригодится исследователям.

rasm2 - ассемблер/дизассемблер фреймворка выполнен как отдельное приложение и позволяет дизассемблеровать как бинарные, так и отдельные строки.

root@kali:~/# rasm2 -a x86 nop
90

root@kali:~/# rasm2 -a x86 -d 'eb00'
jmp 0x2

Обычным переводом опкодов туда и обратно правда мало кого удивишь, пусть и с поддержкой большого количества архитектур. Зато описание всех опкодов не всегда есть под рукой:

root@kali:~/# rasm2 -w cmpsb
cmp DS:[SI], ES:[edi] (esi++, edi++)

root@kali:~/# rasm2 -w sqrtpd
compute square roots of packed double-fp values
root@kali:~/# rasm2 -d eb165e31d2525689e189f331c0b00bcd8031db31c040cd80e8e5ffffff2f62696e2f7368
jmp 0x18
pop esi
xor edx, edx
push edx
push esi
mov ecx, esp
mov ebx, esi
xor eax, eax
mov al, 0xb
int 0x80
xor ebx, ebx
xor eax, eax
inc eax
int 0x80
call 0x2
das
bound ebp, [ecx+0x6e]
das
jae 0x8c

rabin2 - утилита для работы с различными исполняемыми файлами (ELF, PE, Java CLASS, MACH-O). Используется для получения различной информации о файле: импортируемые функции, экспортируемые символы, секции, подключаемых библиотеках и т.п. Рассмотрим самые популярные действия:

  1. Получаем информацию о формате и включенных системах защиты.

     root@kali:~/# rabin2 -I 9f2520a3056543d49bb0f822d85ce5dd
     file	9f2520a3056543d49bb0f822d85ce5dd
     type	DLL (Dynamic Link Library)
     pic	false
     canary	false
     nx	false
     crypto	false
     has_va	true
     root	pe
     class	PE32
     lang	unknown
     arch	x86
     bits	32
     machine	i386
     os	windows
     subsys	Windows GUI
     endian	big
     strip	false
     static	false
     linenum	true
     lsyms	true
     relocs	true
     rpath	NONE
    
  2. Получаем список импортируемых функций и из каких библиотек они вызываются:

     root@kali:~/# rabin2 -i 9f2520a3056543d49bb0f822d85ce5dd
    
     ...
     ordinal=001 plt=0x00000000 bind=NONE type=FUNC name=WS2_32.DLL_WSAIoctl
     ordinal=001 plt=0x00000000 bind=NONE type=FUNC name=SHFolder.dll_SHGetFolderPathA
     ordinal=001 plt=0x00000000 bind=NONE type=FUNC name=ntdll_NtUnmapViewOfSection
     ordinal=001 plt=0x00000000 bind=NONE type=FUNC name=user32.dll_EnumDisplayMonitors
     ordinal=002 plt=0x00000000 bind=NONE type=FUNC name=user32.dll_GetMonitorInfoA
     ordinal=001 plt=0x00000000 bind=NONE type=FUNC name=SHELL32.DLL_SHEmptyRecycleBinA
     ordinal=001 plt=0x00000000 bind=NONE type=FUNC name=AVICAP32.DLL_capGetDriverDescriptionA
    
     600 imports
    
  3. Ищем строки и где они находятся. Кто-то скажет, что ему хватает утилиты strings, но данный вариант более умный и показывает дополнительную информацию, которая нужна при анализе:

     root@kali:~/# rabin2 -z 9f2520a3056543d49bb0f822d85ce5dd 
     ...
     addr=0x008c970a off=0x000bcd0a ordinal=441 sz=34 len=16 section=.rsrc type=w string=OriginalFilename
     addr=0x008c972c off=0x000bcd2c ordinal=442 sz=24 len=11 section=.rsrc type=w string=MSRSAAP.EXE
     addr=0x008c974a off=0x000bcd4a ordinal=443 sz=24 len=11 section=.rsrc type=w string=ProductName
     addr=0x008c9764 off=0x000bcd64 ordinal=444 sz=54 len=26 section=.rsrc type=w string=Remote Service Application
     addr=0x008c97a2 off=0x000bcda2 ordinal=445 sz=30 len=14 section=.rsrc type=w string=ProductVersion
    

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

rahash2 - утилита для получения хэш-значений во многих форматах как от бинарных файлов, так и определенных частей данных. Пример получения хэшей для одной из RAT-малвари представлен на скриншоте.

Подсчитанные хэши для вредоносной программы DarkComet

radiff2 - утилита для сравнения бинарных файлов. Для более успешной работы советую доустановить программу xdot, если у тебя её еще нет:

root@kali:~/# apt-get install xdot

Работает как через xdot, так и в консольном (ascii) режиме. Пример её работы я покажу в разделе по решению crackme.

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

ragg2 - экспериментальная утилита для компиляции небольших программ (шеллкодов ;-)) для x86/x64 и ARM-архитектур.

rax2 - утилита для конвертации данных в различных форматах. Преобразуем hex-данные в строку:

root@kali:~/# rax2 -s 43 4a 50
CJP

rarun2 (rr2) - позволяет запускать программу с различными параметрами среды, аргументами, правами и директориями. Это пригодится не только для решения различных crackme или CTF-задач, но и при фаззинге или тестах.

Теперь перейдем к самому radare2 и рассмотрим основные команды для работы с ним на примере небольшого crackme.

Разбираем crackme

В качестве примера я взял простой crackme от пользователя Lord из архива сайта crackmes.de, а работать будет в 32-битном Kali Linux. Запустим загруженный файл:

root@kali:~/crackmes# ./cm1eng

Password : dukebarman
root@kali:~/crackmes# 

Значит нам требуется найти правильный пароль. Причём неверный вариант никак не помечается, программа просто завершается. Ну что же, для начала рассмотрим сам файл:

root@kali:~/crackmes# rabin2 -I cm1eng
...
root	elf
class	ELF32
lang	c
arch	x86
bits	32
machine	Intel 80386
os	linux
subsys	linux
endian	little
strip	true
...

Как видим, опция strip присутствует. Не смотря на то, что crackme записан для новичков, автор решил уж совсем задачу не облегчать и удалил “лишнюю” информацию из файла. Поэтому теперь загрузим программу в radare2 и увидим одну из встречающих случайных фраз:

root@kali:~/crackmes# r2 ./cm1eng
 -- Nothing to see here. Move along.
[0x08048080]> 

После запуска нам нужно проанализировать файл с помощью команду начинающийся с a. Кстати, чтобы увидеть возможные команды, то достаточно добавить знак вопроса к изменяющемуся символу, в нашем случае это будет a?:

[0x08048080]> a?
|Usage: a
| a8 [hexpairs]     analyze bytes
| aa                analyze all (fcns + bbs)
...

Вернемся к анализу. В фреймворке возможно проанализировать как весь файл, так и отдельные блоки, строки и т.п. Проанализируем весь файл и раз требуется ввести пароль, то попробуем его найти, возможно его оставили вшитым в программу. Всё таки этот crackme считается начального уровня:

[0x08048080]> aa
[0x08048080]> iz
addr=0x100910f8 off=0x000000f8 ordinal=000 sz=13 len=12 section=.data type=a string=\nPassword : 
addr=0x10091105 off=0x00000105 ordinal=001 sz=33 len=32 section=.data type=a string=Great you did it !:)\n\n          
addr=0x10091126 off=0x00000126 ordinal=002 sz=8 len=7 section=.data type=a string=QTBXCTU

[0x08048080]> 

Ты уже знаком с командой iz, поэтому уточню небольшой нюанс о работе со строками в фреймворке. Все строки автоматически преобразуются в переменную со схожим именем:

Great you did it !:)\n\n -> str.Great_you_did_it_____n_n

К таким переменным можно обращаться @str.Great_you_did_it_____n_n. Так же работает автодополнение через клавишу TAB, что очень удобно при их большом количестве. Помимо этого есть возможность поиска как строк, так и различных байтов через команду /. Пример поиска строки:

[0x08048080]> / Password
Searching 8 bytes from 0x08048000 to 0x0804a0f8: 50 61 73 73 77 6f 72 64 
hits: 2
0x080480f9 hit3_0 "Password"
0x080490f9 hit3_1 "Password"
[0x08048080]> px 10 @0x080480f9
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x080480f9  5061 7373 776f 7264 203a                 Password :      

Но вернёмся к нашей программе. Так как она небольшая, то у неё нету импортируемых функций, но есть несколько строчек. Одну мы видим постоянно при запуске crackme, а вот остальные две представляют для нас большой интерес. Первая позволит найти место в коде, которое ведёт к верному решению, а вторая возможно является паролем. Попробуем вторую строку:

root@kali:~/crackmes# ./cm1eng

Password : QTBXCTU
root@kali:~/crackmes# 

Увы, но это не является паролем, хотя возможно всё таки нам пригодится. А пока, раз у нас есть строка, которая теоретически выводится при удачном решении, попробуем решить crackme “нечестным” образом - пропатчим файл. Создадим копию файла (заодно она нам пригодится для обещанного примера) и загрузим её в фреймворк, но через дополнительную команду, которая откроет файл в режиме записи:

root@kali:~/crackmes# r2 -w ./cm1eng_crack 
 -- Nothing to see here. Move along.
[0x08048080]> aa
[0x08048080]> pdf

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

Помимо различного встроенного функционала в radare2 есть поддержка запуска системных утилит, в частности grep:

[0x08048080]> pdf | grep str.Great
|     |     0x080480e3    b905910408   mov ecx, str.Great_you_did_it_____n_n ;  0x08049105   

Вот мы и получили сразу нужный адрес, в который передается наша строка, так как проверка пароля должна быть до обращения к ней, то выведем строки до неё. Для начала возьмём 10:

[0x08048080]> pd -10 @0x080480e3
|          0x080480c2    02e2         add ah, dl
|          0x080480c4    f1           int1
|          ; JMP XREF from 0x080480c1 (section..text)
|          0x080480c5    be1b910408   mov esi, 0x804911b ;  0x0804911b 
|          0x080480ca    bf26910408   mov edi, str.QTBXCTU ;  0x08049126 
|          0x080480cf    b907000000   mov ecx, 0x7 ;  0x00000007 
|          0x080480d4    fc           cld
|          0x080480d5    f3a6         repe cmpsb
|      ,=< 0x080480d7    7516         jne 0x80480ef ; (section..text)
|      |   0x080480d9    b804000000   mov eax, 0x4 ;  0x00000004 
|      |   0x080480de    bb01000000   mov ebx, 0x1 ;  0x00000001 
[0x08048080]> 

Вот мы и нашли проверку и переход не к нужной нам функции по адресу 0x080480d7. Более наглядно часть кода представлена на скриншоте, где я проскролил до нужного нам места.

Перейдем к ней и проверим, правильный ли адрес указали:

[0x08048080]> s 0x080480d7
[0x080480d7]> pd 7
|      ,=< 0x080480d7    7516         jne 0x80480ef ; (section..text)
|      |   0x080480d9    b804000000   mov eax, 0x4 ;  0x00000004 
|      |   0x080480de    bb01000000   mov ebx, 0x1 ;  0x00000001 
|      |   0x080480e3    b905910408   mov ecx, str.Great_you_did_it_____n_n ;  0x08049105 
|      |   0x080480e8    ba16000000   mov edx, 0x16 ;  0x00000016 
|      |   0x080480ed    cd80         int 0x80
|      |      syscall[0x80][0]=? ; section_end..shstrtab+91
|      |   ; JMP XREF from 0x080480d7 (section..text)
|      `-> 0x080480ef    b801000000   mov eax, 0x1 ;  0x00000001 
[0x080480d7]> 

А вот запатчить можно разными способами. Примеры операндов в шестнадцатеричном представлении:

[0x080480d7]> !rasm2 -a x86 -d '7516'
jne 0x18
[0x080480d7]> !rasm2 -a x86 -d '7416'
je 0x18
[0x080480d7]> !rasm2 -a x86 -d 'eb00'
jmp 0x2
[0x080480d7]> !rasm2 -a x86 -d '9090'
nop
nop
  1. Наша непосредственная команда.
  2. Старый добрый патчинг - видим n - удаляем, не видим, добавляем.
  3. Прыжок на “следующий” адрес.
  4. Ну и просто забить пропускающимися байтами

Возьмём 3 вариант и выйдем для проверки:

[0x080480d7]> wx eb00
[0x080480d7]> q 

Результат ты можешь увидеть на скриншоте. Теперь любой введённый код будет считаться правильным ;-) А утилиту rasm2 в этом случае можно использовать для проверки правильности ввода. Используя команду w? вида wx ты патчишь в виде шестнадчатеричных чисел, но при желании можно вводить и обычными командами:

wa jmp 0x80480d9 

Удачный патчинг crackme

С помощью “грязного” трюка мы всё таки решили этот crackme, но хотелось бы разобраться с настоящим паролем. Вспомним, что неизвестная строка всё таки проверяется перед выводом победного сообщения. При анализе находим небольшой цикл, который берет 7 символов и xor’ит их с ключом 0x21.

Найденная строка с нужным ключом

Попробуем провести обратную операцию с найденной строкой. Найдем её представление в коде:

[0x08048080]> px 16 @str.QTBXCTU 
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x08049126  5154 4258 4354 5500 0054 6865 204e 6574  QTBXCTU..The Net

Мне было быстрее найденные hex-значения загрузить в 010-Editor и расшифровать, но radare2 поддерживает различные арифметические операции и при желании можно сделать xor для каждого символа:

[0x08048080]> ? 51h^21h
112 0x70 0160 112.0 0000:0070 112 "p" 01110000 112.0 0.000000

Или написать небольшой плагин ;-) Но в итоге всё равно получаем строку “pucybut”. Она и является нашим паролем.

На будущее можно сразу искать необычные xor-команды.

[0x08048080]> pdf | grep xor
|           0x080480b3    31db         xor ebx, ebx
|      |    0x080480b7    3421         xor al, 0x21
| ||||      0x08048149    2e3338       xor edi, [cs:eax]
[0x08048080]> 

Такую выборку еще используют для нахождения различных call-команд. Но теперь покажу обещанный пример использования утилиты radiff2. У нас имеются два файла с одной отличной функцией. Я предпочитаю смотреть сразу на два файла, то есть на одном отличия первого, на другом второго.

root@kali:~/crackmes# radiff2 -g main cm1eng_crack cm1eng > /tmp/cm1
root@kali:~/crackmes# radiff2 -g main cm1eng cm1eng_crack > /tmp/cm2  
root@kali:~/crackmes# xdot /tmp/cm1 & xdot /tmp/cm2
root@kali:~/crackmes# radiff2 -g main cm1eng cm1eng > /tmp/cm & xdot /tmp/cm

Ну раз мы коснулись темы с визуализацией, то рассмотрим существующие возможности.

GUI

Единственная, на мой взгляд, почему radare2 до сих пор пробивается в массы не такими быстрыми шагами, потому что отсутствует нормальный GUI-интерфейс. Во времена обилия как карманных, так и настольных устройств с touch-экранами это уже считается минимумом. На данный момент существует несколько встроенных утилит:

  • визуальный интерфейс в консольном окне, который запускается командой VV (согласен, страшновато выглядит)
root@kali:~/crackmes# r2 -c=H cm1eng

Для сравнения с мобильным интерфейсом я открыл этот же crackme на своем android-устройстве.

Анализ crackme на телефоне Android при альбомном режиме экрана

Outro

Увы, полностью описать работу с каждым модулем я не смогу, так как ограничен размером статьи. Но надеюсь тех небольших знаний, которых ты получил из статьи тебе хватит. Так же советую просмотреть материалы по указанным ссылкам в конце статьи и врезках. Некоторые примеры тебя приятно удивят. В случае, если возникнут проблемы с освоением, найдешь возможную ошибку в фреймворке или может захочешь помочь с программированием, то милости просим на irc-канал #radare в сети irc.freenode.net. Причём в отличии от некоторых каналов, на которых я тоже присутствую, на этом ежедневно ведется обсуждение как проекта, так и других различных вещей.

Разработка фреймворка не стоит на месте и версия 1.0 всё ближе. Одно из планируемых нововведений, которое, как мне кажется, пригодится многим - это поддержка 010-шаблонов для одноименного шестнадцатеричного редактора. А такие шаблоны особенно помогают при фаззинге.

Поэтому не удивляйся, если в момент чтения этого номера ты установишь версию 1.x.

Полезные материалы

Официальный сайт проекта

Официальный блог проекта

Книга по Radare2 от Maijin( находится в процессе написания, поэтому постоянно обновляется)

Сравнение фреймворка с другими популярными инструментами для реверсинга - IDA Pro и Hopper

Список докладов по Radare2

Использование radare2 для анализа BIOS

P.S. Антон Кочков (@akochkov aka xvilka) является одним из разработчиков этого фреймворка и представил его, как мне кажется впервые на русском языке, в виде небольшого доклада на PHDays 2014. В докладе он показал пример использования radare2 для анализа вредоносных программ. В качество экземпляров были представлены Windows-троян Shylock и 64-битного Linux-вирус Snakso.A. Для которых был проведен как статический анализ, так и использование дебаггера. Видео доклада доступно на официальном сайте PHDays. А с презентацией ты можешь ознакомиться на slideshare-аккаунте мероприятия

Знаменитый хакер @pof, а по совместительству тот, кто написал Android Hacker Handbook и поддерживает android-версию фреймворка, написал статью. В ней он объясняет разницу между взломом RAM-памяти и ROM-образа на примере игры Super Street Fighter II Turbo, используя для редактирования образа radare2.

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

e scr.utf8=true

Такие небольшие команды можно прописать в файле конфигурации ./radarerc, чтобы они выполнялись автоматически при запуске фреймворка.