15

次の属性を持つメモリを提供するアロケータを作成したいと考えています。

  • ディスクにページングできません。
  • 接続されたデバッガーからアクセスするのは非常に困難です

これには、ユーザーがアクセスできない機密情報 (ライセンス情報など) が含まれるという考えです。私はオンラインで通常の調査を行い、これについて他の何人かの人々に尋ねましたが、この問題を開始するのに適した場所を見つけることができません.

アップデート

JoshVirtualAllocは、メモリ空間に保護を設定するために使用することについて言及しています。カスタム アロケータを作成しました (以下を参照) 。この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によるPractical Cryptographyも非常に役に立ちました。

4

13 に答える 13

19

メモリアクセスから実際に保護することはできません。管理者またはシステムとして実行している場合、おそらくページングを防ぐことができますが、管理者またはシステムがメモリを読み取るのを防ぐことはできません。他のプロセスがメモリを読み取るのを何らかの方法で完全にブロックできたとしても (それはできません)、別のプロセスが実際にプロセスに新しいスレッドを挿入し、その方法でメモリを読み取ることができます。

何らかの方法でプロセスを完全にロックダウンし、OS が他のユーザーにプロセスへのアクセスを許可しないことを保証できたとしても、完全な保護はありません。OS 全体を仮想マシンで実行し、いつでも一時停止して検査することができます。

システムの所有者からメモリの内容を保護することはできません。ハリウッドと音楽業界は、この問題に何年も悩まされてきました。可能であれば、彼らはすでにそれを行っているでしょう。

于 2008-08-12T05:17:09.473 に答える
8

Unix システムでは、mlock(2)を使用してメモリ ページを RAM にロックし、ページングを防止できます。

mlock() と mlockall() はそれぞれ、呼び出しプロセスの仮想アドレス空間の一部またはすべてを RAM にロックし、そのメモリがスワップ領域にページングされるのを防ぎます。

各プロセスがロックできるメモリ量には制限がありulimit -l、キロバイト単位で表示できます。私のシステムでは、デフォルトの制限はプロセスあたり 32 kiB です。

于 2008-09-02T02:25:23.350 に答える
5

これを少しずつ見てみましょう。

次の属性を持つメモリを提供するアロケータを作成したいと考えています。

それは十分に公平です。

* cannot be paged to disk.

それは難しいでしょう。私の知る限り、仮想ページングは​​ OS によって処理されるため、無効にすることはできません。方法があれば、OS の内部を探索することになります。

* is incredibly hard to access through an attached debugger

PGP を介して実行し、暗号化してメモリに保存し、必要に応じて暗号化を解除することができます。大規模なパフォーマンス ヒット。

これには、ユーザーがアクセスできない機密情報 (ライセンス情報など) が含まれるという考えです。私はオンラインで通常の調査を行い、これについて他の何人かの人々に尋ねましたが、この問題を開始するのに適した場所を見つけることができません.

すべての機密情報をマシンから遠ざけてください。真剣に。機密情報をメモリに保存しないでください。実行する割り当てからすべてのデータを自動的に削除するカスタム削除ルーチンを記述します。機密性の高い素材が置かれた機械への一般的なアクセスを決して許可しないでください。db アクセスを実行する場合は、起動する前にすべてのアクセスがサニタイズされていることを確認してください。特定のログインを持つ人だけがアクセスできます。一般グループ アクセスはありません。

余談ですが、デバッガーを接続する以外に、プロセスのメモリにアクセスする方法は他にどのようなものがありますか?

メモリのダンプを取る。

于 2008-08-12T05:13:00.637 に答える
5

Windows 向けに開発している場合、メモリへのアクセスを制限する方法はいくつかありますが、他のアクセスを完全にブロックすることはできません。機密情報を保持したい場合は、Writing Secure Codeをお読みください。この問題について詳しく説明していますが、コードが実際のマシンで実行されているか仮想マシンで実行されているかを知る方法がないことに注意してください。秘密の安全な保管を含む、この種のことを処理する暗号を処理するための Win32 API がたくさんあります - 本はそれについて語っています。詳細については、オンラインのMicrosoft CyproAPIを参照してください。OS 設計者は、まさにこの問題と、クリアテキストを安全に保つ必要性を認識しています (もう一度、Writing Secure Codeを読んでください)。

Win32 API 関数VirtualAllocは、OS レベルのメモリ アロケータです。アクセス保護を設定できます。あなたができることは、PAGE_GUARDまたはへのアクセスを設定PAGE_NOACCESSし、プログラムの読み取り中にアクセスをより使いやすいものに切り替え、後でリセットすることですが、誰かがあなたの秘密を一生懸命に覗き見しようとしている場合、それは単なるスピードハンプです.

要約すると、プラットフォームの暗号化 API を見てください。自分で何かをハックするよりも、問題にうまく対処できます。

于 2008-08-26T01:16:51.790 に答える
5

Libsodium をインストールし、#include による割り当てメカニズムを使用します<sodium.h>

保護されたヒープ割り当て

malloc() やその仲間よりも遅く、3 ページまたは 4 ページの追加の仮想メモリが必要です。

void *sodium_malloc(size_t size);

sodium_malloc()とを使用して機密データを格納するメモリを割り当てますsodium_allocarray()sodium_init()これらのヒープ ガードを使用する前に、まず呼び出す必要があります。

void *sodium_allocarray(size_t count, size_t size);

このsodium_allocarray()関数は、それぞれ size バイトのメモリである count オブジェクトにアクセスできるポインタを返します。と同じ保証を提供しますが、を超えるsodium_malloc()場合の算術オーバーフローからも保護します。count * sizeSIZE_MAX

これらの関数は、保護されたデータの周囲にガード ページを追加して、ハートブリードのようなシナリオでアクセス可能になる可能性を低くします。

さらに、そのように割り当てられたメモリ領域の保護は、ロック メモリ操作を使用して変更できます: sodium_mprotect_noaccess()sodium_mprotect_readonly()およびsodium_mprotect_readwrite()

メモリのロック解除と割り当て解除にsodium_malloc使用できます。sodium_free()実装のこの時点で、使用後にメモリをゼロにすることを検討してください。

使用後にメモリをゼロにする

void sodium_memzero(void * const pnt, const size_t len);

使用後、機密データは上書きする必要がありますが、 memset() と手書きのコードは、最適化コンパイラまたはリンカーによって静かに取り除かれます。

コードに最適化が適用されている場合でも、sodium_memzero() 関数は、pnt から始まる len バイトを効果的にゼロにしようとします。

メモリ割り当てのロック

int sodium_mlock(void * const addr, const size_t len);

このsodium_mlock()関数は、addr から始まる少なくとも len バイトのメモリをロックします。これにより、機密データをディスクにスワップすることを回避できます。

int sodium_mprotect_noaccess(void *ptr);

sodium_mprotect_noaccess()関数は、sodium_malloc()またはsodium_allocarray()を使用して割り当てられた領域にアクセスできないようにします。読み書きはできませんが、データは保持されます。この機能を使用して、特定の操作で実際に必要な場合を除き、機密データにアクセスできないようにすることができます。

int sodium_mprotect_readonly(void *ptr);

sodium_mprotect_readonly() 関数は、sodium_malloc() またはsodium_allocarray() を使用して割り当てられた領域を読み取り専用としてマークします。データを変更しようとすると、プロセスが終了します。

int sodium_mprotect_readwrite(void *ptr);

この関数は、またはを使用して保護された後、またはをsodium_mprotect_readwrite()使用して割り当てられた領域を読み取りおよび書き込み可能としてマークします。sodium_malloc()sodium_allocarray()sodium_mprotect_readonly()sodium_mprotect_noaccess()

于 2015-11-06T13:45:38.610 に答える
2

あなたが求めていることは、OSレベルで処理されます。データがプログラムに入ると、ページアウトされる可能性があります。

メモリにアクセスするために、やる気のある人はハードウェア デバッガを取り付けることができます。

于 2008-08-12T05:07:08.837 に答える
1

@グラハム

PGP を介して実行し、暗号化してメモリに保存し、必要に応じて暗号化を解除することができます。大規模なパフォーマンス ヒット。

次に、キーをメモリに保持する必要があります。それは少し難しくなりますが、絶対に不可能ではありません。やる気のある人なら誰でも、メモリからデータを取得することができます。

于 2008-08-12T05:21:33.053 に答える
0

最善の策は、.NET の SecureString クラスに似たものを実装し、完了したらすぐにデータのプレーンテキスト コピーをゼロにするように十分に注意することです (例外がスローされた場合でも、クリーンアップを忘れないでください)。std::string などでこれを行う良い方法は、カスタム allocatorを使用することです。

Windows では、CryptProtectMemory (または古いシステムでは RtlEncryptMemory) を使用する場合、暗号化パスワードは非ページ可能 (カーネル?) メモリに保存されます。私のテストでは、これらの関数は非常に高速です。彼らがあなたに与えている保護を考慮して。

他のシステムでは、速度と強さのバランスが良いため、Blowfish を使用するのが好きです。後者の場合、プログラムの起動時に独自のパスワード (Blowfish の場合は 16 バイト以上のエントロピー) をランダムに生成する必要があります。残念ながら、OS のサポートなしでそのパスワードを保護するためにできることはあまりありませんが、一般的な難読化手法を使用して、パスワードと組み合わせることができるハードコードされたソルト値を実行可能ファイルに埋め込むことができます (少しでも役に立ちます)。

全体として、この戦略は、より広範な多層防御アプローチの一部にすぎません。また、バッファ オーバーフローやプログラム入力の無害化などの単純なバグが、依然として最も一般的な攻撃ベクトルであることにも留意してください。

于 2011-10-31T22:05:01.513 に答える
0

システムの所有者からメモリの内容を保護することはできません。ハリウッドと音楽業界は、この問題に何年も悩まされてきました。可能であれば、彼らはすでにそれを行っているでしょう。

Vista(およびそれ以降)の保護されたプロセス( .docの直接ダウンロード)をご覧になりましたか。オペレーティング システムによる保護は、エンターテインメント業界の好意によるものだと思います。

于 2010-08-22T16:38:41.963 に答える
-1

@Derek: ああ、でもトラステッド コンピューティングでは、メモリ カーテンを使用できます。:-P</devils-advocate>

于 2008-08-12T06:03:16.773 に答える
-1

@ルー

それが可能であることを本当に望んでいましたが、まだそれを見つけていませんでした。あなたの例は、まさにそれが私たちがやろうとしていることであることに気づきました.私たちのプログラムのコンテキストでファイルへのアクセスのみを許可し、IPを保持します.

特にある時点でそのファイルへのアクセスが所有者によって許可されている場合は、誰かのファイルを別のコンピューターに保存するための本当に安全な方法がないことを受け入れる必要があると思います。

それは間違いなく問題です。アクセスを許可しない限り、何かを安全に保存できますが、アクセスを許可するとすぐに、コントロールが失われます。もう少し難しくすることもできますが、それだけです。

于 2008-08-12T06:12:44.027 に答える
-1

@クリス

ああ、でもトラステッド コンピューティングでは、メモリ カーテンを使用できます。:-P

しかし、その場合、他の誰かが所有するコンピューターに対して実際に喜んで支払う必要があります。:p

于 2008-08-12T06:15:27.640 に答える
-1

@デレク・パーク

彼はもっと難しいと言っただけで、不可能ではありません。PGP はそれを難し​​くしますが、不可能ではありません。

于 2008-08-12T08:10:27.393 に答える