Не могу изменить адрес возврата функции x64 - PullRequest
0 голосов
/ 17 мая 2019

Я пытаюсь изменить адрес возврата какой-либо функции в Си для пропуска одной инструкции. Я делаю это на виртуальной машине с Ubuntu Server (потому что на Mac gcc не позволяет отключить защиту стека).

Я компилирую свой код с помощью gcc:

gcc –g –fno-stack-protector –z execstack –o bufover bufover.c

Это код:

void foo(int a, int b, int c) {
   char buff[256];
   long *ret, *ret2;

   ret = buff + 256 + 8;
   (*ret) += 5; 
}

int main() {
  char x;
  x = '0';
  foo(1,2,3);
  x = '1';
  printf("%c\n",x);
}

По адресу buff Я добавил 256 (размер баффа) и 8 (размер% RBP). Перед этим в стеке должен быть адрес возврата. Затем я добавил 5 байтов к этому адресу, потому что я с помощью gdb проверил, что следующая инструкция находится в 5 байтах.

Но это не работает ... Я анализирую переменные (адреса) шаг за шагом, используя gdb, но я не вижу никакой ошибки. Есть идеи?

Редактировать: Код сборки:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14
    .globl  _foo                    ## -- Begin function foo
    .p2align    4, 0x90
_foo:                                   ## @foo
Lfunc_begin0:
    .file   1 "me.c"
    .loc    1 3 0                   ## me.c:3:0
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $160, %rsp
    leaq    -272(%rbp), %rax
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    %edx, -12(%rbp)
Ltmp0:
    ##DEBUG_VALUE: foo:buff <- [%rax+0]
    .loc    1 7 19 prologue_end     ## me.c:7:19
    addq    $256, %rax              ## imm = 0x100
Ltmp1:
    .loc    1 7 25 is_stmt 0        ## me.c:7:25
    addq    $8, %rax
    .loc    1 7 12                  ## me.c:7:12
    movq    %rax, -280(%rbp)
    .loc    1 8 10 is_stmt 1        ## me.c:8:10
    movq    -280(%rbp), %rax
    .loc    1 8 15 is_stmt 0        ## me.c:8:15
    movq    (%rax), %rcx
    addq    $5, %rcx
    movq    %rcx, (%rax)
    .loc    1 9 5 is_stmt 1         ## me.c:9:5
    addq    $160, %rsp
    popq    %rbp
    retq
Ltmp2:
Lfunc_end0:
    .cfi_endproc
                                        ## -- End function
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
Lfunc_begin1:
    .loc    1 11 0                  ## me.c:11:0
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $1, %edi
    movl    $2, %esi
    movl    $3, %edx
Ltmp3:
    .loc    1 13 9 prologue_end     ## me.c:13:9
    movb    $48, -1(%rbp)
    .loc    1 14 7                  ## me.c:14:7
    callq   _foo
    leaq    L_.str(%rip), %rdi
    .loc    1 15 9                  ## me.c:15:9
    movb    $49, -1(%rbp)
    .loc    1 16 21                 ## me.c:16:21
    movsbl  -1(%rbp), %esi
    .loc    1 16 7 is_stmt 0        ## me.c:16:7
    movb    $0, %al
    callq   _printf
    xorl    %edx, %edx
    .loc    1 17 5 is_stmt 1        ## me.c:17:5
    movl    %eax, -8(%rbp)          ## 4-byte Spill
    movl    %edx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
Ltmp4:
Lfunc_end1:
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "%c\n"

    .section    __DWARF,__debug_str,regular,debug

1 Ответ

0 голосов
/ 17 мая 2019

Вы должны использовать встроенные GCC адреса возврата , такие как __builtin_frame_address или __builtin_return_address, и вам следует внимательно изучить спецификацию x86-64 ABI , чтобы понять в детали соответствующие x86 соглашения о вызовах .

Попробуйте также понять их, написав код на C в foo.c и скомпилировав его с gcc -O -fverbose-asm -S foo.c, а затем изучив сгенерированный foo.s

Наконец, сегмент стека обычно не является исполняемым (это может иметь значение для некоторых батутных техник). Читайте о NX бит . В Linux научитесь использовать mprotect (2) , mmap (2) , backtrace (3) .

Нет никакой гарантии, что GCC даже использует стек вызовов . Он может оптимизироваться, чтобы избежать его использования ( tail-call оптимизация может * иногда происходить ), и вашему коду могут даже не потребоваться дополнительные кадры вызова. Поэтому, конечно, вы не можете достичь своей цели в стандарте C или без дополнительной гипотезы о вашем конкретном компиляторе GCC (а GCC 8 и GCC 9 могут оптимизироваться по-разному).

Конечно, изменение обратного адреса: неопределенное поведение .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...