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)
那么,数据和代码只是字节.只有你如何解释它们才能使它们成为现实.代码可以解释为数据,反之亦然.在大多数情况下,它会产生无效的东西,但无论如何它都是可能的.
该部分的属性取决于链接器,默认情况下,大多数属性都是.textRO,但并不意味着它不能更改.
整个例子是一个聪明的方法来获取/bin/sh刚刚使用的地址call.基本上call堆栈上的位置是下一条指令的地址(下一个字节),在这种情况下它将是该字符串的地址,因此pop esi将从堆栈中获取该地址并使用它.
最顶层的答案是,x86 机器不知道“.text”和“.data”部分。现代 x86 CPU 为操作系统提供了创建具有特定权限(如只读、无执行和读写)的虚拟地址空间的工具。
但内存的内容只是字节,这些字节可以被读取、写入或执行,CPU 无法猜测内存的哪部分是数据,哪部分是代码,并且会很乐意执行你指向的任何内容。
这些.text/.data/...部分是由编译器、链接器和操作系统(可执行加载程序)支持的逻辑构造,它们共同协作为代码准备运行时环境,现在是.text只读的,您需要将可写变量放入.dataor.bss或相似的。某些操作系统和配置也可能提供不可执行的堆栈。
操作系统通常也有 API,因此应用程序可以更改权限或内存映射,或者使用所需的属性分配更多内存(例如,如果 JIT 编译器无法首先将编译后的代码写入内存,然后再将其写入内存,那么 JIT 编译器将无处可去。执行它)。
因此,如果您将在默认配置中的常见 Linux 上使用代码示例,则很可能会出现段错误,因为它将.text是只读的。许多“利用”书籍都有完整的专门章节,介绍如何为其示例编译+设置运行时环境,从而关闭多种保护(ASLR、 NX ...),从而允许它们的示例工作。
然后,真正的漏洞利用通常会利用应用程序中的一些错误/弱点将其有效负载注入某处。根据“某处”的敌意,真正的漏洞可能必须首先提升其权限以获得可写+可执行内存(或者必须以不写入代码部分并使用其他内存作为变量的方式编写),除非应用程序由于其内部的需要,其本身已经具备了一些友好的可利用环境。
请记住,操作系统和应用程序并不是以确保漏洞利用有效的方式编写的,恰恰相反。每个漏洞通常针对特定版本操作系统上的特定应用程序版本,该版本很容易受到攻击,预计稍后会随着安全更新而崩溃。因此,如果您知道自己有可写和可执行的内存,您只需按原样利用它,而不必担心下一版本中会发生什么,届时他们将修复应用程序以保留其代码内存 RO。