如何手动编写和执行 Windows .exe(使用十六进制编辑器的机器代码)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11743662/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 09:45:16  来源:igfitidea点击:

How to write and executable Windows .exe manually (machine code with Hex editor)?

windowsexeexecutablemachine-code

提问by petersaints

I'd like to know how is it possible to write something as simple as an Hello World program just by using an Hex Editor. I know that I could use an assembler and assembly language to this at a near machine level but I just want to experiment with really writing machine code in a toy example such as Hello World.

我想知道如何仅使用十六进制编辑器来编写像 Hello World 程序这样简单的东西。我知道我可以在接近机器级别使用汇编程序和汇编语言,但我只想尝试在诸如 Hello World 之类的玩具示例中真正编写机器代码。

This could be a simple DOS .COM file that I can run on DOSBox. But it would be nice if someone could provide an example for an .EXE file for running it directly on my Windows PC.

这可能是一个简单的 DOS .COM 文件,我可以在 DOSBox 上运行它。但如果有人可以提供一个 .EXE 文件的示例,以便直接在我的 Windows PC 上运行它,那就太好了。

This is just pure curiosity. No... I'm not thinking of writing programs directly in binary machine code (I don't even usually write assembly code, I just use C/C++ as my most low level tools most of the time). I just want to see if that's possible to do it, because probably someone had to do it in the very early days of computers.

这只是纯粹的好奇。不...我不想直接用二进制机器代码编写程序(我什至通常不编写汇编代码,我大部分时间只是使用 C/C++ 作为我最底层的工具)。我只是想看看这是否有可能做到,因为可能有人在计算机的早期就不得不这样做。

P.S.: I know that there are similar questions about this topic around but none provide a working example. I just want a simple example so that it can help me understand how compilers and assemblers generate an executable file. I mean... someone must have done this by hand in the past for the very first programs. Also, for the Windows EXE format there must have been someone at Microsoft that wrote the first tools to generate the format and the way that Windows itself reads it and then executes it.

PS:我知道关于这个话题有类似的问题,但没有一个提供一个有效的例子。我只想要一个简单的例子,它可以帮助我理解编译器和汇编器如何生成可执行文件。我的意思是……在过去的第一个程序中,一定有人手工完成了这项工作。此外,对于 Windows EXE 格式,Microsoft 中一定有人编写了第一个工具来生成格式以及 Windows 本身读取它然后执行它的方式。

回答by harold

There's a quite minimalistic but fully working (on Win7, too) exe on corkami/wiki/PE101, every byte of it is explained in the nice graphic. You can type it all by hand in a hex editor, but the paddings may make that a little tedious.

corkami/wiki/PE101上有一个非常简约但完全可用(也在 Win7 上)的 exe ,它的每个字节都在漂亮的图形中进行了解释。您可以在十六进制编辑器中手动输入所有内容,但填充可能会使这有点乏味。

As for the history, yes someone at Microsoft invented the exe format (the old DOS MZ exe format) and he (or someone else at Microsoft) wrote a loader for it and a linker, which is the thing that traditionally turns the output of a compiler ("object files") into executable files. It's possible (and even likely, I would say) that the first exe programs were written by hand, after all they were only meant to test the new loader.

至于历史,是的,微软的某个人发明了 exe 格式(旧的 DOS MZ exe 格式),他(或微软的其他人)为它编写了一个加载程序和一个链接器,这是传统上转换输出的东西编译器(“目标文件”)转换为可执行文件。有可能(甚至可能,我会说)第一个 exe 程序是手工编写的,毕竟它们只是为了测试新的加载程序。

Later, AT&T's COFF format was extended by Microsoft to the PE format, which still has the MZ header and typically (but optionally, it's not in the corkami example, and it can be anything really) includes a small DOS program just to print the message "This program cannot be run in DOS mode".

后来,AT&T 的 COFF 格式被微软扩展为 PE 格式,它仍然具有 MZ 标头,并且通常(但可选地,它不在 corkami 示例中,它可以是任何东西)包括一个小的 DOS 程序,只是为了打印消息“此程序无法在 DOS 模式下运行”。

回答by old_timer

1) a .com file is the simplest place to start and will run on a dosbox, basically the program starts at something like offset 0x100 in the file, I think the first 0x100 can be whatever, dont remember

1) .com 文件是最简单的开始位置,将在 dosbox 上运行,基本上程序从文件中的偏移量 0x100 开始,我认为第一个 0x100 可以是任何东西,不记得了

2) although true that first programs are often written and assembled by hand into machine code, we are talking about when you add two numbers save them in memory and are so happy that you take the rest of the day off. a "hello world" program that prints stuff to a video card is significantly more complicated. Now you can make a very simple one using dos system calls, and perhaps that is not what you are interested in, perhaps it is.

2) 虽然第一个程序通常是手工编写和组装成机器代码的,但我们谈论的是当您将两个数字相加时,将它们保存在内存中,并且很高兴您可以休息一天的剩余时间。将内容打印到视频卡的“hello world”程序要复杂得多。现在你可以使用 dos 系统调用来做一个非常简单的,也许这不是你感兴趣的,也许它是。

3) based on 2, anything more complicated than one or a few instructions at a time for testing back in the 1960s or 1970s, even when writing hand assembling a program you write your program in assembler by hand, then assemble it to machine code, then load it. Basically learn assembly language first, then learn how to generate the machine code for it, then start typing those bytes into a hex editor. It is not then 1960s, unless you enjoy excessive pain, learn the above by writing asm, using an assembler to generate the machine code, then use a disassembler to disassemble it and examine the assembly language and the machine code side by side to significantly improve the amount of time it is going to take you to get a working program. If you worked for a chip company before there were operating systems and instruction sets, you would still take advantage of other members of the team, the chip designers, etc for understanding how to make the machine code and arrange it. You wouldnt be coming at this with only high level language experience and doing it all on your own with a hope of success.

3) 基于 2,任何比在 1960 年代或 1970 年代测试时一次一条或几条指令更复杂的东西,即使在编写手工汇编程序时,您也可以手工在汇编程序中编写程序,然后将其汇编为机器代码,然后加载它。基本上先学习汇编语言,然后学习如何为其生成机器代码,然后开始将这些字节输入到十六进制编辑器中。现在不是1960年代了,除非你过分的痛苦,通过写asm学习上面的,用汇编器生成机器码,然后用反汇编器反汇编它,并排检查汇编语言和机器码,显着提高您获得一个有效程序所需的时间。如果你在有操作系统和指令集之前就在一家芯片公司工作,您仍然可以利用团队的其他成员、芯片设计人员等来了解如何制作机器代码和安排它。您不会只拥有高级语言经验并带着成功的希望独自完成这一切。

4) x86 is a horrible instruction set, if you dont know assembly I strongly discourage you to not learn it first. having an x86 is the worst excuse I have heard to learn x86 first. you already mentioned dosbox so are already planning to emulate/simulate so use a good instruction set and simulate it or buy that hardware (under $50 even under $20 will buy you a board with a much better instruction sets). I recommend simulate/emulate first and in parallel with the hardware if you choose to buy some. If you really want an education write your own simulator it is not difficult at all. Perhaps invent your own instruction set.

4) x86 是一个可怕的指令集,如果你不知道汇编,我强烈建议你不要先学习它。有一个 x86 是我听说过的最糟糕的借口,首先学习 x86。您已经提到了 dosbox,因此已经计划进行模拟/模拟,因此请使用良好的指令集并对其进行模拟或购买该硬件(低于 50 美元甚至低于 20 美元将为您购买具有更好指令集的板)。如果您选择购买一些,我建议首先模拟/仿真并与硬件并行。如果你真的想接受教育,编写自己的模拟器并不难。也许发明你自己的指令集。

5) none of this will help you understand what a compiler does. Knowing assembly language then disassembling the compilers output is your best path toward that knowledge, machine code is not involved, no need to actually run the programs. A compiler goes from the higher level language to a lower level language (C to asm or C++ to asm for example). Then understand what an assembler does, there are many different solutions, both due to history and due to other reasons. The typical solution today is a separate compiler, assembler and linker (your compiler calls the assembler and linker for you unless you tell it not to, the three steps are hidden from view, in fact the compile process may be more than one program that is run to complete that task). Assemblers that output a binary will have to resolve the whole program, assemblers that output to an object will leave holes in the machine code for the linker to fill in. things like branching or calling items in another object that it cannot encode until the linker places things in the binary and knows the spacing/addressing. Also accessing variables that live in other objects.

5)这些都不会帮助您理解编译器的作用。了解汇编语言然后反汇编编译器输出是获得该知识的最佳途径,不涉及机器代码,无需实际运行程序。编译器从高级语言到低级语言(例如,C 到 asm 或 C++ 到 asm)。然后了解汇编程序是做什么的,由于历史原因和其他原因,有许多不同的解决方案。今天典型的解决方案是一个单独的编译器、汇编器和链接器(你的编译器会为你调用汇编器和链接器,除非你告诉它不要,这三个步骤是隐藏的,实际上编译过程可能不止一个程序运行以完成该任务)。输出二进制文件的汇编程序必须解析整个程序,输出到对象的汇编器会在机器代码中留下漏洞供链接器填充。诸如分支或调用另一个对象中的项目之类的东西,在链接器将内容放入二进制文件并知道间距/寻址之前,它无法编码。还访问存在于其他对象中的变量。

You are likely not seeing actual examples on hex editing a program because first off it is such a broad question there isnt a simple answer (what operating, system, what system calls or are you creating those, what file format, what hex editor, etc). Also because it is a high level question and problem, the real questions are where do I learn assembly, where do I learn about the relationship between assembly and machine code, where do I learn about system calls (which are not an assembly question, they are unrelated to learning asm, you learn assembly language itself then you learn to USE it as a tool to perform system calls if you cannot perform the system calls directly using a higher language), where do I learn about executable file formats like .com, .exe, coff, elf, etc. What is a good or easy or some adjective, hex editor that runs on xyz operating system or environment. Ask those questions separately and you will find the answers and examples and once you have those answers you will know how to make a program using a hex editor typing in machine code. A shorter example is that you ARE seeing hex examples of complete programs when you see the disassembly of a program posted at SO, some of those are complete programs shown in hex. and if you know the file format you can simply type that stuff into a hex editor.

您可能没有看到有关十六进制编辑程序的实际示例,因为首先它是一个如此广泛的问题,没有简单的答案(什么操作系统、系统、什么系统调用或您正在创建这些、什么文件格式、什么十六进制编辑器等) )。也因为是一个高层次的问题和问题,真正的问题是我在哪里学习汇编,我在哪里学习汇编和机器代码之间的关系,我在哪里学习系统调用(这些不是汇编问题,他们与学习 asm 无关,你学习汇编语言本身,然后你学会将它用作执行系统调用的工具,如果你不能直接使用高级语言执行系统调用),我在哪里学习可执行文件格式,如 .com, .exe、coff、elf等什么是good或者easy或者一些形容词,在 xyz 操作系统或环境上运行的十六进制编辑器。单独提出这些问题,您将找到答案和示例,一旦您有了这些答案,您就会知道如何使用十六进制编辑器输入机器代码来编写程序。一个较短的例子是,当您看到在 SO 上发布的程序的反汇编时,您正在看到完整程序的十六进制示例,其中一些是以十六进制显示的完整程序。如果您知道文件格式,您可以简单地将这些内容输入到十六进制编辑器中。其中一些是以十六进制显示的完整程序。如果您知道文件格式,您可以简单地将这些内容输入到十六进制编辑器中。其中一些是以十六进制显示的完整程序。如果您知道文件格式,您可以简单地将这些内容输入到十六进制编辑器中。

回答by Ange

I make binaries by hand, but I think it's easier in assembly itself than a pure hex editor, where updating anything would be difficult.

我手工制作二进制文件,但我认为汇编本身比纯十六进制编辑器更容易,在纯十六进制编辑器中更新任何东西都很困难。

  • The easiest is surely DOS COM format, which you can even type in notepad, or at least, it's very easy even for a normal Hello World.

  • The EXE (non DOS format) doesn't require much either see here.

  • If you're trying to make a PE, you can make a TinyPE.

  • 最简单的肯定是 DOS COM 格式,您甚至可以在记事本中输入它,或者至少,即使对于普通的Hello World也很容易。

  • EXE(非 DOS 格式)不需要太多,请参见此处

  • 如果您正在尝试制作 PE,则可以制作TinyPE

Most binaries should be available as PE, and EXE and COM.

大多数二进制文件应以PEEXE 和 COM 形式提供

回答by Charlie Rudenst?l

Not spot on, but this tutorial should give you a better insight into how assembly maps to machinde code (x86 ELF): http://timelessname.com/elfbin/(especially look at the lower half of the page)

不正确,但本教程应该让您更好地了解程序集如何映射到机器代码(x86 ELF):http://timelessname.com/elfbin/ (特别是查看页面的下半部分)

This page is [...] about my attempts at creating the smallest x86 ELF binary that would execute saying Hello World on Ubuntu Linux My first attempts started with C then progressed to x86 assembly and finally to a hexeditor.

这个页面是 [...] 关于我尝试创建最小的 x86 ELF 二进制文件,该二进制文件将在 Ubuntu Linux 上执行 Hello World 我的第一次尝试从 C 开始,然后进展到 x86 程序集,最后到一个十六进制编辑器。

It's great to analyze really small executables like these because the mapping between assembly and machine code will be easier to spot. This is also a really interesting article on the subject (not exactly related to your question though): http://www.phreedom.org/research/tinype/(x86 PE)

分析像这样非常小的可执行文件非常好,因为汇编代码和机器代码之间的映射将更容易被发现。这也是一篇关于该主题的非常有趣的文章(尽管与您的问题并不完全相关):http: //www.phreedom.org/research/tinype/(x86 PE)

回答by Skullquake

you can do a disassembly and try figure out the machine code for the opcodes you use in your assembler

您可以进行反汇编并尝试找出您在汇编程序中使用的操作码的机器代码

for example

例如

org 0x100
mov dx,msg
mov ah,0x09
int 0x21
ret
msg db 'hello$'

compiled with nasm -fbin ./a.asm -o ./a.com has ndisasm a.com deliver the following disassembly:

使用 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

so you can play with the ba0801 machine code, using some hex editor, try changing it to ba0901, and only 'ello' will be printed, you can play around with your hex editor and pad stuff out with NOP, which is 0x90 in machine code, for example:

所以你可以使用 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:  -- -- -- -- -- -- -- --  -- -- -- -- -- -- -- --  ----------------

if you save this with the extension .com you can run it in DosBox

如果您使用扩展名 .com 保存它,您可以在 DosBox 中运行它

回答by Colin Ord

I wrote an article on creating executable DOS binary files just by using the ECHO at the command prompt. No other 3rd party HEX utilities or x86 IDEs required!

我写了一篇关于仅在命令提示符下使用 ECHO 创建可执行 DOS 二进制文件的文章。不需要其他第 3 方 HEX 实用程序或 x86 IDE!

The technique uses a a combination of keypad - ALT ASCII codes which convert OPCODES to a binary format readable directly under MSDOS. The output is a fully runnable binary *.com file.

该技术使用键盘 - ALT ASCII 代码的组合,将 OPCODES 转换为可直接在 MSDOS 下读取的二进制格式。输出是一个完全可运行的二进制 *.com 文件。

http://colinord.blogspot.co.uk/2015/02/extreme-programming-hand-coded.html

http://colinord.blogspot.co.uk/2015/02/extreme-programming-hand-coded.html

Excerpt:Type the following key commands at the DOS prompt remembering to hold Left ALT.

摘录:在 DOS 提示符下键入以下键命令并记住按住 Left ALT。

c:\>Echo LALT-178 LALT-36 LALT-180 LALT-2 LALT-205 LALT-33 LALT-205 LALT-32 > $.com

The codes above are actually opcode values describing an X86 assembly program to print a dollar sign to the screen.

上面的代码实际上是描述 X86 汇编程序在屏幕上打印美元符号的操作码值。

Your prompt should look something similar below when finished. Press enter to build!

完成后,您的提示应如下所示。按回车键构建!

c:\>Echo ▓$┤?═!═  > $.com

Run the file '$.com' and you will see a single dollar ($) character displayed on the screen.

运行文件“$.com”,您将看到屏幕上显示一个美元 ($) 字符。

c:\>$.com
$
c:\> 

Congratulations! You just created your first hand coded executable file called $.com.

恭喜!您刚刚创建了名为 $.com 的第一手编码可执行文件。