admin / 16.01.2018

Программирование в машинных кодах

Программирование в машинных кодах и ассемблере

Любая программа для ЭВМ — системная или приклад­ная — воспринимается (распознается) процессором толь­ко в том случае, если она состоит из специальных ко­манд, коды которых известны процессору определенного типа. Команды записаны в памяти компьютера в специ­альном формате. Каждая команда состоит из операционной и адресной частей. В первой из них находится позиционный двоичный код, определяющий требуемое от процессора действие (сложение, вычитание и т.д.). Во второй – адресной части команды, также в виде двоичного позиционного кода, находятся адреса данных (операндов), над которыми это действие необходи­мо выполнить, либо сами операнды. В вольном переводе на русский язык не­которую команду можно, например, интерпретировать так: сложить два числа, находящиеся в памяти по ад­ресам 100 и 120.

Разные типы ЭВМ имеют отличные друг от друга спосо­бы кодировки команд. Так, на персональных IВМ-совместимых компьютерах некоторая команда сложения в двоичном коде может иметь вид: 0000001111000011D или в шестнадцатиричном коде 03С3H . А на «древних» компью­терах типа М-220 команда сложения двух чисел могла выглядеть так:

001 00000001100100 00000001111000 00000001111011.

Поэтому программа в кодах компьютера (машинных кодах) является ма­шинно-зависимойи непереносимой,т.е. подготовленная для компьютера одного типа, она не сможет выполняться на других. Этот факт определяет основной недостаток про­граммирования в машинных кодах.

Вторым недостатком программирования в кодах явля­ется сильное дробление программы. Дело в том, что логи­чески команды процессора достаточно примитивны и обу­славливают выполнение простейших операций. Так, про­граммирование несложной формулы x=(a+b)(c+d) требо­вало задания серии команд типа:

— сложить а и b, промежуточный результат записать в ,

— сложить c и d, промежуточный результат записать в ,

умножить на , результат записать в х.

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

Однако программированию в кодах присущи и значи­тельные плюсы. Программист управляет всеми ресурсами компьютера, полностью контролирует текущее состояние ЭВМ, выбирает наиболее оптимальный код команды. Са­мые короткие по объему и наиболее быстрые по выполнению программы или их фрагменты разрабатываются и се­годня в кодах. Для облегчения наглядности программы в кодах разработаны специальные символические языки — ассемблеры. В них каждой команде компьютера сопостав­ляется определенный символьный код, являющийся со­кращением «родных» для человека слов. Специальная программа (она также называется ассемблером) переводит (транслирует)«непонятную» для компьютера (но более понятную для человека) символьную строку в коды ком­пьютера. Так, приведенные выше коды команд сложения на ассемблере могли выглядеть так: ADD АХ, BX (сло­жить числа из регистров АХ и ВХ и результат запомнить в АХ). При программировании на ассемблере программист мо­жет оперировать не с адресами памяти, в которых хра­нятся данные, а с их символическим представлением. На­пример, вначале ассемблеру специальной инструкцией со­общается, что по такому-то адресу хранится число, на­званное для программиста как . Далее программист не заду­мывается над тем, по какому адресу находится соответ­ствующее число, но просто использует его имя .

Ассемблер является машинно-зависимым языком про­граммирования, так как его инструкции соответствуют кодам команд компьютера. Поэтому ассемблерная програм­ма может выполняться только на тех ЭВМ, для которых она разрабатывалась. Кроме того, для работы на ассемб­лере требуется детальное знание особенностей конкретной ЭВМ.


Дата добавления: 2016-07-18; просмотров: 1074;


Похожие статьи:

Содержание

Введение

1. Идентификация математических операторов

1.1 Идентификация оператора "+"

1.2 Идентификация оператора "-"

1.3 Идентификация оператора "/"

1.4 Идентификация оператора "%"

1.5 Идентификация оператора "*"

1.6 Комплексные операторы

2. Идентификация SWITCH — CASE – BREAK

2.1 Отличия switch от оператора case языка Pascal

2.2 Обрезка (балансировка) длинных деревьев

2.3 Сложные случаи балансировки

или оптимизирующая балансировка

2.4 Ветвления в case-обработчиках.

Заключение

Введение

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

Программирование в машинных кодах

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

Одним из передовых продуктов для дизассемблирования программ является пакет программ от CSO Computer Services — IDA (Interactive Disassembler). IDA не является автоматическим дизассемблером. Это означает, что IDA выполняет дизассемблирование лишь тех участков программного кода, на которые имеются явные ссылки. При этом IDA старается извлечь из кода максимум информации, не делая никаких излишних предположений. После завершения предварительного анализа программы, когда все обнаруженные явные ссылки исчерпаны, IDA останавливается и ждет вмешательства; просмотрев готовые участки текста, можно как бы подсказать ей, что нужно делать дальше. После каждого вмешательства снова запускается автоматический анализатор IDA, который на основе полученных сведений пытается продолжить дизассемблирование.

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

Целью, данной работы, является задача дизассемблирования программ написанных на языке программирования C/C++ и скомпилированных на компиляторах Microsoft Visual C++ 6.0, Borland C++ 5.0 и WATCOM.

В процесс дизассемблирования входит:

1) идентификация математических операций таких как: сложение, вычитание, деление, операция вычисления остатка, умножение и определения комплексных операций;

2) Идентификация операторов SWITCH — CASE – BREAK.

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

1. Идентификация математических операторов

1.1 Идентификация оператора "+"

В общем случае оператор "+" транслируется либо в машинную инструкцию ADD, "перемалывающую" целочисленные операнды, либо в инструкцию FADDx, обрабатывающую вещественные значения. Оптимизирующие компиляторы могут заменять "ADD xxx, 1" более компактной командой "INC xxx", а конструкцию "c = a + b + const" транслировать в машинную инструкцию "LEA c, [a + b + const]". Такой трюк позволяет одним махом складывать несколько переменных, возвратив полученную сумму в любом регистре общего назначения, — не обязательно в левом слагаемом как это требует мнемоника команды ADD. Однако, "LEA" не может быть непосредственно декомпилирована в оператор "+", поскольку она используется не только для оптимизированного сложения (что, в общем-то, побочный продукт ее деятельности), но и по своему непосредственному назначению — вычислению эффективного смещения. Рассмотрим следующий пример: main(){int a, b,c;c = a + b;printf("%x\n",c);c=c+1;printf("%x\n",c); }

Демонстрация оператора "+"

Результат его компиляции компилятором Microsoft Visual C++ 6.0 с настройками по умолчанию должен выглядеть так: main proc near ; CODE XREF: start+AF p var_c = dword ptr -0Chvar_b = dword ptr -8var_a = dword ptr -4 push ebpmov ebp, esp; Открываем кадр стека sub esp, 0Ch; Резервируем память для локальных переменных mov eax, [ebp+var_a]; Загружаем в EAX значение переменной var_a add eax, [ebp+var_b]; Складываем EAX со значением переменной var_b и записываем результат в EAX mov [ebp+var_c], eax; Копируем сумму var_a и var_b в переменную var_c, следовательно:; var_c = var_a + var_b mov ecx, [ebp+var_c]push ecxpush offset asc_406030 ; "%x\n"call _printfadd esp, 8; printf("%x\n", var_c) mov edx, [ebp+var_c]; Загружаем в EDX значение переменной var_c add edx, 1; Складываем EDX со значением 0х1, записывая результат в EDX mov [ebp+var_c], edx; Обновляем var_c; var_c = var_c +1 mov eax, [ebp+var_c]push eaxpush offset asc_406034 ; "%x\n"call _printfadd esp, 8; printf("%\n",var_c) mov esp, ebppop ebp; Закрываем кадр стека retn main endp

Теперь посмотрим, как будет выглядеть тот же самый пример, скомпилированный с ключом "/Ox" (максимальная оптимизация): main proc near ; CODE XREF: start+AF ppush ecx; Резервируем место для одной локальной переменной; (компилятор посчитал, что три переменные можно ужать в одну и это дейст. так) mov eax, [esp+0]; Загружаем в EAX значение переменной var_a mov ecx, [esp+0]; Загружаем в EAX значение переменной var_b; (т.к .переменная не инициализирована загружать можно откуда угодно) push esi; Сохраняем регистр ESI в стеке lea esi, [ecx+eax]; Используем LEA для быстрого сложения ECX и EAX с последующей записью суммы; в регистр ESI; "Быстрое сложение" следует понимать не в смысле, что команда LEA выполняется; быстрее чем ADD, — количество тактов той и другой одинаково, но LEA; позволяет избавиться от создания временной переменной для сохранения; промежуточного результата сложения, сразу направляя результат в ESI; Таким образом, эта команда декомпилируется как; reg_ESI = var_a + var_b push esipush offset asc_406030 ; "%x\n"call _printf; printf("%x\n", reg_ESI) inc esi; Увеличиваем ESI на единицу; reg_ESI = reg_ESI + 1 push esipush offset asc_406034 ; "%x\n"call _printfadd esp, 10h; printf("%x\n", reg_ESI) pop esipop ecxretn main endp

Остальные компиляторы (Borland C++, WATCOM C) генерируют приблизительно идентичный код, поэтому, приводить результаты бессмысленно — никаких новых "изюминок" они в себе не несут.

Программирование в машинных кодах и ассемблере

Любая программа для ЭВМ — системная или приклад­ная — воспринимается (распознается) процессором толь­ко в том случае, если она состоит из специальных ко­манд, коды которых известны процессору определенного типа. Команды записаны в памяти компьютера в специ­альном формате. Каждая команда состоит из операционной и адресной частей. В первой из них находится позиционный двоичный код, определяющий требуемое от процессора действие (сложение, вычитание и т.д.). Во второй – адресной части команды, также в виде двоичного позиционного кода, находятся адреса данных (операндов), над которыми это действие необходи­мо выполнить, либо сами операнды. В вольном переводе на русский язык не­которую команду можно, например, интерпретировать так: сложить два числа, находящиеся в памяти по ад­ресам 100 и 120.

Разные типы ЭВМ имеют отличные друг от друга спосо­бы кодировки команд. Так, на персональных IВМ-совместимых компьютерах некоторая команда сложения в двоичном коде может иметь вид: 0000001111000011D или в шестнадцатиричном коде 03С3H . А на «древних» компью­терах типа М-220 команда сложения двух чисел могла выглядеть так:

001 00000001100100 00000001111000 00000001111011.

Поэтому программа в кодах компьютера (машинных кодах) является ма­шинно-зависимойи непереносимой,т.е. подготовленная для компьютера одного типа, она не сможет выполняться на других. Этот факт определяет основной недостаток про­граммирования в машинных кодах.

Вторым недостатком программирования в кодах явля­ется сильное дробление программы. Дело в том, что логи­чески команды процессора достаточно примитивны и обу­славливают выполнение простейших операций. Так, про­граммирование несложной формулы x=(a+b)(c+d) требо­вало задания серии команд типа:

— сложить а и b, промежуточный результат записать в ,

— сложить c и d, промежуточный результат записать в ,

умножить на , результат записать в х.

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

Однако программированию в кодах присущи и значи­тельные плюсы. Программист управляет всеми ресурсами компьютера, полностью контролирует текущее состояние ЭВМ, выбирает наиболее оптимальный код команды. Са­мые короткие по объему и наиболее быстрые по выполнению программы или их фрагменты разрабатываются и се­годня в кодах. Для облегчения наглядности программы в кодах разработаны специальные символические языки — ассемблеры. В них каждой команде компьютера сопостав­ляется определенный символьный код, являющийся со­кращением «родных» для человека слов. Специальная программа (она также называется ассемблером) переводит (транслирует)«непонятную» для компьютера (но более понятную для человека) символьную строку в коды ком­пьютера. Так, приведенные выше коды команд сложения на ассемблере могли выглядеть так: ADD АХ, BX (сло­жить числа из регистров АХ и ВХ и результат запомнить в АХ). При программировании на ассемблере программист мо­жет оперировать не с адресами памяти, в которых хра­нятся данные, а с их символическим представлением. На­пример, вначале ассемблеру специальной инструкцией со­общается, что по такому-то адресу хранится число, на­званное для программиста как .

Секреты машинного кода

Далее программист не заду­мывается над тем, по какому адресу находится соответ­ствующее число, но просто использует его имя .

Ассемблер является машинно-зависимым языком про­граммирования, так как его инструкции соответствуют кодам команд компьютера. Поэтому ассемблерная програм­ма может выполняться только на тех ЭВМ, для которых она разрабатывалась. Кроме того, для работы на ассемб­лере требуется детальное знание особенностей конкретной ЭВМ.


Дата добавления: 2016-07-18; просмотров: 1075;


Похожие статьи:

главная  программы  pe explorer  обзорный тур

Дизассемблер

Простота, ясность и удобство навигации

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

Мы попытались достичь уровня IDA Pro, при этом не требуя от пользователя специфических знаний и умений, поскольку большинство стадий процесса дизассемблирования в PE Explorer автоматизированы. Во многих случаях использование IDA Pro для быстрого анализа кода файла напоминает стрельбу из очень тяжёлой и дорогой пушки по очень маленьким воробьям. Мы же сделали просто хороший дизассемблер по очень доступной цене. И если ваша повседневная работа включает реверсинг и исследование уязвимостей программного кода, восстановление исходных кодов и поиск параметров, тестирование или изучение поведения неизвестных файлов, PE Explorer сэкономит вам немало часов и во многом упростит вашу работу.

Использование дизассемблера PE Explorer предполагает последующее редактирование полученного листинга вручную. Однако, чтобы избавить пользователя от значительного количества рутинной работы и уменьшить объём ручной правки, дизассемблер использует очень гибкий и интелектуальный алгоритм дизассемблирования, способный реконструировать ассемблерный код изучаемого исполняемого файла с высокой степенью достоверности.

Я очень впечатлён возможностями, появившимися в последней версии PE Explorer — и особенно дизассемблером.

Conrad Herrmann,
Zone Labs, Inc.

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

Gerald Beuchelt,
Sun Microsystems, Inc.

После сравнения PE Explorer с другими продуктами я полагаю, что выбрал самое лучшее предложение на рынке за свои деньги — вместо того, чтобы платить $400 за Ida Pro.

Программирование в машинных кодах и ассемблере

David Burlingame,
Intel Corporation

Отзывы пользователей

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

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

Процесс дизассемблирования

Дизассемблер запускается в своём отдельном окне, и вы можете переключаться из окна дизассемблера в основное окно PE Explorer. Дизассемблер поддерживает основные наборы инструкций Intel x86 и расширения MMX, 3D Now!, SSE, SSE2 и SSE3. В начале процесса окно Options предлагает выбрать следующие опции:

Нажатие кнопки Start Now запускает процесс, кнопка Start Later откладывает запуск.

Verify Offsets — При включении этой опции дизассемблер особо тщательно проверяет, является ли анализируемое значение смещением.

Reverse Offset Checking Order — По умолчанию, дизассемблер рассматривает необработанные данные как код, и только потом как смещения к данным. При включении этой опции дизассемблер будет рассматривать необработанные данные как данные.

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

Find ANSI and Unicode Strings — При включении этой опции дизассемблер автоматически обнаруживает текстовые ANSI и Unicode строки длиннее 3-х символов. В отдельных случаях, если результаты анализа позволяют однозначно интерпретировать данные как строку, эта длина может быть и менее 3-х символов.

Find Alignment — Поскольку доступ к выравненным данным происходит быстрее, многие компиляторы выравнивают код, добавляя лишние команды, не влияющие не ход выполнения программы, такие как nop, mov eax,eax и т.п.
При включении этой опции дизассемблер интерпретирует подобный код/данные как выравнивание.

Forcible Find Offsets — При включении этой опции дизассемблер автоматически обнаруживает смещения к данным в коде, который остался нераспознанным после первого прохода по файлу.
Используйте эту опцию с осторожностью, так как правильно определить, являются ли найденные данные смещением или фрагментами кода/данных, довольно сложно. Не рекомендуется использовать эту опцию без особых причин.

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

Окно Processing Info отображает информацию о ходе процесса дизассемблирования:

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

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

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

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

Нахождение VCL объектов и методов Delphi

Дизассемблер отображает список всех найденных VCL объектов и методов в отдельных закладках VCL Objects и VCL Methods:

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

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

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

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

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

 

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

 

 

Скриншоты программы

Скачать 30-дневную пробную версию PE Explorer    Купить лицензию

 

FILED UNDER : IT

Submit a Comment

Must be required * marked fields.

:*
:*