簡単な紹介
ます。https://github.com/elfmaster/taskverseここでは、カーネルメモリにアクセスするためには/ proc / kcoreはgithubのアドレスを使用して隠されたプロセス検出ツールの作者によって調製「Linuxのバイナリ解析は、」taskverseです。
/ procの/ KCORE
このファイルは、カーネルが提供するカーネルメモリ・インタフェースを通過するために使用され、ELFファイルフォーマットは、彼はカーネルファイル\ FS \ procの\ kcore.c、リストkclist_head周りの主要オペレーティングファイルproc_kcore_operationsを整理するのエルフに実装されています個々のセグメント。セグメントは、メモリの期間を表し、メモリセグメントに実行可能ファイルをマッピングしました。、これらのセグメント上の情報を見てくださいノートでは前に、このセグメントであり、ここでいくつかの他の情報が保持しているカーネルのソースコードから、分析されていませんはい入れget_kcore_sizeノートどのようなネットワークセグメントで見ることができます。
このドキュメントの使用を説明するために、私は簡単な例を書いて、ここでコード:https://github.com/smakk/kocre_sample
readelfが-hコマンドを表示するために使用することができ、このファイルは何のお祭りの領域ではないの/ proc / KCOREに見出すことができ、それはシンボルテーブルにアクセスする方法はありません、の/ proc / kallsymsシンボリックアドレスの使用は、このファイルにアクセスするために、特定のコード次のように名前は、アドレスに基づいて、シンボルのシンボルファイルを見つけるために読み続けます
// / PROC / KCOREないヘッダ部は、シンボルテーブルを見つけることができない、シンボルアドレスがkallsym介して来ないので 、符号なしのロング get_sym(CHAR * 名){ FILE * FD; チャー symbol_s [ 255 ]; int型I、 符号なしのロング・アドレス。 チャー TMP [ 255 ]、タイプを、 IF((FDにはfopen(= " の/ proc / kallsyms "、" R&LTを"))== NULL) { のprintf(" のfopen / PROC / kallsym間違っ\ N- " ); 出口( -1 ); } ながら(!FEOF(FD)) { 場合(関数fscanf(FD、" %のLX%のC%sの"、およびアドレス、およびタイプ、symbol_s)<= 0 ){ のprintf(" 関数fscanf間違っする\ n " ); 出口( - 1 )。 } であれば(のstrcmp(symbol_s、名)== 0 ) { FCLOSE(FD)。 リターンアドレス。 } もし(!strcmpの(symbol_s、"" )) 休憩。 } FCLOSE(FD)。 リターン 0 ; }
情報のセグメントを表現するグローバルリストKCOREの使用は、/仮想アドレス、ファイルオフセットとサイズをKCORE / PROC / KCOREの使用、続いて、これら3つの量が存在するメモリにアクセスすることができます
構造体kcore_list { 構造体 kcore_list * リスト、 符号なしのロングVADDR、 符号なしのロング・オフセット、 size_tのサイズ; }; 構造体kcore_list KCORE; / * 、KCOREリストを生成昇順に仮想アドレスによって提供されるすべてのアドレス空間KCOREを格納し、これらのアドレス空間はありませんオーバーラップ * / ボイド * (){init_kcore_list INT(FD =オープン" の/ proc / KCORE " O_RDONLYの、); IF(FD < 0 ){ のprintf(" N- \間違っオープン/ PROC / KCORE " ); 出口( - 1。); } Elf64_Ehdrヘッド。 (FD、読み&ヘッド、はsizeof (Elf64_Ehdr)); もし(のlseek(FD、head.e_phoff、SEEK_SET)< 0 ){ のprintf(" のlseek / PROC / KCORE間違ったの\ n " ); 出口( - 1 )。 } Elf64_Phdr PHDR [head.e_phnum]。 (FD、読み&PHDR、はsizeof(Elf64_Phdr)* head.e_phnum)。 クローズ(FD)。 int型私は、 用(i = 0 ; I <head.e_phnum; I ++ ){ 構造体 kcore_list * k_list = のmalloc(はsizeof(構造体kcore_list))。 k_list - > VADDR = PHDR [I] .p_vaddr。 k_list - >オフセット= head.e_phoff + はsizeof(Elf64_Phdr)* I。 k_list - >サイズ= PHDR [I] .p_memsz。 構造体 kcore_list * tmplist =&KCORE。 一方、(!tmplist->リスト= NULL && tmplist->リスト- > VADDR <k_list-> VADDR){ tmplist = tmplist-> リスト。 } k_list - >リスト= tmplist-> リスト。 tmplist - >リスト= k_list。 //printf( "%LXの\ nを"、k_list-> VADDR); } を返します。 }
今、仮想アドレスを指すアドレス記号にアクセスするためにKCORE記憶セグメント情報を完了した、仮想アドレスが最初に配置されているセグメントを見つけるし、ファイル内のこのセグメントをオフセットに変換することで、ファイルが最終的にかかるオフセットアクセスファイル。コードは以下の通りであります:
/ * メモリサイズSIZE / PROC / KCOREこの場所から読み出された仮想アドレスaddr、 * / ボイド * get_area(符号なしロングADDR、size_tのサイズ){ ボイド *のRET; 構造体 kcore_list k_list * = kcore.list; 一方(k_list != NULL && ADDR> k_list-> + k_list- VADDR> サイズ){ k_list = k_list-> リスト; } IF(ADDR> = k_list-> VADDR && ADDR +サイズ<k_list-> + k_list- VADDR> サイズ){ INT FD =オープン(" / PROC / KCORE " O_RDONLYの、); IF(FD < 0 ){ のprintf(" / procの/ KCORE間違った\ nを開きます" ); 出口( - 1 )。 } であれば(のlseek(FD、k_list->オフセット+(ADDR-k_list-> VADDR)、SEEK_SET)< 0 ){ のprintf(" のlseek / PROC / KCORE間違ったの\ n " ); 出口( - 1 )。 } RET = malloc関数(サイズ)。 (FD、RET、サイズ)を読み取ります。 クローズ(FD)。 } 戻りRET。 }
最後に、この言い訳を使用して、私は、プロセス記述、カーネルプロセス記述子をinit_task見つけ、使用の簡単な例を作った、最初のフィールドは、プロセス状態init_taskの出力は、それを印刷プロセスの状態を表し、結果。
INT メイン(){ init_kcore_list(); のprintf(" _TEXTのアドレスが使わ%LX \ N- IS "、get_sym(" _TEXT " ;)) ボイド *符号= get_area(get_sym(" init_task ")、100 )、 符号なしのロング *像= (符号なしロング * )コード; // 0 0より大きい停止を示し、実行中を表す のprintfは(" init_task像は、%LDの\のN-である"、* ;像) 戻り 0 ; }
taskverse分析
Taskverse.cミアン機能のホームディレクトリにあるプログラムのエントリアドレス、taskverseに二つのシンボルを見つけることができ、一方が他方のsystemmapファイルであるkallsyms、です。
注目すべきはその構造が3つのMEMコンテンツを置くMEMエルフ構造の構造、