• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

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

发布: 2009-6-02 09:50 | 作者: 不详 | 来源: 测试时代采编 | 查看: 235次 | 进入软件测试论坛讨论

领测软件测试网

做左边,有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了。


延伸阅读

文章来源于领测软件测试网 https://www.ltesting.net/

22/2<12

关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备10010545号-5
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网