科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件用DLL控制Windows中进程的方法

用DLL控制Windows中进程的方法

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在Microsoft Windows中,每个进程都有它自己的私有地址空间。当使用指针来引用内存时.......

作者:佚名 来源:VC编程网 2007年10月22日

关键字: Dll Windows 进程

  • 评论
  • 分享微博
  • 分享邮件
在Microsoft Windows中,每个进程都有它自己的私有地址空间。当使用指针来引用内存时,指针的值将引用你自己进程的地址空间中的一个内存地址。你的进程不能创建一銎湟用属于另一个进程的内存指针。因此,如果你的进程存在一个错误,改写了一个随机地址系内存,那么这个错误不会影响另一个进程使用的内存。Windows 98 在Windows 98下运行的各个进程共享2 GB的地址空间,该地址空间从0x80000000至0xFFFFFFFF。只有内存映像文件和统组件才能映射到这个区域。

  独立的地址空间对于编程人员和用户来说都是非常有利的。对于编程人员来说,系统更容易捕获随意的内存读取和写入操作。对于用户来说,操作系统将变得更加健壮,因个应用程序无法破坏另一个进程或操作系统的运行。当然,操作系统的这个健壮特性是要冻代价的,因为要编写能够与其他进程进行通信,或者能够对其他进程进行操作的应用程序难得多。

  有些情况下,必须打破进程的界限,访问另一个进程的地址空间,这些情况包括:

  当你想要为另一个进程创建的窗口建立子类时。
  当你需要调试帮助时(例如,当你需要确定另一个进程正在使用哪个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“插入”进程的地址空间。有若干种方法可以用来进行这项操作。下面将逐个介绍它们

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章