2012-01-04 14 views
1

バイトコード解析を使用して、クラスファイルのインポート済みクラスをすべて取得しています(BCEL付き)。今、私が定数プールを読み込んだとき、インポートされたすべてのクラスがCONSTANT_Class(spec参照)として記述されているわけではなく、CONSTANT_Utf8としてのみ記述されています。私の質問:インポートされたファイルを読み込むために定数プールのCONSTANT_Classエントリだけに依存することはできませんか?私は本当にすべてのエントリを見て、クラス名の場合は、推測する必要がありますか?これはすべての状況で正しいとは思われません。または、私はバイトコード全体を読まなければならないのですか? についてクラスファイルのクラスがありません定数プール

+0

あなたがリンクしている本は1999年に出版されたので、私は参考にしません。 – Viruzzo

答えて

2

いいえ、CONSTANT_Class_infoエントリだけを使用して他のクラス/インタフェースの依存関係を検出することは正しくありません。あなたが信頼する入力ファイルを解析している場合や、間違った情報を許容している場合は、コーナーケースを除いて定数プールの解析だけを行うことができます。任意の入力に関する正確な情報を得るには、クラスファイル全体を解析する必要があります。 (IはJVMS chapter 5に記載されているように、例外が発生することができるあなたはどのローディングなしで、またはクラスを連結これらのクラスまたはインタフェースを意味し、「依存性」で想定しています。これはClass.forName又は他の反射手段を介して取得したクラスが含まれていない。)

考慮する次のクラス。

public class Main { 
    public static void main(String[] args) { 
     identity(null); 
    } 
    public static Object identity(Foo x) { 
     return x; 
    } 
} 
javap -p -v Main.class

プリント:

Classfile /C:/Users/jbosboom/Documents/stackoverflow/build/classes/Main.class 
    Last modified Jul 2, 2014; size 346 bytes 
    MD5 checksum 2237cda2a15a58382b0fb98d6afacc7e 
    Compiled from "Main.java" 
public class Main 
    SourceFile: "Main.java" 
    minor version: 0 
    major version: 52 
    flags: ACC_PUBLIC, ACC_SUPER 
Constant pool: 
    #1 = Methodref   #3.#17   // java/lang/Object."<init>":()V 
    #2 = Class    #18   // Main 
    #3 = Class    #19   // java/lang/Object 
    #4 = Utf8    <init> 
    #5 = Utf8    ()V 
    #6 = Utf8    Code 
    #7 = Utf8    LineNumberTable 
    #8 = Utf8    LocalVariableTable 
    #9 = Utf8    this 
    #10 = Utf8    LMain; 
    #11 = Utf8    identity 
    #12 = Utf8    (LFoo;)Ljava/lang/Object; 
    #13 = Utf8    x 
    #14 = Utf8    LAAA; 
    #15 = Utf8    SourceFile 
    #16 = Utf8    Main.java 
    #17 = NameAndType  #4:#5   // "<init>":()V 
    #18 = Utf8    Main 
    #19 = Utf8    java/lang/Object 
    #20 = Utf8    java/lang/Thread 
    #21 = Class    #20   // java/lang/Thread 
    #21 = Utf8    (LBar;)LFakename; 
{ 
    public Main(); 
    descriptor:()V 
    flags: ACC_PUBLIC 
    Code: 
     stack=1, locals=1, args_size=1 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 
     LineNumberTable: 
     line 6: 0 
     LocalVariableTable: 
     Start Length Slot Name Signature 
      0  5  0 this LMain; 

    public static java.lang.Object identity(Foo); 
    descriptor: (LFoo;)Ljava/lang/Object; 
    flags: ACC_PUBLIC, ACC_STATIC 
    Code: 
     stack=1, locals=1, args_size=1 
     0: aload_0 
     1: areturn 
     LineNumberTable: 
     line 11: 0 
     LocalVariableTable: 
     Start Length Slot Name Signature 
      0  2  0  x LAAA; 
} 
Foo

クラスは、メソッドidentityにパラメータとして参照される、CONSTANT_Class_infoエントリとして定数プールに表示されません。 identity(エントリ#12)のメソッド記述子に表示されます。フィールド記述子は、CONSTANT_Class_infoエントリとして現れないクラスを参照することもできます。したがって、定数プールだけからすべての依存関係を見つけるには、すべてのUTF8項目を調べる必要があります。

コーナーケース:CONSTANT_String_infoエントリによって参照されるUTF8エントリが存在することがあります。重複するUTF8エントリがマージされるため、1つのUTF8エントリはメソッド記述子、文字列リテラル、またはその両方になります。あなたが定数プールを解析しているだけの場合は、このあいまいさで生きていなければなりません(おそらく、過大近似とそれを依存関係として処理する)。

あなたのコントロール下で適切に動作するJavaコンパイラによって入力が生成されたことを信頼する場合は、すべてのUTF8エントリを解析し、文字列のコーナーケースを気にして、ここでの読み上げを中止できます。手作業で作成したクラスファイル(例えば、デコンパイラを作成しており、攻撃者が逆コンパイルを防止したいなど)を攻撃者から守る必要がある場合は、クラスファイル全体を解析する必要があります。潜在的な問題のいくつかの例を次に示します。

  • エントリ#20は、Mainで使用されていないクラスの名前です。 JVMはこの参照を解決しようとすることもあれば、試みないこともあります(JVMS 5.4は遅延読み込みと熱心な読み込みの両方を許可します)。クラスが存在するため、エラーは発生しませんので、この余分な項目は無害ですが、Threadが依存関係であると考えるために定数プールを見ているツールを欺くでしょう。
  • エントリ#21は、2つの架空のクラスを参照する未使用のメソッドディスクリプタです。この記述子が使用されないので、エラーは発生しませんが、定数プールを信頼するツールは解析します。
  • エントリ#14は、架空のクラスを参照するフィールド記述子です。このエントリは実際にはLineNumberTable属性によって使用されますが、このデバッグ情報はJVMによってチェックされないため、参照は無害ですがツールを欺くかもしれません。
  • 私はこの例を持っていませんが、InnerClasses属性はCONSTANT_Class_infoエントリを参照し、他のクラスファイルとの整合性をチェックしません(非標準的なメモではありますがJVMS 4.7.6)。これらのリファレンスは、読み込みやリンクを妨げるものではありませんが、定数プールを調べるツールを混乱させます。

これは私の頭の上から出てきたものです。きれいな攻撃者は、JVMSを細かい歯のついた櫛で捉えて、使用されていると見える定数プールにエントリを追加する場所をもっと見つけることができます。攻撃者の側でも正確な情報が必要な場合は、クラスファイル全体を解析し、JVMでどのように使用するかを理解する必要があります。

0

JVMS 4.2, The Internal Form of FQ Class and Interface Namesを参照してください。

Nutshell:クラス構造がUTF8エントリを指します。

(または、代わりに参照されるすべてのクラスは、クラスと名前のエントリで表されていないことを言っている?)


FWIWは、依存関係を判断するために、この情報のみに依存を警戒するクラスをロードすることができますよう動的に表示され、まったく表示されないことがあります。

+0

はい、私は知っている、私はこれに専ら依存しない...しかし、私のusecaseのために、十分に良い。私の要点は、私が必要とするすべての参照は、utf8のエントリとして表現されていますが、クラスエントリとして表現されていないことです。だから私は推測する必要があります、utf8エントリは実際にクラス名です..(私の理解では、すべてのクラスはクラスエントリとして表されますが、このようには見えません) – wrm

関連する問題