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; 
    } 
} 

而且這是我的「注入」了代碼(我直接從jar中加載,這就是爲什麼它使用zip文件)

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

如果要在方法的末尾添加代碼,則需要在編譯Java代碼時將其添加到其最後一條指令後面,該指令總是goto,switch,throw或return語句。即使是編譯的方法時沒有明確return語句像

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(); instructions.remove(instructions.getLast()); instructions.remove(instructions.getLast()); – NacOJerk

+0

我會嘗試,雖然thx – NacOJerk

+0

我發現我的問題thx你的出於某種原因在我最後的測試中,我不得不在方法的末尾添加一個certin代碼,所以我讀了方法的最後一個指令後,它現在看來它似乎就像我做了愚蠢的事情並且添加了兩次返回碼。 – NacOJerk

相關問題