web-dev-qa-db-ja.com

ASLRとプログラムが実際にその関数を呼び出す方法

私は保護技術を研究していますが、Windows環境でプログラムに対してASLRがどのように機能するかについて疑問があります。

私が知る限り、ASLRは、モジュールをメモリにロードするときにイメージベースアドレスの一部をランダム化することで機能するため、エクスプロイトはハードコードされたアドレスに依存できません。

私の質問は、プログラムがモジュール「kernel32.dll」を使用して、それをアドレス空間にロードするとします。そのようなプログラムの中におそらくCALL命令があるでしょう

...
CALL some_address_inside_kernel32.dll
...
...

kernel32.dll関数のアドレスが信頼できなくなった場合、プログラムはどのようにジャンプするかをどのようにして知るのですか?ローダーはこのプロセスに介入しますか?

5
Marco A.

カーネル内ではfunctionsを呼び出しません。カーネルは別の特権レベルにあります。そのメモリページは通常のコードからアクセスできません。カーネルコードにジャンプするために、アプリケーションコードは システムコール を実行します。これは、一時的な特権昇格を処理する特定の出入り口の使用を伴います。 Linuxを実行する32ビットx86システムでは、これはint 0x80:ソフトウェアによってトリガーされる割り込み。システムコールパラメータは、特定のCPUレジスタで呼び出し元によって提供されます。特に、%eax registerには、アプリケーションが実行するシステムコールのシンボリック識別子が含まれています。割り込みハンドラー(カーネル内)は、CPUレジスターを調べて、アプリケーションがカーネルに何を実行したいか(システムコールが許可されているかどうかはまだ)を確認します別の問題)。

システムコール用のASLRはありません。これは関連する概念ではありません。 ASLRは [〜#〜] dll [〜#〜] 用です。 DLLはapplicationコードの一部であり、アプリケーションのアドレス空間にロードされ、以下のアプリケーションからアクセスできます。その通常の特権、特に、アプリケーションコードはDLLコードに通常の「ジャンプ」オペコードを使用して「ジャンプ」できます(関数呼び出しは栄光のジャンプにすぎません)。

DLLがロードされる実際のアドレスは、DLLが実際にロードされた場合にのみ認識されるため、アプリケーションコードは特別な規則に従い、ジャンプオペコードがDLLがロードされた場所を指すように動的に調整されます。この動的調整は、動的リンカーによって実行されます。このリンカーは、再配置テーブルを使用してそのジョブを実行します。このようなテーブルのエントリは、調整が必要なオペコードと関数の名前を記述しますDLLが(ダイナミックリンカによって)ロードされると、その関数のメモリへの配置が判明し、再配置テーブルに記述されているジャンプオペコードが調整されます。

ご覧のように、DLLの概念全体では、DLLをRAMの任意の配置でロードすることができます。その配置は、実際の配置は、ロードを実行するために十分な空きメモリの「穴」がある場所に依存するため、アプリケーションの動作、以前に割り当てられたメモリの量などに応じて変化する可能性があります。DLL「自然に」ロードすることは、固定されていないロードアドレスを意味します。 [〜#〜] aslr [〜#〜]voluntaryDLL内を移動する:ダイナミックリンカーは、ランダムな(フリー)ロードアドレスを意図的に選択します。これは(ほぼ)完全に透過的ですアプリケーション用。

9
Thomas Pornin

kernel32.dll関数のアドレスが信頼できなくなった場合、プログラムはどのようにジャンプするかをどのようにして知るのですか?ローダーはこのプロセスに介入しますか?

クマはASLRの一般的な概要を説明しました。ただし、Windowsに固有のいくつかのポイントを取り除く必要があります。

  • 実際には、DLLは常に再配置に対処する必要がありました。それらには、アドレス空間内の優先ベースアドレスが含まれています。これは、Win32アプリの開発における以前の最適化手順の1つである DLLのリベース のためです。多くのDLLにロードすると、多くの衝突が発生しました。
  • これは、UnixのPICアプローチとは対照的です wikipedia を参照してください。
  • DLLがロードされると、最後のハンドルが閉じられるまでメモリ内に残ります。DLLを一意のアドレス位置にマップすることは非効率的であることを考えるとこれは、プロセスごとに読み込まれると、kernel32.dllなどの一般的なシステムDLLがすべてのアプリケーションの同じアドレスに存在することを意味します。ASLRの内部については、優れた回答から詳細を読むことができます here 。そのため、再起動後にkernel32.dllのアドレスを予測することは難しいかもしれませんが、特定のブートで検出されると、アドレスは変更されません。
  • Windowsアーキテクチャでは、kernel32.dllは実際にはユーザーモードヘルパーライブラリです。 Thomasが正しく言っているように、カーネルモードに入るにはシステムコールが必要です。これらは実際にntdll.dll(はい、別のDLL)で発生し、さまざまなNt接頭辞付きの関数をシステムコールにラップし、パッケージ化してカーネルまで起動します。
  • カーネルドライバーは非決定的に読み込まれます-カーネルにはASLRがあります。 this osr thread および this presentation を参照してください。私が理解しているように、Windowsブートマネージャはntoskrnlhal.dllをランダムな場所にロードします。 Server 2008以降のドライバーは、常に非決定論的にロードされます。
4
user2213