Опыт дизассемблирования большой .com программы

Quick Example

The following example program uses Zydis to disassemble a given memory buffer and prints the output to the console (more examples here).

#include <stdio.h>
#include <inttypes.h>
#include <Zydis/Zydis.h>

int main()
{
    ZyanU8 data[] =
    {
        0x51, 0x8D, 0x45, 0xFF, 0x50, 0xFF, 0x75, 0x0C, 0xFF, 0x75,
        0x08, 0xFF, 0x15, 0xA0, 0xA5, 0x48, 0x76, 0x85, 0xC0, 0x0F,
        0x88, 0xFC, 0xDA, 0x02, 0x00
    };

    // Initialize decoder context
    ZydisDecoder decoder;
    ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);

    // Initialize formatter. Only required when you actually plan to do instruction
    // formatting ("disassembling"), like we do here
    ZydisFormatter formatter;
    ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);

    // Loop over the instructions in our buffer.
    // The runtime-address (instruction pointer) is chosen arbitrary here in order to better
    // visualize relative addressing
    ZyanU64 runtime_address = 0x007FFFFFFF400000;
    ZyanUSize offset = ;
    const ZyanUSize length = sizeof(data);
    ZydisDecodedInstruction instruction;
    while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, data + offset, length - offset,
        &instruction)))
    {
        // Print current instruction pointer.
        printf("%016" PRIX64 "  ", runtime_address);

        // Format & print the binary instruction structure to human readable format
        char buffer;
        ZydisFormatterFormatInstruction(&formatter, &instruction, buffer, sizeof(buffer),
            runtime_address);
        puts(buffer);

        offset += instruction.length;
        runtime_address += instruction.length;
    }
}

Дизассемблеры и эмуляторы

Динамический дизассемблер может быть включен в выходные данные эмулятора или гипервизора, чтобы построчно «отслеживать» выполнение в реальном времени любых выполняемых машинных инструкций. В этом случае, а также строки, содержащие дизассемблированный машинный код, регистр (ы) и / или изменение (я) данных (или любые другие изменения « состояния », такие как коды условий), которые вызывает каждая отдельная инструкция, могут быть показаны рядом или под разобранной инструкцией. Это обеспечивает чрезвычайно мощную отладочную информацию для окончательного решения проблемы, хотя размер результирующего вывода иногда может быть довольно большим, особенно если он активен для выполнения всей программы. OLIVER предоставлял эти функции с начала 1970-х годов как часть своего предложения продуктов для отладки CICS, и теперь они включены в продукт XPEDITER от Compuware .

Компиляция по примеру условного выражения

Дизассемблированный вариант в radare2

1605793045836.png

1 — инициализации переменной var_4h (i = 3)2 — выполнения инструкций (add, printf)

Чтобы понять какой «case» выбран, происходит сравнение (cmp, а затем je, jne) переменной i с значением case.

Режим графов

1605793347813.pngscreen13.pngscreen_13_2.png

Глядя на этот код, сложно (если вообще возможно) сказать, что представлял собой оригинальный исходный текст — конструкцию switch или последовательность выражений if . В обоих случаях код выглядит одинаково, поскольку оба выражения используют множество инструкций cmp и je или jne.

Проблемы разборки

Возможно написание дизассемблера, который производит код, который после сборки дает в точности исходный двоичный файл; однако часто бывают различия. Это предъявляет требования к выразительности ассемблера. Например, ассемблер x86 делает произвольный выбор между двумя двоичными кодами для чего-то столь же простого, как . Если исходный код использует другой вариант, исходный код просто не может быть воспроизведен в любой данный момент времени. Однако даже при полностью правильной разборке проблемы остаются, если программа требует модификации. Например, та же самая инструкция перехода на машинном языке может быть сгенерирована ассемблерным кодом для перехода в указанное место (например, для выполнения определенного кода) или для перехода на указанное количество байтов (например, для пропуска нежелательной ветви) . Дизассемблер не может знать, что предназначено, и может использовать любой синтаксис для создания дизассемблера, воспроизводящего исходный двоичный файл. Однако, если программист хочет добавить инструкции между инструкцией перехода и ее местом назначения, необходимо понимать работу программы, чтобы определить, должен ли переход быть абсолютным или относительным, то есть должно ли его место назначения оставаться в фиксированном месте или быть перемещен так, чтобы пропустить как исходную, так и добавленную инструкции.

Дизассемблеры и эмуляторы

Динамический дизассемблер может быть включен в вывод эмулятор или же гипервизор Построчно «проследить» выполнение любых выполняемых машинных инструкций в реальном времени. В этом случае, а также строки, содержащие дизассемблированный машинный код, регистр (ы) и / или изменение (я) данных (или любые другие изменения «государственный», такие как коды условий), которые каждая отдельная инструкция может вызывать рядом с дизассемблированной инструкцией или под ней. Это обеспечивает чрезвычайно мощную отладочную информацию для окончательного решения проблемы, хотя размер результирующего вывода может иногда быть довольно большим, особенно если выполнение всей программы. OLIVER предоставил эти функции с начала 1970-х годов как часть своей CICS отладочное предложение продукта, и теперь его можно найти включенным в XPEDITER продукт из Compuware.

Как мыслит процессор

Что­бы понять, как рабо­та­ет Ассем­блер и поче­му он рабо­та­ет имен­но так, нам нуж­но немно­го разо­брать­ся с внут­рен­ним устрой­ством про­цес­со­ра.

Кро­ме того, что про­цес­сор уме­ет выпол­нять мате­ма­ти­че­ские опе­ра­ции, ему нуж­но где-то хра­нить про­ме­жу­точ­ные дан­ные и слу­жеб­ную инфор­ма­цию. Для это­го в самом про­цес­со­ре есть спе­ци­аль­ные ячей­ки памя­ти — их назы­ва­ют реги­стра­ми.

Реги­стры быва­ют раз­но­го вида и назна­че­ния: одни слу­жат, что­бы хра­нить инфор­ма­цию; дру­гие сооб­ща­ют о состо­я­нии про­цес­со­ра; тре­тьи исполь­зу­ют­ся как нави­га­то­ры, что­бы про­цес­сор знал, куда идти даль­ше, и так далее. Подроб­нее — в рас­хло­пе ↓

Какими бывают регистры

Обще­го назна­че­ния. Это 8 реги­стров, каж­дый из кото­рых может хра­нить все­го 4 бай­та инфор­ма­ции. Такой регистр мож­но раз­де­лить на 2 или 4 части и рабо­тать с ними как с отдель­ны­ми ячей­ка­ми.

Ука­за­тель команд. В этом реги­стре хра­нит­ся толь­ко адрес сле­ду­ю­щей коман­ды, кото­рую дол­жен выпол­нить про­цес­сор. Вруч­ную его изме­нить нель­зя, но мож­но на него повли­ять раз­лич­ны­ми коман­да­ми пере­хо­дов и про­це­дур.

Регистр фла­гов. Флаг — какое-то свой­ство про­цес­со­ра. Напри­мер, если уста­нов­лен флаг пере­пол­не­ния, зна­чит про­цес­сор полу­чил в ито­ге такое чис­ло, кото­рое не поме­ща­ет­ся в нуж­ную ячей­ку памя­ти. Он туда кла­дёт то, что поме­ща­ет­ся, и ста­вит в этот флаг циф­ру 1. Она — сиг­нал про­грам­ми­сту, что что-то пошло не так.

Фла­гов в про­цес­со­ре мно­го, какие-то мож­но менять вруч­ную, и они будут вли­ять на вычис­ле­ния, а какие-то мож­но про­сто смот­реть и делать выво­ды. Фла­ги — как сиг­наль­ные лам­пы на пане­ли при­бо­ров в само­лё­те. Они что-то озна­ча­ют, но толь­ко само­лёт и пилот зна­ют, что имен­но.

Сег­мент­ные реги­стры. Нуж­ны были для того, что­бы рабо­тать с опе­ра­тив­ной памя­тью и полу­чать доступ к любой ячей­ке. Сей­час такие реги­стры име­ют по 32 бита, и это­го доста­точ­но, что­бы полу­чить 4 гига­бай­та опе­ра­тив­ки. Для про­грам­мы на Ассем­бле­ре это­го обыч­но хва­та­ет.

Так вот: всё, с чем рабо­та­ет Ассем­блер, — это коман­ды про­цес­со­ра, пере­мен­ные и реги­стры.

Здесь нет при­выч­ных типов дан­ных — у нас есть толь­ко бай­ты памя­ти, в кото­рых мож­но хра­нить что угод­но. Даже если вы поме­сти­те в ячей­ку какой-то сим­вол, а потом захо­ти­те рабо­тать с ним как с чис­лом — у вас полу­чит­ся. А вме­сто при­выч­ных цик­лов мож­но про­сто прыг­нуть в нуж­ное место кода.

Установка

Рекомендуемым разработчиками способом установки и обновления Radare2 является установка из официального git-репозитория. Предварительно в системе должны присутствовать установленные пакеты git, build-essential и make.

Далее устанавливаем графическую оболочку для Radare2. Мы будет устанавливать официальный GUI под названием Iaito. Установим пакеты, необходимые для установки Iaito:

Для дистрибутивов Linux на базе Debian, есть готовые пакеты, ссылки на которые можно взять тут. Скачаем и установим нужную версию пакета:

Теперь установим плагин r2ghidra, который является интеграцией декомпилятора Ghidra для Radare2. Плагин не требует отдельной установки Ghidra, так как содержит в себе всё необходимое. Для установки плагин доступен в качестве r2pm пакета:

Установленный плагин автоматически интегрируется в GUI Iaito. После установки запускаем графическую оболочку и если все сделали правильно, то видим стартовый экран:

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

Открываем файл в Iaito, оставляем настройки анализа по умолчанию:

После того, как Radare2 проанализирует файл, смотрим результат, открывшийся во вкладке Dashboard:

Программа скомпилирована под 64-битную версию Linux, написана на языке C. Слева мы видим список функций, которые Radare2 смог обнаружить. Среди них импортируемые из библиотеки libc функции printf, puts и putchar, выводящие на экран строку по формату и символ.

Функция main – это главная функция программы. Выполнение начинается с неё. Кликнув два раза по её названию, открывается вкладка Disassembly с результатом её дизассемблирования:

Немного про Ассемблер

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

Команды ассемблера

Каждая команда Ассемблера — это команда для процессора. Синтаксис команды состоит из нескольких частей:

Команда — означает какую операцию необходимо выполнить. Например:

  • mov — команда пересылки данных. Копирует содержимое одного операнда в другой;

  • lea — вычисляет эффективный адрес операнда-источника и сохраняет его в регистре;

  • cmp — сравнение двух операндов;

  • условные и безусловные переходы (jmp, jne, je, jle, …) — безусловные и условные (требуется выполнение условия) переходы к меткам. Например, jump @exit выполняет безусловный переход к метке exit;

  • nop — однобайтовая команда, которая ничего не выполняет, а только занимает место и время. В основном используется для создание задержки в программе или как заполнитель удаленных инструкций. Например, команду проверки лицензионного ключа во взломанных программах заменяют на «ничего не делать»;

  • и тд

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

Комментарий — понятно из названия, что это комментарий для удобства чтения кода. Пишется после точки с запятой.

Метки — обозначение участка кода. Также улучшает читаемость кода, но нужны еще и для перехода к помеченному им участку.

где:

  • mov — команда (перемещение значения из одного операнда в другой);

  • ax, — операнды (регистр и значение);

  • ; <текст> — комментарий

Или рассмотрим другой пример как выглядит возведение числа в степень в Ассемблере:

Это же действие будет выглядеть на языке высокого уровня, например, Си как:

Проблемы разборки

Возможно написание дизассемблера, который производит код, который после сборки дает в точности исходный двоичный файл; однако часто есть различия. Это предъявляет требования к выразительности ассемблера. Например, ассемблер x86 делает произвольный выбор между двумя двоичными кодами для чего-то столь же простого, как . Если исходный код использует другой вариант, исходный код просто не может быть воспроизведен в любой момент времени. Однако даже при полностью правильной разборке проблемы остаются, если программа требует модификации. Например, та же самая команда перехода на машинном языке может быть сгенерирована ассемблерным кодом для перехода в указанное место (например, для выполнения определенного кода) или для перехода на указанное количество байтов (например, чтобы пропустить нежелательную ветвь). . Дизассемблер не может знать, что предназначено, и может использовать любой синтаксис для создания дизассемблера, воспроизводящего исходный двоичный файл. Однако, если программист хочет добавить инструкции между инструкцией перехода и ее местом назначения, необходимо понимать работу программы, чтобы определить, должен ли переход быть абсолютным или относительным, то есть должно ли его место назначения оставаться в фиксированном месте или быть перемещен так, чтобы пропустить как исходную, так и добавленную инструкции.

Нахождение всех текстовых строк внутри EXE файла

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

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

Литература

  • Вострикова З. П. Программирование на языке ассемблера ЕС ЭВМ. М.: Наука, 1985.
  • Галисеев Г. В. Ассемблер для Win 32. Самоучитель. — М.: Диалектика, 2007. — С. 368. — ISBN 978-5-8459-1197-1.
  • Зубков С. В. Ассемблер для DOS, Windows и UNIX. — М.: ДМК Пресс, 2006. — С. 608. — ISBN 5-94074-259-9.
  • Ирвин Кип. Язык ассемблера для процессоров Intel = Assembly Language for Intel-Based Computers. — М.: Вильямс, 2005. — С. 912. — ISBN 0-13-091013-9.
  • Калашников О. А. Ассемблер? Это просто! Учимся программировать. — БХВ-Петербург, 2011. — С. 336. — ISBN 978-5-9775-0591-8.
  • Магда Ю. С. Ассемблер. Разработка и оптимизация Windows-приложений. СПб.: БХВ-Петербург, 2003.
  • Нортон П., Соухэ Д. Язык ассемблера для IBM PC. М.: Компьютер, 1992.
  • Владислав Пирогов. Ассемблер для Windows. — СПб.: БХВ-Петербург, 2002. — 896 с. — ISBN 978-5-9775-0084-5.
  • Владислав Пирогов. Ассемблер и дизассемблирование. — СПб.: БХВ-Петербург, 2006. — 464 с. — ISBN 5-94157-677-3.
  • Сингер М. Мини-ЭВМ PDP-11: Программирование на языке ассемблера и организация машины. М.: Мир, 1984.
  • Скэнлон Л. Персональные ЭВМ IBM PC и XT. Программирование на языке ассемблера. М.: Радио и связь, 1989.
  • Юров В., Хорошенко С. Assembler: учебный курс. — СПб.: Питер, 2000. — С. 672. — ISBN 5-314-00047-4.

Внешний осмотр

Кратко: на этом этапе производится внешний осмотр устройства с целью поиска маркировок, доступных разъемов.

  • Микроконтроллер STM32F042 – тут сразу стоит обратиться к документации на микроконтроллер (если такая есть), откуда можно узнать архитектуру, разрядность микроконтроллера и много чего полезного (для нашего случая – 32 разрядный микроконтроллер на архитектуре ARM);
  • На тыльной стороне имеется разъем без обозначений – те, кто работал с микроконтроллерами, могут сделать верное предположение, что это разъем для прошивки устройства (во-первых, он не промаркирован; во-вторых, он имеет 5 контактов, что соответствует необходимому количеству контактов для перешивки микроконтроллера);
  • Контакты GND, TX;
  • USB-разъем для питания устройства (об этом говорится и в «Инструкции»);
  • Неизвестный разъем XP2 на лицевой стороне устройства;
  • Непонятная желтая блямба на ноге носорога – вероятно, сенсорная кнопка.

RHINOCEROS-220x

Отладчики и дизассемблеры.

Отладчик даёт возможность проследить выполнение запущенной программы пошагово в режиме непосредственной её работы.

Встроенные в среду программирования любого языка отладчики позволяют отслеживать выполнение кода именно того языка, с помощью которого вы создаёте программу. Однако, есть «стандартные» отладчики, которые позволяют распотрошить любой исполняемый файл, показав пошаговое выполнение инструкций. Там балом правит исключительно ассемблер!

Дизассемблер — это программа, позволяющая преобразовать исполняемый файл в код на языке ассемблера.

Пока мы с вами изучаем программирование на ассемблере в системе MS-DOS, воспользуемся отладчиком Turbo Debugger, дизассемблерами Sourcer и IDA. Рассмотрим краткие характеристики и особенности указанных программ. Более подробно отладчики и дизассемблеры мы рассмотрим попозже.

Win32 PE Disassembler: Dig into Executables

The PE Explorer Disassembler is designed to be easy to use compared with other disassemblers. To that end, some of the functionality found in other products has been left out in order to keep the process simpleand fast. While as powerful as the more expensive, dedicated disassemblers, PE Explorer focuses on ease of use, clarity and navigation.

Name List to the right provides a list of labeled addresses (including conditional and unconditional branching destinations, function prologues, named data, and string references) by the disassembler, with the entry point clearly indicated. Labels can be renamed by pressing N (Edit | Rename Label).

The Strings tab provides a list of detected strings; you can further manipulate strings detection by using the toolbar, using menu items (Edit | Mark as String/Pascal String/Long Pascal String/Unicode), or pressing S, A, L, or U to activate each of them.

The lower left tabs View 1, View 2, View 3, and View 4 (F6, F7, F8, and F9) provide persistent disassemble views that are independent of the main view and are swappable.

Code can be manually marked in the assembly listing by pressing ‘C.’ Dwords and offsets can be marked by pressing D and O, respectively.

Comments can be entered by pressing ;.

The Unprocessed data tab displays some blocks of data that do not have a reference to a procedure.

The main disassembly view is towards the top-left. A nice feature in this view is the provision for an immediate adjustment of the space between each assembly line (Ins and Del) and the number of opcodes per line (Shift + Ins and Shift + Del).

Navigation is really simple. Branching addresses can be navigated by selecting the relevant line and pressing Enter. For instructions with a second operand destination address, press Ctrl + Enter. Going back to a previous address requires pressing Esc, and to visit a particular address, you have press Ctrl + G and type the address in the hexadecimal format.

Subroutines that might have references can be listed in a pop-up window by selecting the starting address of the procedure and pressing R (Search | References). The list can then be traversed by double-clicking on each listed address.

We tried to achieve most of the power of IDA Pro, while requiring less skill or knowledge, by automating more of the disassembly process. We just made a good disassembler at a reasonable price. If your daily work involves reverse engineering of software and exploiting code, source code reviews, testing and evaluation of vulnerabilities, PE Explorer will save you hours of time and it’s easy to use!

The PE Explorer disassembler assumes that some manual editing of the reproduced code will be needed. To facilitate additional hand coding, however, the disassembler utilizes a qualitative algorithm designed to reconstruct the assembly language source code of target binary win32 PE files (EXE, DLL, OCX) with the highest degree of accuracy possible.

I’ve been using the PE Explorer for a while, and am very impressed with the latest version’s functions — especially the Disassembler. Conrad Herrmann,Zone Labs, Inc.

One of the reasons that I bought PE Explorer was the Disassembler. Good stuff. Gerald Beuchelt,Sun Microsystems, Inc.

After using your tool vs. other shareware products I felt that I was getting the best deal for my $ instead of paying $400 for Ida Pro. David Burlingame,Intel Corporation

More user testimonials

Известные ограничения

Важно понимать, что PE Explorer не декомпилирует код. Он дизассемблирует код, т.е

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

Дизассемблирование файлов размером более 1 Мб может занять несколько минут. Во многом скрость зависит от возможностей вашего компьютера. В общем случае, для каждого байта дизассемблируемого файла требуется 40 байт памяти. Т.е. для файла размером в 1 Мб требуется 40 Мб памяти, для 2 Мб — 40 Мб памяти, и так далее.

Полученный дизассемблерный листинг не может быть заново скомпилирован «как есть». Мы не ставили перед собой задачи формировать листинг, который мог бы быть рекомпилирован. Это не имеет большого смысла для сколь-либо значимого размера входного файла. Нашей целью было получить продукт, способный БЫСТРО и достаточно качественно дать представление о содержимом исполняемого файла, обнаружить в нём интересующие исследователя места и проанализировать их. Получение же листинга, способного быть откомпилированным, представляется нам задачей мало применимой в реальной жизни в силу внушительных размеров современных исполняемых файлов и, как следствие, КРАЙНЕ ВЫСОКОЙ СЛОЖНОСТИ качественного анализа ВСЕХ данных, содержащихся в программе. Нам кажется, что имеет смысл вести разговор только о возможности извлечь какую-либо процедуру из листинга для использования ее в своих целях (естественно, в рамках действующего законодательства).

Обзорный тур   назад | след. 

Подытожим…

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

  1. Создание загрузчиков, прошивок устройств (комплектующих ПК, встраиваемых систем), элементов ядра ОС.

  2. Низкоуровневая работа с железом, в т.ч. с процессором, памятью.

  3. Внедрение кода в процессы (injection), как с вредоносной целью, так и с целью защиты или добавления функционала. Системный софт.

  4. Блоки распаковки, защиты кода и прочего функционала (с целью изменения поведения программы, добавления новых функций, взлома лицензий), встраиваемые в исполняемые файлы (см. UPX, ASProtect и пр).

  5. Оптимизация кода по скорости, в т.ч. векторизация (SSE, AVX, FMA), математические вычисления, обработка мультимедиа, копирование памяти.

  6. Оптимизация кода по размеру, где нужно контролировать каждый байт. Например, в демосцене.

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

  8. При создании компиляторов и трансляторов исходного кода с какого-либо языка на язык ассемблера (например, многие компиляторы C/C++ позволяют выполнять такую трансляцию). При создании отладчиков, дизассемблеров.

  9. Собственно, отладка, дизассемблирование, исследование программ (reverse engineering).

  10. Создание файлов данных с помощью макросов и директив генерации данных.

  11. Вы не поверите, но ассемблер можно использовать и для написания обычного прикладного ПО (консольного или с графическим интерфейсом – GUI), игр, драйверов и библиотек 🙂

Примеры дизассемблеров

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

Любой интерактивный отладчик будет включать некоторый способ просмотра дизассемблера отлаживаемой программы. Часто один и тот же инструмент дизассемблирования будет упакован как автономный дизассемблер, распространяемый вместе с отладчиком. Например, objdump, часть GNU Binutils, относится к интерактивному отладчику GDB.

  • Бинарный ниндзя
  • ОТЛАЖИВАТЬ
  • Интерактивный дизассемблер (ИДА)
  • Гидра
  • Hiew
  • Дизассемблер бункера
  • Netwide Disassembler (Ndisasm), спутник Сетевой ассемблер (НАСМ).
  • ОЛИВЕР (CICS интерактивный тест / отладка) включает дизассемблеры для Ассемблера, КОБОЛ, и PL / 1
  • OllyDbg это 32-битный отладчик, анализирующий уровень ассемблера
  • Radare2
  • SIMON (пакетное интерактивное тестирование / отладка) включает дизассемблеры для Assembler, COBOL и PL / 1.
  • Sourcer, комментирующий 16-битный / 32-битный дизассемблер для ДОС, OS / 2 и Windows к V Связь в 1990-е годы

Проверка на устройстве

Кратко: проверим отдельные предположения на работающем устройствеСтатический анализsub_8005234x_bluetooth_send

  • – возвращает «ОК», включает эхо-режим – команда дублируется отправителю;
  • – выключает эхо-режим;
  • – возвращает «mur-mur (>._.<)\r\n » — то ли пасхалка, то ли отладочная команда;
  • — выключает один из ярких светодиодов;
  • – возвращает «ОК»;
  • — однократно мигает красным светодиодом;
  • – возвращает «ERROR: Not auth!»
  • – возвращает «ERROR: Not auth!»
  • – возвращает «ERROR: auth error!»
  • – возвращает «ERROR: Not auth!»
  • — возвращает «Wrong won’t give up!»
  • команда состоит минимум из 4 символов;
  • есть довольно странные команды, как-то связанные с авторизацией (зачем авторизация на осветительном приборе?).

A General view of Disassembling[edit | edit source]

8 bit CPU codeedit | edit source

Most embedded CPUs are 8-bit CPUs.

Normally when a subroutine is finished, it returns to executing the next address immediately following the instruction.

However, assembly-language programmers occasionally use several different techniques that adjust the return address, making disassembly more difficult:

  • jump tables,
  • calculated jumps, and
  • a parameter after the call instruction.

parameters after the call instructionedit | edit source

Instead of picking up their parameters off the stack or out of some fixed global address, some subroutines provide parameters in the addresses of memory that follow the instruction that called that subroutine. Subroutines that use this technique adjust the return address to skip over all the constant parameter data, then return to an address many bytes after the «call» instruction. One of the more famous programs that used this technique is the «Sweet 16» virtual machine.

The technique may make disassembly more difficult.

A simple example of this is the procedure implemented as follows:

; assume ds = cs, e.g like in boot sector code
start:
        call write       ; push message's address on top of stack
        db   "Hello, world",dh,ah,00h
; return point
        ret              ; back to DOS

write proc near
        pop  si          ; get string address
        mov  ah,eh      ; BIOS: write teletype
w_loop:
        lodsb            ; read char at  and increment si
        or   al,al       ; is it 00h?
        jz   short w_exit
        int  10h         ; write the character
        jmp  w_loop      ; continue writing
w_exit:
        jmp  si
write   endp
        end start

A macro-assembler like TASM will then use a macro like this one:

_write macro message
       call write
       db message
       db 
_write endm

From a human disassembler’s point of view, this is a nightmare, although this is straightforward to read in the original Assembly source code, as there is no way to decide if the db should be interpreted or not from the binary form, and this may contain various jumps to real executable code area, triggering analysis of code that should never be analysed, and interfering with the analysis of the real code (e.g. disassembling the above code from 0000h or 0001h won’t give the same results at all).

However a half-decent tool with possibilities to specifiy rules, and heuristic means to identify texts will have little trouble.

32 bit CPU codeedit | edit source

Most 32-bit CPUs use the ARM instruction set.

Typical ARM assembly code is a series of subroutines, with literal constants scattered between subroutines.
The for subroutines is pretty easy to recognize.

  • objdump, part of the GNU binutils, can disassemble code for several processors and platforms. binutils is an important part of the toolchain as it provides the linker, assembler and other utilties (like objdump) to manipulate executables on the target platform, and is available for most popular platforms.

Таблица переходов

Следующий пример ассемблерного кода часто можно встретить в больших смежных выражениях switch. Мы добавим case 4 и инструкцию по умолчанию.

Дизассемблированный вариант в radare2

1605793648917.png1605793656018.png

1 — инициализации переменной var_4h (i = 3) 2 — выполнения инструкций (add, printf)

Вот этот дизасcемблированный код довольно сложно быстро отличить от if и вообще понять что и как тут. В режиме графов всё будет более понятно.

Режим графов

1605793750977.png1605793673414.png1605793684884.png1605793691266.png

Режим графов — ваш друг в дизасcемблировании 🙂

На этом всё. Рекомендую попробовать самому написать программы на Си, скомпилировать и изучить дизасcемблированный код. Практика и ещё раз практика!

Архитектура виртуальной машины ассемблера

Ассемблер fasmg (архитектура CALM-инструкций)

Является наследником ассемблера flat assembler (fasm) со схожим синтаксисом, но в отличие от fasm не привязан ни к какой архитектуре процессора. Его парадигмой является формирование посредством макросов выходных файлов любых форматов и с машинным кодом под любые архитектуры процессоров. Помимо макросов в fasmg присутствуют т. наз. CALM-инструкции (букв. «инструкции компилируемой сборки, подобные макросам») — собственные инструкции виртуальной машины ассемблера, эквивалентные макросам, которые преобразуются транслятором в байт-код. Архитектуру этих CALM-инструкций можно считать «родной» архитектурой ассемблера fasmg. В комплекте имеются наборы CALM-инструкций для эмуляции поддержки инструкций архитектур x86, x64, 8052, AVR; разработчиком могут быть описаны наборы CALM-инструкций для поддержки любой другой архитектуры, поддержки любых выходных форматов файлов. Имеются вариации транслятора для Mac OS, Linux и Windows.

Examples

The following command causes the metadata and disassembled code for the PE file to display in the Ildasm.exe default GUI.

The following command disassembles the file and stores the resulting IL Assembler text in the file MyFile.il.

The following command disassembles the file and displays the resulting IL Assembler text to the console window.

If the file contains embedded managed and unmanaged resources, the following command produces four files: MyApp.il, MyApp.res, Icons.resources, and Message.resources:

The following command disassembles the method within the class in and displays the output to the console window.

In the previous example, there could be several methods named with different signatures. The following command disassembles the instance method with the return type of void and the parameter types int32 and string.

Note

In the .NET Framework versions 1.0 and 1.1, the left parenthesis that follows the method name must be balanced by a right parenthesis after the signature: . Starting with the .NET Framework 2.0 the closing parenthesis must be omitted: .

To retrieve a method ( method in Visual Basic), omit the keyword . Class types that are not primitive types like and must include the namespace and must be preceded by the keyword . External types must be preceded by the library name in square brackets. The following command disassembles a static method named that has one parameter of type AppDomain and has a return type of AppDomain.

A nested type must be preceded by its containing class, delimited by a forward slash. For example, if the class contains a nested class named , the nested class is identified as follows: .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector