x86 程序集:文本部分中的数据
x86 Assembly: Data in the Text Section
我不太明白文本部分如何存储变量以及如何操作它们。不应该所有变量都在 .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'
好吧,数据和代码只是字节。只有你如何解释它们才能使它们成为现在的样子。代码可以解释为数据,反之亦然。在大多数情况下,它会产生一些无效的东西,但无论如何它是可能的。
节的属性依赖于链接器,其中大多数默认情况下使 .text
节成为 RO,但这并不意味着它不能更改。
整个例子是通过call
获取/bin/sh
地址的巧妙方法。基本上 call
将下一条指令(下一个字节)的地址放在堆栈上,在这种情况下它将是该字符串的地址,因此 pop esi
将从堆栈中获取该地址并使用它。
顶级答案是,x86 机器不知道“.text”和“.data”部分。现代 x86 CPU 为 OS 提供了创建具有特定权限(如只读、不可执行和读写)的虚拟地址 space 的工具。
但是内存的内容只是字节,可以读,可以写,可以执行,CPU没法猜测内存的哪一部分是数据,什么是代码,会愉快地执行你指向的任何事情。
那些.text/.data/...
部分是编译器、链接器和OS(可执行加载器)支持的逻辑结构,它们共同合作为代码准备运行时环境,.text
现在是只读的,你需要将可写变量放入 .data
或 .bss
或类似的。一些 OS 和配置也可能提供不可执行的堆栈。
OS 通常也有 API,因此应用程序可以更改权限或内存映射,或者使用它需要的属性分配更多内存(例如,JIT 编译器将无处可去,如果它们将无法先将编译后的代码写入内存,然后再执行。
因此,如果您将在默认配置中的通用 linux 上使用您的代码示例,则很可能会出现段错误,因为 .text
将是只读的。其中许多 "exploits" 书籍都有完整的专门章节,如何以这种方式为他们的示例编译 + 设置运行时环境,关闭了几种保护(ASLR,NX,...),从而允许他们的样品可以工作。
然后,真正的攻击通常会使用应用程序中的一些 bug/weak 点将其有效负载注入某处。根据 "somewhere" 的敌意,真正的漏洞可能必须首先提升其权限以获得可写+可执行内存(或者它必须以不写入代码部分和使用其他内存作为变量的方式编写),除非由于其内部需求,该应用程序本身已经具有一些友好的利用环境。
请记住,OS 和应用程序的编写方式并没有确保漏洞能够发挥作用,恰恰相反。每个漏洞利用通常针对特定版本 OS 上的特定应用程序版本,这很容易受到攻击,预计稍后会随着安全更新而中断。所以如果你知道你有可写和可执行的内存,你只需按原样利用它,而不用担心下一个版本会发生什么,当他们修复应用程序以保持他们的代码内存 RO。
我不太明白文本部分如何存储变量以及如何操作它们。不应该所有变量都在 .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'
好吧,数据和代码只是字节。只有你如何解释它们才能使它们成为现在的样子。代码可以解释为数据,反之亦然。在大多数情况下,它会产生一些无效的东西,但无论如何它是可能的。
节的属性依赖于链接器,其中大多数默认情况下使 .text
节成为 RO,但这并不意味着它不能更改。
整个例子是通过call
获取/bin/sh
地址的巧妙方法。基本上 call
将下一条指令(下一个字节)的地址放在堆栈上,在这种情况下它将是该字符串的地址,因此 pop esi
将从堆栈中获取该地址并使用它。
顶级答案是,x86 机器不知道“.text”和“.data”部分。现代 x86 CPU 为 OS 提供了创建具有特定权限(如只读、不可执行和读写)的虚拟地址 space 的工具。
但是内存的内容只是字节,可以读,可以写,可以执行,CPU没法猜测内存的哪一部分是数据,什么是代码,会愉快地执行你指向的任何事情。
那些.text/.data/...
部分是编译器、链接器和OS(可执行加载器)支持的逻辑结构,它们共同合作为代码准备运行时环境,.text
现在是只读的,你需要将可写变量放入 .data
或 .bss
或类似的。一些 OS 和配置也可能提供不可执行的堆栈。
OS 通常也有 API,因此应用程序可以更改权限或内存映射,或者使用它需要的属性分配更多内存(例如,JIT 编译器将无处可去,如果它们将无法先将编译后的代码写入内存,然后再执行。
因此,如果您将在默认配置中的通用 linux 上使用您的代码示例,则很可能会出现段错误,因为 .text
将是只读的。其中许多 "exploits" 书籍都有完整的专门章节,如何以这种方式为他们的示例编译 + 设置运行时环境,关闭了几种保护(ASLR,NX,...),从而允许他们的样品可以工作。
然后,真正的攻击通常会使用应用程序中的一些 bug/weak 点将其有效负载注入某处。根据 "somewhere" 的敌意,真正的漏洞可能必须首先提升其权限以获得可写+可执行内存(或者它必须以不写入代码部分和使用其他内存作为变量的方式编写),除非由于其内部需求,该应用程序本身已经具有一些友好的利用环境。
请记住,OS 和应用程序的编写方式并没有确保漏洞能够发挥作用,恰恰相反。每个漏洞利用通常针对特定版本 OS 上的特定应用程序版本,这很容易受到攻击,预计稍后会随着安全更新而中断。所以如果你知道你有可写和可执行的内存,你只需按原样利用它,而不用担心下一个版本会发生什么,当他们修复应用程序以保持他们的代码内存 RO。