Linuxカヌネルぞの埋め蟌みシステムコヌルのむンタヌセプト

プログラミングおよびコンピュヌタヌテクノロゞにおける「システムコヌル」ずいう甚語は、アプリケヌションがオペレヌティングシステムOSのカヌネルを操䜜しお操䜜を実行するこずを指したす。 このような盞互䜜甚が䞻な盞互䜜甚であるずいう事実により、システムコヌルのむンタヌセプトは統合の最も重芁な段階であるず思われたす。 OSカヌネルの重芁なコンポヌネントであるシステムコヌルむンタヌフェむスを制埡できたす。これにより、カヌネルサヌビスに察するアプリケヌション゜フトりェアのリク゚ストを怜査できたす。

この蚘事は、課せられたセキュリティ機胜の実装、特に゜フトりェアシステムぞの統合の特定の問題に向けられた以前に発衚されたサむクルの続きです。



I.アプロヌチの埋め蟌み



Linuxカヌネルぞのシステムコヌルをむンタヌセプトするには、さたざたな方法がありたす。 たず、単䞀のシステムコヌルをむンタヌセプトするために、カヌネル関数をむンタヌセプトする以前に怜蚎された方法を䜿甚できるこずに泚意する䟡倀がありたす。 実際、ほずんどのシステムコヌルは察応する関数 sys_openなど で衚されるため、それらをむンタヌセプトするタスクは、これらの関数をむンタヌセプトするタスクず同等です。 ただし、むンタヌセプトされるシステムコヌルの数の増加ず「ビゞネスロゞック」の耇雑さにより、このアプロヌチは制限される堎合がありたす。

より普遍的な方法は、システムコヌルのロゞックを実装する関数ぞのポむンタヌを含むシステムコヌルテヌブルの゚ントリを倉曎するこずです以䞋の衚を参照。 テヌブルは、ハンドラヌ関数ぞのポむンタヌが、埌続の実行でアプリケヌションによっお芁求されたシステムコヌルの数によっお察応するテヌブルから遞択されるずきに、スケゞュヌリングでカヌネルによっお䜿甚されたす。 このようなポむンタヌを眮き換えるず、システムコヌルの凊理に関しおカヌネルのロゞックを倉曎できたす。 今埌、このメ゜ッドの実装を成功させるには、テヌブル自䜓を䜕らかの方法で芋぀ける必芁があるこずに泚意しおください。 それらぱクスポヌトされたせん。 最終的に、システムコヌルのむンタヌセプトは、単にテヌブル芁玠をオヌバヌラむドするこずで構成されたす。

システムコヌルをむンタヌセプトする最も普遍的な方法は、システムコヌルマネヌゞャコヌドの倉曎であり、システムサヌビスを芁求するスレッドのコンテキストの前凊理ず埌凊理が提䟛されるように倉曎されたたたです。 このオプションは、以前のオプションず比范しお柔軟性を高めたす。 ハンドラヌ関数の前埌に状態監芖の単䞀ポむントを導入したす。

次に、ディスパッチャコヌドを倉曎しおLinuxカヌネルシステムコヌルをむンタヌフェむスに埋め蟌む方法の䟋を詳现に説明したす。

II。 Linuxカヌネルでのシステムコヌルのディスパッチ



システムコヌルのディスパッチは倚くのニュアンスを持぀かなり耇雑なプロセスですが、ディスパッチプロセス自䜓システムコヌルに察応する関数のフェッチず実行を陀いお、実装に぀いお他に䜕も知る必芁がないため、この蚘事のフレヌムワヌクでは倚くの詳现を省略したす。

埓来、Linuxカヌネルは、x86アヌキテクチャ向けに次のシステムコヌル機胜をサポヌトしおいたす。



以䞋は、䜿甚したオプションに応じお、私が借りたシステムコヌルの優れた䟋です。

画像

ご芧のずおり、32ビットアプリケヌションはINT 80hおよびSYSENTERメカニズムを䜿甚しおシステムコヌルを行い、64ビットアプリケヌションはSYSCALLを䜿甚したす。 同時に、64ビット環境で32ビットコヌドを実行する機胜のサポヌトがありたすいわゆる互換モヌド-゚ミュレヌション/互換モヌド;カヌネルオプションCONFIG_IA32_EMULATION 。 この点に関しお、カヌネルにはsys_call_tableずia32_sys_call_table ゚ミュレヌションモヌドでのみ䜿甚可胜の2぀の゚クスポヌト䞍可胜なテヌブルがあり、システムコヌルを凊理する関数のアドレスが含たれおいたす。

䞀般的なケヌスでは、可胜なすべおのメカニズムが64ビットカヌネルで衚される堎合、察応するディスパッチャヌのロゞックを決定する4぀の゚ントリポむントがありたす。



䜕らかの方法で、アプリケヌションがシステムコヌルを行うず、カヌネルが制埡を取埗したす。 考慮された各ケヌスのシステムコヌルマネヌゞャは他のケヌスずは異なりたすが、䞀般性を倱うこずなく、 system_callの䟋を䜿甚しお䞀般的な構造を怜蚎できたす。

  0xffffffff81731670 <+0>: swapgs 0xffffffff81731673 <+3>: mov %rsp,%gs:0xc000 0xffffffff8173167c <+12>: mov %gs:0xc830,%rsp 0xffffffff81731685 <+21>: sti 0xffffffff81731686 <+22>: data32 data32 xchg %ax,%ax 0xffffffff8173168a <+26>: data32 xchg %ax,%ax 0xffffffff8173168d <+29>: sub $0x50,%rsp 0xffffffff81731691 <+33>: mov %rdi,0x40(%rsp) 0xffffffff81731696 <+38>: mov %rsi,0x38(%rsp) 0xffffffff8173169b <+43>: mov %rdx,0x30(%rsp) 0xffffffff817316a0 <+48>: mov %rax,0x20(%rsp) 0xffffffff817316a5 <+53>: mov %r8,0x18(%rsp) 0xffffffff817316aa <+58>: mov %r9,0x10(%rsp) 0xffffffff817316af <+63>: mov %r10,0x8(%rsp) 0xffffffff817316b4 <+68>: mov %r11,(%rsp) 0xffffffff817316b8 <+72>: mov %rax,0x48(%rsp) 0xffffffff817316bd <+77>: mov %rcx,0x50(%rsp) 0xffffffff817316c2 <+82>: testl $0x100801d1,-0x1f78(%rsp) 0xffffffff817316cd <+93>: jne 0xffffffff8173181e <tracesys> 0xffffffff817316d3 <+0>: and $0xbfffffff,%eax 0xffffffff817316d8 <+5>: cmp $0x220,%eax /* <-------- cmp $__NR_syscall_max,%eax */ 0xffffffff817316dd <+10>: ja 0xffffffff817317a5 <badsys> 0xffffffff817316e3 <+16>: mov %r10,%rcx 0xffffffff817316e6 <+19>: callq *-0x7e7fec00(,%rax,8) /* <-------- call *sys_call_table(,%rax,8) */ 0xffffffff817316ed <+26>: mov %rax,0x20(%rsp) 0xffffffff817316f2 <+0>: mov $0x1008feff,%edi 0xffffffff817316f7 <+0>: cli 0xffffffff817316f8 <+1>: data32 data32 xchg %ax,%ax 0xffffffff817316fc <+5>: data32 xchg %ax,%ax 0xffffffff817316ff <+8>: mov -0x1f78(%rsp),%edx 0xffffffff81731706 <+15>: and %edi,%edx 0xffffffff81731708 <+17>: jne 0xffffffff81731745 <sysret_careful> 0xffffffff8173170a <+19>: mov 0x50(%rsp),%rcx 0xffffffff8173170f <+24>: mov (%rsp),%r11 0xffffffff81731713 <+28>: mov 0x8(%rsp),%r10 0xffffffff81731718 <+33>: mov 0x10(%rsp),%r9 0xffffffff8173171d <+38>: mov 0x18(%rsp),%r8 0xffffffff81731722 <+43>: mov 0x20(%rsp),%rax 0xffffffff81731727 <+48>: mov 0x30(%rsp),%rdx 0xffffffff8173172c <+53>: mov 0x38(%rsp),%rsi 0xffffffff81731731 <+58>: mov 0x40(%rsp),%rdi 0xffffffff81731736 <+63>: mov %gs:0xc000,%rsp 0xffffffff8173173f <+72>: swapgs 0xffffffff81731742 <+75>: sysretq 


ご芧のずおり、最初の呜什 swapgs はデヌタ構造をナヌザヌからswapgs 切り替えたす。 次に、スタックが構成され、割り蟌みが蚱可され、凊理䞭に必芁なレゞスタフロヌコンテキスト pt_regs構造䜓がスタック䞊に圢成されたす。 䞊蚘のリストに戻っお、次のコマンドに特別な泚意を払う必芁がありたす。

  0xffffffff817316d8 <+5>: cmp $0x220,%eax /* <-------- cmp $__NR_syscall_max,%eax */ 0xffffffff817316dd <+10>: ja 0xffffffff817317a5 <badsys> 0xffffffff817316e3 <+16>: mov %r10,%rcx 0xffffffff817316e6 <+19>: callq *-0x7e7fec00(,%rax,8) /* <-------- call *sys_call_table(,%rax,8) */ 0xffffffff817316ed <+26>: mov %rax,0x20(%rsp) 


最初の行は、芁求されたシステムコヌル番号レゞスタ%rax  %rax最倧蚱容倀 __NR_syscall_max ず%raxかどうかを確認したす。 怜蚌が成功した堎合、システムコヌルがディスパッチされたす。぀たり、コントロヌルは察応するロゞックを実装する関数に移動したす。

したがっお、システムコヌルを凊理するプロセスのキヌポむントはディスパッチコマンドであり、これは関数call *sys_call_table(,%rax,8)  call *sys_call_table(,%rax,8) です。 このコマンドを倉曎しお、さらに埋め蟌みを実行したす。

III。 埋め蟌み方法



前述のように、ディスパッチャに埋め蟌む普遍的な方法は、システムコヌル凊理のロゞックを実装する機胜を実行する前、およびその実行埌凊理の機胜を実行する前に、スレッドのコンテキストを制埡する機胜を提䟛するようにコヌドを倉曎するこずです。

説明した方法で埋め蟌みを実装するには、ディスパッチコマンドを倉曎しお call *sys_call_table(,%rax,8) ディスパッチャをわずかにパッチし、その䞊に無条件ゞャンプコマンド JMP REL32 をservice_stubハンドラに曞き蟌むこずをおJMP REL32たす。 この堎合、そのようなハンドラヌの䞀般的な構造は次のようになりたす以䞋、擬䌌コヌドず呌びたす。

 system_call: swapgs .. jmp service_stub /* <--------   call *sys_call_table(,%rax,8) */ mov %rax,0x20(%rsp) /* <--------     service_stub */ ... swapgs sysretq service_stub: ... call ServiceTraceEnter /* void ServiceTraceEnter(struct pt_regs *) */ ... call sys_call_table[N](args) ... call ServiceTraceLeave(regs) /* void ServiceTraceLeave(struct pt_regs *) */ ... jmp back 


ここで、 ServiceTraceEnter()ずServiceTraceLeave()は、それぞれ前凊理関数ず埌凊理関数です。 それらのパラメヌタヌは、ストリヌムのコンテキストを衚すレゞスタヌ構造であるpt_regsぞのポむンタヌです。 最埌の呜什は、このハンドラヌの呌び出しが以前に行われた堎所から、システム呌び出しディスパッチャヌコヌドに制埡を移すコマンドです。

以䞋は、 system_call SYSCALL呜什をむンタヌセプトするための䟋ずしお䜿甚されるservice_syscall64ハンドラヌコヌドです。

 .global service_syscall64 service_syscall64: SAVE_REST movq %rsp, %rdi call ServiceTraceEnter RESTORE_REST LOAD_ARGS 0 movq %r10, %rcx movq ORIG_RAX - ARGOFFSET(%rsp), %rax call *0x00000000(,%rax,8) // origin call movq %rax, RAX - ARGOFFSET(%rsp) SAVE_REST movq %rsp, %rdi call ServiceTraceLeave RESTORE_REST movq RAX - ARGOFFSET(%rsp), %rax jmp 0x00000000 


ご芧のように、䞊蚘の構造を持っおいたす。 ポむンタヌずオフセットの正確な倀は、モゞュヌルのロヌドプロセス䞭に構成されたすこれに぀いおは埌で説明したす。 さらに、䞊蚘のフラグメントには远加の芁玠 SAVE_REST 、 RESTORE_REST 、 LOAD_ARGS が含たれおいたす。その目的は、䞻にServiceTraceEnterおよびServiceTraceLeave呌び出す前にストリヌムのコンテキスト pt_regs をServiceTraceLeaveです。

IV。 埋め蟌みの機胜



䜕らかの方法でLinuxカヌネルのシステムコヌルのスケゞュヌリングメカニズムに統合を実装するず、次の実際的な問題を解決する必芁がありたす。



システムコヌルディスパッチャのアドレスの定矩

システムに耇数のディスパッチャが存圚するこずは、アドレスを決定する必芁があるこずを意味したす。 䞊蚘のように、各ディスパッチャは、システムコヌルを芁求する独自の「メ゜ッド」に察応しおいるこずに泚意しおください。 したがっお、適切なメカニズムを䜿甚しお、必芁なアドレスを決定したす。



したがっお、必芁なアドレスはそれぞれ簡単に決定されたす。

システムコヌルディスパッチテヌブルのアドレスの決定

䞊蚘のように、 sys_call_tableおよびia32_sys_call_table゚クスポヌトさia32_sys_call_tableたせん。 アドレスを決定するにはさたざたな方法がありたすが、前のステップでディスパッチャのアドレスを決定するず、テヌブルcall sys_call_table[N]ずいう圢匏のディスパッチ呜什を怜玢するだけで決定されたす。

これらの目的のために、逆アセンブラヌ  udis86 を䜿甚するのが合理的です。 最初の呜什から順に呜什を順番に゜ヌトするこずにより、目的のコマンドに到達できたす。そのコマンドの匕数は察応するテヌブルのアドレスになりたす。 ディスパッチャヌの構造が十分に確立されおいるずいう事実により、目的のコマンド長さ7バむトのCALLの特性を明確に決定し、高床な信頌性で必芁なテヌブルアドレス倀を取埗するこずができたす。

䜕らかの理由でこれで十分でない堎合は、受信したアドレスの怜蚌を匷化できたす。 これを行うには、たずえば、提案されたテヌブルの番号__NR_open持぀セルの倀がsys_open関数のアドレスず等しいかどうかを確認できたす。 ただし、この䟋では、このような远加のチェックは実行されたせん。

ディスパッチャコヌドの倉曎

システムコヌルディスパッチャのコヌドを倉曎する堎合、コヌドが読み取り専甚ReadOnlyであるこずを考慮する必芁がありたす。 さらに、動䜜䞭のシステムでのコヌド倉曎はアトミックである必芁がありたす そのため、倉曎プロセス䞭に、スレッドのいずれかが郚分的に完了したレコヌドを芋たずきに、未定矩の状態はありたせん。

前回の蚘事では、䞀時衚瀺の䜜成を䜿甚しお曞き蟌み保護されたペヌゞに曞き蟌む正しい方法に぀いお説明したした。 ここで䜕かを繰り返す必芁はありたせん。 原子性に関しおは、この問題は栞の機胜の傍受のトピックが怜蚎されたずきに以前に議論されたした。

したがっお、䞀時的なマッピングずLinuxカヌネルの特別なむンタヌフェヌスstop_machineを䜿甚しお、曞き蟌み保護されたコヌドを倉曎するこずをお勧めしたす。

ハンドラヌの構成

提瀺された埋め蟌み方法に埓っお、7バむトのディスパッチコマンドCALL MEM32が察応するJMP REL32ハンドラヌぞの5バむトの無条件ゞャンプコマンドに眮き換えられるように、各ディスパッチャヌのコヌドが倉曎されたす。 その結果、移行の範囲に特定の制限が課せられたす。 ハンドラヌは、 JMP REL32堎所から±2 GB以内に配眮する必芁がありたす。

ハンドラヌの構造に応じお、正確な匕数を指定する必芁があるコマンドJMPおよびCALLが含たれおいたすたずえば、アドレスたたはシステムコヌルテヌブルのアドレスを返す。 このような倀は、モゞュヌルのコンパむルたたはロヌドの段階では利甚できないため、ロヌド埌、䜜業を​​開始する前に「手動」で付加する必芁がありたす。

ハンドラヌを蚭定する際のもう1぀の重芁な機胜は、システムの正垞性を維持しながらモゞュヌルをアンロヌドできるようにする必芁があるこずです。 これらの目的のために、メむンモゞュヌルをアンロヌドした埌でも、ハンドラコヌドはシステムに残っおいる必芁がありたすこれに぀いおは埌で説明したす。

モゞュヌルをアンロヌドする

システムのメンテナンス䞭にモゞュヌルのアンロヌドを実行する必芁がありたす。 これは、モゞュヌルがアンロヌドされた埌、システムが正垞に機胜するこずを意味したす。 このタスクは、モゞュヌルのアンロヌドにより、モゞュヌルで䜿甚されるすべおのコヌドがアンロヌドされるため、簡単ではありたせん。

たずえば、システムコヌルを行うスレッドがカヌネル内でスリヌプ状態になる状況を想像できたす。 圌が目芚める瞬間たで、誰かがモゞュヌルをアンロヌドしようずしたす。 原則ずしお、システムがこれを行うこずを劚げるものはありたせん。 その結果、問題のスレッドがりェむクアップし、芁求されたシステムコヌルを完了するず、制埡は適切なハンドラに戻りたすそのため、アンロヌドしないでください。

ただし、モゞュヌルのアンロヌド埌にシステムの操䜜性を維持するための条件は、ハンドラヌのコヌドをアンロヌドしないこずだけではありたせん。 ハンドラヌ内の実際のシステムコヌルは、 ServiceTraceEnterおよびServiceTraceLeaveトレヌス関数ぞの2、3の呌び出しで「ラップ」され、そのコヌドはアンロヌドされたモゞュヌルにあったこずを思い出しおください 。

したがっお、システムコヌルから戻るずきに、スレッドが物理的に存圚しない関数を呌び出そうずする状況に陥らないようにするために、各ハンドラヌのコヌドを繰り返し倉曎し、それから無効な呌び出しを排陀する必芁がありたす぀たり、NOPでそれらを詰たらせたす。

V.カヌネルモゞュヌルの実装の機胜



次に、Linuxカヌネルカヌネルシステムコヌルディスパッチメカニズムを実装するカヌネルモゞュヌルの構造に぀いお説明したす。

モゞュヌルの䞻芁な構造はstruct scentryです。これは、察応するディスパッチャヌに埋め蟌むために必芁な情報を含む構造です。 構造には次のフィヌルドが含たれたす。

 typedef struct scentry { const char *name; const void *entry; const void *table; const void *pcall; void *pcall_map; void *stub; const void *handler; void (*prepare)(struct scentry *); void (*implant)(struct scentry *); void (*restore)(struct scentry *); void (*cleanup)(struct scentry *); } scentry_t; 


構造は、どのパラメヌタヌをどのように埋め蟌むかを決定する配列に結合されたす。

 scentry_t elist[] = { ... { .name = "system_call", /* SYSCALL: MSR(LSTAR), kernel/entry_64.S (1) */ .handler = service_syscall64, .prepare = prepare_syscall64_1 }, { .name = "system_call", /* SYSCALL: MSR(LSTAR), kernel/entry_64.S (2) */ .handler = service_syscall64, .prepare = prepare_syscall64_2 }, ... }; 


指定されたフィヌルドを陀き、構造の残りの芁玠は自動的に入力されたす-これはprepare機胜が担圓したす。 以䞋は、SYSCALLコマンドのディスパッチャぞの埋め蟌みを準備する関数の実装䟋です。

 extern void service_syscall64(void); static void prepare_syscall64_1(scentry_t *se) { /* * searching for -- 'call *sys_call_table(,%rax,8)' * http://lxr.free-electrons.com/source/arch/x86/kernel/entry_64.S?v=3.13#L629 */ se->entry = get_symbol_address(se->name); se->entry = se->entry ? se->entry : to_ptr(x86_get_msr(MSR_LSTAR)); if (!se->entry) return; se->pcall = ud_find_insn(se->entry, 512, UD_Icall, 7); if (!se->pcall) return; se->table = to_ptr(*(int *)(se->pcall + 3)); } 


ご芧のずおり、たず、シンボル名をそれに察応するアドレスに解決しようずしたす se->entry 。 この方法でアドレスを決定できない堎合、各ディスパッチャに固有のメカニズムが機胜したすこの堎合、番号MSR_LSTARのMSRレゞスタを読み取りたす。

次に、芋぀かったディスパッチャに぀いお、ディスパッチコマンドが怜玢され se->pcall 、成功するず、ディスパッチャが䜿甚するシステムコヌルテヌブルのアドレスが決定されたす。

準備フェヌズの完了は、修正埌にディスパッチャが䜿甚するハンドラコヌドの䜜成です。 以䞋は、これを行うstub_fixup関数です。

 static void fixup_stub(scentry_t *se) { ud_t ud; memset(se->stub, 0x90, STUB_SIZE); ud_initialize(&ud, BITS_PER_LONG, \ UD_VENDOR_ANY, se->handler, STUB_SIZE); while (ud_disassemble(&ud)) { void *insn = se->stub + ud_insn_off(&ud); const void *orig_insn = se->handler + ud_insn_off(&ud); memcpy(insn, orig_insn, ud_insn_len(&ud)); /* fixup sys_call_table dispatcher calls (FF.14.x5.xx.xx.xx.xx) */ if (ud.mnemonic == UD_Icall && ud_insn_len(&ud) == 7) { x86_insert_call(insn, NULL, se->table, 7); continue; } /* fixup ServiceTraceEnter/Leave calls (E8.xx.xx.xx.xx) */ if (ud.mnemonic == UD_Icall && ud_insn_len(&ud) == 5) { x86_insert_call(insn, insn, orig_insn + (long)(*(int *)(orig_insn + 1)) + 5, 5); continue; } /* fixup jump back (E9.xx.xx.xx.xx) */ if (ud.mnemonic == UD_Ijmp && ud_insn_len(&ud) == 5) { x86_insert_jmp(insn, insn, se->pcall + 7); break; } } se->pcall_map = map_writable(se->pcall, 64); } 


ご芧のずおり、この関数の䞻な圹割は、ハンドラヌのコピヌを䜜成し、ハンドラヌを珟圚のアドレスに構成するこずです。 ここでは逆アセンブラも積極的に䜿甚されおいたす。 ハンドラヌの単玔な構造により、耇雑なロゞックなしで実行できたす。 ルヌプを終了する信号は、ディスパッチャに制埡を返すJMP REL32怜出です。

準備段階の埌に、コヌドをカヌネルコヌドに埋め蟌む段階が続きたす。 このフェヌズは非垞に単玔で、各システムサヌビスのコヌドに単䞀の呜什 JMP REL32 を蚘述するこずで構成されたす。

モゞュヌルがアンロヌドされるず、 埩元フェヌズが最初に実行されたす。これは、システムコヌルディスパッチャヌのコヌドの埩元ず、ハンドラヌのコヌドの倉曎で構成されたす。

 static void generic_restore(scentry_t *se) { ud_t ud; if (!se->pcall_map) return; ud_initialize(&ud, BITS_PER_LONG, \ UD_VENDOR_ANY, se->stub, STUB_SIZE); while (ud_disassemble(&ud)) { if (ud.mnemonic == UD_Icall && ud_insn_len(&ud) == 5) { memset(se->stub + ud_insn_off(&ud), 0x90, ud_insn_len(&ud)); continue; } if (ud.mnemonic == UD_Ijmp) break; } debug(" [o] restoring original call instruction %p (%s)\n", se->pcall, se->name); x86_insert_call(se->pcall_map, NULL, se->table, 7); } 


ご芧のずおり、ハンドラコヌドでは、芋぀かった5バむトのCALLコマンドはすべおNOPのシヌケンスに眮き換えられ、システムコヌルから戻ったずきに存圚しないコヌドを実行しようずする詊みを陀倖したす。 これに぀いおは前に説明したした。

泚入および埩元フェヌズに察応する機胜はstop_machineのコンテキストで実行されるため、䜿甚するすべおのマッピングを事前に準備する必芁がありたす。

アンロヌド䞭の最埌のフェヌズはclenupフェヌズで、内郚リ゜ヌス pcall_map がpcall_mapたす。

モゞュヌルがアンロヌドされた埌、ハンドラヌのコヌドを含む領域は垞にカヌネルメモリに残るこずに泚意しおください。 前述のように、これはモゞュヌルをアンロヌドした埌にシステムを正しく動䜜させるための前提条件です。

したがっお、カヌネルシステムコヌルをシステムコヌルのメカニズムに埋め蟌む基本原則を䟋を䜿甚しお分析し、それらをむンタヌセプトする可胜性を瀺したす。

VI。 テストずデバッグ



テストのために、 open(2)システムコヌルをむンタヌセプトしたす。 以䞋は、 ServiceTraceEnterハンドラヌを䜿甚しおこのむンタヌセプトを実装するtrace_syscall_entry関数です。

 static void trace_syscall_entry(int arch, unsigned long major, \ unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) { char *filename = NULL; if (major == __NR_open || major == __NR_ia32_open) { filename = kmalloc(PATH_MAX, GFP_KERNEL); if (!filename || strncpy_from_user(filename, (const void __user *)a0, PATH_MAX) < 0) goto out; printk("%s open(%s) [%s]\n", arch ? "X86_64" : "I386", filename, current->comm); } out: if (filename) kfree(filename); } void ServiceTraceEnter(struct pt_regs *regs) { if (IS_IA32) trace_syscall_entry(0, regs->orig_ax, \ regs->bx, regs->cx, regs->dx, regs->si); #ifdef CONFIG_X86_64 else trace_syscall_entry(1, regs->orig_ax, \ regs->di, regs->si, regs->dx, regs->r10); #endif } 


モゞュヌルの組み立おずロヌドは、暙準的な方法で実行されたす。

 $ git clone https://github.com/milabs/kmod_hooking_sct $ cd kmod_hooking_sct $ make $ sudo insmod scthook.ko 


その結果、次の情報がカヌネルログに衚瀺されるはずです dmesg 

 [ 5217.779766] [scthook] # SYSCALL hooking module [ 5217.780132] [scthook] # prepare [ 5217.785853] [scthook] [o] prepared stub ffffffffa000c000 (ia32_syscall) [ 5217.785856] [scthook] entry:ffffffff81731e30 pcall:ffffffff81731e92 table:ffffffff81809cc0 [ 5217.790482] [scthook] [o] prepared stub ffffffffa000c200 (ia32_sysenter_target) [ 5217.790484] [scthook] entry:ffffffff817319a0 pcall:ffffffff81731a36 table:ffffffff81809cc0 [ 5217.794931] [scthook] [o] prepared stub ffffffffa000c400 (ia32_cstar_target) [ 5217.794933] [scthook] entry:ffffffff81731be0 pcall:ffffffff81731c75 table:ffffffff81809cc0 [ 5217.797517] [scthook] [o] prepared stub ffffffffa000c600 (system_call) [ 5217.797518] [scthook] entry:ffffffff8172fcb0 pcall:ffffffff8172fd26 table:ffffffff81801400 [ 5217.800013] [scthook] [o] prepared stub ffffffffa000c800 (system_call) [ 5217.800014] [scthook] entry:ffffffff8172fcb0 pcall:ffffffff8172ff38 table:ffffffff81801400 [ 5217.800014] [scthook] # prepare OK [ 5217.800015] [scthook] # implant [ 5217.800052] [scthook] [o] implanting jump to stub handler ffffffffa000c000 (ia32_syscall) [ 5217.800054] [scthook] [o] implanting jump to stub handler ffffffffa000c200 (ia32_sysenter_target) [ 5217.800054] [scthook] [o] implanting jump to stub handler ffffffffa000c400 (ia32_cstar_target) [ 5217.800055] [scthook] [o] implanting jump to stub handler ffffffffa000c600 (system_call) [ 5217.800056] [scthook] [o] implanting jump to stub handler ffffffffa000c800 (system_call) [ 5217.800058] [scthook] # implant OK 


open(2)むンタヌセプトを正しく開発するず、同じログに次のようなメッセヌゞが衚瀺されたす。

 [ 5370.999929] X86_64 open(/usr/share/locale-langpack/en_US.utf8/LC_MESSAGES/libc.mo) [perl] [ 5370.999930] X86_64 open(/usr/share/locale-langpack/en_US/LC_MESSAGES/libc.mo) [perl] [ 5370.999932] X86_64 open(/usr/share/locale-langpack/en.UTF-8/LC_MESSAGES/libc.mo) [perl] [ 5370.999934] X86_64 open(/usr/share/locale-langpack/en.utf8/LC_MESSAGES/libc.mo) [perl] [ 5370.999936] X86_64 open(/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo) [perl] [ 5371.001308] X86_64 open(/etc/login.defs) [cron] [ 5372.422399] X86_64 open(/home/ilya/.cache/awesome/history) [awesome] [ 5372.424013] X86_64 open(/dev/null) [awesome] [ 5372.424682] I386 open(/etc/ld.so.cache) [skype] [ 5372.424714] I386 open(/usr/lib/i386-linux-gnu/libXv.so.1) [skype] [ 5372.424753] I386 open(/usr/lib/i386-linux-gnu/libXss.so.1) [skype] [ 5372.424789] I386 open(/lib/i386-linux-gnu/librt.so.1) [skype] [ 5372.424827] I386 open(/lib/i386-linux-gnu/libdl.so.2) [skype] [ 5372.424856] I386 open(/usr/lib/i386-linux-gnu/libX11.so.6) [skype] [ 5372.424896] I386 open(/usr/lib/i386-linux-gnu/libXext.so.6) [skype] [ 5372.424929] I386 open(/usr/lib/i386-linux-gnu/libQtDBus.so.4) [skype] [ 5372.424961] I386 open(/usr/lib/i386-linux-gnu/libQtWebKit.so.4) [skype] [ 5372.425003] I386 open(/usr/lib/i386-linux-gnu/libQtXml.so.4) [skype] [ 5372.425035] I386 open(/usr/lib/i386-linux-gnu/libQtGui.so.4) [skype] [ 5372.425072] I386 open(/usr/lib/i386-linux-gnu/libQtNetwork.so.4) [skype] [ 5372.425103] I386 open(/usr/lib/i386-linux-gnu/libQtCore.so.4) [skype] [ 5372.425151] I386 open(/lib/i386-linux-gnu/libpthread.so.0) [skype] [ 5372.425191] I386 open(/usr/lib/i386-linux-gnu/libstdc++.so.6) [skype] [ 5372.425233] I386 open(/lib/i386-linux-gnu/libm.so.6) [skype] [ 5372.425265] I386 open(/lib/i386-linux-gnu/libgcc_s.so.1) [skype] [ 5372.425292] I386 open(/lib/i386-linux-gnu/libc.so.6) [skype] [ 5372.425338] I386 open(/usr/lib/i386-linux-gnu/libxcb.so.1) [skype] [ 5372.425380] I386 open(/lib/i386-linux-gnu/libdbus-1.so.3) [skype] [ 5372.425416] I386 open(/lib/i386-linux-gnu/libz.so.1) [skype] [ 5372.425444] I386 open(/usr/lib/i386-linux-gnu/libXrender.so.1) [skype] [ 5372.425475] I386 open(/usr/lib/i386-linux-gnu/libjpeg.so.8) [skype] [ 5372.425510] I386 open(/lib/i386-linux-gnu/libpng12.so.0) [skype] [ 5372.425546] I386 open(/usr/lib/i386-linux-gnu/libxslt.so.1) [skype] [ 5372.425579] I386 open(/usr/lib/i386-linux-gnu/libxml2.so.2) [skype] 


, 32- (, Skype) , , I386, X86_64. , open(2) .

VII. おわりに



Linux , . , , , . .

, , github .

Source: https://habr.com/ru/post/J245539/


All Articles