如何创建一个只有 NOP 的 Linux ELF?
How to create a Linux ELF with only a NOP?
出于好奇,我正在尝试在 Linux 上创建一个简单的 64 位 ELF 文件,而不使用编译器。为了简单起见,我只需要它来 NOP (0x90)。
我当前的文件可以被“readelf”读取,而且它的输出似乎没问题。然而,当我执行它时,遇到了段错误。
有问题的文件(未格式化以便更容易复制粘贴):
7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00 02 00 3E 00 01 00 00 00 78 00 40 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 38 00 01 00 00 00 00 00 00 00 01 00 00 00 05 00 00 00 78 00 00 00 00 00 00 00 78 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 90
GDB 在地址 0x400079 处显示段错误,尽管入口点位于 0x400078 且 NOP 文件的大小为 1 字节,那么为什么要执行非保留内存?
奖金:为什么很多可执行文件在大虚拟地址而不是 0x0 开始它们的代码?
当您让编译器处理低级操作时,您可以构建一个什么都不做 的程序。但是如果你直接用机器代码(甚至汇编语言)编写它,你必须处理血淋淋的细节,比如正确结束程序。
你问为什么要执行非保留内存。好吧,你在 0x400078 处加载一些东西(一个 NOP 代码)并声明它是程序的开始。加载程序在 0x400078 处初始化内存,用该地址加载指令指针,处理器乖乖地从那里开始执行。它成功执行了 NOP,并且由于没有指示它执行任何其他操作,它尝试在 0x400079 处执行以下指令。哪些段错误归功于内存隔离和虚拟内存管理器。在内核模式或实模式下,它会执行该内存位置的任何内容,并具有无限的副作用...
所以你不能执行简单的 NOP,而是告诉 OS 程序结束的系统调用。根据维基百科上的 exit (system call),它应该在 Linux 64 位上:
mov eax, 60 ; sys_exit syscall number: 60
xor edi, edi ; set exit status to 0 (`xor edi, edi` is equal to `mov edi, 0` )
syscall ; call it
如果您的程序从 mov eax, 60
开始,那么它将干净地退出,甚至 return 其调用者的状态为 0。
出于好奇,我正在尝试在 Linux 上创建一个简单的 64 位 ELF 文件,而不使用编译器。为了简单起见,我只需要它来 NOP (0x90)。
我当前的文件可以被“readelf”读取,而且它的输出似乎没问题。然而,当我执行它时,遇到了段错误。
有问题的文件(未格式化以便更容易复制粘贴):
7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00 02 00 3E 00 01 00 00 00 78 00 40 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 38 00 01 00 00 00 00 00 00 00 01 00 00 00 05 00 00 00 78 00 00 00 00 00 00 00 78 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 80 00 00 00 00 00 90
GDB 在地址 0x400079 处显示段错误,尽管入口点位于 0x400078 且 NOP 文件的大小为 1 字节,那么为什么要执行非保留内存?
奖金:为什么很多可执行文件在大虚拟地址而不是 0x0 开始它们的代码?
当您让编译器处理低级操作时,您可以构建一个什么都不做 的程序。但是如果你直接用机器代码(甚至汇编语言)编写它,你必须处理血淋淋的细节,比如正确结束程序。
你问为什么要执行非保留内存。好吧,你在 0x400078 处加载一些东西(一个 NOP 代码)并声明它是程序的开始。加载程序在 0x400078 处初始化内存,用该地址加载指令指针,处理器乖乖地从那里开始执行。它成功执行了 NOP,并且由于没有指示它执行任何其他操作,它尝试在 0x400079 处执行以下指令。哪些段错误归功于内存隔离和虚拟内存管理器。在内核模式或实模式下,它会执行该内存位置的任何内容,并具有无限的副作用...
所以你不能执行简单的 NOP,而是告诉 OS 程序结束的系统调用。根据维基百科上的 exit (system call),它应该在 Linux 64 位上:
mov eax, 60 ; sys_exit syscall number: 60
xor edi, edi ; set exit status to 0 (`xor edi, edi` is equal to `mov edi, 0` )
syscall ; call it
如果您的程序从 mov eax, 60
开始,那么它将干净地退出,甚至 return 其调用者的状态为 0。