我有一个家庭作业,要求我使用缓冲区溢出调用函数而不显式调用它。代码基本上是这样的:
#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()的地址,但我不知道如何访问它。无论如何,提示会很棒。
答案 0 :(得分:13)
基本思想是改变函数的返回地址,以便在函数返回时继续在新的黑客地址执行。正如Nils在其中一个答案中所做的那样,你可以声明一块内存(通常是数组)并以这样的方式溢出它,使得返回地址也被覆盖。
我建议你不要盲目地接受这里给出的任何程序,而不要真正了解它们是如何工作的。这篇文章写得很好,你会发现它非常有用:
答案 1 :(得分:11)
这是依赖编译器的,所以不能给出单一答案。
以下代码将为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
答案 2 :(得分:7)
由于这是作业,我想回应 codeaddict's suggestion 了解缓冲区溢出实际上是如何工作的。
我通过阅读关于利用缓冲区溢出漏洞 Smashing The Stack For Fun And Profit 的优秀(如果有点过时)文章/教程来学习该技术。
答案 3 :(得分:3)
试试这个:
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;
}
答案 4 :(得分:3)
虽然此解决方案不使用溢出技术覆盖堆栈上函数的返回地址,但仍会导致g()
在返回f()
的途中从main()
调用f()
仅修改g()
而不是直接调用f()
。
Function epilogue - 类似于内联汇编添加到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;
}
返回。
{{1}}
了解此代码的工作原理可以更好地理解如何为构成缓冲区溢出技术基础的特定体系结构设置函数的堆栈帧。