GNU/Linux >> Linux の 問題 >  >> Linux

Linux のリバース エンジニアリング ツール – 文字列、nm、ltrace、strace、LD_PRELOAD

この記事では、Linux 環境で実行可能ファイルをリバース エンジニアリングするために使用できるツールとコマンドについて説明します。

リバース エンジニアリングとは、ソフトウェアの機能を解明する行為であり、利用可能なソース コードはありません。リバース エンジニアリングでは、ソフトウェアの正確な詳細が得られない場合があります。しかし、ソフトウェアがどのように実装されたかについてはかなりよく理解できます。

リバース エンジニアリングには、次の 3 つの基本的な手順が含まれます。

<オール>
  • 情報収集
  • プログラムの動作の決定
  • ライブラリ呼び出しのインターセプト
  • I.情報収集

    最初のステップは、ターゲット プログラムとその機能に関する情報を収集することです。この例では、「who」コマンドを使用します。 「who」コマンドは、現在ログインしているユーザーのリストを出力します。

    1.文字列コマンド

    Strings は、印刷可能な文字列をファイルに出力するコマンドです。それでは、これをターゲット (who) コマンドに対して使用してみましょう。

    # strings /usr/bin/who

    重要な文字列のいくつかは、

    users=%lu
    EXIT
    COMMENT
    IDLE
    TIME
    LINE
    NAME
    /dev/
    /var/log/wtmp
    /var/run/utmp
    /usr/share/locale
    Michael Stone
    David MacKenzie
    Joseph Arceneaux

    about の出力から、「who」が 3 つのファイル (/var/log/wtmp、/var/log/utmp、/usr/share/locale) を使用していることがわかります。

    続きを読む:Linux 文字列コマンドの例 (UNIX バイナリ ファイル内のテキストを検索)

    2. nmコマンド

    nm コマンドは、ターゲット プログラムからシンボルを一覧表示するために使用されます。 nm を使用すると、ローカル関数とライブラリ関数、および使用されるグローバル変数を知ることができます。 nm は、「strip」コマンドを使用してストライプ化されたプログラムでは動作しません。

    注:デフォルトでは、「who」コマンドは削除されています。この例では、「who」コマンドをもう一度コンパイルしました。

    # nm /usr/bin/who

    これにより、以下がリストされます:

    08049110 t print_line
    08049320 t time_string
    08049390 t print_user
    08049820 t make_id_equals_comment
    080498b0 t who
    0804a170 T usage
    0804a4e0 T main
    0804a900 T set_program_name
    08051ddc b need_runlevel
    08051ddd b need_users
    08051dde b my_line_only
    08051de0 b time_format
    08051de4 b time_format_width
    08051de8 B program_name
    08051d24 D Version
    08051d28 D exit_failure

    上記の出力では:

    • t|T – シンボルが .text コード セクションに存在する
    • b|B – シンボルは UN 初期化された .data セクションにあります
    • D|d – シンボルは初期化された .data セクションにあります。

    大文字または小文字によって、シンボルがローカルかグローバルかが決まります。

    about 出力から、次のことがわかります。

    • グローバル関数 (main、set_program_name、usage など) があります
    • いくつかのローカル関数 (print_user、time_string など) があります
    • グローバルに初期化された変数 (Version、exit_failure) があります
    • UN 初期化された変数 (time_format、time_format_width など) があります

    場合によっては、関数名を使用して、関数が何をするかを推測できます。

    続きを読む:10 の実用的な Linux nm コマンドの例

    情報を取得するために使用できる他のコマンドは

    • ldd コマンド
    • 定着コマンド
    • lsof コマンド
    • /proc ファイル システム

    II.プログラムの動作の決定

    3. ltrace コマンド

    ライブラリ関数への呼び出しをトレースします。そのプロセスでプログラムを実行します。

    # ltrace /usr/bin/who

    出力を以下に示します。

    utmpxname(0x8050c6c, 0xb77068f8, 0, 0xbfc5cdc0, 0xbfc5cd78)          = 0
    setutxent(0x8050c6c, 0xb77068f8, 0, 0xbfc5cdc0, 0xbfc5cd78)          = 1
    getutxent(0x8050c6c, 0xb77068f8, 0, 0xbfc5cdc0, 0xbfc5cd78)          = 0x9ed5860
    realloc(NULL, 384)                                                   = 0x09ed59e8
    getutxent(0, 384, 0, 0xbfc5cdc0, 0xbfc5cd78)                         = 0x9ed5860
    realloc(0x09ed59e8, 768)                                             = 0x09ed59e8
    getutxent(0x9ed59e8, 768, 0, 0xbfc5cdc0, 0xbfc5cd78)                 = 0x9ed5860
    realloc(0x09ed59e8, 1152)                                            = 0x09ed59e8
    getutxent(0x9ed59e8, 1152, 0, 0xbfc5cdc0, 0xbfc5cd78)                = 0x9ed5860
    realloc(0x09ed59e8, 1920)                                            = 0x09ed59e8
    getutxent(0x9ed59e8, 1920, 0, 0xbfc5cdc0, 0xbfc5cd78)                = 0x9ed5860
    getutxent(0x9ed59e8, 1920, 0, 0xbfc5cdc0, 0xbfc5cd78)                = 0x9ed5860
    realloc(0x09ed59e8, 3072)                                            = 0x09ed59e8
    getutxent(0x9ed59e8, 3072, 0, 0xbfc5cdc0, 0xbfc5cd78)                = 0x9ed5860
    getutxent(0x9ed59e8, 3072, 0, 0xbfc5cdc0, 0xbfc5cd78)                = 0x9ed5860
    getutxent(0x9ed59e8, 3072, 0, 0xbfc5cdc0, 0xbfc5cd78)

    getutxent とそのライブラリ関数ファミリへの一連の呼び出しがあることがわかります。 ltrace は、関数がプログラムで呼び出された順序で結果を提供することにも注意してください。

    これで、「who」コマンドが getutxent とその一連の関数を呼び出してログインしているユーザーを取得することで機能することがわかりました。

    4. strace コマンド

    strace コマンドは、プログラムによって行われたシステム コールをトレースするために使用されます。プログラムがライブラリ関数を使用しておらず、システム コールのみを使用している場合、単純な ltrace を使用すると、プログラムの実行を追跡できません。

    # strace /usr/bin/who
    [b76e7424] brk(0x887d000)               = 0x887d000
    [b76e7424] access("/var/run/utmpx", F_OK) = -1 ENOENT (No such file or directory)
    [b76e7424] open("/var/run/utmp", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
    .
    .
    .
    [b76e7424] fcntl64(3, F_SETLKW, {type=F_RDLCK, whence=SEEK_SET, start=0, len=0}) = 0
    [b76e7424] read(3, "\10\325"..., 384) = 384
    [b76e7424] fcntl64(3, F_SETLKW, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0

    malloc 関数が呼び出されるたびに、brk() システム コールが呼び出されることがわかります。 getutxent ライブラリ関数は実際に「open」システム コールを呼び出して「/var/run/utmp」を開き、読み取りロックを設定して内容を読み取り、ロックを解除します。

    これで、who コマンドが utmp ファイルを読み取って出力を表示することを確認しました。

    「strace」と「ltrace」の両方に、使用できる優れたオプションのセットがあります。

    • -p pid – 指定された pid にアタッチします。プログラムが既に実行されていて、その動作を知りたい場合に役立ちます。
    • -n 2 – ネストされた各呼び出しを 2 つのスペースでインデントします。
    • -f – フォークをたどる

    続きを読む:Linux でプログラムの実行をデバッグするための 7 つの Strace の例

    III.ライブラリ呼び出しの傍受

    5. LD_PRELOAD &LD_LIBRARY_PATH

    LD_PRELOAD を使用すると、プログラムの特定の実行にライブラリを追加できます。このライブラリの関数は、実際のライブラリ関数を上書きします。

    注:「suid」ビットが設定されたプログラムではこれを使用できません。

    次のプログラムを見てみましょう。

    #include <stdio.h>
    int main() {
      char str1[]="TGS";
      char str2[]="tgs";
      if(strcmp(str1,str2)) {
        printf("String are not matched\n");
      }
      else {
        printf("Strings are matched\n");
      }
    }

    プログラムをコンパイルして実行します。

    # cc -o my_prg my_prg.c
    # ./my_prg

    「文字列が一致しません」と表示されます。

    次に独自のライブラリを作成し、ライブラリ関数をインターセプトする方法を見ていきます。

    #include <stdio.h>
    int strcmp(const char *s1, const char *s2) {
      // Always return 0.
      return 0;
    }

    コンパイルして、LD_LIBRARY_PATH 変数を現在のディレクトリに設定します。

    # cc -o mylibrary.so -shared library.c -ldl
    # LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH

    これで「library.so」という名前のファイルが作成されます。
    LD_PRELOAD 変数をこのファイルに設定し、文字列比較プログラムを実行します。

    # LD_PRELOAD=mylibrary.so ./my_prg

    これで、strcmp 関数のバージョンを使用するため、「文字列が一致しました」と出力されます。

    注:ライブラリ関数をインターセプトする場合、独自のライブラリ関数は元のライブラリ関数と同じプロトタイプを持つ必要があります。

    プログラムのリバース エンジニアリングに必要な非常に基本的なことを説明しました。

    リバース エンジニアリングの次のステップに進みたい人は、ELF ファイル形式とアセンブリ言語プログラムを理解することが大いに役立ちます。


    Linux
    1. Linuxmvコマンド

    2. Linuxduコマンド

    3. Linuxipコマンド

    1. Linuxでファイルをすばやく検索するための5つのコマンドラインツール

    2. Linuxcdコマンド

    3. バイナリまたは非ASCIIファイルで文字列を検索するLinuxコマンド

    1. Linuxコマンドラインで試す価値のある5つのRustツール

    2. 4Linuxコマンドライン用のマークダウンツール

    3. Linux で strace および ltrace コマンドを使用する方法