首页 > 解决方案 > 从进程内存中清除字符串

问题描述

为了提高我的应用程序的安全性,我试图从进程内存中删除字符串数据,但是由于 Internet 上关于此的信息很少,我无法编写工作代码。

谁能帮我?

要清除的字符串数据(来自 ProcessHacker)。 内存中的字符串 (ProcessHacker)

我粘贴的代码:

void MemoryStringsClear() {
    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
    MEMORY_BASIC_INFORMATION mbi;
    char* addr = 0;

    while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)))
    {
        if (mbi.State != MEM_COMMIT || mbi.Protect == PAGE_NOACCESS)
        {
            //char* buffer = new char[mbi.RegionSize];

            //ReadProcessMemory(hProc, addr, buffer, mbi.RegionSize, nullptr);
            if (addr) {
                cout << "Addr: " << &addr << " is cleared!" << endl;
                memset(addr, '0', mbi.RegionSize);
            }
            
        }
        addr += mbi.RegionSize;
    }

    CloseHandle(hProc);
}

已编辑: 我选择这种解决问题的方法是因为我的应用程序包含许多模块(.exe 应用程序),其中一些我无法更改。

标签: c++memory

解决方案


您的方法存在一些问题(我对解决方案的想法更进一步):

列出的大多数字符串都是环境变量

您计算机上运行的所有程序都可以访问这些程序。它们在启动时被复制到每个程序的内存空间,因此每个程序都知道在哪里查找某些文件。将它们从应用程序的内存中删除是没有意义的,因为在您的计算机上运行的每个应用程序都已经知道它们。

您可以通过运行cmd.exe、键入set然后按来查看它们return

OpenProcess并且VirtualQueryEx用于访问另一个进程

您可以简单地使用VirtualQuery,因为您只想访问自己的进程。

我猜您正试图通过这样做来访问未提交的内存页面,但memset只能访问您自己程序地址空间中已提交的可写内存页面。所以这两种方法不能混用。

但还有更重要的一点:

未提交的内存不存在

如果未提交内存页面,则没有实际分配给该地址的内存。这意味着,没有什么可以用零覆盖。包含您的字符串的内存可能已经分配给另一个应用程序。阅读有关虚拟内存管理的一些信息以获取详细信息。

free大多数对的调用delete或垃圾收集并不总是真正取消提交页面

出于效率原因,当您的代码分配和取消分配内存时,您的运行时库会将较大内存页面(称为“堆”)的一小部分碎片交给您,只有在其中的每一块都被释放时才会取消提交。

您可以通过遍历堆条目来找到已释放的内存块,但其工作方式取决于您的 C 运行时库或其他运行时库。

操作系统可能会移动你的字符串

如果操作系统检测到内存不足,它可以将您的字符串保存到磁盘以为其他应用程序释放内存,并在您的应用程序再次激活时重新加载它们。之后通常不会费心清理磁盘。你对此没有影响(除非你格式化你的硬盘)。


我对解决方案的想法

在每次调用freedelete在您的代码中使用敏感信息(并且只有那些)释放内存之前,您可以调用 memset(...)该单个内存块。正如 Alan Birtles 在他的评论中指出的那样,在 C++ 中,您可以将其包装在一个在销毁时清除其内存的类中。

我认为没有一种解决方案可以让您简单地弹出一个现有程序来在内存被释放后清除敏感信息。

这种方法只留下最后一个问题。如果您从不将未加密的敏感信息存储在内存中,您只能避免这种情况。这可能是不可行的,因为这意味着您不会仅加密处理它。

什么是困难或不可能的

如果您想清除其他进程中释放的内存(您在编辑中引用的无法更改的单独 *.exe 文件),您必须了解这些进程的内部堆布局并WriteProcessMemory使用memset.

但这并没有捕捉到其他程序实际取消提交页面的情况,因为您不知道操作系统是否已经重新分配了它。当这种情况发生时,您完全无法控制。

您也可以尝试在 C 运行时库中重新实现freedelete函数,以便它们首先清除内存然后调用原始版本,但这仅在这些 *.exe 文件实际使用它们并且它们是动态链接的情况下才有效。如果满足这些条件,您可能仍然很难。


推荐阅读