2016-02-20 3 views
2

Я хотел бы создать граф потока управления (CFG) из файла сборки с использованием языка C. Я думал об этом, и это мои идеи: 1. создать блоки - файл сборки процесса по строке - найти важные инструкции, такие как имя функции, имя блока, инструкции перехода, инструкции вызова или оставить/ret и, возможно, некоторые другие - Может быть, найти их с регулярными выражениями? Но я еще не нашел реализацию регулярных выражений для C на Windows. - после матча команд выше, за исключением инструкции перед матчем с некоторой структурой, и это мой блок 2. создать CFG - somhow из блоков создать CFG, но все же я понятия не имею,Создать граф потока управления из файла сборки

Может кто-нибудь дать мне совет, как сделай это? Также, если есть лучший язык для этого, я бы сказал, если вы скажете мне.
Спасибо за ваше время и помощь.

+0

Это скорее зависит от того, насколько хороша работа, которую вам нужно делать. Регулярные регулярные выражения на любом языке, который вам наиболее удобен, являются разумным первым приближением. У вас возникнут проблемы с макросами, внешними связями, вычисленными ветвями и т. Д., Но тогда идеальное решение невозможно начать, поэтому все зависит от того, насколько хороша эвристика, которую вы требуете. – doynax

+0

Если вы проводите специальный синтаксический анализ, вы получите в лучшем случае специальные графики потока управления. Почему вы хотите, чтобы плохой CFG был вне меня; что бы вы сделали с этим, что полезно? –

+1

Для чего вам это нужно? Возможно, есть другое направление для решения настоящей проблемы. –

ответ

2

Какие потребности в OP - это дисциплинированный подход к решению этой задачи.

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

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

(Вот трюк я использую в большом приложении x86 я хочу добавить здравомыслие проверки в мой код во многих местах Тестов здравомыслия выглядеть следующим образом:.

<test for some sane condition> 
    jf location+3  ; this branchs to a breakpoint in the middle of the next instruction 
    cmp al, 0xCC  ; the immediate value is a BREAKPOINT opcode 

Они компактны, и Точка останова происходит, когда некоторые плохое случается. Но при анализе этой программы для управления потоком, то «JMP ложные» иногда разветвляется на то, что, как представляется, средней из инструкции. Как будет модель OP что?)

Следующее осложнение указатели для кода. Код ассемблера часто генерирует много указателей на другие другие команды, а затем скрывает эти указатели в разных местах (команда вызова выталкивает их в стек данных для x86), извлекает их, а затем делает «jmp косвенным». Если вы хотите знать, куда может идти этот jmp, вам необходимо отслеживать возможные значения, которые может содержать ячейка памяти, а это означает, что вам нужно выполнить анализ потока данных (как значения получают там и откуда) и комбинировать с графиком вызовов (не может добраться до этой функции? ОК, тогда, где это происходит, это не повлияет на этот код), чтобы вычислить разумный ответ.

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

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

(Проверьте мою биографию для такой структуры. OP может использовать любую фреймворк, которая работает для него).

+0

Кажется, много работы. Я хочу сделать это для небольших программ, которые используют простой алгоритм, например, как quicksort или hanoi tower, или, может быть, какую-то программу, где можно открыть файл, прочитанный из него, и написать ему или что-то в этом роде. Я получаю источник сборки из C soure с помощью GCC, и я буду использовать синтаксис AT & T. Было бы менее сложно, чем мне кажется, после того, как я прочитал ваше сообщение (кстати, очень интересно - я не знал обо всех аспектах задачи, которую я собираюсь сделать) – Paul

+0

В коде ассемблера нет «простых» алгоритмов. Quicksort использует рекурсию (указатели кода в стеке) и разделение значений, подлежащих сортировке (часто реализуется с указателями, а также индексы массива в ассемблере). –

+1

Если вы хотите получить больше информации, прочитайте мое эссе «Life After Parsing»; искать в Интернете или видеть мою биографию. –

1

Простым подходом было бы собрать сборку, а затем разобрать ее. Большинство проблем синтаксического анализа устранены. Разборки будут иметь фиксированные столбцы для метки, op-кода и операндов, поэтому требуется очень мало парсинга.

Используя демонтаж, выполните два прохода. Первый проход заключается в создании структур данных для представления каждой команды и для сбора всех целей перехода.

Второй проход предназначен для создания структур, представляющих basic blocks (блок кода с одной точкой входа и выходом). Свяжите каждый базовый блок с его преемником (-ами). Базовый блок может иметь нулевой, один или два преемника (или N преемников в случае таблицы перехода). Базовый блок, который заканчивается с RET, имеет нулевых преемников. Базовый блок, заканчивающийся безусловным прыжком, имеет один преемник. И базовый блок с условным прыжком имеет двух преемников - либо проваливается, либо нацеливается на прыжок. Базовые блоки без предшественников являются либо точками входа подпрограммы, либо мертвым (или недействительным) кодом.

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

Недостаточно запуска программы (с помощью реального оборудования или эмулятора), зная, что цели косвенных прыжков с уверенностью неосуществимы. Я предлагаю поддерживать несколько простых случаев: 1) таблица перехода, в которой таблица находится внутри программы; 2) переход через глобальную ячейку памяти, которая использовалась для связи с другим исполняемым файлом (и дизассемблер перечисляет, какова цель). В первом случае основной блок может иметь произвольно много преемников. Во втором случае основной блок имеет единственный преемник.

Обратите внимание, что я намеренно оставляю CALLs как часть CFG. Когда я реализовал CFG grapher, это то, что я сделал. На моем графике одновременно показывалась только одна функция. Если вы дважды щелкнули CALL, тогда отобразился CFG подпрограмм.

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

Я оставляю INT и IRET, потому что предполагаю, что вы имеете дело с приложениями пользовательского режима. Если нет, то обрабатывайте INT как вызовы и IRET, такие как RET. Аппаратное прерывание Serivce Routine (ISR) может быть вызвано из любого места, где разрешены прерывания, поэтому нет (обычно) каких-либо прямых вызовов ISR - он просто будет сидеть в стороне. В более общих терминах, если вы имеете дело с программным обеспечением режима ядра, у вас будет множество других соображений.

+1

Демонтаж не разрешит команду jmps-to-middle. Он может даже не распознавать, когда область памяти на самом деле является кодом, или может неправильно интерпретировать регион данных как содержащий код. Этот подход добавляет шум, и вы не избегаете трудной проблемы анализа точек. Что вы делаете, избегайте самой легкой части: разбор исходного кода сборки. –

+0

Разборщик «objconv» Agner Fog (http://agner.org/optimize/) уже производит выходные данные с отмеченными целями ветви. IDK, что он делает с перескакиванием до середины инструкции (которую вы можете найти в запутанном коде машинного языка). Это с открытым исходным кодом (я забыл лицензию), поэтому вы могли бы даже использовать это как отправную точку. –

+0

@IraBaxter Я подозреваю, что OP в основном занимается кодом не ассемблера (в частности, кодом C). Очевидно, что в сборке можно закодировать материал, что делает невозможным создание точного CFG. Однако это не означает, что CFG не могут быть с пользой полезны. IDA является хорошим примером продукта, который эффективно генерирует CFG. –

Смежные вопросы