Windows DLL实际上如何共享

How are windows DLL actually shared?

本文关键字:共享 何共享 DLL 实际上 Windows      更新时间:2023-10-16

通过检查Windows机器中的几个dll(例如kernel32.dll),我注意到它们的部分都没有,甚至没有读取数据部分都没有image_scn_mem_shared标志设置。

dll是从.dll文件映射的,因此只有在您读取文件的一页时,它将被复制到物理内存,但是如果同一个页面,请说kernel32.dll均通过过程A和Process B访问,然后该页面将在物理内存中两次存在。我要求最后一个语句的真实性。

如果.Text或.rodata段共享共享它们只能将其复制到物理内存中,即使启用ASLR时,ASLR首次加载时ASLR的作用是随机化模块的基数(应用了相应的重新定位,)但是,加载此模块的下一个过程重新启动系统将在同一地址获得模块,以便以相同的方式共享.Text和.rodata。

这些都是我做出的假设,请纠正我。

谢谢!

,只要页面内容不(需要)[以不同的方式,用于不同的过程],OS肯定能够将多个虚拟地址映射到同一物理内存页面上。。但是,如果代码使用绝对地址(在内部或外部对DLL上使用),例如VTable/function Pointers,对全局数据(常数或非恒定恒定)的指针,或者简单地使用绝对地址函数函数,则地址必须是修改以匹配OS给出的实际地址与该内存的那部分。这称为"搬迁"。

因此,至少从理论上讲,即使在地址空间随机化中,您也可以共享相同的DLL,它只需要编译器和/或程序员的更多工作即可。特别是,它要求没有重新定位(在代码的大部分中)。如果代码具有基于代码地址重新定位的绝对地址,则需要每个DLL副本。

我实际上不知道 OS如何处理此问题。一个简单的解决方案显然是每个DLL仅随机将地址随机化一次(直到该特定的DLL卸载),无论使用多少应用程序使用相同的DLL。它仍然使局外人很难知道DLL已加载的地址,因为每次第一次加载它会加载不同的地址(更重要的是,它并不是所有机器的静态值使用相同版本的OS,没有此功能)。但是,这确实意味着可以通过复制来自已知内容的堆栈来"检查"长期运行的过程。Web服务器,数据库服务器和系统服务通常是长期运行的过程,因此,仅当系统"关闭"(或至少重新启动长期运行过程)时才具有不同的地址。

第二个更棘手的版本是检查特定页面(通常是4KB的内存区域)是否具有重新定位,并共享所有没有重新定位的页面。重新安置的页面需要每个基础地址一个副本。典型的是在DLL(" thunk aftern")的一个块中具有"所有参考外部资源",因此,DLL的典型大部分不会不管代码的基础地址如何,这意味着那是绝对是可行的解决方案。

如果这些方案在操作系统中都没有"工作",则必须多次加载相同的DLL。无论如何,从操作系统的角度来看,这显然可以起作用,因为在ASLR之前,如果两个DLL试图在同一地址加载时,则需要移动同一dll的基本地址(例如,DLL由不同的供应商生成,恰好选择代码的相同基础地址,或经典和常见的"我从未给出基本地址,因此使用默认地址") - OS将通过更改加载的一个基础地址来解决此类冲突首先。

关于IMAGE_SCN_MEM_SHARED的含义,我认为开发人员会请求此问题,其中DLL中的页面共享是自动完成的。换句话说,IMAGE_SCN_MEM_SHARED将由特定DLL或EXE的开发人员设置,以表示内容应与同一内容的其他用户共享在没有内容的用户的情况下完成的"完成"(当然共享代码是这种情况,并且(可写的)数据通常不会在dll之间共享。只要没有重新搬迁,只要读取数据就可以隐含地共享[该内容的用户无法分辨出它是否共享]。