Системный интегратор
В Arduino скетч (прошивку) пишут на C, затем ее компилируют. Получают hex файл с прошивкой и загружают эту прошивку в микроконтроллер.
В процессе компиляции программы в Arduino так же создается ELF файл (Executable and Linkable Format) с возможностью включения отладочной информации.
Обратная задача – получить исходный листинг программы дизассемблируя двоичный (hex) файл с прошивкой.
Настройте среду разработки Arduino показывать подробный вывод при компиляции. В меню / откройте окно диалога Настройки:
Откройте или наберите в среде разработки Arduino какую нибудь программу, например, следующую:
int led = 4; void setup() { pinMode(led, OUTPUT); } void loop() { digitalWrite(led, HIGH); delay(10); digitalWrite(led, LOW); delay(200); }
На панели инструментов в программе Arduino нажмите кнопку проверить. Ваша программа будет скомпилирована. В среде Arduino исследуйте последние строки вывода компилятора и найдите там путь к файлам своей программы:
На этой картинке это /tmp/build5923081435602699287.tmp/Blink_ATtiny13.cpp.hex. Где Blink_ATtiny13.cpp.hex файл прошивки. Перейдите в командной строке в указанную папку. В этой же папке так же можно найти файл Blink_ATtiny13.cpp.elf
Дизассемблируем файл Blink_ATtiny13.cpp.elf
avr-objdump -d Blink_ATtiny13.cpp.elf Blink_ATtiny13.cpp.elf: file format elf32-avr Disassembly of section .text: 00000000 : 0: 09 c0 rjmp .+18 ; 0x14 2: 21 c0 rjmp .+66 ; 0x46 4: 20 c0 rjmp .+64 ; 0x46 6: 34 c0 rjmp .+104 ; 0x70 8: 1e c0 rjmp .+60 ; 0x46 a: 1d c0 rjmp .+58 ; 0x46 c: 1c c0 rjmp .+56 ; 0x46 e: 1b c0 rjmp .+54 ; 0x46 10: 1a c0 rjmp .+52 ; 0x46 12: 19 c0 rjmp .+50 ; 0x46 00000014 : 14: 11 24 eor r1, r1 16: 1f be out 0x3f, r1 ; 63 18: cf e9 ldi r28, 0x9F ; 159 1a: cd bf out 0x3d, r28 ; 61 0000001c : 1c: 10 e0 ldi r17, 0x00 ; 0 1e: a0 e6 ldi r26, 0x60 ; 96 20: b0 e0 ldi r27, 0x00 ; 0 22: ec e7 ldi r30, 0x7C ; 124 24: f1 e0 ldi r31, 0x01 ; 1 26: 02 c0 rjmp .+4 ; 0x2c 00000028 : 28: 05 90 lpm r0, Z+ 2a: 0d 92 st X+, r0 0000002c : 2c: a2 36 cpi r26, 0x62 ; 98 2e: b1 07 cpc r27, r17 30: d9 f7 brne .-10 ; 0x28 00000032 : 32: 10 e0 ldi r17, 0x00 ; 0 34: a2 e6 ldi r26, 0x62 ; 98 36: b0 e0 ldi r27, 0x00 ; 0 38: 01 c0 rjmp .+2 ; 0x3c 0000003a : 3a: 1d 92 st X+, r1 0000003c : 3c: a6 36 cpi r26, 0x66 ; 102 3e: b1 07 cpc r27, r17 40: e1 f7 brne .-8 ; 0x3a 42: 96 d0 rcall .+300 ; 0x170 44: 99 c0 rjmp .+306 ; 0x178 00000046 : 46: dc cf rjmp .-72 ; 0x0 00000048 : 48: 80 91 60 00 lds r24, 0x0060 4c: 61 e0 ldi r22, 0x01 ; 1 4e: 6a d0 rcall .+212 ; 0x124 50: 8a e0 ldi r24, 0x0A ; 10 52: 90 e0 ldi r25, 0x00 ; 0 54: 32 d0 rcall .+100 ; 0xba 56: 80 91 60 00 lds r24, 0x0060 5a: 60 e0 ldi r22, 0x00 ; 0 5c: 63 d0 rcall .+198 ; 0x124 5e: 88 ec ldi r24, 0xC8 ; 200 60: 90 e0 ldi r25, 0x00 ; 0 62: 2b d0 rcall .+86 ; 0xba 64: 08 95 ret 00000066 : 66: 80 91 60 00 lds r24, 0x0060 6a: 61 e0 ldi r22, 0x01 ; 1 6c: 3f d0 rcall .+126 ; 0xec 6e: 08 95 ret 00000070 : 70: 1f 92 push r1 72: 0f 92 push r0 74: 0f b6 in r0, 0x3f ; 63 76: 0f 92 push r0 78: 11 24 eor r1, r1 7a: 8f 93 push r24 7c: 9f 93 push r25 7e: af 93 push r26 80: bf 93 push r27 82: 80 91 62 00 lds r24, 0x0062 86: 90 91 63 00 lds r25, 0x0063 8a: a0 91 64 00 lds r26, 0x0064 8e: b0 91 65 00 lds r27, 0x0065 92: 01 96 adiw r24, 0x01 ; 1 94: a1 1d adc r26, r1 96: b1 1d adc r27, r1 98: 80 93 62 00 sts 0x0062, r24 9c: 90 93 63 00 sts 0x0063, r25 a0: a0 93 64 00 sts 0x0064, r26 a4: b0 93 65 00 sts 0x0065, r27 a8: bf 91 pop r27 aa: af 91 pop r26 ac: 9f 91 pop r25 ae: 8f 91 pop r24 b0: 0f 90 pop r0 b2: 0f be out 0x3f, r0 ; 63 b4: 0f 90 pop r0 b6: 1f 90 pop r1 b8: 18 95 reti 000000ba : ba: 20 e6 ldi r18, 0x60 ; 96 bc: 39 e0 ldi r19, 0x09 ; 9 be: 04 c0 rjmp .+8 ; 0xc8 c0: f9 01 movw r30, r18 c2: 31 97 sbiw r30, 0x01 ; 1 c4: f1 f7 brne .-4 ; 0xc2 c6: 01 97 sbiw r24, 0x01 ; 1 c8: 00 97 sbiw r24, 0x00 ; 0 ca: d1 f7 brne .-12 ; 0xc0 cc: 08 95 ret 000000ce : ce: 83 b7 in r24, 0x33 ; 51 d0: 81 60 ori r24, 0x01 ; 1 d2: 83 bf out 0x33, r24 ; 51 d4: 8f b5 in r24, 0x2f ; 47 d6: 83 60 ori r24, 0x03 ; 3 d8: 8f bd out 0x2f, r24 ; 47 da: 89 b7 in r24, 0x39 ; 57 dc: 82 60 ori r24, 0x02 ; 2 de: 89 bf out 0x39, r24 ; 57 e0: 12 be out 0x32, r1 ; 50 e2: 78 94 sei e4: 86 b1 in r24, 0x06 ; 6 e6: 87 68 ori r24, 0x87 ; 135 e8: 86 b9 out 0x06, r24 ; 6 ea: 08 95 ret 000000ec : ec: 38 2f mov r19, r24 ee: 86 30 cpi r24, 0x06 ; 6 f0: c0 f4 brcc .+48 ; 0x122 f2: 66 23 and r22, r22 f4: 61 f4 brne .+24 ; 0x10e f6: 27 b3 in r18, 0x17 ; 23 f8: 81 e0 ldi r24, 0x01 ; 1 fa: 90 e0 ldi r25, 0x00 ; 0 fc: 02 c0 rjmp .+4 ; 0x102 fe: 88 0f add r24, r24 100: 99 1f adc r25, r25 102: 3a 95 dec r19 104: e2 f7 brpl .-8 ; 0xfe 106: 80 95 com r24 108: 82 23 and r24, r18 10a: 87 bb out 0x17, r24 ; 23 10c: 08 95 ret 10e: 27 b3 in r18, 0x17 ; 23 110: 81 e0 ldi r24, 0x01 ; 1 112: 90 e0 ldi r25, 0x00 ; 0 114: 02 c0 rjmp .+4 ; 0x11a 116: 88 0f add r24, r24 118: 99 1f adc r25, r25 11a: 3a 95 dec r19 11c: e2 f7 brpl .-8 ; 0x116 11e: 28 2b or r18, r24 120: 27 bb out 0x17, r18 ; 23 122: 08 95 ret 00000124 : 124: 38 2f mov r19, r24 126: 86 30 cpi r24, 0x06 ; 6 128: 10 f5 brcc .+68 ; 0x16e 12a: 82 30 cpi r24, 0x02 ; 2 12c: 40 f4 brcc .+16 ; 0x13e 12e: 88 23 and r24, r24 130: 19 f4 brne .+6 ; 0x138 132: 8f b5 in r24, 0x2f ; 47 134: 8f 77 andi r24, 0x7F ; 127 136: 02 c0 rjmp .+4 ; 0x13c 138: 8f b5 in r24, 0x2f ; 47 13a: 8f 7d andi r24, 0xDF ; 223 13c: 8f bd out 0x2f, r24 ; 47 13e: 66 23 and r22, r22 140: 61 f4 brne .+24 ; 0x15a 142: 28 b3 in r18, 0x18 ; 24 144: 81 e0 ldi r24, 0x01 ; 1 146: 90 e0 ldi r25, 0x00 ; 0 148: 02 c0 rjmp .+4 ; 0x14e 14a: 88 0f add r24, r24 14c: 99 1f adc r25, r25 14e: 3a 95 dec r19 150: e2 f7 brpl .-8 ; 0x14a 152: 80 95 com r24 154: 82 23 and r24, r18 156: 88 bb out 0x18, r24 ; 24 158: 08 95 ret 15a: 28 b3 in r18, 0x18 ; 24 15c: 81 e0 ldi r24, 0x01 ; 1 15e: 90 e0 ldi r25, 0x00 ; 0 160: 02 c0 rjmp .+4 ; 0x166 162: 88 0f add r24, r24 164: 99 1f adc r25, r25 166: 3a 95 dec r19 168: e2 f7 brpl .-8 ; 0x162 16a: 28 2b or r18, r24 16c: 28 bb out 0x18, r18 ; 24 16e: 08 95 ret 00000170 : 170: ae df rcall .-164 ; 0xce 172: 79 df rcall .-270 ; 0x66 174: 69 df rcall .-302 ; 0x48 176: fe cf rjmp .-4 ; 0x174 00000178 : 178: f8 94 cli 0000017a : 17a: ff cf rjmp .-2 ; 0x17a
В результате, из скетча на C мы получили программу на Assembler.
Хотите дизассемблировать прошивку (двоичный hex файл)? Выполните команду:
avr-objdump -D Blink_ATtiny13.cpp.hex -m AVR
Источник: http://integrator.adior.ru/index.php/proshivki/431-dizassembler-sketcha-arduino
HexRaysPyTools: декомпилируй с удовольствием
В этой статье я собираюсь рассказать о плагине для IDA Pro, который написал прошлым летом, еще находясь на стажировке в нашей компании. В итоге, плагин был представлен на ZeroNights 2016 (Слайды), и с тех пор в нём было исправлено несколько багов и добавлены новые фичи.
Хотя на GitHub я постарался описать его как можно подробнее, обычно коллеги и знакомые начинают пользоваться им только после проведения небольшого воркшопа. Кроме того, опущены некоторые детали внутренней работы, которые позволили бы лучше понять и использовать возможности плагина.
Поэтому хотелось бы попытаться на примере объяснить, как с ним работать, а также рассказать о некоторых проблемах и тонкостях.
HexRaysPyTools, как можно догадаться из названия, предназначен для улучшения работы декомпилятора Hex-Rays Decompiler. Декомпилятор, создавая псевдо-С код, существенно облегчает работу ревёрсера.
Основым его достоинством, выделяющим инструмент на фоне других, является возможность трансформировать код, приводя его к удобному и понятному виду, в отличие от ассемблерного кода, который, даже при самом лучшем сопровождении, требует некоторой доли внимания и сосредоточенности для понимания его работы. У Hex-Rays Decompiler, как и самой IDA Pro, есть API, позволяющий писать расширения и выходить за рамки стандартного функционала. И хотя API очень широк, и в теории позволяет удовлетворить самые изысканные потребности разработчика дополнений, у него есть несколько существенных недостатков, а именно:
- Слабая документированность. Для того, чтобы найти подходящие функции или классы, самый эффективный способ — произвести поиск регулярными выражениями по файлам, угадывая ключевые слова
- Произвольные названия функций и структур — часто их название не говорит ни о чём
- Deprecated методы, для которых не предложено замены
- Общая запутанность работы. Например, для изменения типа аргумента у функции, нужно написать 8 строк кода и задействовать 3 класса. И это не самый странный пример
- API для языка Python не совсем совпадает с тем, что для C++. idaapi содержит новые методы, наткнуться на которые получилось чисто случайно
- Есть неочевидные вещи: например, IDA Pro будет падать, если не отключать Garbage Collector для объектов, добавленных с помощью idaapi в абстрактное синтаксическое дерево (оно всегда строится, когда происходит декомпиляция, и в нём можно изменять объекты или вставлять свои).
Чтобы разобраться во всем этом, помогали рабочие примеры, собранные в Интернете (что-то интересное нашлось даже в китайском сегменте). Так что теперь, если кто-то захочет создать что-то своё для декомпилятора, можно обратиться еще и к исходным кодам моего плагина.
Перейдем к описанию плагина. В HexRaysPyTools можно выделить две отдельные категории — это помощь по трансформации дефолтного вывода Hex-Rays Decompiler к удобному виду и реконструкция структур и классов.
Изначально, после запуска декомпилятора клавишей F5, IDA Pro выдаёт не очень понятый код, состоящий преимущественно из стандартных типов и имён переменных. И несмотря на то, что местами пытается угадать типы, создать массивы или назвать эти переменные (которым повезло оказаться аргументами у стандартных функций), получается это не очень хорошо.
В целом, задача ревёрсера — привести в адекватный вид декомпилированный код. К сожалению, есть вещи, которые невозможно сделать, не прибегая к IDA SDK.
Например, отрицательные обращения к полям структур, которые всегда выглядят безобразно (порой превращаясь в массивы с отрицательными индексами), а также длинные условные вложения, тянущиеся из левого верхнего угла в правый нижний. Кроме этого, очень не хватает горячих клавиш и опций для более быстрой трансформации кода.
По мере получения информации в процессе анализа программы приходится изменять сигнатуры функций, переименовывать переменные и изменять типы. Всё это требует большого количества манипуляций мышкой и копирований-вставок. Перейдем к описанию того, что предлагает плагин для решения этих проблем.
Отрицательные смещения
Очень часто встречаются при реверсинге драйверов или ядра Windows или модулей ядра Linux. Например, несколько разных структур может быть расположено в двусвязном списке с использованием структуры LIST_ENTRY. При этом у каждой структуры обращение к двусвязному списку может производиться из произвольного поля.
В результате, когда мы смотрим на то, что получается в IDA Pro, видим следующую картину:
Такой вывод будет всякий раз, когда в исходных кодах программ используются макросы CONTIAINING_RECORD (windows) и container_of (linux). Эти макросы возвращают указатель на начало структуры по её типу, адресу и названию поля. И именно их плагин позволяет вставлять в дизассемблер. Вот как выглядит пример после его применения:
Еще с отрицательными смещениями можно встретиться при множественном наследовании, но это довольно изысканный пример, он редко встречается на практике.
Для того, чтобы вставить макрос в дизассемблер, нужно, чтобы подходящая в данном контексте структура существовала в Local Types или в одной из библиотек в Types Library (их может быть несколько). Мы кликаем по вложенной структуре правой кнопкой и выбираем Select Containing Structure.
Далее определяем, где искать структуру, — либо в Local Types, либо в Types Library, и плагин составляет список подходящих структур. Для этого он анализирует, как указанная переменная используется в коде и определяет минимальную и максимальную границы, в которых может находиться поле типа этой переменной.
Затем, используя эти сведения, проходит по всем структурам, содержащим поле, у которых все в порядке с границей. При поиске плагин смотрит вложенные структуры и объединения на любую глубину.
В примере выше у exe-файла есть символы, поэтому список подходящих структур получился довольно большой:
Помимо этого, существует ситуация, когда плагин автоматически может вставить макрос. Дело в том, что если есть явное присвоение указателя, IDA Pro догадывается (иногда неправильно) его вставить, но не распространяет его дальше в коде.
Без плагина:
С плагином:
Сильная вложенность
Пожалуй, лучше всего показать искусственный пример. Без плагина:
С плагином:
Подобное изменение будет произведено автоматически, если установлен плагин. Хотелось бы, чтобы можно было накладывать и вручную, но увы — то, что выдаёт декомпилятор, очень нестабильно в плане сохранения вносимых изменений в синтаксическое дерево.
Переименования
Идея в том, чтобы называть переменную или аргумент приходилось не более одного раза, а дальше все переименования совершались горячими клавишами или двумя кликами.
Часто IDA Pro создаёт дублированные переменные. Можно было бы, используя стандартную опцию “map to another variable”, избавиться от них. Но это не всегда удобно при отладке, может быть ошибочно и к тому же невозможно откатить, не пересоздавая функцию заново.
Перебросить можно имя с одной переменной на другую, при этом добавляется символ “_”:
До:
После:
Можно переименовать аргумент у функции, заставив её взять имя переменной (при этом лишние символы подчёркивания уберутся). Либо, наоборот, переменной присвоить имя аргумента функции.
Recasts
Существует множество ситуаций, когда есть взаимодействие между двумя некоторыми сущностями с разными типами, и нам нужно перенести тип одной сущности на другую.
Под сущностями понимаются локальные, глобальные переменные, аргументы, функции, поля структур (с обращением по ссылке и без) и возвращаемые значения функции. Плагин позволяет это быстро произвести.
Сложно показать картинкой, рекомендую в случае, если нужно перенести тип одной сущности на другую, кликнуть правой кнопкой мыши по ней и посмотреть на опции. Наверняка там появится “Recast …” (а если не появится, то можно написать мне, и я попробую её добавить).
Прочее
Помимо этого, добавляются следующие опции:
- Поиск структуры по размеру и замена числа на sizeof(Structure)). Удобно для поиска структуры подходящего размера по числу байт, указанных оператору new или функции malloc.
- Быстрое изменение сигнатуры функции. Кликнув правой кнопкой по её объявлению, можно добавить/удалить возвращаемое значение, удалить аргумент, сбросить соглашение о вызове к __stdcall.
- Переход по двойному клику у виртуальных методов.
Одной из самых сложных и энергозатратных задач ревёрс-инжиниринга является понимание работы и реконструкция структур и классов. HexRaysPyTools выступает помощником в этом процессе.
В чём, собственно, проблема? Средствами по умолчанию можно только залить уже готовое объявление структуры, поэтому приходится “ползать” по коду, пытаясь насобирать сведения о полях, вручную высчитывать смещения и записывать куда-то всю информацию (например, в блокнот).
Но, если у нас размеры классов исчисляются сотнями байт и, в придачу, имеют множество методов и несколько виртуальных таблиц, всё становится гораздо сложнее.
Рассмотрим на примере, как помогает в данном случае плагин. Когда-то (исключительно ради самообразования :D) мной был создан бот для онлайн-игрушки. В процессе наткнулся на защиту, шифрующую пакеты, не позволявшую модифицировать код в памяти и мешающую хукать вызов шифрующей функции (которая была жестко обфусцирована).
Для того, чтобы обойти её, нужно было распарсить класс, отвечающий за обмен данными между клиентом и сервером и научиться, используя его, вызывать отправку пакетов и считывать полученные, расшифрованные пакеты за несколько вызовов от функций защиты. Тогда это было непростой задачей, но с плагином всё делается довольно просто.
Вот так выглядит метод, принимающий пакеты. this и v1 являются указателями на объект класса, gepard_1 — это функция, заменяющая recv
Если заглянуть внутрь функций sub_41AF50 и sub_41AFF0, можно увидеть довольно много кода, обращающегося к разным полям. И даже это — лишь часть функционала, ответственного за создание и отправку пакетов, поэтому разобраться в назначении полей может быть непросто.
Плагин помогает автоматически проанализировать большое количество кода, и из собранной информации составить некий каркас структуры, которая в дальнейшем анализе может быть изменена исследователем и использована для автоматического создания нового типа.
Для начала надо открыть Structure Builder через Edit->Plugins->HexRaysPyTools.
Это окошко будет содержать собранную информацию, предоставлять возможность для редактирования имен полей и разрешения конфликтов, а также просмотра виртуальных таблиц и сканирования виртуальных функций.
Есть 3 возможных способа собирать информацию о полях:
1) Можно кликнуть правой кнопкой по переменной и, нажав Scan Variable, запустить сканирование в пределах одной функции. При сканировании будет рассматриваться то, как происходит обращение к переменной и, если оно под падает под паттерн обращения к полю, такая информацию будет запомнена.
Если другой переменной присваивается значение первой (причем их типы не обязательно должны совпадать), она так же подключается к сканированию (и отключается, если ей будет присвоено новое значение).
Вот какой результат будет, если применить этот метод к переменной this в функции выше:
Хотя мы запускали сканирование для переменной this, информация о v1 также была собрана.
Жёлтым отмечены разного рода обращения к полям, и нужно выбрать, какой вариант подходит больше всего, отключив все остальные.
До тех пор, пока есть конфликты, создать финальную структуру будет нельзя. Красный — это смещение, начиная с которого производится сканирование. Его можно сдвинуть с помощью кнопки Origin для того, чтобы просканировать потенциальную подструктуру.
Например, можно зайти в функцию sub_41AF50 и, сдвинув указатель, собрать немного новой информации:
Если дважды кликнуть по столбцу Offset интересующего поля, можно увидеть список всех обращений к этому полю и быстро переместиться в дизассемблере к месту обращения.
Поэтому есть смысл как можно больше покрывать сканированиями все места использования восстанавливаемой структуры. Больше информации о полях — проще разобраться, что зачем нужно.
Сканировать каждую переменную может быть весьма утомительно, поскольку указатель на структуру может путешествовать по большому количеству функций, поэтому есть другой способ сбора информации.
2) Кликнув правой кнопкой по переменной, можно выбрать опции “Deep Scan Variable”. Основной процесс сканирования будет таким же, как и у первого способа, только теперь, если указатель на структуру будет передаваться как аргумент функции, будет запущено рекурсивное сканирование данного аргумента.
Warning! Здесь есть одна проблема — декомпилятор не всегда распознает правильно аргументы функции, которую он еще не декомпилировал, поэтому приходится рекурсивно заходить и декомпилировать каждую функцию, которая потенциально может содержать указатель на нашу структуру как аргумент. Этот процесс запускается автоматически, и происходит только один раз за сессию для каждой функции.
Поэтому первые процессы глубокого сканирования могут занять некоторое время (порядка пары минут).
Переместившись несколько раз вверх по цепочке вызов, можно найти место, где создается структура:
Запустив здесь сканирование, получаем следующее:
3) Начинать сканировать лучше всего там, где структура впервые возникает, чтобы максимально покрыть её использование в коде. Плагин предоставляет возможность просканировать все переменные, которым присваивается результат, возвращаемый конструктором.
Если зайти в функции sub_419890, которая впервые возвращает указатель на структуру, то можно увидеть, что используется паттерн-одиночка:
Количество вызовов этой функции очень велико:
Сканировать каждую переменную было бы утомительно, поэтому есть возможность запустить сканер для всех сразу, кликнув по заголовку функции и выбрав опцию “Deep Scan Returned Variables”.
Вот результат применения на примере:
Можно заметить, что нашлась информация об обращении к полям 0x8 — 0x14. Так же нашлись виртуальные таблицы — они отображены жирным шрифтом и, дважды кликнув по ним, можно увидеть список виртуальных функций (а заодно и просканировать их как по одной, так и все сразу).
Теперь можно разбираться с устройством структуры. Напомним, что, кликнув по офсету, можно увидеть все обращения к полям.
Вот, что получилось после непродолжительного анализа:
Подготовка создания структуры завершена. Теперь можно кликнуть “Finalize” и, внеся последние изменения, закончить её создание:
Далее, везде, куда “дотянулся” сканнер, переменным, которые являлись указателем на эту структуру, будет применён её новосозданный тип. Вот как преобразится функция отправки пакетов:
Помимо представленного, в Structure Builder можно создать или попытаться угадать подструктуры, выделив необходимое количество полей и нажав Pack или Recognize Shape соответственно. При поиске подходящей структуры учитываются типы полей — они должны точно совпадать, за исключением базовых типов (char — BYTE, int — DWORD — int *), считающихся одинаковыми.
Для уже созданных классов (структур с виртуальными таблицами), в плагине есть возможность более удобной работы с ними. По пути View-> Open Subviews-> Classes можно открыть следующее окошко:
Здесь можно:
- Переименовать методы, в результате чего изменения будут произведены сразу в коде и виртуальных таблицах (сделано, чтобы избежать рассинхронизации)
- Изменить объявление методов
- Быстро конвертировать первый аргумент в this
- Переместиться к функции в окне дизассемблера
- Фильтровать информацию регулярными выражениями
И еще. Хотелось бы еще раз напомнить, что при работе с классами очень удобно использовать плагин ClassInformer. Если в файле есть RTTI-информация, это поможет восстановить иерархию классов, а плагин возьмёт имена виртуальных таблиц, что поможет получить близкие к оригиналу имена классов.
Надеемся, что эта статья поможет разобраться, как пользоваться плагином. Найти его и сообщить о багах можно по адресу — https://github.com/igogo-x86/HexRaysPyTools. Также ждем feature requests.
Источник: https://habr.com/company/dsec/blog/329788/
Ардуино. Альтернативное начало
Всем привет. Меня зовут Никита. Я один из участников проекта «Философия Звука». Это моя первая статья на блоге – строго не судите. В комментариях можете поделиться своими размышлениями по теме. Это будет полезно как мне, так и всем остальным. Начнём).
Только «ленивый» не знает про такую разработку как «Arduino». Хотя как раз и «ленивые», в том числе, используют её в своих задачах. Существует много разных мнений по поводу «Arduino». Есть как сторонники, так и противники – классика жанра. К какому лагерю отношусь я? Сложно ответить однозначно.
Могу лишь сказать, что «Arduino» мне нравится в том варианте, который использую именно я).
Вкратце расскажу из чего состоит платформа:
Имеется ПО Arduino, в котором пользователь пишет специальный текст – код. Далее этот код преобразуется встроенным в ПО компилятором AVR GCC в другой специальный текст (машинный язык). Также в ПО Arduino интегрирована консольная программка AVRDude для прошивки микроконтроллеров AVR. С её помощью написанный нами программный код отправляется в память микроконтроллера через USB порт ПК.
Со стороны «железа» Arduino есть, или приобретается отдельно, преобразователь USB-USART. Он служит мостом между программной и аппаратной частью Arduino. Вообще, «чистый» контроллер AVR прошить по интерфейсу USART нельзя. Поэтому изготовитель Arduino зашивает в микроконтроллер программу – «загрузчик» (пользователь тоже может это проделать).
Вот теперь контроллер принимает наш «машинный код» и сохраняет его у себя в памяти. Ну и потом мы проверяем, что всё правильно работает или опять не работает).
Недостатки программирования в Arduino
Добрались до самого интересного – программирования). Эта статья не посвящена какому-то отдельному проекту.
Она только подготовит тех, кто выберет тот же путь программирования в Arduino, что и я.
Казалось бы, что не нравится? Многие пишут в Arduino так, как задумали разработчики, и даже проекты рабочие и симпатичные выходят.
Есть куча библиотек для различных подключаемых электронных устройств: датчики температуры, дисплеи, сервоприводы, GSM модули и многое другое.
Но у этих библиотек есть недостатки, связанные со стилем программирования в Arduino:
- Из-за универсальности код в Arduino IDE выполняется медленно и занимает много места в памяти микроконтроллера – критично для «насыщенных» проектов.
- Даже в библиотеках используются задержки, во время которых контроллер ничего не делает – неэффективное использование ресурсов.
- Весь код программы приходится писать в одной странице Arduino IDE, что затрудняет написание, чтение и редактирование большого проекта.
- Нет «прозрачности» написания программ. Мы не видим, что скрывается за скетчем – не знаем, какие регистры используются, какие прерывания выполняются без нашего ведома. Поэтому не можем напрямую работать с регистрами и прерываниями.
Хочется устранить недостатки и расширить возможности платформы Arduino. К лёгкой прошивке по USB кабелю добавить возможность написания программы с разбиением на файлы. Использовать полноценное программирование микроконтроллера, с применением регистров и векторов прерываний.
Если коротко, то мне хотелось бы совместить лёгкую прошивку микроконтроллера AVR, как это сделано в Arduino IDE, и возможность написания «быстрого», «прозрачного», разбитого на файлы и занимающего мало места кода на C/C++ как, например, в IAR Embedded Workbench.
«Исправление» Arduino IDE
Мы используем 8-битные микроконтроллеры от AVR, поэтому будем работать с последней классической версией Arduino 1.0.6.
Программисты на C/C++ привыкли, что главной функцией является функция main(), но здесь её нет… или может быть она скрыта?
Копнём в папку установки Arduino. Вот здесь можно много чего интересного найти: C:Program Files (x86)Arduino-1.0.6hardwarearduinocoresarduino. Начнём, конечно же, с найденного там файла main.cpp. О чудо, вот она main() … нет, так и должно было быть 🙂
Вот и нашлись наши знакомые void setup() и void loop(), которые нужно определять в каждом скетче. Эти функции мы перенесём в свой файл, например, main_my.cpp и там определим. Это позволит разбить программу на файлы.
Из интересного тут ещё функция init(). Её определение можно найти в файле wiring.c. Функция длинная, поэтому покажу только её начало:
Здесь глобально разрешаются прерывания. Происходит настройка и запуск всех таймеров, которые имеются в микроконтроллере. Да-да, всё, что связано с функциями задержек, ШИМ, отсчётов временных интервалов от старта контроллера, предварительно настраивается тут. Выбирается частота работы АЦП, и сразу же АЦП включается. И в самом конце сбрасываются настройки USART, который использовался для «загрузчика».
Получается, что все предварительные настройки, которые используют библиотеки Arduino, описаны в init(). Если мы уберём эту функцию, то сможем работать с регистрами и векторами прерываний микроконтроллера напрямую, не боясь, что они уже используются.
И что теперь будем делать? Править функцию main(), чтобы отключать ненужную нам работу таймеров или АЦП? А если хочется совмещать свой код, например, с уже готовой удобной библиотечной отладкой по USART? Да и не все пользователи Arduino оценят такой подход. Нужно такое решение, которое бы устроило всех, и оно есть:
Оставим всё как есть. И в нашем проекте, если это нужно, остановим всю периферию, которой не будем пользоваться с помощью библиотек Arduino или которая нам не нужна совсем.
Атрибуты
Кто-то спросит, а что там с прерываниями? Например, если остановим Timer 0, то как мы сможем использовать прерывание TIM0_OVF_vect, ведь этот вектор уже используется средой для формирования задержек, а компилятор обязательно будет ругаться на повторное применение? Выход такой: в компиляторе GCC существуют особые способы объявления функций, называются они атрибуты. Ключевое слово для использования __attribute__. В частности есть такой атрибут weak. Он делает функцию «слабой». Это значит, что если функция определена и объявлена как weak в одном месте, то в другом – мы можем написать её второе определение, и вызываться будет именно оно. А если не напишем, тогда будет использоваться определение с атрибутом weak.
Теперь по-простому: как сделать так, чтобы можно было у себя в программе, если это нужно, использовать TIM0_OVF_vect, но чтобы была возможность в другом проекте использовать функции Arduino? Нужно в исходниках Arduino в файле wiring.c (именно тут используется этот вектор) написать такую строчку:
ISR(TIMER0_OVF_vect) __attribute__((weak));
Выглядеть эта доработка будет так:
Аналогично можно дообъявить другие уже использующиеся вектора. Да, нам придётся исправить исходные файлы среды Arduino. Но зато всего один раз, и потом мы «забудем » об этом :).
Универсальный скетч
Больше не буду забивать Вам голову умными мыслями), а покажу как теперь будет выглядеть скетч для всех проектов. Он поможет отвязаться от написания всей программы в одном окне Arduino IDE:
Файл main_my.h пустой и находится вместе со всеми файлами нашей программы. В файле main_my.cpp определены функции void setup() и void loop(). Собственно, дальше можно уже писать свою программу в любом удобном для Вас текстовом редакторе, например Notepad++. Добавлять столько *.cpp и *.h файлов, сколько нужно для проекта. Если необходимо, делать код ёмким и быстрым – без использования функций Arduino. Или, для быстроты реализации программы, совмещать свой код с кодом Arduino.
На этом всё :). Ну а в следующий раз напишем какую-нибудь очень полезную программу).
С уважением, Никита О.
Источник: https://phsound.blogspot.com/2016/03/blog-post_31.html
Декомпиляторы, или Что делать, если нужно восстановить исходники из бинарников?
Проблема восстановления исходного кода из скомпилированных бинарников возникает сравнительно часто и протекает остро, с воем и рыданиями. Здесь нам, до некоторой степени, помогут замечательные программы-декомпиляторы, и в этом посте автор собрал свои скромные попытки выдрать исходники (или хотя бы намёки на них) из скомпилированных из С-шного кода бинарников.
Задача для декомпилятора бинарников, собранных из С кода:
Классический случай: один деятель на факультете написал на правильном ANSI C (и используя библиотеки BLAS и LAPACK) нужные и хорошие алгоритмы, и скомпилировал их в виде MEX-файлов для использования (это С-шный код, который можно вызывать из МАТЛАБ). Но потом он повздорил с народом, разозлился и свалил в частную контору, унеся все исходники с собой. Документации нет.
Копий исходников нет. Есть обрывки личной переписки и намёки в сопровождающих файлах на тип алгоритма. Вариант физического воздействия на автора тупыми тяжёлыми предметами не рассматривается. Нужно восстановить исходники если и не до компилируемого состояния, то во всяком случае выудить оттуда алгоритмы и ключевые методы, использованные при реализации.
Кратко: суть и сложность проблемы
Декомпилятор (Decompiler) пытается перевести скомпилированный бинарный файл обратно в некое подобие исходного кода. Качество выхлопа зависит от особенностей языка исходника:
- Для C# или Java есть много декомпиляторов – байткод на java содержит много информации. Это помогает восстанавливать декомпилятору исходник до состояния, пригодного к повторной компиляции.
- Совершенно другая история с двоичными файлами, в которых, как правило, отладочной информации нет. Тем не менее, динамически связанные библиотеки функций, как правило, вызываются по имени. Часто, типы параметров библиотечных функций известны, и это может помочь до известных пределов.
Декомпиляторы пытаются восстановить информацию, которая частично утрачена при компиляции в бинарный файл – в этом и заключается основная сложность.
Если вы думаете, что с помощью декомпилятора вы получите обратно красивый код на С – вы будете сильно разочарованы. В лучшем случае на выходе будет общая (и довольно грубая) структура программы, в худшем – только имена функций и немного мусора.
Так что ответ на вопрос заголовка поста: “Обхватить голову руками и закричать #$@@@@@!” 🙂
Программы для декомпилирования (decompilers) для C/C++
Декомпиляторов для C/C++ немного, и ниже список из наиболее работоспособных.
Здесь нет разделения на опенсорс или Linux-only – для такого дела, как вскрытие исходников, можно (и нужно) поступиться своими светлыми идеалами и наступить на горло собственной песне.
Сразу замечу: скорее всего, ни один декомпилятор не выдаст вам сразу компилируемый код. Придётся потратить порядком времени и сил, чтобы это месиво превратить в код, который можно читать (желательно, не только компилятору).
Boomerang
Boomerang это C decompiler с открытыми исходами:
- поддерживаемые бинарные форматы: ELF PE-COFF Mac-OS
- платформы: Windows/Linux
- поддерживаемые архитектуры: IA32 MIPS PPC
- метод работы: поточный, есть жалкий графический интерфейс, лучше использовать CLI.
Весьма продвинутый набор алгоритмов анализа кода, что не удивительно – один из соавтором защитил на этом докторскую диссертацию [Michael James Van Emmerik, Static Single Assignment for Decompilation, Ph.D. thesis, the University of Queensland, Australia. PDF, mirror PDF]. Качество кода, выдаваемого декомпилятором:
- Структурирование: очень хорошее
- Переменные: хорошее
- Типы данных: очень хорошее
Выдаваемое качество кода сильно варьируется: некоторые функции почти идеально восстановлены, хорошо видна структура кода и есть указание типа переменных. В других случаях функции сильно запутаны и их почти невозможно прочитать.
Программа всё ещё в состоянии бета-версии и для больших проектов не подходит. Скачать можно здесь.
RecStudio
Интерактивный декомпилятор RecStudio для С и (отчасти) С++, закрытая разработка:
- поддерживаемые бинарные форматы: ELF PE-COFF AOUT RAW PS-X
- платформы: Windows/Linux/MacOS
- поддерживаемые архитектуры: x86 (ia32) x86_64 Mips PowerPC mc68k
- метод работы: поточный и интерактивный, есть графический интерфейс.
Использует продвинутый набор алгоритмов анализа (partial Single Static Assignment, SSA), хотя до сих пор (и это после 20 лет!) в стадии разработки. Качество кода, выдаваемого декомпилятором:
- Структурирование: хорошее
- Переменные: частично
- Типы данных: частично или никак
Выдаваемое качетсво кода, как правило, хуже, чем у Boomerang, хотя обновлённый RecStudio более подробен.
Программа работает вполне стабильно, есть сборки под Linux. Скачать можно здесь.
dcc – DOS to C decompiler
Поточный декомпилятор Dcc, только ANSI C и для exe-файлов, с открытым исходным кодом под GPL:
- поддерживаемые бинарные форматы: EXE/COM
- платформы: Windows
- поддерживаемые архитектуры: x86
- метод работы: поточный.
Один из первых декомпиляторов вообще, и только под DOS. Сильная сторона – структурирование кода. Качество кода, выдаваемого декомпилятором:
- Структурирование: хорошее
- Переменные: частично
- Типы данных: частично или никак
Разработка Cristina Cifuentes, которая защитила PhD в Queensland University of Technology на этом деле [можно полистать, если что – C. Cifuentes, Reverse Compilation Techniques].
Скачать можно отсюда (на сайте университета).
Hex Rays – plugin для IDA Pro
На самом деле Hex Rays не является отдельной программой – это плагин-декомпилятор для IDA Pro. Комбинация продвинутых возможностей IDA Pro (это дизассемблер) и Hex Rays в качестве декомпилятора очень впечатляет, как и аэрокосмическая цена. По причине закрытости продукта (нет даже демо-версии) и нереальной цены в этом разделе про Hex Rays больше ничего написано не будет.
Ходовые испытания в реальных условиях
Для начала попробуем декомпилировать что-нибудь совсем простенькое и написанное на ANSI C и с использованем библиотеки BLAS для векторых и матричных операций. Бинарный файл можно скачать здесь.
1. Простенький C-шный бинарник + BLAS
Собственно, код на C для перемножения матрицы и вектора (используется CBLAS). Исходник:#include
#include double m[] = {
3, 1, 3,
1, 5, 9,
2, 6, 5
}; double x[] = {
-1, -1, 1
}; double y[] = {
0, 0, 0
}; int main(void)
{
int i, j; for (i=0; i 2) {
*(int*)(local3 + 52) = 1;
*(int*)(local3 + 48) = 0x8049868;
*(long long*)(local3 + 40) = 0.
;
*(int*)(local3 + 36) = 1;
*(int*)(local3 + 32) = 0x8049848;
*(int*)(local3 + 28) = 3;
*(int*)(local3 + 24) = 0x8049800;
*(long long*)(local3 + 16) = 1.
;
*(int*)(local3 + 12) = 3;
*(int*)(local3 + 8) = 3;
*(int*)(local3 + 4) = 111;
*(int*)local3 = 101;
cblas_dgemv();
local6 = 0;
for(;;) {
*(long long*)(local3 + 4) = y[0];
*(int*)local3 = 0x80486b6;
proc1();
local7 = *(int*)(local3 + 72) + 1;
}
}
local8 = 0;
for(;;) {
local10 = *(int*)(local3 + 72) + *(int*)(local3 + 72) + *(int*)(local3 + 72);
local15 = m[local10];
*(long long*)(local3 + 4) = local15;
*(int*)local3 = 0x80486b0;
proc1();
local9 = *(int*)(local3 + 76) + 1;
}
} Подробностей тут больше, и тут выловлен самый главный ключик – cblas_dgemv();
Выхлоп RecStudio
Намного более обилен и представляет собой следующий поток сознания:
// Generated by Rec Studio 4 – build Oct 20 2012 _init()
{// addr = 0x08048398
_unknown_ __ebx; // r1
_unknown_ __ebp; // r6
_unknown_ _t2; // _t2 __esp = __esp – 4;
L1();
_pop(__ebx);
if( *((intOrPtr*)(_t2 + 0x1414)) != 0) {
__gmon_start__();
}
frame_dummy();
__do_global_ctors_aux();
_pop(__eax);
return;
} L080483A4()
{
_unknown_ _t2; // _t2 _pop(__ebx);
if( *((intOrPtr*)(_t2 + 0x1414)) != 0) {
__gmon_start__();
}
frame_dummy();
__do_global_ctors_aux();
_pop(__eax);
_pop(__ebx);
__esp = __ebp;
_pop(__ebp);
return;
} __gmon_start__()
{// addr = 0x080483D8
goto __imp____gmon_start__;
} putchar()
{// addr = 0x080483E8
goto __imp__putchar;
} __libc_start_main()
{// addr = 0x080483F8
goto __imp____libc_start_main;
} cblas_dgemv()
{// addr = 0x08048408
goto __imp__cblas_dgemv;
} printf()
{// addr = 0x08048418
goto __imp__printf;
} _start(
signed int __eax, // r0
_unknown_ __edx // r3
)
{// addr = 0x08048430
_unknown_ __ebx; // r1
signed int _t5; // _t5
_unknown_ _t6; // _t6
_unknown_ _t10; // _t10 __edx = __edx;
_t4 = __eax;
_pop(__esi);
__ecx = __esp;
__esp = __esp & 240;
_push(__eax);
_push(__esp);
_push(__edx);
_push(__libc_csu_fini);
_push(__libc_csu_init);
_push(__ecx);
_push(_t10);
_push(main);
__libc_start_main();
asm(“hlt “);
0;
0;
_push(0);
_push(_t6);
__esp = __esp – 4;
if(completed.5982 != 0) {
} else {
_t4 = dtor_idx.5984;
_t6 = ( &__DTOR_END__ – &__DTOR_LIST__ >> 2) – 1;
if(_t4 >= _t6) {
} else {
do {
_t5 = _t4 + 1;
dtor_idx.5984 = _t5;
*((intOrPtr*)(_t5 * 4 + &__DTOR_LIST__))();
_t4 = dtor_idx.5984;
} while(_t4 < _t6);
}
completed.5982 = 1;
}
__esp = __esp + 4;
_pop(__ebx);
_pop(__ebp);
return;
} __do_global_dtors_aux(
_unknown_ __esi // r5
)
{// addr = 0x08048460
_unknown_ __ebx; // r1
_unknown_ __ebp; // r6
_unknown_ _t4; // _t4
signed int _t5; // _t5
signed int _t6; // _t6
_unknown_ _t10; // _t10 if(completed.5982 == 0) {
_t5 = dtor_idx.5984;
_t10 = ( &__DTOR_END__ - &__DTOR_LIST__ >> 2) – 1;
if(_t5 >= _t10) {
L4:
completed.5982 = 1;
return;
}
do {
_t6 = _t5 + 1;
dtor_idx.5984 = _t6;
*((intOrPtr*)(_t6 * 4 + &__DTOR_LIST__))();
_t5 = dtor_idx.5984;
} while(_t5 < _t10);
goto L4;
}
return;
} frame_dummy()
{// addr = 0x080484C0
_unknown_ __ebp; // r6 __eax = __JCR_LIST__;
if(__JCR_LIST__ == 0) {
} else {
__eax = 0;
if(__eax != 0) {
*__esp = &__JCR_LIST__;
*__eax();
return;
}
}
return;
} main(
_unknown_ __fp0 // r28
)
{// addr = 0x080484E4
signed int _v8; // _cfa_fffffff8
signed int _v12; // _cfa_fffffff4
intOrPtr _v32; // _cfa_ffffffe0
char* _v36; // _cfa_ffffffdc
intOrPtr _v48; // _cfa_ffffffd0
char* _v52; // _cfa_ffffffcc
intOrPtr _v56; // _cfa_ffffffc8
char* _v60; // _cfa_ffffffc4
intOrPtr _v72; // _cfa_ffffffb8
intOrPtr _v76; // _cfa_ffffffb4
intOrPtr _v80; // _cfa_ffffffb0
_unknown_ __ebp; // r6 __fp0 = __fp0;
__esp = __esp & 240;
__esp = __esp - 80;
_v12 = 0;
while(_v12 > 2;
if(_t18 == 0) {
} else {
__esi = 0;
do {
_v36 = _a12;
_v40 = _a8;
*__esp = _a4;
*((intOrPtr*)(_t15 + -248 + __esi * 4))();
__esi = __esi + 1;
} while(__esi < _t18);
}
__esp = __esp + 28;
return;
} __i686.get_pc_thunk.bx()
{// addr = 0x0804865A
return;
} __do_global_ctors_aux()
{// addr = 0x08048660
intOrPtr* __ebx; // r1
_unknown_ __ebp; // r6 __eax = __CTOR_LIST__;
if(__eax == 255) {
} else {
__ebx = &__CTOR_LIST__;
asm("o16 nop ");
do {
__ebx = __ebx - 4;
*__eax();
__eax = *__ebx;
} while(__eax != 255);
}
return;
} _fini()
{// addr = 0x0804868C
_unknown_ __ebx; // r1
_unknown_ __ebp; // r6
_unknown_ _t1; // _t1 __esp = __esp - 4;
L1();
_pop(__ebx);
__do_global_dtors_aux(__esi);
_pop(__ecx);
return;
} L08048698()
{
_unknown_ _t1; // _t1 _pop(__ebx);
__do_global_dtors_aux(__esi);
_pop(__ecx);
_pop(__ebx);
__esp = __ebp;
_pop(__ebp);
return;
} L08048698()
{
_unknown_ _t1; // _t1 _pop(__ebx);
@rec __do_global_dtors_aux@__do_global_dtors_aux@(__esi);
_pop(__ecx);
_pop(__ebx);
__esp = __ebp;
_pop(__ebp);
return;
} // Statistics:
// 74 Register nodes
// 35 Temporaries nodes
// 5 Casts
// 207 Statements
// 2 Labels
// 1 Gotos
// 17 Blocks
// 469 Nodes
// 10 Assembly nodes
// 27 Unknown Types Total time: 0 seconds.
Структура программы (вначале) в общем несколько лучше, чем у Boomerang, и куда больше подробностей.
2. Бен, ай нид хелп: MEX-файл, написанный на C + BLAS, исходников которому нет.
Этот пример в посте приводить не стану, так как он длинный, но желающим попробовать своё декомпиляйшн-кунфу такая возможность предоставится:
Некоторые входные данные: это оптимизационный алгоритм для Quadratic Programming типа Branch-and-Bound (почитать тут и здесь). Алгоритм в целом прост и незатейлив, но самая сложная часть в нём – определить lower/upper bound через решение упрощённой оптимизационной задачи, и делать это быстро. Как такое сделать – хороший вопрос, и именно он меня интересует более всего.
Короче, важен не столько алгоритм, сколько его составные компоненты (стратегия и подпрограммы для lower bound estimation).
Автор этих строк, поковыряв выхлоп RecStudio, нашёл для себя подсказку на строчке 12319:
и особенно на строчке 12088:
что позволило автору предположить, что для lower/upper bounds использутеся Liner Programming. Не слишком много, но по крайней мере понятно, в какую сторону копать.
Если у кого-то вдруг проявится желание потыкать в оный бинарник палочкой, IDA Pro и ещё чем – не стесняйтесь отписываться в комментариях.
Ссылки
Интересующийся читатель может попробовать полистать вебстраницы автора RecStudio с полезной информацией, сходить на wiki-ресурс по обратной разработке.
Помимо познавательных диссертаций Michael James Van Emmerik (Boomerang) и Cristina Cifuentes [C. Cifuentes, Reverse Compilation Techniques], есть хорошие книжки по теме:
- “Compilers – Principles, Techniques and Tools”, Aho, Sethi, Ullman, 1986 Addison-Wesley Publishing Co. ISBN 0-201-10088-6.
- “Advanced Compiler Design & Implementation”, Steven Muchnick, 1997 Morgan Kaufmann Publishers, ISBN 1-55860-320-4.
- “How debuggers work – Algorithms, Data Structures, and Architecture”, Jonathan Rosemberg, 1996 John Wiley and Sons, ISBN 0-471-14966-7.
Дело это интересное, но весьма утомительное, хотя может помочь при раскопках очередного legacy-software и сэкономить вам полжизни.
Источник: http://mydebianblog.blogspot.com/2012/12/blog-post.html
Как работает декомпиляция?
Один из величайших декомпиляторов, который здесь находится сейчас, является декомпилятором Hex-Rays. Если вы хотите увидеть, что он может выводить, взгляните на http://www.hex-rays.com/products/decompiler/compare_vs_disassembly.shtml.
Ее автор, Илфак Гилфаны, выступили с речью о внутренней работе своего декомпилятор в каком-то коне, а вот белая бумага: http://www.hex-rays.com/products/ida/support/ppt/decompilers_and_beyond_white_paper.
pdf и презентация здесь: http://www.hex-rays.com/products/ida/support/ppt/decompilers_and_beyond.
ppt Это описывает хороший обзор в том, что все трудностях в создание декомпилятора и как заставить все это работать.
Кроме того, имеются некоторые довольно старые документы, например. классическая кандидатская диссертация Cristina Cifuentes здесь: http://itee.uq.edu.au/~cristina/dcc.html#thesis
Что касается сложности, все «декомпиляционные» материалы зависят от языка и времени исполнения двоичного файла. Например, декомпиляция .NET и Java считается «выполненной», так как есть свободные декомпиляторы, которые имеют очень высокий коэффициент успеха (они создают исходный источник). Но это вызвано спецификой виртуальных машин, которыми пользуются эти среды.
Что касается действительно скомпилированных языков, таких как C, C++, Obj-C, Delphi, Pascal, … задача усложняется. Прочтите приведенные выше документы для получения более подробной информации.
Когда у вас есть двоичная программа (исполняемый файл, библиотека DLL, …), она состоит из инструкций процессора. Язык этих инструкций называется сборка (или ассемблер). В двоичном коде эти команды кодируются двоично, поэтому процессор может их напрямую выполнять.
A дизассемблер принимает этот двоичный код и переводит его в текстовое представление. Этот перевод обычно 1 к 1, то есть одна команда показана как одна строка текста.
Эта задача сложна, но проста, программа просто должна знать все разные инструкции и как они представлены в двоичном формате.
С другой стороны, декомпилятор выполняет гораздо более сложную задачу. Он принимает либо двоичный код, либо вывод дизассемблера (который в основном тот же, потому что он от 1 до 1) и создает высокоуровневый код. Позвольте мне показать вам пример. Скажем, у нас есть эта функция C:
int twotimes(int a) { return a * 2; }
Когда вы компилируете его, компилятор первый генерирует и сборочный файл для этой функции, она может выглядеть следующим образом:
_twotimes: SHL EAX, 1 RET
(первая линия является просто меткой, а не реальной инструкцией, SHL выполняет операцию сдвига влево, которая быстро умножается на два, RET означает, что функция выполнена). В двоичном результате результат выглядит так:
08 6A CF 45 37 1A
(Я сделал это, а не настоящие двоичные инструкции). Теперь вы знаете, что дизассемблер доставит вас из бинарной формы в форму сборки. A декомпилятор перенесет вас в код C (или какой-либо другой язык более высокого уровня).
Источник: https://stackoverrun.com/ru/q/2722156
В arduino ide 1.6.6 появилась возможность визуализировать данные | роботоша
Последняя версия Arduino IDE доступна для скачивания на сайте Arduino.
Новшества включают инструменты компилятора для фанатов командной строки, множество дополнений, исправленных ошибок, но, на мой взгляд самым серьезным дополнением в новой версии является инструмент под названием Serial plotter, позволяющий визуализировать данные, передаваемые по последовательному порту. Это могут быть, например, данные, получаемые с различных датчиков.
Итак, что же нового мы видим в вышедшем релизе?
- На заставке появились веселые, последовательно соединенные конденсаторы
- arduino-builder — инструмент командной строки для компиляции скетчей Arduino, который заботится об ошибках в коде, обеспечивает компиляцию связанных библиотек и устанавливает параметры компиляции. Он может использоваться как отдельная программа для компиляции программного кода.
- Модуль PluggableUSB — теперь Arduino может взаимодействовать со множеством различных USB-устройств и при этом не нужно изменять программное ядро. Это становится возможным благодаря новой модульной архитектуре. Библиотеки основываются на новой разработанной подсистеме.
- Serial Plotter — позволяет визуализировать в реальном времени, поступающие на компьютер данные с Arduino. В Mac OS этот инструмент смешно называется
Простенький скетч, генерирует функцию sin (x) и отправляет результат в Serial порт.
При попытке компиляции в Mac OS — вылезает ошибка
fork/exec /Users/imac21/Library/Arduino15/packages/arduino/tools/avr-gcc/4.8.1-arduino2/bin/avr-g++: no such file or directory Ошибка компиляции. |
Вот тебе и новая версия. Без компилятора
В Ubuntu, работает нормально
Как по мне — так очень даже полезное дополнение к среде разработки.
Вот еще небольшое англоязычное видео с демонстрацией работы Serial Plotter
- Значительно улучшен пример Arduino ISP для использования Arduino в качестве программатора AVR-микроконтроллеров.
- Появилось всплывающее уведомление в Менеджере библиотек и Менеджере плат, если имеется обновления для установленных библиотек/ядра
Полный список изменений, исправлений, дополнений можно посмотреть здесь.
Багов, судя по всему, в этом релизе тоже предостаточно. Наверное, спешить удалять Arduino IDE 1.6.5 пока не стоит…
Источник: http://robotosha.ru/arduino/arduino-ide-1-6-6-data-visualisation.html