Graphic Dexファイルの構造と分析ポイント

Dexファイル形式は非常にシンプルです。下の図を参照してください。



上の画像は、データ構造の観点から描いたDexファイル形式です。各データ構造は、androidのソースコードdalvik / libdexディレクトリで定義されています。上の画像には、いくつか注意点があります。

1.図で(エンコード)とマークされているすべてのデータ構造は、Leb128によってエンコードされたファイル内のデータに対応しています。詳細については、自分で確認できます。エンコードルール:

  • バイト単位で、リトルエンディアンの規則に従って配置
  • 各バイトの最上位ビットはフラグです。最上位ビットが1の場合、新しいバイトがあることを意味し、0の場合、バイトシーケンスの終わりを意味します。
  • 残りの7ビットを順番に結合し、7ビットを順番に左にシフトして整数を生成します。
2. DexCode構造体のdebugInfoOffは、プログラムのデバッグデータを指します。parametersSizeは、関数のパラメーターの数を示すDexCodeのinsSizeと同じである必要があります。parameterSizeフィールドの後には、各パラメーターの名前に対応するstringIdx値が続きます。これはパラメータの名前です。各パラメータのタイプは、DexMethodIdに対応するDexProtoId :: parametersOffで確認できます。Java関数呼び出しにもパラメータを渡すルールがあるため、2つのレコードのパラメータの順序は同じです。さらに、dalvikの各Java関数は特定の数のレジスターを使用することに注意してください。Dalvikは、Java関数が呼び出されると、パラメーターが次のN個のレジスターに配置されることを規定しています。たとえば、関数は5つのレジスター(v0-v4 )、2つのパラメーターがあり、これらの2つのパラメーターはそれぞれv3とv4に配置されます。Dexファイルに対応するsmaliファイルに対して検証できます。
もう1つの注意点は、非静的関数の場合、すべてのパラメーターの前に隠しパラメーターがあり、dexファイルのデバッグデータには保存されませんが、対応するレジスターが予約されています。自分に注意してください。
3.デバッグデータのopcode / valueまたはaddress / line部分の場合、address / lineはバイトコードとソースコードの行番号の対応を表し、opcode / valueはバイトコードアドレスと仮想レジスタの対応を表します。それらはインターリーブされ、dexファイルに格納されます。それで、それがオペコード/値であるか、アドレス/行であるかをどのように判断しますか?opcode> = 0 && opcode <0x0aの場合、opcode / valueを意味します。それ以外の場合、opcodeの値は、address / lineの値です。
デバッグデータをダンプして、位置情報とローカル情報を作成します。これらは、それぞれアドレス/ラインとオペコード/値のデータに対応しています。dexdumpツールのこの部分の出力を見てみましょう。
      positions     : 
        0x0000 line=21
        0x0004 line=22
        0x0018 line=24
        0x001c line=27
        0x0022 line=29
        0x0024 line=30
        0x0039 line=33
        0x0044 line=39
        0x0045 line=34
        0x0046 line=36
        0x0049 line=39
      locals        : 
        0x0022 - 0x0044 reg=1 info Landroid/content/pm/PackageInfo; 
        0x0024 - 0x0044 reg=4 sigs [Landroid/content/pm/Signature; 
        0x0046 - 0x004b reg=0 e Landroid/content/pm/PackageManager$NameNotFoundException; 
        0x001c - 0x004b reg=2 mgr Landroid/content/pm/PackageManager; 
        0x0004 - 0x004b reg=3 package_name Ljava/lang/String; 
        0x0000 - 0x004b reg=8 ctx Landroid/content/Context; 

次の2つのデータ部分の詳細な分析:
  • アドレス/ラインデータの場合、dexファイル内の対応するデータは、直接のアドレスおよびライン値ではなく、オフセット値のみです。このオフセットに従って、アドレスおよびラインの値を計算できます。計算には式が必要です。
 
			int adjopcode = opcode - DBG_FIRST_SPECIAL;
			address += adjopcode / DBG_LINE_RANGE;
			line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
さらに、オペコードがDBG_ADVANCE_LINEの場合、lineの値に現在の値(Leb128エンコード)を現在の値で追加する必要があります。
  • オペコード/値は、オペコードの種類によって、値に記録される内容が異なり、オペコードの値の範囲は以下のとおりです。
    /* debug info opcodes and constants */
    enum {
        DBG_END_SEQUENCE         = 0x00,	/* Terminates a debug info sequence for a method. */
        DBG_ADVANCE_PC           = 0x01,	/* Advances the program counter/address register without emitting a positions entry. */
        DBG_ADVANCE_LINE         = 0x02,	/* Advances the line register without emitting a positions entry. */
        DBG_START_LOCAL          = 0x03,	/* Introduces a local variable at the current address. */
        DBG_START_LOCAL_EXTENDED = 0x04,	/* Introduces a local variable at the current address with a type signature specified. */
        DBG_END_LOCAL            = 0x05,	/* Marks a currently-live local variable as out of scope at the current address. */
        DBG_RESTART_LOCAL        = 0x06,	/* Re-introduces a local variable at the current address. The name and type are the same as the last local that was live in the specified register. */
        DBG_SET_PROLOGUE_END     = 0x07,
        DBG_SET_EPILOGUE_BEGIN   = 0x08,
        DBG_SET_FILE             = 0x09,
        DBG_FIRST_SPECIAL        = 0x0a,
        DBG_LINE_BASE            = -4,
        DBG_LINE_RANGE           = 15,
    };

特定の値の意味は次のとおりです。

    • 0x00(DBG_END_SEQUENCE)、デバッグ情報の終わりを示します
    • 0x01(DBG_ADVANCE_PC)、データは正の整数、つまりアドレス+ =データ。
    • 0x02(DBG_ADVANCE_LINE)、データは正の整数で、行+ =データを示します。
    • 0x03(DBG_START_LOCAL)、0x04(DBG_START_LOCAL_EXTENDED)、新しいレジスター情報を開始することを示します。
    • 0x05(DBG_END_LOCAL)、登録メッセージの終わりを示します。
    • 0x06(DBG_RESTART_LOCAL)、これはレジスター情報を再始動することを意味します。
    • その他の値(0x07〜0x0a)は無視されます。データが空です。

dexファイルのデータのこの部分の特定の形式は次のとおりです。


上の図のregは、仮想レジスタ番号を示しています。アドレス/ラインデータとオペコード/値データはインターリーブされています。図では、オペコード/値データが故意にアドレス/ラインデータを除外していることを示すために、プログラムを作成するとき、どのデータが条件に基づいているかを判断する必要があります。

上記のデバッグ情報のアドレスと行の値、各関数のデバッグ情報は、すべて値0から始まり、オペコードに従って毎回重ね合わされます。

上の図は、各オペコードの後ろに何が格納されているかを非常に明確に示しているため、ここではこれ以上説明しません。次のように言ってください。

  • DBG_START_LOCAL、DBG_START_LOCAL_EXTENDED:これらの2つのオペコードは、新しい登録メッセージの開始を示し、古い登録メッセージの終了を意味します。opcodeの後続のデータは、regインデックス、ローカル変数の名前に対応する文字列インデックス、ローカル変数のタイプに対応する型インデックス、およびローカル変数のシグネチャに対応する文字列インデックスです(opcode == DBG_START_LOCAL_EXTENDEDの場合のみ)。regのインデックスは、現在処理されているレジスタを示します。これは、このregに対応するローカル変数の範囲が終了し、regに対応する新しい変数範囲が開始したことを意味します。つまり、現在のアドレス値は、regの前のローカル変数のendAddressと新しい変数のstartAddressです。
  • DBG_END_LOCAL、後続のデータはregのインデックスであり、対応するreg変数の範囲が終了することを示します。つまり、現在のアドレス値はregに対応する変数のendAddressです。
  • DBG_RESTART_LOCAL後続のデータはregのインデックスです。つまり、regに対応する変数の範囲がリセットされます。つまり、現在のアドレス値はregに対応する変数のstartAddressです。

とりあえず、Dexファイル形式の紹介はここで行いますが、特定の関数の内部コードに関連する命令のデコードと注釈については最初に紹介せず、後で説明します。実際、私が描いた絵は非常に詳細だと個人的には思っていますが、上記のコンテンツを見ただけではまだ比較的抽象的です。Androidシステムのソースコードに含まれているdexdumpのソースコードを非常に簡単に確認することをお勧めします。

私はダンプDexファイル情報の小さなプログラムを書く練習をしました、純粋に個人的な練習、コメントなし、デザインなし、レビューなし、エラー処理なし、単純な自己テストのみ、妥協のないエンジニアリングバージョン、参照のみ、アドレス:https:// github.com/beyond702/DexFileParser.git


私が良いと思うDexファイル形式に関連する2つのリンクを次に示します。

1.  dexdumpを通じてDEXファイル形式を学ぶ

2.  Androidランタイムから始めて、シェルアーティファクトをビルドします

元の記事を60件公開 44のよう 訪問数340,000以上

おすすめ

転載: blog.csdn.net/beyond702/article/details/52460721