PEファイルには「セクション」が含まれており、セクションには独立したベースアドレスがあります。PEは連続したメモリイメージではありません。各セクションは、連続したメモリイメージです。
まず、セクション情報を読み、それらのレイアウトのメモリマップを作成する必要があります。次に、セクションオフセットをファイルベースのオフセットに揃えることができます。
余談ですが、Windows用のフリーウェアでオープンソースのデバッガーおよび逆アセンブラーであるOllyDbgを検討してください。それはおそらくあなたがあなた自身のソフトウェアをテストするのを助けるでしょう、そしてあなたが「あなた自身を転がす」ことによってあなたが満たそうとしているまさにその目的を果たすかもしれません。
出力からの例dumpbin /all
:
セクションヘッダー#1
.text名
BC14仮想サイズ
1000仮想アドレス(00401000〜0040CC13)
生データのBE00サイズ
生データへの400ファイルポインタ(00000400〜0000C1FF)
0再配置テーブルへのファイルポインタ
0行番号へのファイルポインタ
0移転数
0行番号
60000020フラグ
コード
読み取りを実行する
この場合、私の.textセクションはRVA 1000で始まり、RVACE00まで続きます。このセクションへのファイルポインターは400です。600を引く作業により、1000-CDFFの範囲の任意のRVAをファイルポインターに変換できます。(すべての数値は16進数です。)
「RVA」(相対仮想アドレス)に遭遇した場合は常に、次の方法を使用して、ファイルオフセット(またはバイト配列へのインデックス)に解決します。
- RVAが属するセクションを決定します。各セクションには、仮想アドレスからサイズまでのRVAが含まれています。セクションは重複しません。
- RVAからセクション仮想アドレスを減算します。これにより、セクションに対するオフセットが得られます。
- セクションのPointerToRawDataを、手順(2)で取得したオフセットに追加します。これは、RVAに対応するファイルオフセットです。
使用する可能性のある別のアプローチは、 dwDesiredAccess引数に設定されMapViewOfFileEx()
たフラグを使用して呼び出すことです。このAPIは、PEファイルからセクションヘッダーを解析し、セクションの内容を「モジュールベース」に相対的な位置に読み取ります。FILE_MAP_EXECUTE
モジュールベースは、PEヘッダーがロードされるベースアドレスです。関数を使用してDLLをロードする場合、これは関数のメンバーlpBaseOfDllLoadLibrary()
を介して取得できます。 GetModuleInformation()
MODULEINFO
を使用する場合MapViewOfFileEx()
、モジュールベースは単に。からの戻り値ですMapViewOfFileEx()
。
これらの方法でモジュールをロードする設定では、RVAを通常のポインター値に解決することは次の問題です。
- モジュールのベースアドレスを
char *
- RVAをに追加します
char *
char *
を実際のデータ型にキャストし、それを逆参照します。
これらのアプローチのようにOSにファイルをマッピングさせることの欠点は、このツールを使用して疑わしいファイルを調査し、開発者がセクションヘッダーで奇妙な自由を取ったかどうかわからない場合、いくつかの貴重な情報を見逃す可能性があることです。解析のこの部分をOSに処理させることによって。