[翻译]Win32中安全的子类化 (2)


Win32中安全的子类化 (1) 

Win32子类化规则

有两条规则应用到Win32下的实例子类化和全局子类化。

子类化仅被允许用在进程内,一个应用程序不能子类化属于另一个进程的窗口或窗口类。

这条规则的起因很简单:Win32进程具有独立的进程地址空间。在一个特定的进程里,一个窗口过程有一个地址,而在另一个不同的进程里,这个地址值并未指向这个窗口过程,结果就是,在一个进程中,使用从另一个进程获得的地址替换后的地址并不能获得期望的结果,因此32位的Windows不允许这种地址替换发生。SetWindowLong和SetClassLong函数中防止了这种类型的子类化发生。你不能子类化属于另一个进程的窗口或窗口类,你能做的就到此为止。

不过,也还是有些途径能让你把子类化的功能用到每一个进程上。只要能得到位于某个进程地址空间里的某个函数,你就能该进程里的任何东西进行子类化。有几个方法可以达到这个目的,其中最容易(也是最不讲理的)的一个方法就是在下面这个注册表键中添加一个动态链接库名称:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\APPINIT_DLLS

这个键导致Windows把你的DLL附加到系统里的每一个进程上。你的DLL需要一些能在它要子类化的事件发生时被唤醒的方法,通常一个WH_CBT钩子可以实现。这个DLL可以监视HCBT_CREATEWND 事件,然后子类化它想子类化的窗口。例子程序CTL3D就使用了WH_CBT钩子去实现它的子类化,尽管它没有使用注册表键为每个进程实现子类化,想要得到CTL3D功能的应用程序可以把他链接到进程里。

另一个把你的子类化代码附加到每个进程的方法是使用一个系统钩子。当一个系统钩子在另一个进程的上下文中被调用时,系统就把包含这个钩子的DLL加载到这个进程空间中。样例CTL3D 的代码按照使用当前线程中本地WH_CBT 钩子的方式使用系统WH_CBT 钩子。

第三个把子类化代码附加到另一个进程方法更复杂:它使用OpenProcess WriteProcessMemory CreateRemoteThread 函数将代码注入其它进程。我并不推荐这个方法,并且不打算更详细地介绍怎么实现这个方法。如果有人坚持要使用这个方法, Jeffrey Richter 曾说过他计划在Microsoft Systems Journal中他的一个即将开辟的Win32 Q&A专栏中描述这项技术。

现在很多Windows 3.1的应用程序子类化其它进程来扩展操作和增加一些很酷的功能。当Windows转向一个面向对象的系统时,对象链接和嵌入技术(OLE)提供了更好的办法去实现这些功能。在Windows的未来版本中,子类化其它进程可能会变得更加困难,而使用OLE也许会更容易。我推荐的是,只要可能,你应该让你的应用程序转向OLE,而不要子类化其它进程。

子类化操作不要直接使用原窗口过程地址。

Win16中,一个应用程序会去使用从SetWindowLong SetClassLong函数返回的窗口过程地址来直接调用窗口过程,毕竟返回值只是一个简单的指向函数的指针,为什么不使用它呢?在Win32中,这种做法却是个禁忌。SetWindowLong SetClassLong函数的返回值可能根本不是原窗口过程的指针。Win32可能会返回指向一个数据结构的指针,该数据结构能被用来调用当前的窗口过程。这种情况发生在Windows NT中,当一个应用程序用一个非Unicode的窗口过程子类化一个Unicode窗口时,或者用一个Unicode的窗口过程子类化一个非Unicode窗口时。在这两种情况下,操作系统必须为窗口收到的消息执行一个UnicodeANSI之间的转换。如果应用程序直接使用指向这个结构的指针调用窗口过程,应用程序会立即导致一个异常。使用SetWindowLong SetClassLong函数返回的窗口地址的唯一做法是将返回值作为参数调用CallWindowProc函数。

Win32中安全的子类化 (3)

posted on 2006-01-20 11:49  I.AM.Wright  阅读(1765)  评论(0编辑  收藏  举报

导航