web-dev-qa-db-ja.com

物理メモリから直接読み取るにはどうすればよいですか?

CまたはC++(Windows)では、物理(仮想ではない)アドレスを指定してRAM)をどのように読み取りますか?これは、仮想メモリシステム(mmuテーブル)を経由せず、1つに固有であることを意味します処理する。

私はすでにAPI ReadProcessMemory を知っています。これはram(ほとんどのトレーナーが使用)から読み取りますが、これは特定のプロセスのみを対象としています。

MSDNで検索したところ、 Device\PhysicalMemory がそのような可能性を与えているようですが、実用的な例はなく、この機能はWindowsサービスパックによって無効にされているようです(一部の脆弱性を修正するため)。

WinHexがそれを行うため、それが可能であることを知っています(「ツール」>「RAMを開く」>「物理メモリ」を選択した場合)。次に、従来のファイルを開くときと同じように、RAMコンテンツ0x00000000からyour_ram_sizeまでを表示します。管理者権限が必要ですが、インストールするドライバーがありません(つまり、WinHexがユーザーモードから実行します) 。

編集:OSに関する情報を追加しました。

23
tigrou

C言語もC++も「メモリ」という用語を定義していません。 「ストレージ」や「ストレージ分類子」などの抽象的な用語で定義されます。ポインタは抽象的なものです-それらの値は何でもかまいませんが、物理アドレスや仮想アドレスとはまったく無関係です。

システムとその実装のコンテキストでのみ、メモリやアドレス空間などの用語が導入されています。そして、それらはシステム固有のものなので、1つmust OSが提供するメソッドを使用してそれらにアクセスします。

OSカーネルを実装する場合でも、Cを介してではなく(単にそれができないため)、実装とアーキテクチャに固有のメソッドを介して、最低レベルのものにアクセスする必要があります。通常、これは、アセンブリでプログラミングされた一連の低レベル関数を介して行われます。これらの関数は、コンパイラが生成するマシンコードの種類と一致するように記述されています。これにより、Assemblyで記述された関数を、コンパイラーによってコンパイルされたかのようにCから呼び出すことができます。

7
datenwolf

カーネルモードドライバーを作成し、メモリマネージャー関数を使用して物理メモリ範囲をカーネルドライバーのシステムスペースにマップし、機能をユーザーAPIまたはドライバーにエクスポートする必要があります。

Windows 98以降では、ほとんどの場合、ユーザーモードから物理メモリにアクセスできません。他の人が言っているように、これは古いプログラムが人々のコンピュータを破壊することができないようにするためです。カーネルドライバーを作成する必要があります。カーネルドライバーは、署名され、最初にウィンドウのストアに読み込まれた場合にのみインストールできます。これだけでは、DLLをリンクするような単純なプロセスではありません。

要約すると、MmAllocateContiguousMemory()は、連続した物理メモリをシステムメモリにマップするWindowsカーネルモード関数であり、ntoskrnl.exeの一部です。

また、ユーザーモードアプリケーションからこれらのAPIを呼び出すことはできません。ドライバーのみが使用できます。ユーザーモードアプリケーションは、ドライバーの助けなしでは物理メモリにアクセスできません。ドライバーは、ユーザーAPIからの要求を処理するか、IOCTLを使用して、そのリソースをAPIの仮想メモリにマップできます。どちらの方法でも、プラグアンドプレイマネージャーによってインストールされるドライバーの助けが必要になります。 PnPは、ハードウェアのアクティブ化、つまりホットプラグ、または常にオンになっているバスドライバーのような他の方法のいずれかによって、ドライバーを独自にインストールすることを選択する必要があります。

さらにウィンドウがランダムに仮想アドレスを割り当てるため、パターンを識別したり、物理的な場所を特定したりするのは簡単ではありません。

6
marshal craft

このリンクを確認してください: 物理メモリ、ポート、PCI構成スペースにアクセス

しかし、Windows Vistaから始めると、WinHexでさえ物理RAMを開くことができません。

5
Shawnone

Windowsでは、NativeAPIコール NtOpenSection および NtMapViewOfSection を使用する必要があります

マーク・ルシノビッチの例

static BOOLEAN MapPhysicalMemory( HANDLE PhysicalMemory,
                            PDWORD Address, PDWORD Length,
                            PDWORD VirtualAddress )
{
    NTSTATUS            ntStatus;
    PHYSICAL_ADDRESS    viewBase;
    char                error[256];

    *VirtualAddress = 0;
    viewBase.QuadPart = (ULONGLONG) (*Address);
    ntStatus = NtMapViewOfSection (PhysicalMemory,
                               (HANDLE) -1,
                               (PVOID) VirtualAddress,
                               0L,
                               *Length,
                               &viewBase,
                               Length,
                               ViewShare,
                               0,
                               PAGE_READONLY );

    if( !NT_SUCCESS( ntStatus )) {

        sprintf_s( error, "Could not map view of %X length %X",
                *Address, *Length );
        PrintError( error, ntStatus );
        return FALSE;                   
    }

    *Address = viewBase.LowPart;
    return TRUE;
}

static HANDLE OpenPhysicalMemory()
{
    NTSTATUS        status;
    HANDLE          physmem;
    UNICODE_STRING  physmemString;
    OBJECT_ATTRIBUTES attributes;
    WCHAR           physmemName[] = L"\\device\\physicalmemory";

    RtlInitUnicodeString( &physmemString, physmemName );    

    InitializeObjectAttributes( &attributes, &physmemString,
                                OBJ_CASE_INSENSITIVE, NULL, NULL );         
    status = NtOpenSection( &physmem, SECTION_MAP_READ, &attributes );

    if( !NT_SUCCESS( status )) {

        PrintError( "Could not open \\device\\physicalmemory", status );
        return NULL;
    }

    return physmem;
}

\device\physicalmemoryはLinuxでの/dev/memの類似物であり、物理メモリに直接アクセスすることもできます。ちなみに、Windowsについてはわかりませんが、LinuxではBIOSテーブルなどのサービスの低レベルのデータが含まれている可能性があるため、物理アドレス空間は1 MBしか使用できません。他の物理メモリへのアクセスは、OSによって管理されている仮想メモリを破壊する可能性があり、そのため許可されていません

更新:提供されたコードは、Windows Vista以降のユーザーモードでは機能しません。代わりに、GetSystemFirmwareTable()を呼び出して、1 MBのrawメモリから探すことなく、有用な情報を取得できます。

おまけ:Linux(Debian 9)でBoostを使用して物理メモリを読み取るIOメモリマップファイル、クラスの一部:

NativePhysicalMemory::NativePhysicalMemory(size_t base, size_t length)
    : physical_memory_map_(std::make_unique<boost::iostreams::mapped_file_source>())
{
    map_physical_memory(base, length);
}

// ...

void NativePhysicalMemory::map_physical_memory(size_t base, size_t length)
{
#ifdef _SC_PAGESIZE
    size_t mempry_page_offset = base % sysconf(_SC_PAGESIZE);
#else
    size_t mempry_page_offset = base % getpagesize();
#endif /* _SC_PAGESIZE */

    boost_io::mapped_file_params params = {};
    params.path = "/dev/mem";
    params.flags = boost_io::mapped_file::mapmode::readonly;
    params.length = length + mempry_page_offset;
    params.offset = base - mempry_page_offset;
    params.hint = nullptr;
    physical_memory_map_->open(params);
}
2
user707779

PCIカードなどのデバイスはそのようにアクセスする必要があるため、デバイスドライバーは物理メモリアクセスを許可する必要があると思います。ドライバーから実行できる場合は、C++に簡単にリンクできるように、「ユーザー」(管理者のような)モードプログラム用のカスタムアロケーターを記述します。

1
Timmah