Как реализовать защиту от переполнения буфера с использованием ассемблера?

Можете ли вы продемонстрировать на примере x86-64 ассемблера, как компилятор обрабатывает проверку выхода за границы массива в коде на языке, имеющем такую проверку? Также интересно, как выглядит код в случае, если эта проверка отсутствует. Верно ли я понимаю, что в первом случае будет добавлено одна-две инструкции для выполнения проверки и вызова исключения или паники? Спасибо!
  • 16 апреля 2025 г. 12:46
Ответы на вопрос 2
Защита от переполнения буфера — это важный аспект в разработке программного обеспечения, особенно для языков, таких как C и C++, которые не имеют встроенных механизмов проверки выхода за границы массивов.

### Пример на C с проверкой выхода за границы массива

Рассмотрим простой пример на C, который проверяет выход за границы массива. Вот как это может выглядеть:

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void safe_copy(char *dest, const char *src, size_t dest_size) {
    size_t src_len = strlen(src);
    if (src_len >= dest_size) {
        fprintf(stderr, "Buffer overflow detected!\n");
        exit(EXIT_FAILURE);
    }
    strcpy(dest, src);
}

int main() {
    char buffer[10];
    safe_copy(buffer, "HelloWorld", sizeof(buffer));
    printf("%s\n", buffer);
    return 0;
}
```

### Скомпилированный ассемблерный код

Скомпилируем этот код и посмотрим, как работает проверка выхода за границы массива. Примерно вот так будет выглядеть ассемблерный код в x86-64 (упрощенный и может отличаться в зависимости от компилятора и настроек):

```assembly
safe_copy:
    ; Получаем длину строки src
    mov     rax, rdi             ; rax = dest
    mov     rsi, rsi             ; rsi = src
    call    strlen               ; вызываем strlen
    cmp     rax, rdx             ; сравниваем длину строки с размером буфера
    jge     .error               ; если превышает, переход к ошибке
    ; Копируем строку
    mov     rdi, rax             ; dest = rax
    mov     rsi, rsi             ; src = rsi
    call    strcpy               ; вызываем strcpy
    ret

.error:
    ; Обработка ошибки
    ; Вывести сообщение об ошибке, завершить программу
    ; ...
```

В этом примере код включает инструкции для получения длины строки и сравнения её с размером буфера. Если условие проверки не выполняется, происходит переход к обработке ошибки.

### Пример без проверки выхода за границы массива

Теперь рассмотрим вариант без проверки. Вот код:

```c
#include <stdio.h>
#include <string.h>

void unsafe_copy(char *dest, const char *src) {
    strcpy(dest, src);
}

int main() {
    char buffer[10];
    unsafe_copy(buffer, "HelloWorld");
    printf("%s\n", buffer);
    return 0;
}
```

### Скомпилированный ассемблерный код без проверки

Здесь скомпилированный код может выглядеть гораздо проще:

```assembly
unsafe_copy:
    mov     rdi, rax             ; dest
    mov     rsi, rsi             ; src
    call    strcpy               ; вызываем strcpy
    ret
```

Здесь нет проверок, и если копируемая строка превышает размер буфера, может произойти переполнение, что приведет к непредсказуемым последствиям.

### Заключение

Таким образом, вы правильно понимаете, что в случае наличия проверки компилятор добавляет несколько дополнительных инструкций, которые выполняют проверку и могут вызывать исключение или завершать программу при наличии переполнения. Это существенно увеличивает безопасность, но и накладывает определенные накладные расходы на производительность.
Защита от переполнения буфера - это не пара магических инструкций, а проверка при работе с массивами или выделенными участками памяти (впрочем, для C/C++/ASM это примерно одно и то же), что указатель не выходит за границу выделенной памяти. Реализовано может быть самыми разными способами. Например, в C есть функция str n cpy, которая делает всё то же самое, что strcpy, только проверяя, что копируется не более заданного количества байтов. Если вы правильно передали в неё размер буфера, то переполнения при операции не произойдёт. 
Так что на языках низкого уровня только проверки, проверки и ещё раз проверки.
Похожие вопросы