从图上可以看到我们测试工具进程可以同时和多个目标进程通讯,也就是可以获取任意进程窗口的文字信息。
这里就涉及到进程间通讯技术,一般来说最高效的是用内存映射文件,但是这里我们为了简单,采用WM_COPYDATA消息,用WM_COPYDATA就涉及到窗口,显然,我们这里的通讯窗口也应该采用一对多的形式,TAUtil.dll内有一个隐藏的主通讯窗口,另外每个目标进程的Detector.dll内有一个隐藏的辅助通讯窗口,主通讯窗口和辅助通讯窗口之间通过WM_COPYDATA通讯。
下面说下大概的流程:
1. TA Tool加载TAUtil.dll, TAUtil.dll创建主通讯窗口
2. TAUtil.dll在目标进程中创建RemoteThread, 目标进程加载Detector.dll, Detector.dll在Attatch时创建辅助通讯窗口
3. TAUtil.dll发消息给Detector.dll请求获取目标窗口文字信息,然后等待
4. Detector.dll Hook 绘画文字的API,然后请求目标窗口重画窗口,重画结束后卸载Hook,然后Detector.dll再将截获到的文字发回给TAUtil.dll
5.TAUtil.dll收到文字信息后继续执行.
这里有几点要注意,一是主通讯窗口和辅助通讯窗口都要单独的线程中运行,不然会阻塞主线程; 二是如何判断文字是画在目标窗口上的,我们可以通过WindowFromDC来判断,但是对于内存DC,调用这个API时他会返回NULL, 这时我们就要跟踪所有DC拷贝的API,这样才能判断最终文字是不是画到了我们的目标窗口上. 如果我们要知道文字的绘画位置,还要跟踪DC拷贝的相对位置。windows绘画文字的API包括DrawTextA, DrawTextW, DrawTextExA, DrawTextExW, ExtTextOutA, ExtTextOutW, TabbedTextOutA, TabbedTextOutW, PolyTextOutA, PolyTextOutW, TextOutA, TextOutW, DC拷贝的API包括BitBlt,TransparentBlt,PatBlt,StretchBlt等.
上面是屏幕取词的实现原理, 接下来我们考虑如何操作目标进程菜单?
在考虑这个问题之前,我们先要知道Windows内部的对象类型, Windows的内部的对象类型分为GDI Object, User Object, Kernel Object, GDI Object包括Bitmap, Brush, DC, Pen 等,这些都只在该进程内有效; User Object包括HWND,HMENU等,这些对象是跨进程的,任何进程只要知道这个句柄值就可以操作它; Kernel Object 是系统共享的,包括进程句柄,线程句柄,Mutex,Event等,进程只要有权限,进程内核对象表中有该项,就可以访问。
显然,对于菜单,因为他是属于用户对象,外部进程只要得到它的HMENU就可以通过菜单相关的API来操作了。那么接下来我们的问题就是如何得到菜单句柄了. 方法同样是API Hook ,我们只要Hook 系统API TrackPopupMenu和TrackPopupMenuEx就可以了, 大概流程是:
1. 安装菜单相关的API Hook
2. 模拟鼠标点击淡出菜单
3. 得到Hook 到的菜单句柄,卸载Hook
4 .通过菜单相关API查询菜单内容,操作菜单
综上,API Hook技术可以在自动化测试时可以实现我们平时测试时做不到的事情,通过目标进程的窗口层次和该技术结合,基本上可以将自动测试覆盖率达到85%以上, 不能达到100%是因为有一部分UI信息是通过图片来表现,这个涉及到图像识别了。