登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

A1Pass的风清月朗居

追随技术的巅峰,突破欲望的枷锁!我,是技术与精神的享乐者!

 
 
 
 
 

日志

 
 

逆向一个非常有意思的小程序  

2009-11-08 15:27:48|  分类: 思绪燃星火——技 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

题记:用C++类来巧妙描述男孩与女孩的关系……

作者: A1Pass
时间: 2009-11-8
来源: 黑客反病毒 (http://bbs.hackav.com)
出处: http://bbs.hackav.com
注意: 转载请务必附带本组信息,否则侵权必究!

 

注:文章代码参考《高质量C++编程指南》改编,并感谢stuman的文章提供思路(本文自认为改正了stuman原文的错误,但并不可定,希望C++牛人们不惜赐教、使劲拍砖)。

拍砖地址:http://bbs.hackav.com/thread-1026-1-1.html

#include <iostream>
using namespace std;

//男人类
class boy
{
    public:  //他敞开胸怀
    void LoveYou()
    {
        cout << "Jessica, I love you, marry me!" << endl;
    }
    void KissYou()
    {
        cout << "Jessica, you are too sexy, I want to kiss you..." << endl;
    }
};

//上帝说女人是男人的肋骨做的,所以女人就由男人派生出来吧……
class girl : public boy
{
public:    //她也敞开胸怀……我什么都没看见 -_-!
    void LoveYou()
    {
        cout << "I love you too...But I am too shy to say..." << endl;
    }
    void KissYou()
    {
        cout << "You do what you want..." << endl;
    }
};

void main(void)
{
    boy  A1Pass;  //一个男孩叫A1Pass ^_^
    girl Jessica; //一个女孩叫杰西卡

    boy  *the_A1Pass_home  = &Jessica;
    girl *the_Jessica_home = &Jessica;

    //////////////////////////////////////////
    //------他们在干什么呀?请写出结果---------

    the_A1Pass_home ->LoveYou();
    the_Jessica_home->LoveYou();

    the_A1Pass_home ->KissYou();
    the_Jessica_home->KissYou();

    //////////////////////////////////////////
}

语法分析:
    通过“girl *the_Jessica_home = &Jessica”与“boy  *the_A1Pass_home  = &Jessica”我们可以断定这两个指针指向的地址都在同一位置,
因此下面调用其中指向的成员函数必然也会在同一个类中,因此其输出结果应该是两句重复的话,但真的是这样吗?
    我们可以将其具体化的描述一下,一个女孩类型的“杰西卡的家”指向了一个对象杰西卡,一个男孩类型的“A1Pass的家”指向了一个对象杰西卡
我们现在可以理解为“具有分身本领的杰西卡分别住进了一个女孩的家与一个男孩的家”。
    好了,现在我要分别调用“女孩家”与“男孩家”里拥有的方法了,现在假设男孩家里有一个“玩游戏机方法”,女孩家里有一个“玩布娃娃方法”,
试问假如我调用“男孩家”的某一方法后,男孩家会因为家里住着个女孩杰西卡从而改变自己原有的“玩游戏机”方法吗?肯定不会!
    因此我特意用以下两种方式做了试验,程序运行结果完全一样。
    boy  *the_A1Pass_home  = &A1Pass;
    girl *the_Jessica_home = (girl *)&A1Pass;
    与
    boy  *the_A1Pass_home  = NULL;
    girl *the_Jessica_home = NULL;
    因此其正确结果应该是:
    Jessica, I love you, marry me!
    I love you too...But I am too shy to say...
    Jessica, you are too sexy, I want to kiss you...
    You do what you want..

逆向分析:
注:此逆向分析主要为了帮助初学者建立这一种观念与看汇编代码的感觉,因此注释非常多,解释非常详细!忘大牛止步、菜鸟狂啃……

逆向一个非常有意思的小程序 - A1Pass - A1Pass的风清月朗居

解释:
04-10行是典型的VC DeBug版 编出来的特征,它会为每个函数开辟较大的空间,并用0xCC填充,以方便调试。
11-12行就是从堆栈里取地址,然后赋值给堆栈的另一块空间,通过堆栈结构图不难看出来,这就是将变量Jessica取地址并赋值给“girl *the_Jessica_home”的过程。
13-14行,很明显是“boy  *the_A1Pass_home  = &Jessica”。
15-16行,15行压栈的ECX在调用成员函数时会用到,这里我们不用管那么多,16行就是调用boy::Love you()了。
17-22行,原理同上,略。
23-28行同样是典型的VC DeBug版 编出来的特征,它会在函数结束时验证堆栈是否平衡,否则的话就会弹出一句提示。
29行是将在进入此函数时保存的堆栈状态还原回去。
30行是弹出保存堆栈原始状态的EBP寄存器。
31行是汇编里的返回语句,类似于C/C++的return。

    通过上面的反汇编指令可以看出来,源代码中的
    boy  A1Pass;
    girl Jessica;
    并没有真正的反映出来,而是默认就给了它们共计8字节的空间,并且程序执行的自始至终其内容都为被初始化后的0xCCCCCCCC。而反观我们用类类型指针调用的成员函数
并没有以指针的的方式表现出来,而是直接Call的地址。这就说明我们的代码再被编译器编译成二进制可执行文件之间就已经对我们的语法做了处理,绑定了其要调用的成员函数地址。

    由这篇文章初学者们可以学到两个知识点,一个是反汇编的重要性与大致意思,另一个就是C++的函数调用有很多情况都是分为编译前绑定调用与编译后动态调用的。
   
    时隔2个月的又一篇科普技术文章,希望大家喜欢。

  评论这张
 
阅读(2966)| 评论(12)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018