Интерпретировать эту строку на ассемблере? - PullRequest
0 голосов
/ 10 мая 2018

Ниже приведены первые 5 строк дизассемблированной C-программы, которую я пытаюсь преобразовать обратно в ее C-код для лучшего изучения ассемблера. В начале этого кода я вижу, что он освобождает место в стеке и немедленно вызывает

0x000000000040054e <+8>:    mov    %fs:0x28,%rax

Я запутался, что делает эта строка, и что может вызывать это из соответствующей программы на Си. Единственный раз, когда я видел эту строку, это когда вызывается другой метод в программе на C, но на этот раз за ним не следуют никакие инструкции Callq, так что я не уверен ... Любые идеи, что еще может быть в этом С какой программой будет звонить?

0x0000000000400546 <+0>:    push   %rbp
0x0000000000400547 <+1>:    mov    %rsp,%rbp   
0x000000000040054a <+4>:    sub    $0x40,%rsp
0x000000000040054e <+8>:    mov    %fs:0x28,%rax
0x0000000000400557 <+17>:   mov    %rax,-0x8(%rbp)
0x000000000040055b <+21>:   xor    %eax,%eax
0x000000000040055d <+23>:   movl   $0x17,-0x30(%rbp)
...

Я знаю, что это должно обеспечить некоторую форму защиты стека для атак переполнения буфера, мне просто нужно знать, какой код на С запустил бы эту защиту, если бы не отдельный метод.

1 Ответ

0 голосов
/ 10 мая 2018

Как вы говорите, это код, используемый для защиты от переполнения буфера. Компилятор генерирует эту «канарскую проверку стека» для функций, которые имеют локальные переменные, которые могут быть буферами, которые могут быть переполнены. Обратите внимание на инструкции непосредственно над и под строкой, о которой вы спрашиваете:

sub  $0x40, %rsp
mov  %fs:0x28, %rax
mov  %rax, -0x8(%ebp)
xor  %eax, %eax

sub выделяет 64 байта пространства в стеке, что достаточно для хотя бы одного небольшого массива. Затем секретное значение копируется из %fs:0x28 в верхнюю часть этого пространства, сразу под указателем предыдущего кадра и адресом возврата, и затем оно стирается из файла регистров.

Тело функции что-то делает с массивами; если он пишет достаточно далеко за концом массива, он перезапишет секретное значение. В конце функции будет код, аналогичный

    mov    -0x8(%rbp), %rax
    xor    %fs:28, %rax
    jne    1
    mov    %rbp, %rsp
    pop    %rbp
    ret
1:
    call    __stack_chk_fail   # does not return

Это подтверждает, что секретное значение не изменилось, и вылетает из программы, если оно изменилось. Идея состоит в том, что кто-то, пытающийся использовать простую уязвимость переполнения буфера, как вы, когда вы используете gets, не сможет изменить адрес возврата без изменения секретного значения.

Компилятор имеет несколько различных эвристик , выбираемых с помощью параметров командной строки, для решения, когда необходимо сгенерировать код защиты стека и канареек.

Вы не можете написать код C, соответствующий этому языку ассемблера, потому что он использует необычный режим адресации% fs: nnnn; Канарский код стека преднамеренно использует режим адресации, на который не опирается никакая другая генерация кода, чтобы противнику было как можно сложнее узнать секретное значение.

...