x86_64 程序集 - 尝试在 x64 程序集中编辑数组中的字节时出现段错误 [英] x86_64 Assembly - Segfault when trying to edit a byte within an array in x64 assembly

查看:23
本文介绍了x86_64 程序集 - 尝试在 x64 程序集中编辑数组中的字节时出现段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习的教程是针对 x86 编写的,是使用 32 位汇编编写的,我正在尝试在学习 x64 汇编的过程中继续学习.这一直很顺利,直到本课,我有以下简单的程序,它只是尝试修改字符串中的单个字符;它编译良好,但运行时出现段错误.

The tutorial I am following is for x86 and was written using 32-bit assembly, I'm trying to follow along while learning x64 assembly in the process. This has been going very well up until this lesson where I have the following simple program which simply tries to modify a single character in a string; it compiles fine but segfaults when ran.

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?

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

If I comment it out, then the program runs fine, outputting the message 'AAAABBBNAAAAAAAABBBBBBBB', why can't I modify the string?

作者代码如下:

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,任何指针(没有双关语!)将不胜感激

But even that causes a segfault, images on the page show it working properly and changing the N into a space, however I seem to be stuck in segfault land :( Google isn't really being helpful in this case, and so I turn to you stackoverflow, any pointers (no pun intended!) would be appreciated

推荐答案

我认为这是因为您正在尝试访问 .text 部分中的数据.通常,为了安全起见,您不允许写入代码段.可修改的数据应该在 .data 部分.(或者 .bss 如果零初始化.)

I would assume it's because you're trying to access data that is in the .text section. Usually you're not allowed to write to code segment for security. Modifiable data should be in the .data section. (Or .bss if zero-initialized.)

对于不想使用单独部分的实际 shellcode,请参阅写入 db [assembly] 分配的字符串时出现段错误 用于替代解决方法.

For actual shellcode, where you don't want to use a separate section, see Segfault when writing to string allocated by db [assembly] for alternate workarounds.

此外,我永远不会建议使用 call 将地址后面的地址推送到堆栈的副作用来获取指向其后面数据的指针,除了 shellcode.

Also I would never suggest using the side effects of call pushing the address after it to the stack to get a pointer to data following it, except for shellcode.

这是shellcode中的一个常见技巧(必须与位置无关);32 位模式需要调用以某种方式获取 EIP.call 必须有一个向后位移以避免机器代码中的 00 字节,因此将调用放在创建返回"的地方您特别想要的地址保存了 addlea.

This is a common trick in shellcode (which must be position-independent); 32-bit mode needs a call to get EIP somehow. The call must have a backwards displacement to avoid 00 bytes in the machine code, so putting the call somewhere that creates a "return" address you specifically want saves an add or lea.

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

Even in 64-bit code where RIP-relative addressing is possible, jmp / call / pop is about as compact as jumping over the string for a RIP-relative LEA with a negative displacement.

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

Outside of the shellcode / constrained-machine-code use case, it's a terrible idea and you should just lea reg, [rel buf] like a normal person with the data in .data and the code in .text. (Or read-only data in .rodata.) This way you're not trying execute code next to data, or put data next to code.

(允许 shellcode 的代码注入漏洞已经暗示存在具有 write 和 exec 权限的页面,但现代工具链中的正常进程没有任何 W+X 页面,除非您采取某些措施来实现这一点.W^X 是一个很好的安全特性,所以正常的工具链安全特性/默认值必须测试shellcode失败.)

(Code-injection vulnerabilities that allow shellcode already imply the existence of a page with write and exec permission, but normal processes from modern toolchains don't have any W+X pages unless you do something to make that happen. W^X is a good security feature for this reason, so normal toolchain security features / defaults must be defeated to test shellcode.)

这篇关于x86_64 程序集 - 尝试在 x64 程序集中编辑数组中的字节时出现段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆