- Как открыть машинный код
- Ломаем хаКс полностью. Читаем машинные коды как открытую книгу
- Немного теории
- Подготовка
- Первый этап: ищем динамические обёртки
- Второй этап: самые простые случаи
- Третий этап: когда между обёртками две подпрограммы
- Четвёртый этап: закрываем большие пробелы в VMT
- Методы hx.Object
- Определение типов данных полей и аргументов
- Статические поля и методы
- Чтение машинного кода exe файла
- Машинный код и компиляция в него — это как?
- 1 ответ 1
- Baremetal
- Операционная система
- А нужно ли вам это?
- Как читать / писать.exe машинный код вручную?
- 12 ответов
Как открыть машинный код
Многие любители не испытывают серьезных трудностей в овладении БЕЙСИКом. Для этого достаточно немного практики. Но рано или поздно они приходят к барьеру «машинного кода». Как это ни печально, но некоторые так перед ним и останавливаются. Это ни в коей мере не связано с отсутствием желания или способностей, просто многие не знают, с чего начать. Если в БЕЙСИКе можно начинать с чего угодно (при ошибке компьютер сам Вас поправит), то здесь Вы оказываетесь с процессором один на один, и такой метод проб и ошибок не срабатывает.
Итак, давайте напишем первую программу в машинном коде. Прежде всего, выделим для нее область памяти. Если Вы читали нашу книгу «Большие возможности Вашего «ZX-Spectrum`а», то знаете, что для БЕЙСИКа в оперативной памяти компьютера отведена область памяти, начинающаяся с адреса, на который указывает системная переменная PROG и заканчивается адресом, на который указывает системная переменная RAMTOP. Предположим, что Вы хотите записать программу в машинных кодах, начиная с адреса 30000. Дайте команду CLEAR 29999. Эта команда установит RAMTOP в 29999 и Ваша программа будет защищена от возможной порчи из БЕЙСИКа. Даже если Вы дадите команду NEW, области памяти, находящиеся выше RAMTOP, не будут поражены.
Теперь дайте две прямые команды одну за другой:
Если все, что Вы здесь прочитали, Вам понятно, то Вы уже поняли, как составляются программы в машинных кодах. Можно, конечно, возразить, что пользы от такой программы не очень много, но сейчас не в этом суть. Важно, чтобы Вы поняли, что некая последовательность чисел может быть последовательностью команд для процессора Z-80.
Теперь давайте вернемся к нашей первой программе и попробуем ее несколько развить, чтобы она все же что-то делала. Процессор Z-80 имеет несколько регистров, у которых есть имена – «А», «В», «С» и т.д. Каждый из них может содержать одно какое-либо целое число от 0 до 255 (т.е. один байт).
Существуют десятки команд процессора, которые позволяют копировать содержимое регистров из одного в другой, а также выполнять связь с внешним миром, в т.ч. и с оперативной памятью.
Итак, мы уже готовы к тому, чтобы написать программу, которая будет перебрасывать какое-либо число из одного регистра процессора в другой.
Источник
Ломаем хаКс полностью. Читаем машинные коды как открытую книгу
Если haXe оттранслирован в C++, а из него — в машинные коды, это может показаться безнадёжным, тем более, на первый взгляд этот код пестрит вызовами виртуальных методов, которые, не запуская отладчик, трудно соотнести с адресами тел методов.
Но всё не так уж плохо. Даже при отключенной поддержке сценариев (HXCPP_SCRIPTABLE) в файле можно обнаружить строки с названиями методов и полей. Разбираем, как можно размотать этот клубок, сопоставить имена методов с их адресами и смещениями в таблице виртуальных методов.
Немного теории
После трансляции в C++ все классы haXe наследуются от hx.Object (определён в hxcpp/include/hx/Object.h). Особый интерес представляют следующие методы:
Эти методы переопределяются в классах, оттранслированных в C++, и реализация их везде выглядит примерно так:
Как можно видеть, полями в понимании транслятора хаКс оказывается не только то, что обычно считается полями, но и методы тоже, правда, в динамических обёртках, из которых их ещё предстоит вытащить.
Подготовка
Соответственно, начинать стоит с того, чтобы найти метод __Field. Например, в него можно попасть по обратной ссылке на строку с именем метода. Если почитать, какие в файле есть строки, то по обратным ссылкам можно попасть, например, в __ToString или RTTI. Из них по обратной ссылке надо перейти в VMT. Если строка является именем поля, то вместо __Field можно попасть в похожий метод __SetField, который хуже подходит, так как там нет ссылок на динамические обёртки для методов. Находясь в VMT, открываем переопределённые методы (выделяются по адресам) и ищем, какие из них похожи на __Field (видно большой switch в начале):
__Field в таблице виртуальных методов идёт раньше, чем __SetField, и вариантов там обычно меньше. В данном примере 13 против 28.
Первый этап: ищем динамические обёртки
Когда найдены оба метода, нужно зайти в __Field, смотреть, куда идёт ветвление после 0 == memcmp и давать имена обёрткам. Попадаться при этом могут как обычные поля, так и обёртки. Научиться отличать их несложно, вот пример сначала обычного поля, потом динамической обёртки для метода:
Встречалась, но не в этом файле, такая проблема, что указатели на обёртки не распознаются. Выглядит это как аномально большой целочисленный операнд оранжевого цвета. Через Ctrl+R его надо в IDA сделать смещением.
Второй этап: самые простые случаи
Для начала посмотрим, как вообще после трансляции в C++ расположены методы и обёртки для них:
Видно, что идёт сначала тело метода, потом макросом конструируется динамическая обёртка, потом следующий метод, потом динамическая обёртка для него и так далее. Поскольку обёрткам имена на первом этапе дали, а собственно методам — ещё нет, в списке подпрограмм IDA должна получиться «полосатая» картина, когда именованные подпрограммы перемежаются с именованными.
Это не вполне так, но на этом этапе нужно обработать только самые очевидные случаи — когда между динамическими обёртками ровно одна подпрограмма, и, скорее всего, это и есть метод. Ему даётся имя по обёртке, которая ниже него.
Осторожно: попадались случаи, но не в этом файле, когда IDA не распознавала тело метода как подпрограмму, зато распознавала что-то вспомогательное, идущее после метода. На настоящий метод идёт обратная ссылка из VMT.
Третий этап: когда между обёртками две подпрограммы
Как можно видеть, обёрток здесь создаётся сразу две, типизированная и нетипизированная, но типизированная обычно выбрасывается транслятором C++ за ненадобностью. Если между динамическими обёртками сразу две безымянных подпрограммы, то, скорее всего, первая из них — это нужный метод, а вторая — типизированная обёртка.
К началу третьего этапа большая часть методов уже должна быть проименована, так что если смотреть из VMT, то это будут одиночные пробелы, и на данном этапе они устраняются.
Четвёртый этап: закрываем большие пробелы в VMT
Бывает, остаются большие пробелы в VMT, по два и более метода. В очередной раз можно отметить удобство взгляда из VMT. Так, если при обходе __Field упустить один метод, он будет выглядеть в списке подпрограмм IDA как три безымянные подпрограммы между динамическими обёртками, но хаКс может генерировать дополнительные подпрограммы и для других нужд, и тогда тоже может получаться три безымянные подпрограммы между динамическими обёртками.
Из VMT же видно: если пробел из двух элементов, значит, это упущенная динамическая обёртка в __Field. Находим в списке подпрограмм, где этот пробел, переходим к средней подпрограмме, это должна быть обёртка. С помощью X открываем список обратных ссылок, среди них должен быть __Field. Переходим туда, выясняем имя обёртки, пробел в списке подпрограмм «затягивается» полосой, и дальше по описанному алгоритму проставляем имена методов.
Методы hx.Object
Для полноты можно открыть hxcpp/include/hx/Object.h, выписать оттуда все виртуальные методы по порядку, и так идентифицировать методы в начале VMT.
Определение типов данных полей и аргументов
Когда у полей и аргументов вызываются методы (как и все, виртуальные), надо понять, в какой VMT их искать, а для этого надо понять, каких вообще они типов. Если не запускать отладчик, помогают это сделать динамические обёртки. На вход они получают аргументы формальных типов (Dynamic, Dynamic, Dynamic, … ) и, чтобы сделать вызов, они сначала приводят Dynamic к реальному ожидаемому методом типу. Во время этого преобразования как раз можно и узнать эти самые типы.
Например, если в теле обёртки видим:
…то видно, что делается приведение из hx.Object во что-то другое. Если hx_Obejct_ci у вас ещё не идентифицирован, то оба класса будут неизвестные, но это решаемо. Смотрим, в чей RTTI ведут указатели (в данном примере off_22D9DE0), проставляем имена, делаем выводы.
Аналогично для полей пригождается __SetField, который вынужден приводить тип от Dynamic к реальному типу поля, тем самым давая подсказку.
Статические поля и методы
Если у класса есть статические элементы, у него переопределяются статические методы __GetStatic и/или __SetStatic. В VMT их по понятным причинам не видно, но если в классе есть одновременно и статические, и обычные элементы, то в транслированном коде идут по порядку __Field, __GetStatic, __SetField, __SetStatic, так что, зная, где __Field и __SetField, можно вычислить __GetStatic и __SetStatic рядом с ними. Там так же в начале switch по длине строки, и затем операции сравнения.
Источник
Чтение машинного кода exe файла
Я пытаюсь прочитать машинный код своего консольного Win32 приложения, написанного в MS Visual Studio:
Помощь в написании контрольных, курсовых и дипломных работ здесь.
динамическое выполнение машинного кода
Есть некий набор ассемблерных команд, переведенный уже в машинный код. Нужно загнать его в память в.
Запуск машинного кода из программы
Подскажите,как запустить машинный код из программы в Delphi.Т.е имеется EXE-файл,который нужно.
Перевод из машинного кода в команду
Здравствуйте. Моя задача- перевести из машинного кода в команду. Мой пример- нужно перевести BB.
За это, спасибо, розумеется. Но чисто человеческим языком сказать лучше, что я хочу узнать. Вот есть какая та программа и мне надо посмотреть его код, и не только посмотреть но что то изменить в нем. Ну к примеру не нравиться мне мой paint или что то другое. Никак не могу добраться до исполняемого файла. Даже самым написанный екзешник не могу посмотреть. Есть конечно исходник, но если программу перенести на другой компьютер, там же не будет исходника. И если тот человек захочет посмотреть, как он должен поступить без всяких hex редакторов. Лежит же все таки где то в памяти это единство единиц и нолей. Наверное это у меня потому пройсходит, что не до конца довел изучение ассемблера.
Добавлено через 3 минуты
И еще; когда я щелкну » открыть файл: просто запускается программа.
Я для таких целей IDA Pro использую, удобно.
Источник
Машинный код и компиляция в него — это как?
1 ответ 1
Baremetal
Каждый конкретный процессор (например, Intel Core i3-4160 или ARM Cortex-A9) имеет свою микроархитектуру и реализует архитектуру уровня набора команд (англ. instruction set architecture).
Микроархитектура определяет структуру процессора на уровне электронных компонентов и логических вентилей.
Архитектура уровня набора команд (ISA), грубо говоря, определяет то, какие команды может выполнять процессор. Эта архитектура абстрагированна от микроархитектуры. Процессоры разных комнаний могут реализовывать одну и ту же архитектуру (например, многие процессоры Intel и AMD реализует одно и то же семейство архитектур x86).
Если два процессора реализуют одну и ту же ISA, то они могут исполнять одни и те же программы. ISA определяет, какие команды доступны программисту, какие регистры он может использовать, как он может использовать страничную адресацию, виртуальную память и т. д. Кроме того, она определяет формат команд, которые понимает процессор.
Каждая программа процессора — это просто набор подряд идущих команд. При своем запуске процессор выбирает команду из память по адресу, называемому вектором сброса (англ. reset vector) и начинает исполнять эту программу, пока питание не будет отключено.
Написать программу в машинных кодах достаточно просто — нужно лишь взять справочник по ISA (например, Intel 64 and IA-32 Architectures Software Developer Manuals), которую реализует ваш процессор и написать нужные команды байт за байтом.
Конечно, в наше время никто в машинных кодах не пишет, потому что человеку тяжело работать с большим объемом чисел и сложными форматами команд (особенно в x86). Из-за таких сложностей были придуманы языки ассемблера, которые вводят простые мнемоники для инструкций процессора.
Вот так может выглядет отрывок программы на языке ассемблера:
Вот так выглядит программа на машинном языке:
Очевидно, что асссемблерный код и читать, и писать проще.
Теперь у вас достаточно знаний, чтобы открыть справочник, как по словарю, написать программу в машинных кодах и исполнить ее на процессоре. Но, это не сработает в случае, если вы хотите написать программу, которая будет работать в какой-либо операционной системе.
Операционная система
Как я уже сказал, каждая программа процессора — это просто последовательность команд, однако каждая программа операционной системы — это особая последовательность байт, имеющая специальную структуру, в которую входят не только команды процессора.
Поэтому чтобы вручную написать программу в машинных кодах, которая будет запускаться в Windows 10, например, нам, по-мимо написания самой программы, потребуется привести ее к формату Portable Executable.
Но и этого будет не достаточно. Нам придется ознакомится с соглашениями, которые называются ABI и написать программу в машинных кодах, используя именно эти соглашения, а не какие-то другие.
Здесь необходимо, чтобы все части паззла подходили друг к другу по форме: программа должна быть валидной для процессора, формат бинарного файла должен быть понятен операционной системе, программа должна уметь корректно общаться с ОС и т. д. Это все очень сложно обеспечить, если писать программу в шестнадцатеричном редакторе.
Можете начать с написания программ на языке ассемблера (да, вам придется еще выучить синтаксис конкретного языка ассемблера и диалект Intel или AT&T). «Hello, World» на языке NASM будет выглядеть так:
А нужно ли вам это?
В наше время компьютеры стали очень сложными, с десятками слоями абстраций. Даже инструкции ISA современных процессоров — не атомарные сущности, и процессоры выполняет каждую такую инструкцию как набор еще более мелких инструкций — микрооперации (из таких мокроопераций складывается микрокод).
На самом деле, умение писать на языке ассемблера (а тем более, на машинном языке) довольно бесполезно. Умение просто читать и понимать ассемблерный листинг гораздо более практично и действительно может вам пригодится.
А непрактично это в первую очередь потому, что ничего сложнее «Hello, World!» в машинных кодах вы не напишете. На ассемблере — да, напишете, но потратите на это колоссальное количество времени, которое можно было бы потратить на более полезные вещи.
1. Что интересно, инструкция MOV в x86 является Тьюринг-полной, т. е. любая программа может быть написана с использованием одной только этой инструкции. Есть даже специальный компилятор, который использует только одну эту инструкцию.
2. Некоторые ассемблеры могут сразу формировать исполняемые файлы в нужном формате. В том числе и Portable Executable.
3. Я говорю о современных ОС типа Windows или Linux.
Источник
Как читать / писать.exe машинный код вручную?
Я не очень хорошо знаком с магией компилятора. Акт преобразования читаемого человеком кода (или не действительно читабельной инструкции по сборке) в машинный код, для меня, ракетостроение в сочетании с магией.
есть ли простой способ чтения машинного кода? Открывая exe как файловый поток и читая его байт за байтом, как можно превратить эти отдельные байты в сборку? Существует ли прямое отображение между этими инструкция байт а инструкция по сборке?
Как я могу понять, что происходит внутри EXE-файл?
12 ответов
OllyDbg является удивительным инструментом, который разбирает EXE в читаемые инструкции и позволяет выполнять инструкции один за другим. Он также сообщает вам, какие функции API использует программа и, если возможно, аргументы, которые она предоставляет (пока аргументы находятся в стеке).
вообще говоря, инструкции CPU имеют переменную длину, некоторые из них один байт, другие два, некоторые три, некоторые четыре и т. д. Это в основном зависит от типа данных, которые инструкция ожидает. Некоторые инструкции обобщены, например «mov», который говорит процессору переместить данные из регистра процессора в место в памяти или наоборот. На самом деле существует много различных инструкций «mov», для обработки 8-битных, 16-битных, 32-битных данных, для перемещения данных из разных регистров и так далее.
вы можете забрать доктора Пола Картера PC Assembly Language Tutorial это бесплатная книга начального уровня, которая рассказывает о сборке и о том, как Intel 386 CPU работает. Большинство из них применимо даже к современным процессорам Intel.
формат EXE специфичен для Windows. Точка входа (т. е. первая исполняемая инструкция) обычно находится в одном и том же месте в EXE-файле. Все это трудно объяснить сразу, но ресурсы, которые я предоставил, должны помочь вылечить хотя бы часть вашего любопытства! 🙂
исполняемый файл, который вы видите, имеет формат Microsofts PE (Portable Executable). Это, по сути, контейнер, который содержит некоторые данные операционной системы о программе, а сами данные программы разделены на несколько разделов. Например, код, ресурсы, статические данные хранятся в отдельных разделах.
формат раздела зависит от того, что в нем. Раздел кода содержит машинный код в соответствии с исполняемой целевой архитектурой. В наиболее распространенных случаях это является Intel x86 или AMD-64 (так же, как EM64T) для двоичных файлов Microsoft PE. Формат машинного кода-CISC и начинается с 8086 и более ранних версий. Важным аспектом CISC является то, что его размер инструкции не является постоянным, вы должны начать читать в нужном месте, чтобы получить что-то ценное из него. Intel публикует хорошие руководства по набору инструкций x86/x64.
вы можете использовать дизассемблер для просмотра машинного кода. В сочетании с руководствами вы можете угадать исходный код большую часть времени.
эти можно осмотреть с инструментом как рефлектор.
содержимое EXE-файла описано в Портативный Исполняемый Файл. Он содержит код, данные и инструкции для ОС о том, как загрузить файл.
существует сопоставление 1:1 между машинным кодом и сборкой. Программа disassembler выполнит обратную операцию.
на i386 нет фиксированного количества байтов на инструкцию. Некоторые из них представляют собой один байт, некоторые намного длиннее.
вы можете использовать debug из командной строки, но это сложно.
A пара книг, которые помогут вам понять:-
чтобы получить идею, установите точку останова на каком-то интересном коде, а затем перейдите в окно CPU.
Если вас интересует больше, проще скомпилировать короткие фрагменты со свободным Паскалем, используя параметр-al.
FPC позволяет выводить сгенерированный ассемблер во множестве форматов ассемблера (TASM,MASM,GAS ) с помощью параметра-A, и вы можете иметь исходный код pascal, чередующийся в комментариях (и более) для удобства перекрестной связи.
Я бы предложил взять немного исходного кода Windows C и построить и начать отладку в Visual Studio. Переключитесь в режим разборки и выполните команды. Вы можете увидеть, как код C был скомпилирован в машинный код, и наблюдать, как он выполняется шаг за шагом.
просто касаясь этого вопроса, кто-нибудь все еще читает такие вещи, как CD 21?
Я вспомнил Сандру Буллок в одном шоу, на самом деле читая экран, полный шестнадцатеричных чисел и выяснить, что делает программа. Что-то вроде текущей версии кода матрицы чтения.
Если Вы читаете такие вещи, как CD 21, Как вы помните различные различные комбинации?
и ваше любопытство, и ваш уровень понимания-это именно то, где я был в какой-то момент. Я!—1—>очень рекомендую код: скрытый язык компьютерного оборудования и программного обеспечения. Это не ответит на все вопросы, которые вы задаете здесь, но прольет свет на некоторые из совершенно черных магических аспектов компьютеров. Книга толстая, но читабельная.
(Я понятия не имею, что именно ACD видит так что возьмите это с большой солью, но я do известно, что некоторые программа генерируется таким образом.)
знакомство с низкоуровневой сборкой (и я имею в виду низкоуровневую сборку, а не «макросы» и этот бык), вероятно, является обязательным. Если вы действительно хотите прочитать сам исходный машинный код напрямую, обычно для этого используется шестнадцатеричный редактор. Однако, чтобы понять, что делают инструкции, большинство людей будут использовать дизассемблер для преобразования этого в соответствующие инструкции по сборке. Если вы принадлежите к меньшинству, которое хочет понять сам машинный язык, я думаю, вы захотите руководства разработчика программного обеспечения Intel® 64 и IA-32 Architectures. Раздел 2 в частности, охватывает набор инструкций, который относится к вашему запросу о том, как читать сам машинный код и как сборка относится к нему.
Источник