9

標準のシステム コール (SYS_mkdir など) を独自の実装に置き換える必要があります。

Stackoverflow に関するこの質問を含むいくつかの情報源を読んだようにsys_call_table、カーネル バージョン以降、シンボルはエクスポートされません2.6

次のコードを試しました:

    #include <linux/module.h> 
    #include <linux/kernel.h> 
    #include <linux/unistd.h> 
    #include <asm/syscall.h> 

    int (*orig_mkdir)(const char *path); 

    ....

    int init_module(void) 
    { 
            orig_mkdir=sys_call_table[__NR_mkdir]; 
            sys_call_table[__NR_mkdir]=own_mkdir;  
            printk("sys_mkdir replaced\n"); 
            return(0); 
    } 

    ....

残念ながら、次のコンパイラ エラーが表示されます。

 error: assignment of read-only location ‘sys_call_table[83]’

システムコールを置き換えるにはどうすればよいですか?

編集:カーネルにパッチを適用せずに解決策はありますか?

4

5 に答える 5

8

これは私にとってはうまくいきます。

Linux カーネル: システム コールのフックの例https://bbs.archlinux.org/viewtopic.php?id=139406を参照 してください。

asmlinkage long (*ref_sys_open)(const char __user *filename, int flags, umode_t mode);
asmlinkage long new_sys_open(const char __user *filename, int flags, umode_t mode)
{
  return ref_sys_open(filename, flags, mode);
}

static unsigned long **aquire_sys_call_table(void)
{
  unsigned long int offset = PAGE_OFFSET;
  unsigned long **sct;

  while (offset < ULLONG_MAX) {
    sct = (unsigned long **)offset;

    if (sct[__NR_close] == (unsigned long *) sys_close) 
      return sct;

    offset += sizeof(void *);
  }
  print("Getting syscall table failed. :(");
  return NULL;
}


// Crazy copypasted asm stuff. Could use linux function as well...
// but this works and will work in the future they say.
static void disable_page_protection(void) 
{
  unsigned long value;
  asm volatile("mov %%cr0, %0" : "=r" (value));

  if(!(value & 0x00010000))
    return;

  asm volatile("mov %0, %%cr0" : : "r" (value & ~0x00010000));
}

static void enable_page_protection(void) 
{
  unsigned long value;
  asm volatile("mov %%cr0, %0" : "=r" (value));

  if((value & 0x00010000))
    return;

  asm volatile("mov %0, %%cr0" : : "r" (value | 0x00010000));
}


static int __init rootkit_start(void) 
{

  //Hide me

  print("loaded");

  if(!(sys_call_table = aquire_sys_call_table()))
    return -1;

  disable_page_protection(); 
  {
    ref_sys_open = (void *)sys_call_table[__NR_open];
    sys_call_table[__NR_open] = (unsigned long *)new_sys_open;
  }
  enable_page_protection();
  return 0;
}

static void __exit rootkit_end(void) 
{
  print("exiting");

  if(!sys_call_table) {
    return;
  }

  disable_page_protection();
  {
    sys_call_table[__NR_open] = (unsigned long *)ref_sys_open;
  }
  enable_page_protection();
}
于 2012-12-16T21:29:02.073 に答える
7

はい、カーネルにパッチを適用/再構築せずに解決策があります。Kprobesインフラストラクチャ (または SystemTap)を使用します。

これにより、カーネル モジュールを使用して、カーネル内の任意のポイントに「プローブ」(関数) を配置できます。

sys_call_table を変更して同様のことを行うことは防止され (読み取り専用)、汚いハックと見なされます! Kprobes/Jprobes/etc は、これを行うための「クリーンな」方法です。また、カーネル ソース ツリーで提供されるドキュメントとサンプルは優れています (カーネル src ツリーのDocumentation/kprobes.txtを参照してください)。

于 2012-12-15T07:48:00.710 に答える
1

この問題は、sys_call_tableが読み取り専用であることが原因で発生します。エラーを回避するには、sys_call_tableを操作する前に、書き込み可能にする必要があります。カーネルはそれを実現するための機能を提供します。そして、その関数はset_mem_rw()として与えられます。

sys_call_tableを操作する前に、以下のコードスニペットを追加するだけです。

set_mem_rw((long unsigned int)sys_call_table,1);

カーネルモジュールのexit関数では、sys_call_tableを読み取り専用に戻すことを忘れないでください。これは次のように実行できます。

set_mem_ro((long unsigned int)sys_call_table,1);    
于 2013-01-17T16:05:46.270 に答える
0

LSMインフラストラクチャを使用します。

LSMフックpath_mkdirまたはinode_mkdir詳細を確認してください。解決する必要がある1つの質問は、システムが明示的に許可していないときに、独自のLSMモジュールを登録する方法です。詳細については、回答を参照してください。

LSMで独自のフック関数を実装するにはどうすればよいですか?

于 2012-12-17T18:57:54.213 に答える
0

まず、sys_call_table の場所を特定する必要があります。ここを参照してください。

配置したばかりのシステム テーブルに書き込む前に、そのメモリ ページを書き込み可能にする必要があります。ここで確認してください。うまくいかない場合は、これを試してください。

于 2012-12-14T13:14:01.193 に答える