2012-01-04 20 views
1

我正在使用字節碼分析來獲取所有導入的類文件(使用BCEL)。現在,當我讀取常量池時,並非所有導入的類都被提及爲CONSTANT_Class(請參閱spec),但僅作爲CONSTANT_Utf8提及。我現在的問題:我不能僅僅依靠常量池中的CONSTANT_Class條目來讀取導入的文件嗎?我真的不得不看看每一個條目,並猜測,如果它的類名?在任何情況下,這似乎也不是正確的。或者我必須通讀整個字節碼? 問候classfiles常量池中缺少的類

+0

你正在鏈接的這本書在1999年出版,所以我不會用它作爲參考。 – Viruzzo 2012-01-04 15:36:55

回答

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條目。

的極端情況:可能存在一些UTF8條目由CONSTANT_String_info項引用。重複的UTF8條目將被合併,所以一個UTF8條目可能是一個方法描述符,一個字符串文本或兩者。如果你只是解析常量池,你必須忍受這種模糊性(可能通過過度使用並將其視爲依賴)。

如果您信任已經被你控制下的乖巧Java編譯器產生的輸入,可以分析所有UTF8項,銘記串角落情況下,停止閱讀這裏。如果您需要防禦攻擊者爲您的工具提供手工製作的類文件(例如,您正在編寫反編譯器並且攻擊者想要防止反編譯),則需要解析整個類文件。以下是一些潛在問題的例子。

  • 條目#20命名不被Main使用的類。 JVM可能會或可能不會嘗試解決此引用(JVMS 5.4允許延遲加載和預先加載)。當類存在時,無論哪種方式,都不會引發錯誤,所以這個額外的入口是無害的,但它會欺騙工具看待常量池,認爲Thread是依賴關係。
  • 條目#21是一個未使用的方法描述符,指的是兩個虛構的類。由於未使用此描述符,因此不會引發錯誤,但同樣,信任常量池的工具將解析它。
  • 條目#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

果殼:類結構指向UTF8條目。

(或者,你不是說,不是所有引用的類是由類和名稱條目表示?)


FWIW,謹防僅僅根據這些信息來確定依賴依靠作爲類載入動態並且可能根本不顯示。

+0

是的,我知道,我不能完全依靠這個......但對於我的用例來說,它已經足夠好了。我的觀點是,我需要的所有引用都表示爲utf8條目,但不是作爲類條目。所以我需要猜測,如果一個utf8-entry實際上是一個類名(根據我的理解,所有的類加載都表示爲class-entries,但似乎並不是這樣) – wrm 2012-01-05 09:11:56