Я получил присвоение домашней работы, прося, чтобы я вызвал функцию, явно не называя его, с помощью переполнения буфера. Код - в основном это:
#include <stdio.h>
#include <stdlib.h>
void g()
{
printf("now inside g()!\n");
}
void f()
{
printf("now inside f()!\n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
}
int main (int argc, char *argv[])
{
f();
return 0;
}
Хотя я не уверен, как продолжить двигаться. Я думал об изменении обратного адреса для счетчика команд так, чтобы это продолжилось непосредственно к адресу g (), но я не уверен, как получить доступ к нему. Так или иначе подсказки будут большими.
: Предметы, отмеченные выше как Питон, STL включены как часть Библиотеки Стандарта Питона, как перечислено в документация Питона v2.6.4 .
-121--4103932-Основная идея состоит в том, чтобы изменить обратный адрес функции так, чтобы при возврате функция продолжала выполняться по новому взломанному адресу. Как сделано Нильсом в одном из ответов, можно объявить фрагмент памяти (обычно массив) и переполнить его путь, чтобы обратный адрес также был перезаписан.
Я предлагаю вам не принимать вслепую программы, приведенные здесь, не понимая, как они работают. Эта статья очень хорошо написана, и вы найдете ее очень полезной:
Это зависит от компилятора, поэтому однозначного ответа дать нельзя.
Следующий код сделает то, что вы хотите для gcc 4.4.1. Компиляция с отключенной оптимизацией (важно!)
#include <stdio.h>
#include <stdlib.h>
void g()
{
printf("now inside g()!\n");
}
void f()
{
int i;
void * buffer[1];
printf("now inside f()!\n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
// place the address of g all over the stack:
for (i=0; i<10; i++)
buffer[i] = (void*) g;
// and goodbye..
}
int main (int argc, char *argv[])
{
f();
return 0;
}
Вывод:
nils@doofnase:~$ gcc overflow.c
nils@doofnase:~$ ./a.out
now inside f()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
Segmentation fault
Поскольку это домашнее задание, я хотел бы повторить предложение codeaddict о том, чтобы понять, как на самом деле работает переполнение буфера.
Я научился этой технике, прочитав отличную (хотя и немного устаревшую) статью/учебник по эксплуатации уязвимостей переполнения буфера Smashing The Stack For Fun And Profit.
Попробуйте этот:
void f()
{
void *x[1];
printf("now inside f()!\n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
x[-1]=&g;
}
или этот:
void f()
{
void *x[1];
printf("now inside f()!\n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
x[1]=&g;
}
Хотя это решение не использует метод переполнения для перезаписи адреса возврата функции в стеке, оно по-прежнему вызывает вызов g ()
из f ()
на обратном пути к main ()
путем изменения только f ()
, а не прямого вызова g ()
.
Встроенная сборка, подобная эпилогу функции , добавлена в f ()
для изменения значения адреса возврата в стеке, чтобы f ()
возвращался через g ()
.
#include <stdio.h>
void g()
{
printf("now inside g()!\n");
}
void f()
{
printf("now inside f()!\n");
// can only modify this section
// cant call g(), maybe use g (pointer to function)
/* x86 function epilogue-like inline assembly */
/* Causes f() to return to g() on its way back to main() */
asm(
"mov %%ebp,%%esp;"
"pop %%ebp;"
"push %0;"
"ret"
: /* no output registers */
: "r" (&g)
: "%ebp", "%esp"
);
}
int main (int argc, char *argv[])
{
f();
return 0;
}
Понимание того, как работает этот код, может привести к лучшему пониманию того, как фрейм стека функции настраивается для конкретной архитектуры, которая формирует основу методов переполнения буфера.