推入堆栈时出现分段错误

逆向工程 部件 x86 linux 分割 纳姆
2021-06-24 21:16:27

所以我一直在学习一些关于汇编的教程,讲师编译了以下代码:

;hello3.asm  attempts to make the code position independent

section .text
global _start

_start:
;clear out the registers we are going to need
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx

;write(int fd, char *msg, unsigned int len)
mov al, 4
mov bl, 1
;Owned!!! =  4f,77,6e,65,64,21,21,21
;push !,!,!,d
push 0x21212164
;push e,n,w,O 
push 0x656e774f
mov ecx, esp
mov dl, 8
int 0x80

;exit(int ret)
mov al,1
xor ebx, ebx
int 0x80

请注意,消息Owned!!!被压入堆栈而不是保留在.text段中。因此,当我尝试执行它时,出现Segment Fault错误!

相反,如果我将消息保留在 中.text,则一切正常。

我用来执行的命令:

$> nasm -f elf64 hello4.asm 
$> ld -o hello hello4.o 

有任何想法吗?

3个回答

分段错误错误与将字符串压入堆栈没有任何关系。

我用gdb调试过,问题出在:

;exit(int ret)
mov al,1
xor ebx, ebx
int 0x80

改变

mov al,1

mov eax,1

修复分段错误。

在 Kali Linux 上测试。

除了@user2389688 的回答之外,重要的是要注意,如果您使用 amd64,系统调用号是错误的,传入的寄存器也是如此。这是一个 64 位 abi 版本,它纠正了差异,并提供了预期的输出。

;hello3.asm  attempts to make the code position independent
; rewrite of hello3.asm to use 64 bit syscall interface
section .text
global _start

_start:
xor rax, rax ; syscall
xor rdi, rdi ; arg1
xor rsi, rsi ; arg2
xor rdx, rdx ; arg3

; write(int fd, char *msg, unsigned int len)
mov al, 1
mov di, ax
;Owned!!! =  4f,77,6e,65,64,21,21,21
;push !,!,!,d
;push e,n,w,O
sub rsp, 8
mov dword [rsp], 'Owne'
mov dword [rsp + 4], 'd!!!'
mov rsi, rsp
mov dl, 8 
syscall

; exit(int ret)
; syscall errors will result in rax having a negative value so you
; can't just move al
mov eax, 0xffffffc3
not eax
xor rdi, rdi
syscall

我在 64 位机器上试过你的代码,有一些注意事项:

当您推送字符串的 2 个片段时,堆栈在它们之间包含一个空字:

Breakpoint 1, 0x000000000040009a in _start () [bp before int 0x80] 
(gdb) x/4wx $rsp
0x7fffffffde30: 0x656e774f  0x00000000  0x21212164  0x00000000

这会导致write系统调用失败(因为我们指示长度为 8)。因此,在系统调用之后,寄存器中%rax包含一个错误代码:

(gdb) ni
0x000000000040009c in _start ()
(gdb) info reg
rax            0xfffffffffffffff2   -14

之后,我们用 移动一个字节mov al,1,但结果值为%rax0xffffffffffffff01

exit系统调用将不会被执行,该代码将继续与内存中的内容......结果是不确定的......(某处发生的段错误,在我的情况下试图访问*%rsi时,寄存器%rsi包含0

我希望这对任何人都有帮助。

顺便提一句。以防万一,最好在字符串之前引入一个空值,这样您就可以确定字符串将以一个NULL结尾否则,如果内存中包含另一个值,write()可能会打印一些奇怪的字符。