Arhn - архитектура программирования

Генератор парсеров для написания дизассемблера для проприетарного формата ВМ

Я пытаюсь написать дизассемблер для двоичных файлов Mindstorms EV3 VM, желательно на Python, так как я очень хорошо с ним знаком. У меня есть документы с подробным описанием набора инструкций, кодов операций, параметров, типов данных и т. д., а именно доступно здесь, но у меня возникли проблемы с созданием собственно дизассемблер оттуда.

Насколько я понимаю, написание дизассемблера мало чем отличается от написания компилятора в том смысле, что это просто прославленный детерминированный конечный автомат. Однако, помимо этого, я не могу найти никаких книг или руководств по его написанию. Я пытался использовать инструменты для написания компиляторов, такие как Lex и Yacc (или в python PLY), однако все эти инструменты каким-то образом меня не устраивают.

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

Еще одна проблема, с которой я столкнулся, заключается в том, что я не знаю, как обращаться с такими вещами, как строки с завершающим нулем и кодировка параметров (некоторые аргументы имеют префикс байта с определенным набором битов, сообщающих виртуальной машине, какую длину и тип ожидать, что, как я полагаю, означает Я не могу разобрать весь байткод простым DFA на уровне байтов)

Как мне написать дизассемблер для такого формата?


  • Вы правы, нужно сделать наоборот. Однако это не совсем так, что вы не можете сделать это с комбо lexer + Yacc. Вам нужно будет предварительно обработать ввод, чтобы вы могли передать лексеру осмысленный ввод или написать свой собственный лексер, который принимает байты вместо символов (даже если символы просто преобразуются в байты на основе набора символов). Каждый байт, который вы читаете, определяет, какой последующий ввод является приемлемым и как долго он длится, поэтому, если бит установлен, это просто означает, что вы читаете другое значение байта и находитесь в другом состоянии. 25.09.2016
  • Имейте в виду, что в зависимости от цели это может противоречить правилам (соглашению с конечным пользователем) приобретенного продукта. Не уверен, что это то, что вы ищете, но поищите идеи здесь: github.com/ev3dev/lms-hacker-tools/blob/master/EV3/lmsdisasm.py 25.09.2016
  • Я написал дизассемблер файлов классов Java на Python (Krakatau), который может вам помочь. Я действительно не понимаю, в чем трудная часть. Вам не нужны никакие причудливые фреймворки, просто напишите код, который будет делать то, что вы хотите. 25.09.2016
  • Генераторы парсеров — это инструменты для ввода со сложной грамматикой. Поскольку скомпилированный код предназначен для эффективного выполнения, он, естественно, является его полной противоположностью. Таким образом, включение генераторов синтаксических анализаторов и т. д. является излишним и увеличивает вашу работу, а не сокращает ее. Для большинства форматов дизассемблер может быть реализован как однопроходный транслятор. 26.09.2016
  • @Holger хорошо, если ответ Иры не сработает, похоже, я соглашусь с этим. 07.11.2016

Ответы:


1

Написание двоичных дизассемблеров на самом деле означает, что вы хотите указать шаблоны двоичных данных и отношения между объектами декодирования (если вы распознаете две инструкции, разумно предположить, что они не перекрываются).

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

Самый умный подход, который я видел для этого, — это инструмент под названием SLED от Нормана Рэмси и его команды, который позволяет вам писать краткие шаблоны для двоичных данных и автоматически собирать их в двоичные кодировщики и декодеры. В этом исследовании SLED и количество подобных систем. Ключевой момент: это гораздо больше, чем «генератор синтаксических анализаторов», но концепция похожа: множество шаблонов для описания данных, генератор кода для сборки шаблонов в эффективный механизм, чтобы сопоставить их все.

Чтобы дать вам представление о том, как выглядят эти инструменты, я предлагаю фрагмент частичного кодирования x86-64, основанный на некоторой работе, которую я проделал в этой области. Идея состоит в том, чтобы определить именованные шаблоны (с ограничениями), которые составляются так, чтобы вы могли в конечном итоге написать определение инструкции. Вот краткий пример небольшой части (всего около 1200 строк):

datatype SIB
 { ScaleSize:     unsigned encoding { Times1=0 Times2=1 Times4=2 Times8=3} 2 bits
   ScaledIndex:   unsigned encoding { EAX=0 ECX=1 EDX=2 EBX=3 none=4 EBP=5         ESI=6 EDI=7 } 3 bits
   IndexRegister: unsigned encoding { EAX=0 ECX=1 EDX=2 EBX=3 ESP=4  EBP,disp32=5  ESI=6 EDI=7 } 3 bits
 }

encoding Grp1     { ADD=0 OR ADC SBB AND SUB XOR CMP }
encoding Grp1A    { POP=0 * * * * * * * }
encoding Grp2     { ROL=0 ROR RCL RCR SHL,SAL SHR  * SAR }
encoding Grp3     { TESTIbIz=0 * NOT NEG MULAX,MULrAX IMULAL,IMULrAX DIVAL,DIVrAX IDIVAL,IDIVrAX }
encoding Grp4     { INCEb=0  DECEb * * * * * * }
encoding Grp5     { INCEv=0  DECEv CALLNEv CALLFEp  JMPNEv JMPFEp  PUSHEv * }
encoding Grp6     { SLDTRvMW=0 STRRvMw LLDTEw LTREw VERREw VERWEw * * }
encoding Grp7mem  { SGDTMs=0                          SIDTMs        LGDTMs LIDTMs SMSWMwRv * LMSWEw INVLPGMb }
encoding Grp7reg  { VMCALL,VMLAUNCH,VMRESUME,VMXOFF=0 MONITOR,MWAIT *      *      SMSWMwRv * LMSWEw SWAPGS }
encoding Grp8     { *=0 * * * BT BTS BTR BTC }
encoding Grp9mem  { * CMPXCH8BMq,CMPXCH16BMdq * * * * VMPTRLDMq,VMCLEARMq,VMXONMq VMPTRSTMq }
encoding Grp9reg  { *=0 * * * * * * * }
encoding Grp10    { * * * * * * * }
encoding Grp11Ib  { MOVEbIb * * * * * * * }
encoding Grp11Iz  { MOVEvIz * * * * * * * }
encoding Grp12mem { * * * * * * * * }
encoding Grp12reg { *=0 * * PSRLWNqIb,PSRLWUdqIb *             PSRAWNqIb,PSRAWUdqIb * PSLLWNqIb,PSLLWUdqIb * }
encoding Grp13mem { * * * * * * * * }
encoding Grp13reg { *=0 * * PSRLDNqIb,PSLRDUdqIb *             PSRADNqIb,PSRADUdqIb * PSLLDNqIb,PSLLDUdqIb * }
encoding Grp14mem { * * * * * * * * }
encoding Grp14reg { *=0 * * PSRLQNqIb,PSRLQUdqIb  PSRLDQUdqIb  *                    * PSLLQNqIb,PSLLQUdqIb PSLLDQUDqIb }
encoding Grp15mem { FXSAVE=0 FXRSTOR LDMXCSR STMXCSR * * * CFLUSH }
encoding Grp15reg { *=0 * * * LFENCE MFENCE SFENCE }
encoding Grp16mem { PREFETCHNTA=0 PREFETCHT0 PREFETCHT1 PREFETCHT2 * * * } 
encoding Grp16reg { * * * * * * * * }

...

instruction { ADCr64Immediate => Grp1.ADC
      ADDr64Immediate => Grp1.ADD
      ANDr64Immediate => Grp1.AND
      CMPr64Immediate => Grp1.CMP
      ORr64Immediate  => Grp1.OR
      SBBr64Immediate => Grp1.SBB
      SUBr64Immediate => Grp1.SUB
      XORr64Immediate => Grp1.XOR
    }
   (Target: Register32, Immediate: signed 32 bits)
   BasicInstruction
   & prefix_length0
   & if Intel64 => prefix_REX(W=On R=Target:3)
   & OneByteOpcode & Subcode=ImmGrp1EvIz
   & ModRM(Mod=reg RSlashM=Target:2-0 reg=*)

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

25.09.2016
Новые материалы

Коллекции публикаций по глубокому обучению
Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

Представляем: Pepita
Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

Советы по коду Laravel #2
1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

3 способа решить квадратное уравнение (3-й мой любимый) -
1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

Создание VR-миров с A-Frame
Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

Демистификация рекурсии
КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..