C ++中的安全内存分配器

时间:2020-03-05 18:39:05  来源:igfitidea点击:

我想创建一个分配器,它为内存提供以下属性:

  • 无法分页到磁盘。
  • 通过添加的调试器很难访问

这样做的想法是,它将包含用户应该无法访问的敏感信息(如许可证信息)。我已经在网上进行了常规研究,并询问了其他一些人,但是在这个问题上我找不到合适的起点。

更新

Josh提到使用" VirtualAlloc"来设置对内存空间的保护。我创建了一个自定义分配器(如下所示),我发现使用VirtualLock函数会限制我可以分配的内存量。不过,这似乎是设计使然。由于我将其用于小物体,所以这不是问题。

//
template<class _Ty>
class LockedVirtualMemAllocator : public std::allocator<_Ty>
{
public:
    template<class _Other>
    LockedVirtualMemAllocator<_Ty>& operator=(const LockedVirtualMemAllocator<_Other>&)
    {   // assign from a related LockedVirtualMemAllocator (do nothing)
        return (*this);
    }

    template<class Other>
    struct rebind {
        typedef LockedVirtualMemAllocator<Other> other;
    };

    pointer allocate( size_type _n )
    {
        SIZE_T  allocLen = (_n * sizeof(_Ty));
        DWORD   allocType = MEM_COMMIT;
        DWORD   allocProtect = PAGE_READWRITE;
        LPVOID pMem = ::VirtualAlloc( NULL, allocLen, allocType, allocProtect );
        if ( pMem != NULL ) {
            ::VirtualLock( pMem, allocLen );
        }
        return reinterpret_cast<pointer>( pMem );
    }
    pointer allocate( size_type _n, const void* )
    {
        return allocate( _n );
    }

    void deallocate(void* _pPtr, size_type _n )
    {
        if ( _pPtr != NULL ) {
            SIZE_T  allocLen = (_n * sizeof(_Ty));
            ::SecureZeroMemory( _pPtr, allocLen );
            ::VirtualUnlock( _pPtr, allocLen );
            ::VirtualFree( _pPtr, 0, MEM_RELEASE );
        }
    }
};

和被使用

//a memory safe std::string
 typedef std::basic_string<char, std::char_traits<char>, 
                           LockedVirtualMemAllocato<char> > modulestring_t;

泰德·珀西瓦尔(Ted Percival)提到了mlock,但我还没有实现。

我发现Neil Furguson和Bruce Schneier撰写的实用密码学也很有帮助。

解决方案

回答

我们要求的是在操作系统级别处理的。一旦数据进入程序,就很可能被调出。

为了访问内存,有动力的人员可以连接硬件调试器。

回答

让我们一次来看一下:

I want to create an allocator which
  provides memory with the following
  attributes:

这很公平。

* cannot be paged to disk.

这将很难。据我所知,我们不能禁用虚拟分页,因为它是由操作系统处理的。如果有办法,那么我们将在操作系统中大吃一惊。

* is incredibly hard to access through an attached debugger

我们可以通过PGP运行它,并将其加密存储在内存中,然后根据需要对其进行解密。巨大的性能打击。

The idea is that this will contain
  sensitive information (like licence
  information) which should be
  inaccessible to the user. I have done
  the usual research online and asked a
  few other people about this, but I
  cannot find a good place start on this
  problem.

将所有敏感信息置于机器之外。严重地。不要将敏感信息存储在内存中。编写一个自定义删除例程,该例程将自动从我们执行的所有分配中删除所有数据。切勿一般性地访问装有敏感材料的机器。如果执行数据库访问,请确保在触发之前清除所有访问权限。仅具有特定登录权限的人员可以访问。没有一般的群组访问权限。

On a side note, what other methods are
  there of accessing the memory of a
  process other than attaching a
  debugger?

转储内存。

回答

我们不能真正防止内存访问。如果我们以管理员或者系统身份运行,则可以阻止分页,但不能阻止管理员或者系统读取内存。即使我们可以某种方式完全阻止其他进程读取内存(我们不能这样做),另一个进程实际上仍可以向进程中注入新线程并以这种方式读取内存。

即使我们可以某种方式完全锁定进程并保证操作系统永远不会允许其他人访问进程,我们仍然没有完整的保护。整个操作系统可以在虚拟机中运行,可以随时暂停和检查该虚拟机。

我们不能从系统所有者那里保护内存内容。好莱坞和音乐产业多年来一直对此感到痛苦。如果可能的话,他们已经在这样做了。

回答

@graham

You could run it through PGP and store it encrypted in memory and unencrypt it as needed. Massive performance hit.

然后,我们必须将密钥保存在内存中。这会使它变得更难一点,但绝对不是不可能的。任何有动力的人仍将设法从内存中获取数据。

回答

@Derek:哦,但是有了可信的计算,我们可以使用内存屏蔽! :-P </ devils-advocate>

回答

@roo

I was really hoping that is was possible, and that I just hadn't found it yet. Your example just made me realise that that is exactly what we are trying to do - only allow access to files in the context of our program and so preserve the IP.
  
  I guess I have to accept that there is no truly secure way to store someone’s files on another computer, especially if at some point access is allowed to that file by the owner.

绝对是问题所在。只要我们从不授予访问权限,就可以安全地存储内容,但是一旦授予访问权限,控制权就消失了。我们可以使其更加困难,仅此而已。

回答

@克里斯

Oh, but with trusted computing, you can use memory curtaining! :-P

但是,那么我们实际上必须愿意花钱购买别人拥有的计算机。 :p

回答

@德里克公园

他只是更努力地说,不是没有可能。 PGP将使其变得更加困难,并非没有可能。

回答

如果我们正在为Windows开发,则可以通过多种方法来限制对内存的访问,但是绝对不能阻止其他人。如果希望保密,请阅读《编写安全代码》,该书在一定程度上解决了该问题,但请注意,我们无法知道代码是在真实计算机上还是在虚拟机上运行。有很多Win32 API的东西要处理处理这种事情的加密货币,包括书中谈到的秘密的安全存储。我们可以查看在线Microsoft CyproAPI以获得详细信息。 OS设计师意识到了这个问题,并且需要保持明文的安全(再次阅读"编写安全代码")。

Win32 API函数" VirtualAlloc"是操作系统级别的内存分配器。它允许我们设置访问保护;我们可以做的是将访问权限设置为PAGE_GUARD或者PAGE_NOACCESS,然后在程序读取时将访问权限翻转为更友好的内容,然后再进行重置,但是如果有人真的很努力地窥视秘密,那只是一个速度障碍。

总而言之,请查看我们平台上的加密API,这些API会比我们自己破解某些东西更好地解决该问题。

回答

在Unix系统上,可以使用mlock(2)将内存页面锁定到RAM中,以防止页面被分页。

mlock() and mlockall() respectively lock part or all of the calling
  process’s virtual address space into RAM, preventing that memory from
  being paged to the swap area.

每个进程可以锁定多少内存是有限制的,可以用ulimit -l表示,以千字节为单位。在我的系统上,每个进程的默认限制是32 kiB。

回答

You cannot protect memory contents from the owner of the system.
  Hollywood and the music industry have been aching for this for years.
  If it were possible, they'd already be doing it.

我们是否看过Vista(及以上)受保护的进程(直接.doc下载)。我相信由操作系统实施的保护是娱乐界的礼貌。