2

Так что я пытаюсь добавить простой System.out.println("hey"); в конце метода. Я использовал API дерева. Однако я постоянно получаю эту ошибку:Получение ошибки проверки при работе с asm java

java.lang.VerifyError: Expecting a stackmap frame at branch target 38

Это мой код:

public class MethodNodeCustom extends MethodNode { 

    public MethodNodeCustom(int paramInt, String paramString1, String paramString2, String paramString3, String[] paramArrayOfString) { 
     this(327680, paramInt, paramString1, paramString2, paramString3, paramArrayOfString); 
     return; 
    } 

    @SuppressWarnings({ "unchecked", "rawtypes" }) 
    public MethodNodeCustom(int paramInt1, int paramInt2, String paramString1, String paramString2, String paramString3, 
     String[] paramArrayOfString) { 
     super(paramInt1); 
     this.access = paramInt2; 
     this.name = paramString1; 
     this.desc = paramString2; 
     this.signature = paramString3; 
     this.exceptions = new ArrayList((paramArrayOfString == null) ? 0 : paramArrayOfString.length); 
     int i = ((paramInt2 & 0x400) != 0) ? 1 : 0; 
     if (i == 0) 
      this.localVariables = new ArrayList(5); 
     this.tryCatchBlocks = new ArrayList(); 
     if (paramArrayOfString != null) 
      this.exceptions.addAll(Arrays.asList(paramArrayOfString)); 
     this.instructions = new InsnList(); 
    } 
    @Override 
    public void visitEnd() { 
     AbstractInsnNode label = instructions.getLast(); 
     instructions.remove(instructions.getLast()); 
     instructions.remove(instructions.getLast()); 
     visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", Type.getDescriptor(PrintStream.class)); 
     visitLdcInsn("Cracked by damm ass pro skills"); 
     visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 
     visitInsn(Opcodes.RETURN); 
     instructions.add(label); 

     super.visitEnd(); 
    } 
} 

И это мой класс узел:

public class ClassNodeCustom extends ClassNode { 
    public ClassNodeCustom() { 
     super(ASMContentHandler.ASM4); 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public MethodVisitor visitMethod(int paramInt, String paramString1, String paramString2, String paramString3, String[] paramArrayOfString) { 
     MethodNode localMethodNode = new MethodNodeCustom(paramInt, paramString1, paramString2, paramString3, paramArrayOfString); 
     this.methods.add(localMethodNode); 
     return localMethodNode; 
    } 
} 

И это, как я «впрыснуть» код (я загружаю его непосредственно из банки, поэтому использует zipFile)

InputStream in = zipFile.getInputStream(entry); 
ClassReader cr = new ClassReader(in); 
ClassNodeCustom node = new ClassNodeCustom(); 
cr.accept(node, 0); 
ClassWriter cw = new ClassWriter(0); 
node.accept(cw); 

И, как я уже говорил, когда когда-либо запускаю его, я получаю ошибку проверки, есть ли способ решить ее или какой-либо более умный способ «ввести» этот код?

ответ

5

Если вы добавляете код в конце метода, вы добавляете его после его последней инструкции, которая всегда является оператором goto, switch, throw или return при компиляции кода Java. Даже при компиляции методы без явного оператора возврата, как

void foo() { } 

вы actully компиляции

void foo() { return; } 

где окончательное возвращение неявное. С вашими дополнениями, изменить метод к

void foo() { 
    return; 
    System.out.println("hey"); 
} 

Такой недостижимый код запрещенную JAVAC но вполне законным в байт-код. Однако для недостижимого кода требуется, чтобы вы добавили его с помощью stack map frame, который описывает состояние стека и локального массива переменных в этой точке. Было бы легко добавить описание пустого фрейма в этот момент, но я предполагаю, что вы хотите добавить код перед оператором return.

Чтобы реализовать это, ASM offers an AdviceAdapter, что позволяет добавлять код перед операциями возврата. Насколько мне известно, ничего не похоже на API дерева, но вы можете просто искать узел возврата в списке инструкций любого метода и добавлять код до него.

+0

Эти линии используются для удаления возврата; инструкция и последняя метка, а не читать их AbstractInsnNode label = instructions.getLast(); инструкции.изменить (инструкции.getLast()); инструкции.изменить (инструкции.getLast()); – NacOJerk

+0

Я бы попробовал это, хотя thx – NacOJerk

+0

Я нашел свою проблему thx для вас по какой-то причине в моих последних тестах мне пришлось добавить certin-код в конце метода, поэтому я прочитал последнюю инструкцию метода после его удаления сейчас например, я сделал goofed и дважды добавил код возврата. – NacOJerk