Почему мы не можем понять содержимое двоичного файла после компиляции?
Насколько я знаю, каждая программа состоит из набора инструкций процессора с некоторыми конкретными переменными данных (float, int, char...) для работы с регистрами процессора.
Итак, первое, что я подумал об этом (давно), это то, что если вы знаете, что значение ASCII %¨#$¨#
(просто случайный пример) может быть интерпретирован как адрес регистра указателя стека (просто в качестве примера) процессора x86. Если это так, каждый раз, когда вы находите это "нечитаемое" значение при чтении содержимого двоичного файла, вы можете интерпретировать, что регистр указателя стека используется для управления некоторой переменной данных.
К сожалению, этого не происходит. Ниже приведен пример содержания ping.exe
программа из винды открылась с notepad.exe
:
Это двоичный файл, и его данные непостижимы для нас, людей (это понятно для машин). Это не имеет никакого смысла ни для кого, даже если они знают ассемблерный код(самый низкий уровень машинного языка).
Так что, если я все правильно понял, может кто-нибудь объяснить
- Почему двоичный код не может вернуться к коду ассемблера, если он глубоко, то же самое?
- Если кто-то понимает ассемблерный код, почему скомпилированный двоичный код, полученный в результате этого кода, больше не читается?
3 ответа
Во-первых, регистры не имеют адресов. Каждая инструкция на любом языке ассемблера переводится в код операции. Операционные коды в x86 могут быть одним, двумя, тремя или даже более байтами (в некоторых других процессорах они имеют "фиксированную ширину"). Обычно код операции идентифицирует инструкцию, режим адресации и регистры. "Режим адресации" определяет, требуется ли ЦПУ больше, чем код операции, то есть "режим немедленной адресации" означает, что сразу после (или "сразу после") инструкции для этой инструкции имеются дополнительные данные - "абсолютные" режимы адресации означают, что адрес памяти следует за инструкцией и используется этой инструкцией.
Вы можете узнать код операции что-то вроде MOV AL,SP
или похожий, а затем искать его. В x86 есть много инструкций, которые работают с указателем стека.
Но, пожалуйста, выйдите из программы "Блокнот" и используйте вместо этого шестнадцатеричный редактор. Я бы порекомендовал HxD, хотя есть много других.
И @ Дэвид Шварц прав. Дизассемблер перебирает файл и переводит коды операций обратно в читаемый текст. То, что вы хотите сделать, вполне возможно.
Однако вам нужно знать, где в файле начинаются инструкции, потому что, если вы начинаете с неправильного адреса, некоторые данные, которые должны быть "операндами" для кодов операций (например, инструкции, которые принимают адрес для операнда или "аргумента"), могут быть неправильно истолкованы как коды операций. Знание этого требует знания формата, в котором находится исполняемый файл, для Windows это формат "Portable Executable" или PE (и часто это ELF для систем Linux). Я уверен, что есть дизассемблеры, которые понимают PE и т. Д., Но я не знаю ничего лишнего.
Итак, если я все правильно понял
Не совсем.
Это бинарный файл и его данные непостижимы для нас, людей
Обычно двоичный файл непонятен человеку и машине, особенно когда цель файла неизвестна. Обратите внимание, что не все двоичные файлы являются исполняемыми файлами. Многие двоичные файлы - это файлы данных, которые не содержат никаких машинных инструкций. Вот почему расширения файлов используются при именовании файлов (в некоторых ОС).. Расширениеcom использовалось CP/M для обозначения исполняемого файла.. Расширениеexe было добавлено MS-DOS для обозначения другого исполняемого формата файла. *nixes используют атрибут execute, чтобы указать, какие файлы могут быть выполнены, хотя это может быть как скрипт, так и код.
Как уже упоминалось другими, двоичные файлы, которые содержат числа, должны просматриваться программой hex dump или редактором hex, а не средством просмотра текста.
есть пример содержимого программы ping.exe
Этот файл на самом деле является перемещаемой программой, и не все данные в этом файле представляют машинный код. Здесь есть информация о программе, например, какие динамические библиотеки ей нужны, какие подпрограммы должны быть связаны, требования к стеку, памяти программ и данных, а также точка входа в программу. Операнды адреса в файле могут быть относительными значениями, которые должны быть рассчитаны до абсолютных значений, или ссылками, которые необходимо разрешить.
"Программный файл", о котором вы, вероятно, думаете, называется двоичным файлом изображения или дампом памяти программы. Такой файл будет содержать только машинный код и данные со всеми адресными ссылками, правильно установленными для выполнения.
даже если они знают код ассемблера (самый низкий уровень машинного языка.)
Язык ассемблера не совпадает с языком машин. Типичный (за исключением компьютеров с языками высокого уровня) процессор принимает машинный код в качестве ввода, по одной инструкции за раз. Операндами являются регистры или числовые адреса памяти. Язык ассемблера - это язык более высокого уровня, который может использовать символические метки для положений команд и переменных, а также заменять числовые коды операций мнемоникой. Программа на языке ассемблера должна быть преобразована в машинный язык / код, прежде чем она может быть фактически выполнена (обычно с помощью утилит, называемых ассемблером, компоновщиком и загрузчиком).
Обратная операция, дизассемблирование, может быть выполнена для программных файлов с некоторым успехом и потерей символической информации. Разборка дампа памяти или файла образа программы - это больше проб и ошибок, так как код и местоположение данных должны быть определены вручную.
Кстати, есть люди, которые могут читать и кодировать (числовой) машинный код. Конечно, это намного проще на 8-битном процессоре или микроконтроллере, чем на 32-битном процессоре CISC с дюжиной режимов адресации памяти.
Вы не можете видеть правильную, предполагаемую кодировку двоичного файла через Блокнот. Пожалуйста, просмотрите это для дальнейшего использования. Большинство программ редактирования текста не анализируют двоичные форматы кодирования, и ожидается, что они будут анализировать форматирование кода символов ASCII.
Таким образом, открытие двоичного файла в текстовом редакторе приведет к эквивалентным символам ASCII, которые не имеют никакого смысла в исходном формате двоичных данных, который анализируется текстовым редактором. Как уже упоминалось, шестнадцатеричные редакторы, а некоторые имеют двоичные функции, позволяют просматривать содержимое в чистом двоичном формате.
Вы ошибаетесь в том, что содержимое двоичного файла невозможно понять. Несмотря на то, что они будут сложными, а в современных компьютерных архитектурах чрезвычайно трудно разобрать их вручную от двоичного кода до надлежащих инструкций, распознаваемых ЦП для выполнения (или эмулируемых / виртуальных ЦП) и т. Д., Это можно сделать.
Как вы думаете, эмуляторы запрограммированы? Разработчику необходимо знать коды операций, чтобы можно было запрограммировать фиктивную систему на распознавание и поведение, как в некотором роде будет с реальным оборудованием. Документация объясняет многие архитектуры процессоров, и даже графические процессоры имеют их (хотя и более скрытно).
Следует также отметить, что на самом низком уровне, хотя и относительном, "двоичные данные" на самом деле представляют собой не группу нулей и единиц, а высокие и низкие напряжения, усиливаемые / переключаемые через электрическую цепь как ток.
Двоичный код обычно равен 1:1, поэтому имеет смысл использовать для него систему счисления.