一道有趣的C基础题,感兴趣的可以试试。[5月15日修]
感谢whislter 对本人错误的指出,现对本文进行如下修订。
;===========================================
;一道有趣的C基础题,感兴趣的可以试试。
;Author: Lonkil
;By Lonkil (lonkil_at_gmail.com)
;2008-5-6
;Site:www.vcfans.com
;===========================================
在看雪看到这样的一道题:
原文地址:http://bbs.pediy.com/showthread.php?t=51839
题目如下:
1、如何在下面的test函数里加入代码可以使程序运行起来输入和输出的相等?
(环境是vc6Debug方式下)
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include<stdio.h> void test() { int t; scanf(“%d”,&t); //在这里加入代码 } void main() { int m; test(); printf(“m=%d”,m); } |
—————————–感兴趣的您可以试试做一下————————————–超级无耻分割线—–
很有趣,我花了几份钟想了一下,由于手头没有VC6,VS2005启用了保护机制,过不去。就在GCC里试了一下,Ok。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include<stdio.h> void test() { int t; scanf(“%d”,&t); //GCC下的解法: *( (&t) + 12 ) = t;//加这行代码就OK,没做出来的朋友可以在GCC下试试 //MS编译器下的解法: *( (&t) + 3 ) = t ;//详情请见下面分析 } void main() { int m; test(); printf(“m=%d”,m); } |
原因我分析一下。
MS我编译器下的栈分析,由于t和m的分配在栈中的,栈是由下而上递减,而且MS的栈是4个字节对齐的。
t和m在栈中的分配情况:
| 变量t占用的空间 32位 |
| test函数保存的EBP 32位 |
| test函数返回的空间 32位 |
| 变量m占用的空间 32位 |
GCC下的栈分配情况,GCC是16个字节对齐:
| 变量t占用的空间 16字节 |
| test函数保存的EBP 16字节 |
| test函数返回的空间 16字节 |
| 变量m占用的空间 16字节 |
要想t和m两值相等,就要在test函数中访问m的地址。由于栈是向下增加的,将i的地址加12正好是m的地址,这个题就算搞定了。
其实上贴作者的题目也是不是什么基础最要对栈平衡了解一点的话,几题都OK。
不过能想出这样题的作者不是绝顶高手,对调试逆向肯定拿手好戏。佩服一下。
说明:
在修订之前我没在MS平台上作测试,因为题目作者要求要VC6.0下作测试,我在VS2005下在默认编译设置的情况下,运行出错,以为是平台问 题,就在GCC下试了一下,加12得出了结果,其实我当时那个结果是错误的。正如whislter,我是碰巧蒙对的。因为我当根本没有想到GCC的栈是 16字节对齐。而且我犯了一个极端低级的错误,居然将C语言的指针加1当成汇编下的地址加1了,其实指针加1是将其地址加sizeof(指针类型)个字 节。很巧的是居然正好和GCC上的16字节对齐相吻合。faint,犯了个错误。
另外如果成MS编译环境下运行该程序,需要将生成模式设成Realse,并且将”Project Setting”->”C/C++”->”Optimizations”,设成”Default”,否则编译器会在生成的代码中参杂其它信息,影响分析结果。
4 条评论
*( (&t) + 3 ) = t ;//在VC6下
补充一下,生成模式是Realse
程序如下
#include
void test()
{
int t;
printf(“&t: %08x\n”, &t);
printf(“((&t)+4): %08x\n”, ((&t)+4));
printf(“t=”);
scanf(“%d”,&t);
//在这里加入代码
*((&t)+4) = t;
}
void main()
{
int m;
printf(“&m: %08x\n”, &m);
test();
printf(“m=%d\n”,m);
}
控制台的显示结果:
&m: 0012ff80
&t: 0012ff70
((&t)+4): 0012ff80
t=56
m=4223216
和预期的不一样,我也没想出为什么
在vc6中测试不成功