生活的天平本不平衡,只有通过努力改变其偏向。

一道有趣的C基础题,感兴趣的可以试试。[5月15日修]

2008-05-06

感谢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”,否则编译器会在生成的代码中参杂其它信息,影响分析结果。

作者:lonkil | 分类目录:编程开发 | 标签:

4 条评论

  1. lonkil 说道:

    *( (&t) + 3 ) = t ;//在VC6下

  2. zhjiawei_cn 说道:

    补充一下,生成模式是Realse

  3. zhjiawei_cn 说道:

    程序如下
    #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

    和预期的不一样,我也没想出为什么

  4. zhjiawei_cn 说道:

    在vc6中测试不成功

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>