Как написать и выполнить исполняемый файл Windows .exe вручную (машинный код с шестнадцатеричным редактором)?
Я хотел бы знать, как можно написать что-то столь же простое, как программа Hello World, используя Hex Editor. Я знаю, что мог бы использовать ассемблер и язык ассемблера для этого на почти машинном уровне, но я просто хочу поэкспериментировать с действительно написанием машинного кода в игрушечном примере, таком как Hello World.
Это может быть простой файл DOS .COM, который я могу запустить на DOSBox. Но было бы неплохо, если бы кто-нибудь мог предоставить пример для.EXE-файла для запуска его непосредственно на моем ПК с Windows.
Это просто чистое любопытство. Нет... Я не думаю о написании программ непосредственно в двоичном машинном коде (я даже обычно не пишу ассемблерный код, я просто использую C/C++ в качестве моих самых низкоуровневых инструментов большую часть времени). Я просто хочу посмотреть, возможно ли это сделать, потому что, возможно, кто-то должен был сделать это в самые ранние времена компьютеров.
PS: я знаю, что есть похожие вопросы по этой теме, но ни один не дает рабочего примера. Я просто хочу простой пример, чтобы он мог помочь мне понять, как компиляторы и ассемблеры генерируют исполняемый файл. Я имею в виду... кто-то должен был сделать это вручную в прошлом для самых первых программ. Кроме того, для формата Windows EXE в Microsoft должен был быть кто-то, кто написал первые инструменты для генерации формата и способа, которым Windows сама читает его, а затем выполняет его.
6 ответов
На corkami / wiki / PE101 есть довольно минималистичный, но полностью работающий (тоже на Win7) exe, каждый байт которого объясняется в симпатичной графике. Вы можете напечатать все это вручную в шестнадцатеричном редакторе, но отступы могут сделать это немного утомительным.
Что касается истории, да, кто-то в Microsoft изобрел формат exe (старый формат exe DOS MZ), и он (или кто-то еще в Microsoft) написал для него загрузчик и компоновщик, который традиционно превращает вывод компилятор ("объектные файлы") в исполняемые файлы. Возможно (и даже вероятно, я бы сказал), что первые исполняемые программы были написаны от руки, в конце концов, они предназначались только для тестирования нового загрузчика.
Позже формат AT&T COFF был расширен Microsoft для формата PE, который по-прежнему имеет заголовок MZ и, как правило (но, необязательно, его нет в примере corkami, а может быть что угодно), включает в себя небольшую DOS-программу для печати сообщения. Msgstr "Эту программу нельзя запустить в режиме DOS".
1).com файл - это самое простое место для запуска, и он запускается на dosbox, в основном программа запускается со смещением 0x100 в файле, я думаю, что первый 0x100 может быть любым, не помню
2) хотя верно то, что первые программы часто пишутся и собираются вручную в машинный код, мы говорим о том, что когда вы добавляете два числа, сохраняете их в памяти и так счастливы, что взяли остаток дня. Программа "Привет, мир", которая печатает материал на видеокарту, значительно сложнее. Теперь вы можете сделать очень простой, используя системные вызовы dos, и, возможно, это не то, что вас интересует, возможно, это так.
3) на основе 2 - что-нибудь более сложное, чем одна или несколько инструкций за раз для тестирования еще в 1960-х или 1970-х годах, даже когда вы пишете ручную сборку программы, вы пишете свою программу на ассемблере вручную, а затем собираете ее в машинный код, затем загрузите его. Сначала изучите ассемблер, затем научитесь генерировать машинный код для него, затем начните вводить эти байты в шестнадцатеричный редактор. Это не 1960-е годы, если вы не испытываете чрезмерную боль, изучите вышесказанное, написав asm, используя ассемблер для генерации машинного кода, затем используйте дизассемблер для его разборки и изучите язык ассемблера и машинный код рядом, чтобы значительно улучшить количество времени, которое потребуется вам, чтобы получить рабочую программу. Если бы вы работали в компании по производству микросхем до того, как появились операционные системы и наборы инструкций, вы бы все равно воспользовались преимуществами других членов команды, разработчиков микросхем и т. Д. Для понимания того, как создать машинный код и организовать его. Вы бы не пришли к этому только с языковым опытом высокого уровня и делали бы все это самостоятельно с надеждой на успех.
4) x86 - ужасный набор инструкций, если вы не знаете сборки, я настоятельно рекомендую вам не изучать его в первую очередь. наличие x86 - худшее оправдание, которое я слышал, чтобы сначала изучить x86. Вы уже упоминали о DOSBox, поэтому уже планируете имитировать / имитировать, поэтому используйте хороший набор инструкций и имитируйте его или купите это оборудование (менее чем за 50 долларов, даже менее, чем за 20 долларов вы купите доску с намного лучшими наборами инструкций). Я рекомендую моделировать / эмулировать сначала и параллельно с оборудованием, если вы решите купить его. Если вы действительно хотите получить образование, напишите свой собственный симулятор, это совсем не сложно. Возможно, придумайте свой собственный набор инструкций.
5) У меня есть коллекция симуляторов и других "голых железных" ресурсов: http://github.com/dwelch67 msp430 неплох, вы можете приобрести оборудование менее чем за 5 долларов, если почувствуете необходимость. Arm хорош, как на основе 32/16 (Raspberry Pi, sam7s и т. Д.), Так и на основе 16-битного большого пальца (на основе cortex-m, mbed, maple mini, stm32f4 discovery и т. Д.). Имитатор янтаря происходит от процессора opencores, который я симулирую с помощью verilator, так что вы можете, если захотите, заглянуть внутрь процессора, чтобы увидеть, что происходит на уровне сигнала. thumbulator не требует ничего, кроме компилятора a c/ C++, чтобы его запустить и запустить, в "двоичном" формате файлов вы можете ввести "машинный код" в шестнадцатеричном формате и просто пойти на это, с помощью шестнадцатеричного редактора вы все равно это сделаете. У меня есть несколько симуляторов наборов инструкций на выбор, а также примеры голого металла, встроенного в некоторые платы, стоимостью от 5 до 80 долларов.
6) ничего из этого не поможет вам понять, что делает компилятор. Знание языка ассемблера, а затем дизассемблирование выходных данных компилятора - ваш лучший путь к этим знаниям, машинный код не задействован, нет необходимости фактически запускать программы. Компилятор переходит с языка более высокого уровня на язык более низкого уровня (например, C на asm или C++ на asm). Тогда поймите, что делает ассемблер, есть много разных решений, как из-за истории, так и по другим причинам. Типичное решение сегодня - это отдельный компилятор, ассемблер и компоновщик (ваш компилятор вызывает ассемблер и компоновщик для вас, если вы не скажете этого, три шага скрыты от глаз, фактически процесс компиляции может состоять из нескольких программ, которые запустить, чтобы завершить эту задачу). Ассемблеры, которые выводят двоичный файл, должны будут обрабатывать всю программу, а ассемблеры, которые выводят объект, оставят дырки в машинном коде для заполнения компоновщиком. Такие вещи, как ветвление или вызов элементов в другом объекте, который он не может кодировать, пока компоновщик не разместит вещи в двоичном и знает интервал / адресацию. Также доступ к переменным, которые живут в других объектах.
Вы, вероятно, не видите реальных примеров шестнадцатеричного редактирования программы, потому что, во-первых, это такой широкий вопрос, что нет простого ответа (какая операционная система, какие системные вызовы или вы их создаете, какой формат файла, какой шестнадцатеричный редактор и т. Д.). Кроме того, поскольку это вопрос и проблема высокого уровня, реальные вопросы заключаются в том, где я изучаю сборку, где я узнаю о взаимосвязи между сборкой и машинным кодом, где я узнаю о системных вызовах (которые не являются вопросом сборки, они не связаны с изучением asm, вы изучаете сам ассемблер, затем вы учитесь использовать его как инструмент для выполнения системных вызовов, если вы не можете выполнять системные вызовы напрямую, используя более высокий язык), где я узнаю о форматах исполняемых файлов, таких как.com, .exe, coff, elf и т. д. Что такое хороший или простой или какой-то прилагательный, hex-редактор, работающий в операционной системе или среде xyz. Задайте эти вопросы отдельно, и вы найдете ответы и примеры, и, как только у вас появятся эти ответы, вы узнаете, как создать программу, используя шестнадцатеричный редактор, набирающий машинный код. Более короткий пример - вы видите шестнадцатеричные примеры завершенных программ, когда видите разборку программы, размещенной в SO, некоторые из них представляют собой полные программы, показанные в шестнадцатеричном формате. и если вы знаете формат файла, вы можете просто напечатать этот материал в шестнадцатеричном редакторе.
Я делаю двоичные файлы вручную, но я думаю, что в самой сборке проще, чем в чистом шестнадцатеричном редакторе, где обновление чего-либо будет затруднительным.
Самым простым является, безусловно, формат DOS COM, который вы можете даже ввести в блокноте, или, по крайней мере, он очень прост даже для обычного Hello World.
EXE (не в формате DOS) не требует много, смотрите здесь.
Если вы пытаетесь сделать PE, вы можете сделать TinyPE.
Большинство двоичных файлов должны быть доступны как PE, так и EXE и COM.
Не на месте, но этот урок должен дать вам лучшее представление о том, как сборка отображается в коде машинного кода (x86 ELF): http://timelessname.com/elfbin/ (особенно посмотрите на нижнюю половину страницы)
Эта страница [...] посвящена моим попыткам создать наименьший двоичный файл ELF x86, который будет исполнен со словами Hello World в Ubuntu Linux. Мои первые попытки начались с C, затем перешли к сборке x86 и, наконец, к гекседитору.
Замечательно анализировать действительно маленькие исполняемые файлы, подобные этим, потому что сопоставление между сборкой и машинным кодом будет легче обнаружить. Это также действительно интересная статья на эту тему (хотя она не совсем связана с вашим вопросом): http://www.phreedom.org/research/tinype/ (x86 PE)
Я написал статью о создании исполняемых двоичных файлов DOS, просто используя ECHO в командной строке. Никакие другие сторонние утилиты HEX или x86 IDE не требуются!
В этом методе используется комбинация кодов клавиатуры - ALT ASCII, которые преобразуют OPCODES в двоичный формат, читаемый непосредственно под MSDOS. Выходные данные - это полностью исполняемый двоичный файл *.com.
http://colinord.blogspot.co.uk/2015/02/extreme-programming-hand-coded.html
Выдержка: Введите следующие ключевые команды в командной строке DOS, не забывая удерживать левую клавишу ALT.
c:\>Echo LALT-178 LALT-36 LALT-180 LALT-2 LALT-205 LALT-33 LALT-205 LALT-32 > $.com
Приведенные выше коды на самом деле являются значениями кода операции, описывающими программу сборки X86 для вывода знака доллара на экран.
Ваша подсказка должна выглядеть примерно так, как показано ниже. Нажмите Enter, чтобы построить!
c:\>Echo ▓$┤☻═!═ > $.com
Запустите файл '$.com', и вы увидите один символ доллара ($), отображаемый на экране.
c:\>$.com
$
c:\>
Поздравляем! Вы только что создали свой исполняемый файл из первых рук с именем $.com.
Вы можете выполнить разборку и попытаться выяснить машинный код для кодов операций, которые вы используете в ассемблере.
например
org 0x100
mov dx,msg
mov ah,0x09
int 0x21
ret
msg db 'hello$'
скомпилировано с помощью nasm -fbin ./a.asm -o ./a.com и ndisasm a.com выполнит следующую разборку:
00000000 BA0801 mov dx,0x108
00000003 B409 mov ah,0x9
00000005 CD21 int 0x21
00000007 C3 ret
00000008 68656C push word 0x6c65
0000000B 6C insb
0000000C 6F outsw
0000000D 24 db 0x24
00000000 to 00000007 are the instructions
так что вы можете поиграть с машинным кодом ba0801, используя какой-нибудь шестнадцатеричный редактор, попробуйте изменить его на ba0901, и будет напечатан только "ello", вы можете поиграть с вашим шестнадцатеричным редактором и дополнить NOP, который в машине равен 0x90 код, например:
00000000: ba 50 01 90 90 90 90 90 90 90 90 90 90 90 90 90 .@..............
00000010: b4 09 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
00000020: cd 21 90 90 90 90 90 90 90 90 90 90 90 90 90 90 .!..............
00000030: c3 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
00000040: 71 77 65 72 74 79 75 69 61 73 64 66 67 68 6a 24 qwertyuiasdfghj$
00000050: 61 73 64 66 67 68 6a 6b 61 73 64 66 67 68 6a 24 asdfghjkasdfghj$
00000060: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ----------------
если вы сохраните это с расширением.com, вы можете запустить его в DosBox