Почему мы не можем понять содержимое двоичного файла после компиляции?


11

Насколько я знаю, каждая программа состоит из набора инструкций процессора с некоторыми конкретными переменными данных (float, int, char ...) для работы с регистрами процессора .

Итак, первое, что я подумал об этом (давно), это то, что если вы знаете, что значение ASCII %¨#$¨#(просто случайный пример) может быть интерпретировано как адрес регистра указателя стека (просто в качестве примера) x86 процессор. Если это так, каждый раз, когда вы находите это «нечитаемое» значение при чтении содержимого двоичного файла, вы можете интерпретировать, что регистр указателя стека используется для управления некоторой переменной данных.

К сожалению, этого не происходит. Ниже приведен пример содержимого ping.exeпрограммы из Windows, открытого с помощью notepad.exe:

Ping.exe в MS Notepad

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

Так что, если я все правильно понял, может кто-нибудь объяснить

  1. Почему двоичный код не может вернуться к коду ассемблера, если он глубоко, то же самое?
  2. Если кто-то может понять ассемблерный код, почему скомпилированный двоичный код, полученный в результате этого кода, больше не «читается»?

12
Вы можете, вам просто нужен дизассемблер .
Дэвид Шварц

Так что я могу дизассемблировать любой файл .exe ??? Я просто знал, что он работает с управляемым кодом ...
Diogo

13
Вы можете разобрать любой исполняемый файл. Можете ли вы разобраться в разобранном результате - это другая история.
Дэвид Шварц

5
Компиляция или сборка удаляет много важной для человека информации, такой как имена переменных, метки веток и т. Д. Сборка получает поток инструкций, но вам еще многое предстоит выяснить.
mpez0

1
Также запутывание кода может помешать разборке.
математика

Ответы:


13

Во-первых, регистры не имеют адресов. Каждая инструкция на любом языке ассемблера переводится в код операции. Операционные коды в x86 могут быть одним, двумя, тремя или даже более байтами (в некоторых других процессорах они имеют «фиксированную ширину»). Обычно код операции определяет инструкцию, режим адресации и регистры. «Режим адресации» определяет, требуется ли ЦПУ больше, чем код операции, то есть «немедленный» режим адресации означает, что сразу после (или «сразу после») инструкции имеются дополнительные данные для этой инструкции - «абсолютные» режимы адресации означают, что адрес памяти следует за инструкцией и используется этой инструкцией.

Вы можете узнать код операции чего-то похожего MOV AL,SPили похожего, а затем найти его. В x86 есть много инструкций, которые работают с указателем стека.

Но, пожалуйста, выйдите из программы «Блокнот» и используйте вместо этого шестнадцатеричный редактор. Я бы порекомендовал HxD, хотя есть много других.

И Дэвид Шварц прав. Дизассемблер перебирает файл и переводит коды операций обратно в читаемый текст. То, что вы хотите сделать, вполне возможно.

Тем не менее, вам нужно знать, где в файле начинаются инструкции, потому что если вы начинаете с неправильного адреса, некоторые данные, которые должны быть «операндами» для кодов операций (например, инструкции, которые принимают адрес для операнда или «аргумента»), могут быть неправильно истолкованы как коды операций. Знание этого требует знания формата, в котором находится исполняемый файл, для Windows это формат «Portable Executable» или PE (и часто это ELF для систем Linux). Я уверен, что есть дизассемблеры, которые понимают PE и т. Д., Но я не знаю ничего лишнего.


1
IDA - один из наиболее распространенных PE-дисселлеров. Работает с файлами Linux и Mac тоже. Версия 5.0 все еще доступна в качестве бесплатного программного обеспечения
Скотт Чемберлен,

1
> Если вы начнете не с того адреса,… может быть неправильно истолкован. Вот почему все вхождения %¨#$¨#не обязательно будут ссылками на указатель стека; это может быть просто середина двух разных команд : _3p%¨#и $¨#b5F( _3p   %¨#$¨#   b5F).
Synetech

12

Итак, если я все правильно понял

Не совсем.

Это двоичный файл, и его данные непостижимы для нас, людей

Обычно двоичный файл непонятен человеку и машине, особенно когда цель файла неизвестна. Обратите внимание, что не все двоичные файлы являются исполняемыми файлами. Многие двоичные файлы - это файлы данных, которые не содержат никаких машинных инструкций. Вот почему расширения файлов используются при именовании файлов (в некоторых ОС). . Расширение com использовалось CP / M для обозначения исполняемого файла. . Расширение exe было добавлено MS-DOS для обозначения другого исполняемого формата файла. * nixes используют атрибут execute, чтобы указать, какие файлы могут быть выполнены, хотя это может быть как скрипт, так и код.

Как уже упоминалось другими, двоичные файлы, которые содержат числа, должны просматриваться программой hex dump или редактором hex, а не средством просмотра текста.

есть пример содержимого программы ping.exe

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

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

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

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

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

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


3

Вы не можете видеть правильную, предполагаемую кодировку двоичного файла через Блокнот. Пожалуйста, просмотрите это для дальнейшего использования. Большинство программ редактирования текста не анализируют двоичные форматы кодирования, и ожидается, что они будут анализировать форматирование кода символов ASCII.

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

Вы ошибаетесь в том, что содержимое двоичного файла невозможно понять. Несмотря на то, что они будут сложными, а в современных компьютерных архитектурах чрезвычайно трудно разобрать вручную из двоичного кода в соответствующие инструкции, распознаваемые ЦПУ для выполнения (или эмулируемый / виртуальный ЦП) и т. Д., Это можно сделать.

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.