在 Notepad++ 和 Sublime Text 3 中打开一个简单的 .exe 文件会产生非常不同的结果

Mis*_*esh -5 c assembly notepad++ machine-code sublimetext3

我使用 GCC 为 Windows 10 (mingw-64) 编译了以下 C 代码:

#include <stdio.h>
int main(){
    printf("Hello World!");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

用命令

gcc.exe -o 测试 test.c

它有效是因为当我执行生成的文件时,我确实得到了一个 Hello World!在控制台中,但是我很惊讶,因为当我在记事本 ++ 中打开 test.exe 时,它​​有 220 行长,其中包含一些可读文本,例如

地址 %p 没有图像部分 VirtualQuery 在地址 %p 处失败了 %d 个字节

并且

未知的伪重定位协议版本 %d。未知的伪重定位位大小 %d。

然而,当我在 Sublime Text 3 中打开同一个文件时,我得到了超过 3300 行的一些看似随机的数字和字母,例如:

4d5a 9000 0300 0000 0400 0000 ffff 0000
b800 0000 0000 0000 4000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 8000 0000
0e1f ba0e 00b4 09cd 21b8 014c cd21 5468
6973 2070 726f 6772 616d 2063 616e 6e6f
7420 6265 2072 756e 2069 6e20 444f 5320
6d6f 6465 2e0d 0d0a 2400 0000 0000 0000
5045 0000 6486 0f00 5aca 455d 0068 0000
9304 0000 f000 2700 0b02 021e 001e 0000
0038 0000 000a 0000 e014 0000 0010 0000
0000 4000 0000 0000 0010 0000 0002 0000
0400 0000 0000 0000 0500 0200 0000 0000
0020 0100 0004 0000 0e3e 0100 0300 0000
0000 2000 0000 0000 0010 0000 0000 0000
0000 1000 0000 0000 0010 0000 0000 0000
0000 0000 1000 0000 0000 0000 0000 0000
0080 0000 6c07 0000 0000 0000 0000 0000
0050 0000 7002 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
Run Code Online (Sandbox Code Playgroud)

我还尝试获取汇编版本,这在记事本和 sublime 中是相同的:

    .file   "test.c"
    .text
    .def    __main; .scl    2;  .type   32; .endef
    .section .rdata,"dr"
.LC0:
    .ascii "Hello World!\0"
    .section    .text.startup,"x"
    .p2align 4,,15
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    subq    $40, %rsp    #,
    .seh_stackalloc 40
    .seh_endprologue
 # test.c:2: int main(){
    call    __main   #
 # test.c:3:    printf("Hello World!");
    leaq    .LC0(%rip), %rcx     #,
    call    printf   #
 # test.c:5: }
    xorl    %eax, %eax   #
    addq    $40, %rsp    #,
    ret 
    .seh_endproc
    .ident  "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"
    .def    printf; .scl    2;  .type   32; .endef
Run Code Online (Sandbox Code Playgroud)

第一个问题:

为什么 sublime text 和记事本的输出不同?

第二个问题:

0 和 1 在哪里,我以为机器码只有 0 和 1?

第三个问题:

为什么它只是一个简单的 hello world 的 3300 行,这听起来效率很低吗?

感谢您的任何见解!

Ste*_*mit 5

一个.exe文件是一个二进制文件。其中大部分是不可打印的、非人类可读的字节。所以你的问题实际上归结为,为什么这两个文本编辑器用一个非文本文件做两种不同的事情,它们甚至不是设计用来操作的?

埋在二进制文件中的可能是一些人类可读的字符串。首先,二进制文件中的一些字节将偶然出现在可打印集中。此外,包含诸如“无法打开文件”之类的文本字符串的计算机程序通常最终会包含这些字符串,字面意思是嵌入在其二进制文件中。

通常,文本编辑器将二进制文件显示为垃圾。通常,它显示它知道的那些可打印字符,与不可打印字符的“有趣”表示不加区分地混合在一起。(至少在 Windows 平台上,使用映射到旧的 MS-DOS 字符集来显示非打印字符并不少见,旧的 MS-DOS 字符集确实在许多不可打印的位置具有特殊的图形字符。)看起来这就是记事本是在做。

看起来 Sublime 注意到文件是二进制的,并将其中的每个字节都转换为十六进制。这意味着您不能立即看到打印字符,但您可以并排看到所有字符(可打印和不可打印)(以十六进制形式)。

为了更清楚地说明这一点,让我们看一个稍微不同的案例。考虑这个程序:

#include <stdio.h>

int main()
{
    char binary[] = "\1\2\3Hello\4\5\6World\x1E\x1F\x20\x21";
    fwrite(binary, 1, sizeof(binary), stdout);
}
Run Code Online (Sandbox Code Playgroud)

该程序将文本和二进制字符的混合打印到其标准输出。如果你编译并运行这个程序并将它的输出重定向到一个文件,你最终会得到一个混合了文本和二进制字符的文件,就像(在这方面)你的.exe文件一样。

如果我在正常环境中打印这个程序的输出,我会得到:

HelloWorld !
Run Code Online (Sandbox Code Playgroud)

我们可以看到可打印的字符串HelloWorld正如我们所期望的那样,以及一个我们可能没有预料到的!字符。在我的正常环境中,无法打印的字符根本不打印。

如果我在 MS-DOS 环境中打印这个程序的输出(正如我所提到的,很多理论上“不可打印”的字符确实有图形表示),我们可能会看到类似

???Hello???World?? !
Run Code Online (Sandbox Code Playgroud)

如果我通过一个将每个字节转换为其十六进制表示的程序运行这个程序,我得到

01020348656C6C6F040506576f726C641E1F202100
Run Code Online (Sandbox Code Playgroud)

让我们仔细看看这个。它以 hex 开头010203,显然对应于"\1\2\3"字符串的前导。接下来是48656C6C6F字符串的十六进制 ASCII 代码"Hello"。接下来是040506,它对应于"\4\5\6"零件。接下来576F726C64是,你猜对了,就是"World"。接下来1E1F2021,当然是决赛了"\x1E\x1F\x20\x21"。最后,最后是00,它是'\0'编译器自动附加到binary数组中字符串末尾的字符。

您可能已经弄清楚了这一点,但是 hex2021是空格和!字符的 ASCII 代码(十六进制),所以这就是输出中的内容。

如果我通过 Unix/Linux 命令运行输出cat -v,这使得不可打印字符使用“控制字符”表示可见^X,我得到:

^A^B^CHello^D^E^FWorld^^^_ !^@
Run Code Online (Sandbox Code Playgroud)

最后,这是输出的另一种表示,通过“十六进制转储”程序运行,该程序并排显示十六进制和文本表示,但不可打印的字符由点替换:

01 02 03 48 65 6c 6c 6f  04 05 06 57 6f 72 6c 64   ...Hello...World
1e 1f 20 21 00                                     .. !.           
Run Code Online (Sandbox Code Playgroud)