Spy++更新

嗨,又是帕特·布伦纳。 我最近发表了一篇关于 Spy++内部 . 我有一些更新想和你分享。 如果你先读这篇文章,其中的一些内容会更清楚。

null

首先,已经为visualstudio代码名Orcas更新了Spy++,以处理windowsvista中添加的新公共控件/消息/标志。 这意味着,如果在Vista上运行Spy++,应该正确解码所有新消息及其参数,以便更准确地确定应用程序和系统中发生了什么。 这些更改与MFC的一系列更新同步进行,以包装新的控件和消息(请参阅相关文章) 在这里 ),因此当您使用这些新功能时,MFC将使编写它们更容易,Spy++将使分析更容易。

其次,除了作为32位应用程序构建外,Spy++现在还作为IA64和AMD64的64位本机应用程序构建,因此您也可以在本机64位应用程序中记录消息。 这是因为32位应用程序只能在其他32位应用程序中安装钩子,而64位应用程序只能在其他64位应用程序中安装钩子。

第三,正在努力在Spy++上运行一些真正的自动化测试。 Spy++自15年前问世以来,从未使用任何自动测试工具进行过测试。 所有的测试都是手动的,而且是临时的,我确信一些消息和参数破解方法从来没有被测试过,因为我从来没有在正常使用期间生成那些消息。 然而,VisualC++的QA试图在间谍+上达到70%的代码覆盖率,因此将在间谍+上运行自动化测试,以引起那些更模糊的破解方法被调用。 我对Spy++所带来的新级别的稳定性感到兴奋。 来自VC++QA的benanderson正在做这项工作;我会鼓励他在将来的某个时候把这项工作发到这里。

最后,我终于找到了一个导致WindowsVista出现问题的挂勾问题。 我在钩子中遇到了一个反复出现的死锁,钩子会阻止等待另一个共享资源。 在过去,这会导致系统挂起,因为所有Windows消息队列都将停止,等待钩子解除阻止。 最近,我对Spy++做了一个更改,以便在共享资源不可用时钩子将超时,但这仍然意味着禁用所有钩子,因此消息日志记录基本上被中止。 在多次运行Spy++并插入一些诊断之后,我最终得出结论:循环队列的同步,或者更具体地说,循环队列中的写入和读取偏移量的同步就是问题所在。

实际上,读写偏移量的同步是为了确保挂起的写操作不会覆盖循环队列中尚未读取的区域。 因此写入程序将循环,重置读取事件并等待其重置,直到确定写入不会覆盖未读数据(更详细) 在这里 ). 我盯着做这个同步的代码看了好一阵子,最后得出了一个不寻常的结论:我根本不需要它。

我意识到,当Spy++开始记录消息时,多个writer和一个reader的队列可能很快就满了,从那时起,writer就一直在等待reader。 我想如果是这样的话,为什么要存储多条消息的数据呢? 因此,我本质上减小了循环队列的大小,使其只足以容纳一条消息的数据。 这消除了对偏移量的需要,意味着我只需要mutexe和事件就可以完成同步。 因此,自我上一篇文章以来,作者和读者执行的操作集已经发生了变化。

编写器(在hook DLL中)在消息通过其中一个钩子时,现在执行以下操作:

· 等待read事件被设置。 事件是自动重置的,因此一旦等待得到满足,事件就被重置。

· 获取writer互斥锁,然后获取access互斥锁。

· 将消息数据复制到共享数据区。

· 设置书面事件。

· 释放access mutex,然后释放writer mutex。

而驻留在Spy++应用程序线程中的循环中的读取器现在执行以下操作:

· 等待设置写入的事件。 事件是自动重置的,因此一旦等待得到满足,事件就被重置。

· 使用访问互斥。

· 从共享队列中的消息包复制消息数据。

· 释放访问互斥。

· 设置读取事件。

· 将消息中复制的数据包数据发送到主线程拥有的隐藏窗口。

这确实解决了我的钩挂问题,但我仍然看到一些奇怪的行为。 在与验证我的修复的测试人员进行了长时间的讨论之后,我们意识到有一些安全问题正在发挥作用。 基本上,由于钩子被注入到每个进程中,所以它在被注入的进程的完整性级别上运行。 这意味着,如果同步对象(在本例中是互斥和事件)是在具有较高完整性级别的进程中创建的,则较低完整性进程中的钩子将无法打开或操作这些对象。 这一事实,再加上同步对象操作的错误检查不可靠,意味着一些完整性较低的挂钩在没有正确同步的情况下写入共享内存区域。

这个完整性问题也是我看到的最初挂钩挂起的原因。 有些钩子错误地认为它们可以获得互斥锁,但却不能真正设置事件,因此一旦它们进入一个等待设置事件的循环(这取决于它们设置事件),它们就会使其他钩子死锁。

解决方法是将同步对象上的MIC特权设置为low。 这是通过几个API完成的, ConvertStringSecurityDescriptor到SecurityDescriptor和GetSecurityDescriptorSacl,以及SetSecurityInfo。 这允许低完整性进程打开和操作同步对象。 您可以看到有关此主题的更多信息 在这里 (请参阅降低资源完整性一节)。

这几乎涵盖了我想和你分享的更新。 基于上一篇文章中的一个问题,我还想提到几个使用技巧:

· Spy++可以记录进程中所有窗口的消息。 如果您使用下面的技巧,那么可以使用它来记录所有的创建消息。 在调试器中进入应用程序,获得进程标识符后,启动Spy++。 打开进程树视图(Spy.processs)。 在树中选择进程ID,然后执行Spy.Messages。 在“消息选项”对话框的“Windows”选项卡上,您的进程将已经是选定的对象。 在“消息”选项卡上选择要查看的消息。 确定对话框,然后让进程运行。 现在您应该可以看到进程中所有窗口的窗口创建消息。

· 如果愿意,可以对进程中的单个线程执行相同的操作。 改为从线程树视图开始,并遵循相同的步骤。

谢谢,我再次欢迎您对Spy++的任何问题,或者对未来版本的特性请求。

帕特·布伦纳

VisualC++图书馆团队

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享