Переполнение буфера в C при получении ошибки сегментации - PullRequest
0 голосов
/ 20 октября 2019

Я пытаюсь сделать переполнение буфера для моего класса безопасности, нам не разрешено вызывать какую-либо функцию, и нам нужно перейти к секретной функции, а также вернуть 0 без ошибки сегментации. Я написал код ниже и успешно перешел к секрету, но у меня ошибка сегментации. Как я могу успешно завершить программу? Или же можно просто написать по одному адресу вместо цикла for, когда я попытался, это ничего не изменило.

#include <stdio.h>

void secret()
{
    printf("now inside secret()!\n");
}

void entrance()
{
    int doNotTouch[10];
    // can only modify this section BEGIN
    // cant call secret(), maybe use secret (pointer to function)
    for (int i = 0; i < 14; i++) {
        *(doNotTouch + i) = (int) &secret;
    }
    // can only modify this section END
    printf("now inside entrance()!\n");
}

int main (int argc, char *argv[])
{
    entrance();
    return 0;
}

1 Ответ

1 голос
/ 20 октября 2019

В некотором полу-ассемблере, предполагая что-то вроде x86. (BP является псевдокодом для EBP или RBP, при условии, что вы на самом деле не компилируете для 16-битного режима. Вероятно, 32-битный режим так, что int имеет ту же ширину, что и адрес возврата.)

; entrance:
; - stack has return address to main
push  bp                         ; decrement SP by a pointer width
mov   bp,sp
sub   sp, 10*sizeof(int)         ; reserve space for an array
;....
; doNotTouch[0] is probably at [bp - 10*sizeof(int)]

Когда вы переходите к 14, вы сначала перезаписываете сохраненный bp при i == 10, а затем адрес возврата в main (что правильно), а затем перезаписываете еще немного, что в конечном итоге вызывает ошибку сегмента. Так что вам нужно всего лишь сделать *(doNotTouch + 11) = (int) &secret; - при условии, что int - это размер указателя на функцию. (Или немного больше, если компилятор оставил пробел для выравнивания стека или для собственного использования. В отладочной сборке другие локальные блоки будут иметь слоты стека. Их перезапись может привести к бесконечному циклу, выходящему за пределы.)

Затем следует ваш printf, а затем функция возвращается, но она не возвращается к основному, а «переходит» к secret.

Когда возвращается secret, это фактически теперь возврат из основного, но этоне может сделать return 0;

Так что секрет должен быть:

int secret()
{
    printf("now inside secret()!\n");
    return 0;
}

Отказ от ответственности: ".... Я думаю."

...