assembly - x86_64 程序集 - 尝试在 x64 程序集中编辑数组内的字节时出现段错误

标签 assembly segmentation-fault x86-64

我正在学习的教程是针对 x86 的,并且是使用 32 位汇编语言编写的,我尝试在学习 x64 汇编语言的过程中进行学习。直到本课为止,一切都进展顺利,我有以下简单的程序,它只是尝试修改字符串中的单个字符;它编译得很好,但运行时出现段错误。

section .text

global _start ; Declare global entry oint for ld
_start:

    jmp short message ; Jump to where or message is at so we can do a call to push the address onto the stack

    code:   
    xor rax, rax    ; Clean up the registers
    xor rbx, rbx
    xor rcx, rcx
    xor rdx, rdx

    ; Try to change the N to a space
    pop rsi ; Get address from stack
    mov al, 0x20 ; Load 0x20 into RAX
    mov [rsi], al; Why segfault?
    xor rax, rax; Clear again

    ; write(rdi, rsi, rdx) = write(file_descriptor, buffer, length)
    mov al, 0x01    ; write the command for 64bit Syscall Write (0x01) into the lower 8 bits of RAX
    mov rdi, rax    ; First Paramter, RDI = 0x01 which is STDOUT, we move rax to ensure the upper 56 bits of RDI are zero
    ;pop rsi        ; Second Parameter, RSI = Popped address of message from stack
    mov dl, 25  ; Third Parameter, RDX = Length of message
    syscall     ; Call Write

    ; exit(rdi) = exit(return value)    
    xor rax, rax    ; write returns # of bytes written in rax, need to clean it up again
    add rax, 0x3C   ; 64bit syscall exit is 0x3C
    xor rdi, rdi    ; Return value is in rdi (First parameter), zero it to return 0
    syscall     ; Call Exit

    message:
    call code   ; Pushes the address of the string onto the stack
    db 'AAAABBBNAAAAAAAABBBBBBBB',0x0A

罪魁祸首是这一行:

mov [rsi], al; Why segfault?

如果我把它注释掉,那么程序运行正常,输出消息'AAAABBBNAAAAAAAAAABBBBBBBB',为什么我不能修改字符串?

作者代码如下:

global _start


_start:
        jmp short ender

        starter:

        pop ebx                 ;get the address of the string
        xor eax, eax

        mov al, 0x20
        mov [ebx+7], al        ;put a NULL where the N is in the string

        mov al, 4       ;syscall write
        mov bl, 1       ;stdout is 1
        pop ecx         ;get the address of the string from the stack
        mov dl, 25       ;length of the string
        int 0x80

        xor eax, eax
        mov al, 1       ;exit the shellcode
        xor ebx,ebx
        int 0x80

        ender:
        call starter
        db 'AAAABBBNAAAAAAAABBBBBBBB'0x0A

我已经使用以下方法编译了它:

nasm -f elf <infile> -o <outfile>
ld -m elf_i386 <infile> -o <outfile>

但即使这会导致段错误,页面上的图像显示它工作正常并将 N 更改为空格,但是我似乎陷入了段错误领域:( Google 在这种情况下并没有真正提供帮助,所以我转向你 stackoverflow,任何指针(没有双关语意图!)将不胜感激

最佳答案

我认为这是因为您正在尝试访问 .text 部分中的数据。通常出于安全考虑,您不允许写入代码段。可修改的数据应位于 .data 部分。 (如果零初始化,则为 .bss。)

对于实际的 shellcode,如果您不想使用单独的部分,请参阅 Segfault when writing to string allocated by db [assembly] 以获取替代解决方法。


此外,我绝不会建议使用 call 将其后面的地址插入堆栈来获取指向其后面数据的指针的副作用,shellcode 除外。

这是 shellcode 中的常见技巧(必须与位置无关); 32位模式需要以某种方式调用来获取EIP。 call 必须具有向后位移以避免机器代码中的 00 字节,因此将调用放在创建您特别想要的“返回”地址的位置可以节省 添加lea

即使在可以进行 RIP 相对寻址的 64 位代码中,jmp/call/pop 也与跳过具有负位移的 RIP 相对 LEA 的字符串一样紧凑。

在 shellcode/受限机器代码用例之外,这是一个糟糕的主意,您应该像普通人一样 lea reg, [rel buf] .data 中的数据和 .text 中的代码。 (或者 .rodata 中的只读数据。)这样您就不会尝试在数据旁边执行代码,或者将数据放在代码旁边。

(允许 shellcode 的代码注入(inject)漏洞已经暗示存在具有写入和执行权限的页面,但是现代工具链中的正常进程没有任何 W+X 页面,除非您采取措施来实现这一点。W^X 是因此,这是一个很好的安全功能,因此必须击败正常的工具链安全功能/默认值才能测试 shellcode。)

关于assembly - x86_64 程序集 - 尝试在 x64 程序集中编辑数组内的字节时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45005078/

相关文章:

c - GDB 和 asm 32 字节

c - 将树节点复制到数组中的段错误

c - 学习C,segfailt混淆

c++ - segmentation fault错误如何解决C++

.net - 为什么在调试/反汇编期间我不能进入调用指令?

linux-kernel - Linux针对执行shellcode的安全措施

c - 调用 glibc 时的 x86-64 ELF 初始堆栈布局

.net - JIT-ed 异常处理程序实现

c - 将参数从 C 传递给程序集?

比较内联 c 汇编中的数字