韩小明@xiammy的专栏

没水的地方挖井,有水的地方修渠

韩小明ID:xiammy
438252次访问,排名107好友11人,关注者66
毕业后一直在广联达工作
xiammy的文章
原创 174 篇
翻译 0 篇
转载 22 篇
评论 1131 篇
韩小明的公告
作者毕业于浙江大学,非常热爱体育运动。现在尤其热爱羽毛球运动。在休息时间非常热爱技术文章写作。
最近垃圾评论泛滥,为了不污染大家的视听,暂时关闭评论,请大家理解。
欢迎转载,但请注意,除非特别声明,本站采用Creative Commons License许可:署名,非商业。

最近评论
liquankun:瑞星还是不咋地!
白花了几个月的钱
外国的杀软不一定比国产的好!
但是国产的就是比不上国外的!
没办法!技术赶不上人家 还竟搞内讧
不经历大灾难 就不知道什么是团结!



正真的高手是不用杀毒软件的,没什么好不好的,是你自己技术不行而已
wangdei:http://www.bt285.cn BT下载 有300W部BT种子.
http://www.yaonba.com.cn NBA中文网 有200W条NBA直播
http://www.5a520.cn 小说520网 有300W部小说
http://www.bt285.cn/yazhou/ 亚洲BT 有BT亚洲
http://www.bjxlz.cn p……
hemir:不但不知道团结提高,倒是会找枪手到处胡闹。弄的整个环境乌烟瘴气的。
hemir:不但不知道团结提高,倒是会找枪手到处胡闹。弄的整个环境乌烟瘴气的。
hemir:枪手太多,大家都还是相信自己的眼睛吧。个人认为360做的不错。国内的杀毒软件确实不怎么地……
文章分类
收藏
    相册
    图书
    链接
    宗刚的专栏(RSS)
    快乐学习(RSS)
    陈亮亮的专栏(RSS)
    朋友
    张恂论 OO
    言之有李(RSS)
    赵伟的小家
    存档
    订阅我的博客
    XML聚合  FeedSky

    原创 自动化测试框架:用AOP为每一个操作写Log收藏

    新一篇: 在CSDN写博客后的好处一览 | 旧一篇: 自动化测试框架:没有Surprise的原因

    在写这个自动化测试框架的时候,我一直在留意各方面的需求。毕竟,我本人并没有做过真正的自动化测试。管理测试方面的领导,提出一个需求,就是在用例运行失败的时候,应该将过程记录下来,并形成报告,Email给相关人员。

    个人认为这个需求是非常合理的。事实上,任何系统,如果没有输出,那么只能停留在程序员手里。有了报表,才叫真正解决了用户的目标需求。

    在分析这个需求的过程,我提出了针对每一个操作接口的每一个方法,进行Log。而完成这个工作的第一方法,就想到了AOP,也就是Hook技术的应用。因为Delphi下面并没有对AOP的直接支持,所以考虑这个实现,变成了一个技术研究过程。

    从技术上讲,本篇博客只适合了解VCL的Delphi程序员阅读。但其间的思想,相信大家都可以借鉴。下面我的描述过程,是以我的探索过程来进行讲述的。中间会带出相关技术点,供大家参考。

    第一、接口的方法,是由类来实现的。框架中,已经对所有支持的类都进行了登记。那么,只需要在这些类型中,找到所有实现的接口的所有方法的地址,那么Hook就变得有可能了。

    TObject有一个方法:GetInterfaceTable,可以获取所有接口列表。所有非常容易找到接口对应的VTable。VTable在Delphi中并没有明确的注释,但是可以知道VTable是一个指针列表,每一项都记录着一个方法的“实现地址”。

    可惜的是,我发现VTable本身并没有告诉你,这个接口有多少个方法!另外,你也不能得到每一个方法的名称,以及参数等等描述。

    第二、于是我考虑到接口的RTTI。接口的RTTI,我以前是没有使用过的。通过VCL的代码研究,发现接口中有一个非常特殊的接口定义:{$M+}IInvokable = interface;{$M-}。这个接口本身并没有添加什么服务,只是使用了编译指令M,来使得接口拥有了RTTI。

    实现的时候,可以通过从IInvokable派生,或者直接添加编译指令,从而获得RTTI服务。

    下面的问题是,如何使用RTTI?我们知道,Delphi中有一个单元叫TypInfo.pas,后来我发现,其实有另外一个单元叫:IntfInfo.pas。这里面有一个方法GetIntfMetaData可以帮助你获得RTTI。另外,值得一提的是,获取接口类型的PTypeInfo的方法是调用TypeInfo(IMyInterface);

    第三、通过MetaData分析,我们可以知道接口的方法个数以及每一个方法的详细定义。那么,现在就是如何Hook了。下面是一个Object的对象实例事例图。

     

    做左边,有Self标识的是对象的实例数据块。某一个几口指针IMyInterface指针,指向了一个VTable。而VTable中的每一个Method,都指向了一段代码,这段代码的前一部分,是为了计算EAX(保证将IMyInterface的地址,偏移到Self所在地址)。

    分析上面的结构,再实际在CPU窗体中,调试以下接口方法的调用过程,发现,必然和Method地址有关。因此,Hook的目标,就非常自然地变成修改VTable中的Method1的地址值。

    第四、如何修改代码?这里建议大家学习以下FastCode代码。简单一点,就是通过调用VirutalProtect方法,修改代码段中内存的访问属性,然后修改地址,最后再恢复回去。

    显然在Hook之前,必须声明新的函数。

    第五、新的函数并不是那么好声明的。关注一下,接口函数的调用代码,你会发现很多问题。下面举一个简单的例子。

    IMyInterface = interface(IInvokable)

      procedure AAA;

    end;

    假设TMyIntfImpl类实现了上面的接口。那么oIntfObj: IMyInterface声明的对象,oIntfObj.AAA;的汇编代码是如下的样子:

    上面是两段代码的图片,其中[dex+$0c]指的就是$004661FD,也就是第二段代码图片的首地址。大家可以再联系一下上面的示意图理解一下地址的关键。

    好,言归正传。这里注意一下,我们要修改的是[dex+$0c]里面的值。但是由于这个是call过去的。所以在call之前,会在堆栈中压入函数返回地址。另外,在调用函数之前,还有函数参数的准备。比如说Self指针的传入到EAX中,如果本身方法还有参数的话,可能占用其他寄存器或者堆栈。

    由于我们要求是Hook住所有的方法,并且所有方法的参数类型并不一定一样。所以在call之前的代码,是无法预计的。所以在新的函数中,必须考虑如何做到保存寄存器和做到ret时候的栈平衡。

    通过我的实践,我的做法是通过先弹出当前的ret地址,保存到一个数据区中。等待调用完原先的代码后,再压栈。而调用Writelog的时候,先保存寄存器,调用完了之后,再恢复寄存器。这是因为寄存器也可能是返回值的地方。而且后续代码有可能优化使用。

    第六、完成了汇编的编写,还有一个问题,那就是由于每一个函数的原地址不一样,所以必须为每一个函数,定义一个代理函数。由于这些函数的地址和个数都是未定的,所以,这里就必须要用到动态创建代码。

    动态创建代码的方法看上去简单,申请一段空间,将那一段模板代码地址复制过来。但是,实际情况并非如此。

    首先,申请控件的时候,使用VirutalAlloc,并指定EXECUTE_READWRITE属性。另外,要关注到原来的代码是在代码段执行的,所以有些函数的地址可能只是一个偏移地址。而后申请的代码,是在HEAP中运行的,所以,如果只是单纯地复制,函数调用就会报错了。

    好了,上面讲了六点关键因素。如果你足够理解上面的过程,你也可以做到AOP了。这篇文章是一个纯技术的,可能关心测试的会非常失望,只能说sorry了。

     

    发表于 @ 2007年05月30日 22:48:00|评论(loading...)|编辑

    新一篇: 在CSDN写博客后的好处一览 | 旧一篇: 自动化测试框架:没有Surprise的原因

    评论

    #shrinerain 发表于2007-05-31 12:46:52  IP: 218.108.51.*
    恩,我们公司采用的方法,是进行截屏.
    当fail的时候,log文件记录当前运行的输入数据, 以及当前屏幕截图.
    #shrinerain 发表于2007-05-31 12:48:59  IP: 218.108.51.*
    一般自动化测试中其实最重要的工作,一个是数据驱动的准备.
    一个是错误处理机制.

    特别是要实现无人值守的自动化测试,错误处理机制是重中之重.
    #onemonth 发表于2007-06-01 09:43:44  IP: 222.183.26.*
    1、楼主请更换头像,看着慎人。
    2、AOP这样的技术,从概念上说,类似goto这样的东西,少用为好。自己定义一个metadata,比aop好得多。不需要你作这些事情,好控制得多,可用的地方也多很多。
    3、做事需要真的明白技术到底是什么,要会举一反三。
    #liigo 发表于2007-06-04 10:54:35  IP: 221.201.64.*
    楼上的,“要……,不要……”的语气,还是应该少用呀,呵呵。技术交流是在平等条件下进行的。
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © 韩小明