#include <stdio.h> void attack() { printf("hi,attacked!\n"); } void foo() { int c_foo; int main_eip = (int) *(&c_foo + 3); *(&c_foo + 3) = (int)attack; *(&c_foo + 4) = main_eip; } void main() { int local; foo(); printf("I am retrun!\n"); } |
原帖由 iLRainyday 于 2009-12-14 18:18 发表
模仿着内核版的一个精华帖,写了一个最基础的练习题,不知道为什么会重复输出两次,然后segment fault
#include
void attack() {
& ...
汗,你把那篇东西找出来对一对,连抄都抄错
还是要理解才好呀。
cu.jpg (43.67 KB, 下载次数: 80)
#include <stdio.h> void g() { printf("call g\n"); } void epilogue(void) {} void prologue(void* anchor) { void** top = &anchor - 1; void** end = anchor; top[0] = g; while ( ++top != end ) *top = epilogue; } void f(void* anchor) { void (*noinline)(void*) = prologue; noinline(&anchor - 1); } int main(void) { void (*noinline)(void* ) = f; printf("enter\n"); noinline(0); printf("leave\n"); return 0; } |
原帖由 iLRainyday 于 2009-12-8 22:34 发表
...
#define ARRAY_SIZE(arr)
(sizeof(arr) / sizeof(((typeof(arr)){})[0]))
...
原帖由 iLRainyday 于 2009-12-15 02:04 发表
按照mik老大的指点,从foo()中ret后,应该是这样的:
----------------------------
ret_value
应该没错的,试过没?
#include <stdio.h> void attack() { printf("hi,attacked!n"); } void foo() { int c_foo; int main_eip = (int) *(&c_foo + 3); *(&c_foo + 3) = (int)attack; *(&c_foo + 4) = (int) *(&c_foo + 2); *(&c_foo + 5) = main_eip; } void main() { int var; foo(); printf("I am retrun!n"); } |
那对了没
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. |
原帖由 iLRainyday 于 2009-12-15 11:05 发表
GOD!!!Jesus Christ!!!!这代码也太绕了吧,本来推算堆栈的位置就够费神了,这个连二级指针都能出来了。不过通过参数来确定eip的位置的方法不错,比起用局部变量似乎要清晰。
原帖由 iLRainyday 于 2009-12-15 11:05 发表
1. 如果有 void *ptr_v,肯定是不能对ptr_v进行算术运算,因为没有指向的type信息。但是竟然可以对&ptr_v进行算术运算,而且+1的步长和int *ptr_i是一样的
... frame of prologue ... return of prologue 替换为g anchor of prologue 替换为epilogue ... ... 替换为epilogue frame of f 替换为epilogue ... ... 替换为epilogue return of f 维持 anchor of f |
另外, 如果真的将指针传入这个使用了gcc扩展的ARRAY_SIZE, 会怎样? 编译错误?
难道会得到正确的结果???
关键应该在这里,你只call了一次,也就是eip压入栈只进行了一次,却两个函数的最后的ret却会pop eip两次,所以main中堆栈不平衡了,估计你在主函数的printf之前或则main返回之前加一句__asm__("sub $0x4,%esp"); 就对了
顺便说一句,用你最先那个版本哈,不需要保存ebp
#include <stdio.h> void attack() { printf("hi,attacked!n"); } void foo() { int c_foo; int main_eip = (int) *(&c_foo + 3); *(&c_foo + 3) = (int)attack; *(&c_foo + 4) = main_eip; } void main() { int var; foo(); __asm__("sub $0x4,%esp"); printf("I am retrun!n"); } |
#include <stdio.h> void attack() { printf("hi,attacked!\n"); } void foo() { int c_foo; int main_eip = (int) *(&c_foo + 3); *(&c_foo + 3) = (int)attack; *(&c_foo + 4) = main_eip; } int main(int argc, char *argv[]) { int local; foo(); __asm__("sub $0x4,%esp"); printf("I am retrun!\n"); return 0; } |
将T代换为 void* 即可。 步长当然就是 sizeof( void*) , 在i386下当然和 sizeof(int*), sizeof(int) 是相同的。
#include <stdio.h> int main() { int i; char c; void *ptr = NULL; printf("&ptr is %#x, &ptr+1 is %#xn", &ptr, &ptr+1); ptr = &i; printf("&ptr is %#x, &ptr+1 is %#xn", &ptr, &ptr+1); ptr = &c; printf("&ptr is %#x, &ptr+1 is %#xn", &ptr, &ptr+1); printf("&i is %#x, &i+1 is %#xn", &i, &i+1); printf("&c is %#x, &c+1 is %#xn", &c, &c+1); return 0; } |
2009-12-15 17 29 57.jpg (14.48 KB, 下载次数: 16)
我写那段代码时, 捣鼓了半天, 弄出一对prologue,epilogue 就是为了避免这一句 :
__asm__("sub $0x4,%esp");
在Generic Pointers一节中,“Type void * is considered to be neither an object pointer nor a function pointer"
这个说法是在哪找到的? C: A reference manual ?
这个说法和C标准好像有点冲突。
Type void * is considered to be neither an object pointer nor a function pointer.
...
Any pointer to an object or incomplete type( but not a function type ) can be converted to type void* and back without change.
Type void * is considered to be neither an object pointer nor a function pointer.
...
—— 5.3.1 Generic Pointers, p137 末尾
function pointers and data pointers may have significantly differnet representations,including different sizes.
in standard C,void * can be used as a generic object pointer,but there is no generic funciton pointer.
c89 6.3.4 Cast operators p45
...
A pointer to a function of one type may be converted to a pointer to a function of another
type and back again; the result shall compare equal to the original pointer. If a converted
pointer is used to call a function that has a type that is not compatible with the type of the
called function. the behavior is undefined.
...
欢迎光临 Chinaunix (http://bbs.chinaunix.net/) | Powered by Discuz! X3.2 |