x86 JMP存储在寄存器

时间:2018-05-21 14:15:26

标签: assembly x86 segmentation-fault self-modifying

我想跳转到存储在%rax中的地址,地址只能在运行时知道。这就是我尝试用自修改代码做的事情:

mov    $0x0, %rax
jmp    *%rax 

操作数$ 0x0将在运行时更改为地址。但是运行代码我得到分段错误。我正在使用MacOS和gcc。以下是代码的完整版本:

            .data
fmt_int:
        .ascii "%ld\n\0"
fmt_hex:
        .ascii "%#08x\n\0"

        .global _main


        .text
_main: 
        push    %rbp
        mov     %rsp, %rbp

        # allow us to write to section .text
        lea     _main(%rip), %rdi
        mov     %rdi, %rbx
        call    _getpagesize
        mov     %rax, %rsi
        xor     %rdx, %rdx
        mov     %rbx, %rax
        div     %rsi
        sub     %rdx, %rbx
        lea     _main(%rip), %rcx
        lea     _end(%rip), %rsi
        sub     %rcx, %rsi
        add     %rdx, %rsi
        inc     %rsi
        mov     %rbx, %rdi
        mov     $7, %rdx
        call    _mprotect    

        # change the mov statement at l0
        lea     l0(%rip), %rdi
        lea     l2(%rip), %rax
        movl    %eax, 3(%rdi)

        mov     $2, %rsi

l0:
        mov     $0x0, %rax
        jmp     *%rax
l1:
        mov     $0, %rsi
l2:
        lea     fmt_int(%rip), %rdi
        call    _printf

        pop     %rbp
        ret
_end:

因此,# change the mov statement at l0行下的代码会将mov $0x0, %rax指令的操作数修改为mov $addr_l2, %rax,其中addr_l2l2的地址。因此,当它被执行时,它应该跳转到l2。但是,代码在跳转时会出现分段错误。

我尝试了另一个不涉及自修改代码的代码:

            .data
fmt_int:
        .ascii "%ld\n\0"
fmt_hex:
        .ascii "%#08x\n\0"

        .global _main


        .text
_main: 
        push    %rbp
        mov     %rsp, %rbp

        mov     $2, %rsi

l0:
        lea     l2(%rip), %rax
        jmp     *%rax
l1:
        mov     $0, %rsi
l2:
        lea     fmt_int(%rip), %rdi
        call    _printf

        pop     %rbp
        ret
_end:

此代码工作正常。但在这两种情况下,jmp也会跳转到l2的地址,所以我不知道为什么前一个不起作用而另一个起作用。

为什么自修改代码版本会失败,我该如何解决?

0 个答案:

没有答案