x86汇编:文本部分中的数据

nan*_*man 3 assembly shellcode

我不太明白变量如何存储在文本部分以及如何操作它们.不应该所有变量都在.data部分中,并且不是.text部分只读的所有部分吗?那么这段代码是如何工作的呢?

[代码取自Shellcoder的手册 ]

Section .text
global _start

_start:
    jmp short GotoCall

shellcode:
    pop esi
    xor eax, eax
    mov byte [esi + 7], al
    lea ebx, [esi]
    mov long [esi + 8], ebx
    mov long [esi + 12], eax
    mov byte al, 0x0b
    mov ebx, esi
    lea ecx, [esi + 8]
    lea edx, [esi + 12]
    int 0x80

GotoCall:
    call shellcode
    db '/bin/shJAAAAKKKK'
Run Code Online (Sandbox Code Playgroud)

Paw*_*sik 5

那么,数据和代码只是字节.只有你如何解释它们才能使它们成为现实.代码可以解释为数据,反之亦然.在大多数情况下,它会产生无效的东西,但无论如何它都是可能的.

该部分的属性取决于链接器,默认情况下,大多数属性都是.textRO,但并不意味着它不能更改.

整个例子是一个聪明的方法来获取/bin/sh刚刚使用的地址call.基本上call堆栈上的位置是下一条指令的地址(下一个字节),在这种情况下它将是该字符串的地址,因此pop esi将从堆栈中获取该地址并使用它.

  • 编译器将只读数据(如 `static const char[] = "/bin/sh";`)放入 `.rodata` 部分,链接器将其放置在 [the text *segment*](https://stackoverflow) .com/questions/14361248/whats-the-difference-of-section-and-segment-in-elf-file-format)可执行文件,以及“.text”部分。您通常不想混合代码和常量(因为这会浪费分割 L1I/L1D 缓存中的空间),但正如您所指出的,将它们放在同一段的同一页中是很好的。 (2认同)
  • 更新:GNU `ld` 最近进行了更改,将 `.rodata` 放在自己的段中,具有读取但*不*执行权限,以便更好地防御 ROP 和 Spectre 攻击。 (2认同)

Ped*_*d7g 4

最顶层的答案是,x86 机器不知道“.text”和“.data”部分。现代 x86 CPU 为操作系统提供了创建具有特定权限(如只读、无执行和读写)的虚拟地址空间的工具。

但内存的内容只是字节,这些字节可以被读取、写入或执行,CPU 无法猜测内存的哪部分是数据,哪部分是代码,并且会很乐意执行你指向的任何内容。

这些.text/.data/...部分是由编译器、链接器和操作系统(可执行加载程序)支持的逻辑构造,它们共同协作为代码准备运行时环境,现在是.text只读的,您需要将可写变量放入.dataor.bss或相似的。某些操作系统和配置也可能提供不可执行的堆栈。

操作系统通常也有 API,因此应用程序可以更改权限或内存映射,或者使用所需的属性分配更多内存(例如,如果 JIT 编译器无法首先将编译后的代码写入内存,然后再将其写入内存,那么 JIT 编译器将无处可去。执行它)。

因此,如果您将在默认配置中的常见 Linux 上使用代码示例,则很可能会出现段错误,因为它将.text是只读的。许多“利用”书籍都有完整的专门章节,介绍如何为其示例编译+设置运行时环境,从而关闭多种保护(ASLR、 NX ...),从而允许它们的示例工作。

然后,真正的漏洞利用通常会利用应用程序中的一些错误/弱点将其有效负载注入某处。根据“某处”的敌意,真正的漏洞可能必须首先提升其权限以获得可写+可执行内存(或者必须以不写入代码部分并使用其他内存作为变量的方式编写),除非应用程序由于其内部的需要,其本身已经具备了一些友好的可利用环境。

请记住,操作系统和应用程序并不是以确保漏洞利用有效的方式编写的,恰恰相反。每个漏洞通常针对特定版本操作系统上的特定应用程序版本,该版本很容易受到攻击,预计稍后会随着安全更新而崩溃。因此,如果您知道自己有可写和可执行的内存,您只需按原样利用它,而不必担心下一版本中会发生什么,届时他们将修复应用程序以保留其代码内存 RO。