C代码如何更改代码中的返回地址?
我刚刚编写了如下 C 代码:
#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 is 1\n"); 行。早些时候我得到的线索是修改ret变量,它是函数func的返回地址。
您能否建议我如何更改上述程序中的返回地址,以便跳过 printf("\nx is 1\n"); 。
我发布这个问题是因为我不知道如何更改退货地址。
如果你能帮我的话那就太好了。
谢谢
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");
}
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.
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.
It would be great if you help me out.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
据我了解,您希望代码执行指令
x=1;
,然后跳过下一个 printf,这样它只会打印x is 0
。 没有办法做到这一点。但是,可以做的是让 func() 删除它自己的返回地址,这样代码就会直接跳转到
printf("\nx is 0\n\ n”);
。这也意味着跳过x=1;
。这是可能的,因为您将通过命令行传递的任何内容发送到 func() 并直接复制到固定大小的缓冲区。如果您尝试复制的字符串大于分配的缓冲区,您可能最终会破坏堆栈,并可能覆盖函数的返回地址。
关于这个主题,有一些很棒的书,比如 这本书,我建议您阅读他们。
在 gdb 上加载您的应用程序并反汇编 main 函数,您将看到与此类似的内容:
重要的是您注意到第二个 printf 调用的准备工作从地址开始
0x08048449
。为了覆盖func()
的原始返回地址并使其跳转到0x08048449
,您必须写入超出char 缓冲区的容量[24 ];
。在此测试中,为了简单起见,我使用了 char buffer[6];。在gdb中,如果我执行:
这将成功覆盖缓冲区并将返回地址替换为我希望它跳转到的地址:
我不会解释每一步,因为其他人已经这样做了它已经好多了,但是如果您想直接从命令行重现此行为,您可以执行以下命令:
请记住,gdb 向您报告的内存地址可能会有所不同比我得到的那些。
注意:要使此技术发挥作用,您必须首先禁用内核保护。但如果下面的命令报告任何与 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 printx is 0
. There's no way to do that.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 overx=1;
too.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.
Loading your application on gdb and disassembling the main function, you'll see something similar to this:
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 offunc()
and make it jump to0x08048449
, you'll have to write beyond the capacity ofchar buffer[24];
. On this test I usedchar buffer[6];
for simplicity purposes.While in gdb, if I execute:
this will successfully override the buffer and replace the address of return with the address I want it to jump to:
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:
Keep in mind that the memory addresses that gdb reports to you will probably be different than the ones I got.
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:
to disable it you'll need superuser access:
func
的返回地址位于堆栈上,靠近其局部变量(其中之一是buffer
)。如果你想覆盖返回地址,你必须写到数组的末尾(可能是buffer[24...27]
但我可能错了 - 可能是buffer[ 28...31]
甚至buffer[24...31]
(如果您有 64 位系统)。我建议使用调试器来找出确切的地址。顺便说一句,去掉 ret 变量 - 拥有它你什么也做不了,而且它可能会混淆你的计算。
请注意,这种“缓冲区溢出漏洞利用”有点难以调试,因为 strcpy 在遇到零字节时会停止复制内容,而您要写入堆栈的地址可能包含这样的字节。这样做会更容易:
并在命令行上以十六进制字符串形式给出地址。这使得您想要做的事情更加清晰,并且更容易调试。
The return address from
func
is on the Stack, right near its local variables (one of them isbuffer
). If you want to overwrite the return address, you have to write past the end of the array (possibly tobuffer[24...27]
but i am probably mistaken - could bebuffer[28...31]
or evenbuffer[24...31]
if you have a 64-bit system). I suggest using a debugger to find out the exact addresses.BTW get rid of the
ret
variable - you accomplish nothing by having it around, and it might confuse your calculations.Note that this "buffer overrun exploit" is a bit hard to debug because
strcpy
stops copying stuff when it encounters a zero byte, and the address you want to write to the stack probably contains such a byte. It will be easier to do it like this:And give the address on the command-line as a hexadecimal string. This makes it a bit more clear what you're trying to do, and easier to debug.
这是不可能的 - 这是可能的,如果你知道编译器及其工作原理、生成的汇编代码、使用的库、体系结构、CPU、系统环境和明天的乐透号码 - 如果你有这个知识,你足够聪明,不去问。唯一有意义的情况是当有人尝试某种攻击,并且不期望有人愿意帮助您时。
This is not possible - it would be possible, if you know the compiler and how it works, the generated assembler code, the used libraries, the architecture, the cpu, the system environment and the lotto numbers of tomorrow - and if you had this knowledge, you would be clever enough not to ask. The only scenario where it would make sense is when someone tries some kind of attack, and do not expect that someone is willing to help you with it.