DLL的常见记忆

Common read-only memory of DLL

本文关键字:记忆 常见 DLL      更新时间:2023-10-16

我有两个控制台应用程序a1.exe a2.exe和一个dll。两者都在调试模式下运行,关闭了Optmization。我从该dll导出并在A1和A2中导入的全局const char*变量:

//dll.h
extern "C" {DLLEXPORT extern const char* str;}
//dll.cpp
const char *str = "qwerty123";

我希望在DLL的只读部分中创建" qwerty123",我希望Windows的内存管理器将使用此字符串将真实内存映射到A1.exe的某些虚拟内存地址和A2.exe的不同虚拟地址并且不要创建真实的数据副本。我希望从该DLL的所有功能定义也会发生这种情况。

我同时运行两个应用程序,它们都打印从DLL导入的正确字符串。但是,我想要一些证据,因此我残酷地使用作弊引擎将其附加到A1.EXE过程中,然后将仅读取字符串更改为一些不同的值。结果是A1.EXE打印新值,A2.EXE仍然打印旧值。如何解释这个?1.我认为它是仅读取的内存,并且将共享以保存真实内存,所以为什么仅对一个应用程序更改值?2.我如何获得证据表明,带有程序代码(导出功能(的部分都不重复两个过程?

您在此处考虑的优化在写入时称为复制。在Visual C 的情况下,DLL中定义的所有全局变量最初都加载在带有PAGE_WRITECOPY属性的共享存储页面中。如果某个过程将其写入这样的位置,则它将带有PAGE_READWRITE属性的页面并进一步使用。Visual C 似乎在const和非const全局变量之间没有区别,因为该属性是编译器功能。例如,它可以用铸件扔掉,并从OS的角度处理它也会是头痛和安全孔。

尝试搜索PAGE_WRITECOPY的网络以了解更多详细信息。

'仅读取内存'的概念在很大程度上不适合此讨论。是的,操作系统具有使某些内存区域显示为仅阅读程序的方法,但是a(此内存完全是真实的,就像任何其他内存一样,b(b(字符串的字体并未存储在任何此类内存中无论如何。

当您将字符串声明为const时,您只会阻止自己从C 程序中更改它,并且您可能还可以启用某些编译器的优化,尽管由于您在故障排除时正确地将其关闭,但它们不会播放任何内容在讨论中的角色。为了证明我在说什么,您可以抛弃该char*指针的构成,然后您可以很好地修改它指向的字符串。

DLL的每个实例都有其自己的数据段。DLL实例不共享他们的数据。因此,当然,当您修改项目时,您仅在DLL的一个实例的数据段中修改它,而另一个DLL实例的数据段保持不变。

为了共享数据,您需要使用VirtualAllocEx()WriteProcessMemory(),或者更好的是CreateFileMapping()MapViewOfFile[Ex]()或其他一些机制。

对于连接DLL的过程,DLL的'读取全局变量'的值可能有所不同。因此,如果DLL共享多个过程的"仅读取全局变量"的单个物理内存,则是不安全的。谨慎但安全的解决方案是为多个过程创建"仅读取全局变量"的不同CTC的物理记忆实例。

例如,在dll.cpp中,

int foo(){return 1;}
typedef int (*C_pFunc)();
const C_pFunc pf=foo;

显然,A.Exe和B.Exe都加载DLL的DLL,DLL中的function foo((在A.EXE和B.EXE中可能具有不同的逻辑地址。因此,全局const变量PF在A.EXE和B.EXE中可能具有不同的初始化值。

这是com dll的典型现象,当将com dll附加到一个过程中时,许多vtables作为全局const变量应使用此过程中的函数逻辑地址初始化。