返回libc在gdb中工作,但在单独运行时则不行

时间:2010-11-14 14:54:21

标签: c linux gcc gdb libc

我正在尝试使用以下简单代码返回libc技巧:

#define SYSTEM_CALL_ADDR 0xb7ec5e50  /*my system call addr*/
#define EXIT_CALL_ADDR  0xb7ebbb80   /*my exit call addr*/
char shell[] = "/bin/sh";

int main(){
 int* p; 
 p = (int*)&p + 2;
 *p = SYSTEM_CALL_ADDR;

 p = (int*)&p + 3;
 *p = EXIT_CALL_ADDR;

 p = (int*)&p + 4;
 *p = shell;

 return 1;
}

有趣的是,当我运行这个程序时,它以“分段错误”结束,但是如果我使用gdb进行调试并逐步运行它,那就完全没问题,产生一个shell然后退出程序。有人遇到这种情况吗?或者有人可以指导我如何纠正这个?先谢谢我在ArchLinux内核:2.6.33,gcc 4.5.0。

3 个答案:

答案 0 :(得分:3)

gdb禁用了一些缓冲区溢出漏洞利用缓解技术,如ProPolice和地址空间布局随机化(ASLR)。

答案 1 :(得分:1)

gdb设置ADDR_NO_RANDOMIZE personality(2)以便于调试。

答案 2 :(得分:0)

发生崩溃是因为你的变量'p'的声明在你的堆栈上为单个(int *)指针分配了足够的空间,但是你把值填充到(& p + 2)等等所以你最终覆盖谁知道什么。无论有没有gdb,它的行为都不同,因为谁知道哪个部分在一个环境中可能不是关键,但在另一个环境中却很关键。

您可以通过确保您要删除的空间不是什么重要来“修复”您的程序。

int main(){
 int* p;
 char junk[100];    /* ADD THIS */

现在,为'p'分配的存储空间之后的空间(很可能)将是垃圾字符数组,您可以通过覆盖来逃避。 (当我使用“gcc -O0 -g”编译时,至少在我的特定Linux系统上“修复”程序。)

所有这一切 - 你在那里使用的方法绝不是便携式或安全的。编译器不承诺它将以我们声明它们的特定顺序排列存储分配。此外,使用不同的优化开关进行编译可能会改变行为。因此,尽管这可能是一项有趣的练习,但您当然不应期望这种方法能够始终如一地运作。

以这种方式手动操作C堆栈是一个糟糕的想法!