отсутствующие классы в пуле классов - PullRequest
1 голос
/ 04 января 2012

Я использую анализ байт-кода, чтобы получить все импортированные классы файла классов (с BCEL). Теперь, когда я читаю пул констант, не все импортированные классы упоминаются как CONSTANT_Class (см. spec ), но только как CONSTANT_Utf8. Мой вопрос сейчас: не могу ли я полагаться исключительно на CONSTANT_Class-записи в постоянном пуле для чтения импортированных файлов? мне действительно нужно смотреть на каждую запись и угадывать, если это имя класса? Это также не кажется правильным в любой ситуации. Или я должен прочитать весь байт-код? С уважением

Ответы [ 2 ]

2 голосов
/ 03 июля 2014

Нет, неправильно использовать только записи CONSTANT_Class_info для обнаружения зависимостей от других классов / интерфейсов.Если вы анализируете входные файлы, которым доверяете или можете допустить неверную информацию, вы можете избежать анализа только пула констант, за исключением одного углового случая.Чтобы получить точную информацию о произвольном вводе, вам нужно проанализировать весь файл класса.(Я предполагаю, что под «зависимостями» вы подразумеваете те классы или интерфейсы, без которых загрузка или связывание класса может привести к исключениям, как описано в главе 5 JVMS . Это не включает классы, полученные с помощью 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 голосов
/ 04 января 2012

См. JVMS 4.2, Внутренняя форма класса FQ и имен интерфейсов .

Nutshell: структуры классов указывают на записи UTF8.

(Или вы вместо этого говорите, что не все ссылочные классы представлены записью класса и имени?)


FWIW, будьте осторожны, полагаясь исключительно на эту информацию для определения зависимостей, поскольку классы могут загружаться динамически и могут вообще не отображаться.

...