免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: iLRainyday

这个最基础的注入为什么会出错啊? [复制链接]

论坛徽章:
0
发表于 2009-12-15 16:33 |显示全部楼层
这个跟gcc的版本有很大关系,也不知道你用的哪个gcc, 你最好把main的汇编代码贴出来
你应该知道如何反汇编吧,在gdb中disass main

论坛徽章:
0
发表于 2009-12-15 16:46 |显示全部楼层
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

(gdb) disassemble main
Dump of assembler code for function main:
0x080483d3 <main+0>:    lea    0x4(%esp),%ecx
0x080483d7 <main+4>:    and    $0xfffffff0,%esp
0x080483da <main+7>:    pushl  -0x4(%ecx)
0x080483dd <main+10>:   push   %ebp
0x080483de <main+11>:   mov    %esp,%ebp
0x080483e0 <main+13>:   push   %ecx
0x080483e1 <main+14>:   sub    $0x14,%esp
0x080483e4 <main+17>:   call   0x8048398 <foo>
0x080483e9 <main+22>:   movl   $0x80484dd,(%esp)
0x080483f0 <main+29>:   call   0x8048294 <puts@plt>
0x080483f5 <main+34>:   add    $0x14,%esp
0x080483f8 <main+37>:   pop    %ecx
0x080483f9 <main+38>:   pop    %ebp
0x080483fa <main+39>:   lea    -0x4(%ecx),%esp
0x080483fd <main+42>:   ret   
End of assembler dump.

(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048398 <foo+0>:     push   %ebp
0x08048399 <foo+1>:     mov    %esp,%ebp
0x0804839b <foo+3>:     sub    $0x10,%esp
0x0804839e <foo+6>:     lea    -0x8(%ebp),%eax
0x080483a1 <foo+9>:     add    $0xc,%eax
0x080483a4 <foo+12>:    mov    (%eax),%eax
0x080483a6 <foo+14>:    mov    %eax,-0x4(%ebp)
0x080483a9 <foo+17>:    lea    -0x8(%ebp),%eax
0x080483ac <foo+20>:    add    $0xc,%eax
0x080483af <foo+23>:    mov    $0x8048384,%edx
0x080483b4 <foo+28>:    mov    %edx,(%eax)
0x080483b6 <foo+30>:    lea    -0x8(%ebp),%edx
0x080483b9 <foo+33>:    add    $0x10,%edx
0x080483bc <foo+36>:    lea    -0x8(%ebp),%eax
0x080483bf <foo+39>:    add    $0x8,%eax
0x080483c2 <foo+42>:    mov    (%eax),%eax
0x080483c4 <foo+44>:    mov    %eax,(%edx)
0x080483c6 <foo+46>:    lea    -0x8(%ebp),%eax
0x080483c9 <foo+49>:    add    $0x14,%eax
0x080483cc <foo+52>:    mov    -0x4(%ebp),%edx
0x080483cf <foo+55>:    mov    %edx,(%eax)
0x080483d1 <foo+57>:    leave  
0x080483d2 <foo+58>:    ret   
End of assembler dump.

(gdb) disassemble attack
Dump of assembler code for function attack:
0x08048384 <attack+0>:  push   %ebp
0x08048385 <attack+1>:  mov    %esp,%ebp
0x08048387 <attack+3>:  sub    $0x8,%esp
0x0804838a <attack+6>:  movl   $0x80484d0,(%esp)
0x08048391 <attack+13>: call   0x8048294 <puts@plt>
0x08048396 <attack+18>: leave  
0x08048397 <attack+19>: ret   
End of assembler dump.

论坛徽章:
0
发表于 2009-12-15 16:53 |显示全部楼层
0x080483f5 <main+34>:   add    $0x14,%esp
0x080483f8 <main+37>:   pop    %ecx

关键应该在这里,你只call了一次,也就是eip压入栈只进行了一次,却两个函数的最后的ret却会pop eip两次,所以main中堆栈不平衡了,估计你在主函数的printf之前或则main返回之前加一句__asm__("sub $0x4,%esp"); 就对了

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-12-15 16:54 |显示全部楼层
以i386来说 :

原帖由 iLRainyday 于 2009-12-15 11:05 发表
GOD!!!Jesus Christ!!!!这代码也太绕了吧,本来推算堆栈的位置就够费神了,这个连二级指针都能出来了。不过通过参数来确定eip的位置的方法不错,比起用局部变量似乎要清晰。

你无法确定局部变量和返回地址之间的偏移。 编译器可能会在局部变量之间放入一些填充, 进行一些错误检查。
是否有frame-pointer也会影响这个偏移。

而anchor 和返回地址之间的的偏移就更稳定一些。 我也不知道会不会有例外情况。 但至少在gcc和msvc下是这样的。


原帖由 iLRainyday 于 2009-12-15 11:05 发表
1. 如果有 void *ptr_v,肯定是不能对ptr_v进行算术运算,因为没有指向的type信息。但是竟然可以对&ptr_v进行算术运算,而且+1的步长和int *ptr_i是一样的

不要被2级指针迷惑了。

void f( T anchor ) {
      // &anchor  是 T*
      // &anchor - 1 的步长当然就是是sizeof( T )。
}

将T代换为 void*  即可。 步长当然就是 sizeof( void*) , 在i386下当然和 sizeof(int*), sizeof(int) 是相同的。

取T=void* ,主要是为了少写一些显示类型转换。


原帖由 iLRainyday 于 2009-12-15 11:05 发表
会将f()用于返回时的ebp给覆盖掉,这样子没有问题吗?


假设, 开始执行prologue时, 堆栈如此

...
frame  of prologue
...
return of prologue   替换为g
anchor of prologue   替换为epilogue
...                  ... 替换为epilogue
frame  of f          替换为epilogue
...                  ... 替换为epilogue
return of f          维持
anchor of f


确实将f的frame全部破换了。 但只要g中不使用frame of f, 就应该不会有什么问题。


原帖由 iLRainyday 于 2009-12-15 11:05 发表
ARRAY_SIZE 就是为了防止不小心将指针作为参数传入,别的貌似也没了


将指针传递给ARRAY_SIZE, 就应该去回炉重学。

另外, 如果真的将指针传入这个使用了gcc扩展的ARRAY_SIZE, 会怎样? 编译错误?
难道会得到正确的结果???

论坛徽章:
0
发表于 2009-12-15 16:54 |显示全部楼层
顺便说一句,用你最先那个版本哈,不需要保存ebp

论坛徽章:
0
发表于 2009-12-15 16:59 |显示全部楼层
另外, 如果真的将指针传入这个使用了gcc扩展的ARRAY_SIZE, 会怎样? 编译错误?
难道会得到正确的结果???

的确是编译错误,这样子就能提醒编写者注意到问题,因为误传指针往往是无意之为(假设是个不熟练的程序员),这样子能减少后期的出错麻烦,作者应该是这么考虑的吧:wink:


关键应该在这里,你只call了一次,也就是eip压入栈只进行了一次,却两个函数的最后的ret却会pop eip两次,所以main中堆栈不平衡了,估计你在主函数的printf之前或则main返回之前加一句__asm__("sub $0x4,%esp"); 就对了

这个我今天早上也想到了,我一直觉得段错误是因为返回main()的时候退栈不平衡,因为attack()多pop了4字节,所以我在main()中的foo()之后,printf()之间加上了__asm__("sub $0x4,%esp");结果照样是segment fault.....


顺便说一句,用你最先那个版本哈,不需要保存ebp

以前那个版本也不行...同样的段错误...你现在知道我有多崩溃了吧....

[ 本帖最后由 iLRainyday 于 2009-12-15 17:03 编辑 ]

论坛徽章:
0
发表于 2009-12-15 17:02 |显示全部楼层
我试一下

论坛徽章:
0
发表于 2009-12-15 17:12 |显示全部楼层
哈哈~~~没问题了~~~我想起来了,今天早上我是把那句__asm__加到保存ebp那个版本里了,我刚才把它加到我最初那个版本里面,就ok了~

谢谢"mik,OwnWaterloo ,学与思"不厌其烦的指点!

#include <stdio.h>

void attack() {

&nbsp;&nbsp;printf("hi,attacked!n");
}


void foo() {

&nbsp;&nbsp;&nbsp;&nbsp;int c_foo;
&nbsp;&nbsp;&nbsp;&nbsp;int main_eip = (int) *(&c_foo + 3);

&nbsp;&nbsp;&nbsp;&nbsp;*(&c_foo + 3) = (int)attack;
&nbsp;&nbsp;&nbsp;&nbsp;*(&c_foo + 4) = main_eip;

}

void main()
{
&nbsp;&nbsp;int var;
&nbsp;&nbsp;foo();
&nbsp;&nbsp;__asm__("sub $0x4,%esp");
&nbsp;&nbsp;printf("I am retrun!n");

}


[ 本帖最后由 iLRainyday 于 2009-12-15 17:14 编辑 ]

论坛徽章:
0
发表于 2009-12-15 17:29 |显示全部楼层
#include <stdio.h>

void attack() {
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;printf("hi,attacked!\n");
}


void foo() {
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;int c_foo;
&nbsp;&nbsp;&nbsp;&nbsp;int main_eip = (int) *(&c_foo + 3);
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;*(&c_foo + 3) = (int)attack;
&nbsp;&nbsp;&nbsp;&nbsp;*(&c_foo + 4) = main_eip;
&nbsp;&nbsp;&nbsp;&nbsp;
}

int  main(int argc, char *argv[])
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int local;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foo();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__asm__("sub $0x4,%esp");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("I am retrun!\n");

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;
}

论坛徽章:
0
发表于 2009-12-15 17:30 |显示全部楼层
将T代换为 void*  即可。 步长当然就是 sizeof( void*) , 在i386下当然和 sizeof(int*), sizeof(int) 是相同的。


不止是在这里,发现好像在C里,对于void *类型的pointer的地址做算术运算的时候,统一是按照4字节步进的。

#include <stdio.h>

int main()
{
&nbsp;&nbsp;&nbsp;&nbsp;int i;
&nbsp;&nbsp;&nbsp;&nbsp;char c;
&nbsp;&nbsp;&nbsp;&nbsp;void *ptr = NULL;

&nbsp;&nbsp;&nbsp;&nbsp;printf("&ptr is %#x, &ptr+1 is %#xn", &ptr, &ptr+1);

&nbsp;&nbsp;&nbsp;&nbsp;ptr = &i;
&nbsp;&nbsp;&nbsp;&nbsp;printf("&ptr is %#x, &ptr+1 is %#xn", &ptr, &ptr+1);

&nbsp;&nbsp;&nbsp;&nbsp;ptr = &c;
&nbsp;&nbsp;&nbsp;&nbsp;printf("&ptr is %#x, &ptr+1 is %#xn", &ptr, &ptr+1);

&nbsp;&nbsp;&nbsp;&nbsp;printf("&i is %#x, &i+1 is %#xn", &i, &i+1);
&nbsp;&nbsp;&nbsp;&nbsp;printf("&c is %#x, &c+1 is %#xn", &c, &c+1);

&nbsp;&nbsp;&nbsp;&nbsp;return 0;
}
2009-12-15 17 29 57.jpg
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP