独立的地址空间对于编程人员和用户来说都是非常有利的。对于编程人员来说,系统更容易捕获随意的内存读取和写入操作。对于用户来说,操作系统将变得更加健壮,因个应用程序无法破坏另一个进程或操作系统的运行。当然,操作系统的这个健壮特性是要冻代价的,因为要编写能够与其他进程进行通信,或者能够对其他进程进行操作的应用程序难得多。
有些情况下,必须打破进程的界限,访问另一个进程的地址空间,这些情况包括:
当你想要为另一个进程创建的窗口建立子类时。
当你需要调试帮助时(例如,当你需要确定另一个进程正在使用哪个DLL时)。
当你想要挂接其他进程时。
这里将介绍两种方法,可以用来将DLL插入到另一个进程的地址空间中。一旦你的DLL进入另一个进程的地址空间,就可以对另一个进程为所欲为。这一定会使你非常害怕,因此,究竟应该怎样做,要三思而后行。
1 插入DLL:一个例子
假设你想为由另一个进程创建的窗口建立一个子类。你可能记得,建立子类就能够改变窗口的行为特性。若要建立子类,只需要调用SetWindowLongPtr函数,改变窗口的内婵中的窗口过程地址,指向一个新的(你自己的) WndProc。Platform SDK文档说,应用程虿能为另一个进程创建的窗口建立子类。这并不完全正确。为另一个进程的窗口建立子类的关键问题与进程地址空间的边界有关。
当调用下面所示的SetWindowsLongPtr函数,建立一个窗口的子类时,你告诉系统,发送到或者显示在hwnd设定的窗口中的所有消息都应该送往MySubclassProc,而不是送往口的正常窗口过程:
进程A中代码:
| EXE file: LRESUlT WndProc(HWND hend,UNIT uMsg,...){.....} USER32.DLL file LONG DispatchMessage(CONST MSG*msg) { LONG lRet; WNDPROC lpfnWndProc= (WNDPROC)GetWindowLongPtr(msg,hwnd,GWLP_WNDPROC ); lRet=lpfnWndProc(msg.hwnd,msg.message,msg.wParam,mag. lParam); return lRet; } 进程B中: EXE file void Somefunc(void) { HWND hwnd=Findwindow("class A",NULL); SetWindowLongPtr(hwnd,GWLP_WNDPROC,MySubclassProc); } USER32.DLL file ...... |
换句话说,当系统需要将消息发送到指定窗口的WndProc时,要查看它的地址,然后直接调用WndProc。在本例中,系统发现MySubclassProc函数的地址与窗口相关联,因此就直接调用MySubclassProc函数。
为另一个进程创建的窗口建立子类时遇到的问题是,建立子类的过程位于另一个地址空间中。下面举个例子,说明窗口过程是如何接受消息的。进程A正在运行,并且已经创建了一个窗口。文件User32.dll被映射到进程A的地址空间中。
对User32.dll文件的映射是为了接收和发送在进程A中运行的任何线程创建的任何窗口中发送和显示的消息。当User32.dll的映像发现一个消息时,它首先要确定窗口的WndProc的地址,然后调用该地址,传递窗口的句柄、消息和wParam和lParam值。当WndProc处理该消息后,User32.dll便循环运行,并等待另一个窗口消息被处理。
进程B中的线程试图为进程A中的线程创建的窗口建立子类现在假设你的进程是进程B,你想为进程A中的线程创建的窗口建立子类。你在进程B中的代码必须首先确定你想要建立子类的窗口的句柄。这个操作使用的方法很多。上面的例子只是调用FindWindow函数来获得需要的窗口。接着,进程B中的线程调用SetWindowLongPtr函数,试图改变窗口的WndProc的地址。请注意我说的“试图”二字。这个函数调用⒉进行什么操作,它只是返回NULL。SetWindowLongPtr函数中的代码要查看是否有一个进程正在试图改变另一个进程创建的窗口的WndProc地址,然后将忽略这个函数的调用。
如果SetWindowLongPtr函数能够改变窗口的WndProc,那将出现什么情况呢?系统将把MySubclassProc的地址与特定的窗口关联起来。然后,当有一条消息被发送到这个窗口中时,进程A中的User32代码将检索该消息,获得MySubclassProc的地址,并试图调用这个地址。但是,这时可能遇到一个大问题。MySubclassProc将位于进程B的地址空间中,而进程A是个活动进程。显然,如果User32想要调用该地址,它就要调用进程A的地址空间中的一个地址,这就可能造成内存访问的违规。
为了避免这个问题的产生,应该让系统知道M y S u b c l a s s P r o c是在进程B的地址空间中,然后,在调用子类的过程之前,让系统执行一次上下文转换。M i c r o s o f t没有实现这个辅助函数功能,原因是:应用程序很少需要为其他进程的线程创建的窗口建立子类。大多数应用程序只是为它们自己创建的窗口建立子类,Wi n d o w s的内存结构并不阻止这种创建操作。
切换活动进程需要占用许多C P U时间。
进程B中的线程必须执行M y S u b c l a s s P r o c中的代码。系统究竟应该使用哪个线程呢?是现有的线程,还是新线程呢?
U s e r 3 2 . d l l怎样才能说明与窗口相关的地址是用于另一个进程中的过程,还是用于同一个进程中的过程呢?
由于对这个问题的解决并没有什么万全之策,因此M i c r o s o f t决定不让S e t Wi n d o w s L o n g P t r改变另一个进程创建的窗口过程。不过仍然可以为另一个进程创建的窗口建立子类—只需要用另一种方法来进行这项操作。这并不是建立子类的问题,而是进程的地址空间边界的问题。如果能将你的子类过程的代码放入进程A的地址空间,就可以方便地调用S e t Wi n d o w L o n g P t r函数,将进程A的地址传递给M y S u b c l a s s P r o c函数。我将这个方法称为将D L L“插入”进程的地址空间。有若干种方法可以用来进行这项操作。下面将逐个介绍它们
- 推荐阅讯
- Visual C#2005快速入门之基础语法
- 在VC中实现画任意方向椭圆
- VC#2005快速入门之复合赋值操作符
- 在VC中调用DirectShow全屏播放视频
- Visual C#程序员面试基础问题和答案
- 用VC获取其它程序的命令行参数
- VC中自动改变控件位置和大小的对话框类
- 用VC++制作播放AVI视频流的动画按钮
- Visual C++2005中开发自定义绘图控件
- 理解VC# 2005中的字符串和正规表达式
- 阅读排行
- 1.VC++编程实现广告窗口自动关闭
- 2.深入浅出VC++串口编程之基于控件
- 3.解读VC++编程中的文件操作API和CFile类
- 4.利用Visual C#实现ICMP网络协议
- 5.深入浅出VC++串口编程之第三方类
- 6.掀起你的盖头来——谈VC++对象模型
- 7.Visual C#中用WMI控制远程计算机
- 8.深入浅出VC++串口编程之基于Win32 API
- 9.Visual C++2005中开发自定义绘图控件
- 10.深入浅出VC++串口编程之基本概念
- 专题教程
- Windows Server-Windows Server文档-Windows Server新闻-Windows Ser PostgreSQL-PostgreSQL文档-PostgreSQL新闻-PostgreSQL专家
- WebLogic-WebLogic文档-WebLogic新闻-WebLogic专家 FreeBSD-FreeBSD文档-FreeBSD新闻-FreeBSD专家
- Linux-内核 GUI KDE Gnome DNS FTP 安全 安装-Linux专区 Windows-AD IIS ServerCore 虚拟化 安全 HPC-Windows专区
- 大话G游 专题:手机病毒揭密
- ARP攻击防范与解决方案 路由故障处理手册
