DLL作为公司日常用品,极大的方便了日常的开发(主要是看起来产品就很高大上了)。以下介绍几种跨进程调用DLL的方法。


从《Windows核心编程》的书中可知,Windows下各个进程间的地址是相互独立的。建立新的进程时,会为此进程开辟一块独立的虚拟地址空间,这样有助于系统的稳定。——当一个进程崩溃时,只影响一个进程,回收垃圾时也只需要对本进程地址空间内的数据进行回收即可。

虚拟地址空间由以下几个部分组成:空指针赋值区、用户模式分区、64KB禁入分区、内核模式分区。

因此要对跨进程的数据进行访问,是有一定难度的,需要依赖于操作系统API。

以下是DLL注入的几种方式:

  1. 注册表
  2. Windows挂钩
  3. 远程现场

注册表方式

系统配置都保存在注册表中,而通过DLL进行注入,也可以通过此进行配置。注册表位置如下:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\

java跨进程任务调度 跨进程调用dll_Windows

主要对图中的两个红框中的名称进行配置:AppInit_Dlls和LoadAppInit_Dlls。AppInit_Dlls中增加DLL即可,不同DLL之间用空格或逗号分隔。

启动步骤如下:

  1. 新进程将User32.dll映射到进程空间
  2. 获取AppInit_Dlls的值
  3. 使用LoadLibrary对DLL进行调用
  4. 调用DllMain函数对DLL进行初始化
  5. 即可对进程中的数据进行访问

缺点:

  1. 只有使用了User32.dll的应用才可以使用,对CUI的应用支持较少
  2. 所有基于GUI的应用在初始化时都会载入DLL,其他程序的稳定性难以保证
  3. DLL载入的时机不可控,是否可以按需加载,用完即刻卸载?

Windows挂钩方式

添加挂钩主要使用如下函数:

// 进行映射
HHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hInstDll, 0); 

// 撤销映射
BOOL UnhookWindowsHookEx(HHOOK hHook);

参数1的WH_GETMESSAGE表示要安装的挂钩类型。

参数2的GetMsgProc表示GetMsgProc函数的地址,窗口在处理一条消息的时候,在本进程地址空间内调用。

参数3的hInstDll表示待注入的DLL,其中DLL中包含GetMsgProc函数。

参数4表示要给那个线程安装挂钩,传0表示对系统中所有GUI线程安装挂钩。


远程线程方式

此方法提供了最高的灵活性。DLL注入的本质是让目标进程加载我们想要的DLL。在远程进程中创建线程的方法:

HANDLE CreateRemoteThread(
    HANDLE hProcess,
    PSECURITY_ATTRIBUTES psa,
    DWORD dwStackSize,
    PTHREAD_START_ROUTINE pfnStartAddr,
    PVOID pvParam,
    DWORD fdwCreate,
    PDWORD pdwThreadId);

其中,远程线程的入口函数地址和LoadLibrary函数原型如下:

DWORD WINAPI ThreadFunc(PVOID pvParam);

HMOUDLE LoadLibraryA(LPCSTR lpLibFileName);
HMOUDLE LoadLibraryW(LPCWSTR lpLibFileName);

惊奇的发现,远程线程和LoadLibrary函数的样式很像,都是一个入口参数,一个返回参数。

因此可以这样调用:HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0, LoadLibraryW, L"C:\\MyLib.dll", 0, NULL);

因为是远程线程,因而调用"C:\\MyLib.dll"时可能会造成地址访问失败,当然也有解决方法,使用VirtualAllocEx函数,这个和VirtualAlloc很像,但是可以在不同进程间的地址空间进行内存的申请,与之对应的函数是VirtualFreeEx函数。

再有是ReadProcessMemory和WriteProcessMemory函数,对进程间的地址内容进行读写,这样就可以保证了稳定性。

(不得不说,作者对这块考虑得还真是全面——各种特殊情况都给考虑进去了。)