Merge pull request #403 from GraxCode/bytecode

Various bytecode disassembler fixes / additions.
This commit is contained in:
Konloch 2022-03-19 15:25:34 -07:00 committed by GitHub
commit b5664b2949
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 332 additions and 326 deletions

View file

@ -1,37 +1,19 @@
package the.bytecode.club.bytecodeviewer.decompilers.bytecode; package the.bytecode.club.bytecodeviewer.decompilers.bytecode;
import eu.bibl.banalysis.asm.desc.OpcodeInfo; import eu.bibl.banalysis.asm.desc.OpcodeInfo;
import org.apache.commons.text.StringEscapeUtils;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.*;
import java.util.Collections; import java.util.stream.Collectors;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.text.StringEscapeUtils;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.LineNumberNode;
import org.objectweb.asm.tree.LookupSwitchInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
import org.objectweb.asm.tree.TableSwitchInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -54,8 +36,9 @@ import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/** /**
* @author Konloch * @author Konloch
* @author Bibl * @author Bibl
* @author GraxCode
*/ */
public class InstructionPrinter { public class InstructionPrinter implements Opcodes {
/** /**
* The MethodNode to print * The MethodNode to print
@ -75,16 +58,14 @@ public class InstructionPrinter {
this.args = args; this.args = args;
mNode = m; mNode = m;
labels = new HashMap<>(); labels = new HashMap<>();
precalculateLabelIndexes(m);
// matchedInsns = new ArrayList<AbstractInsnNode>(); // ingnored because // matchedInsns = new ArrayList<AbstractInsnNode>(); // ingnored because
// match = false // match = false
match = false; match = false;
} }
public InstructionPrinter(MethodNode m, InstructionPattern pattern, public InstructionPrinter(MethodNode m, InstructionPattern pattern, TypeAndName[] args) {
TypeAndName[] args) { this(m, args);
this.args = args;
mNode = m;
labels = new HashMap<>();
InstructionSearcher searcher = new InstructionSearcher(m.instructions, pattern); InstructionSearcher searcher = new InstructionSearcher(m.instructions, pattern);
match = searcher.search(); match = searcher.search();
if (match) { if (match) {
@ -94,6 +75,15 @@ public class InstructionPrinter {
} }
} }
private void precalculateLabelIndexes(MethodNode m) {
int lIdx = 0;
for (AbstractInsnNode ain : m.instructions) {
if (ain.getType() == AbstractInsnNode.LABEL) {
labels.put((LabelNode) ain, lIdx++);
}
}
}
/** /**
* Creates the print * Creates the print
* *
@ -105,21 +95,16 @@ public class InstructionPrinter {
for (AbstractInsnNode ain : mNode.instructions) { for (AbstractInsnNode ain : mNode.instructions) {
String line = printInstruction(ain); String line = printInstruction(ain);
if (!line.isEmpty()) { if (!line.isEmpty()) {
if (match) if (match) if (matchedInsns.contains(ain)) line = " -> " + line;
if (matchedInsns.contains(ain))
line = " -> " + line;
info.add(line); info.add(line);
} }
} }
if (firstLabel if (firstLabel && BytecodeViewer.viewer.appendBracketsToLabels.isSelected()) info.add("}");
&& BytecodeViewer.viewer.appendBracketsToLabels.isSelected())
info.add("}");
return info; return info;
} }
public String printInstruction(AbstractInsnNode ain) public String printInstruction(AbstractInsnNode ain) {
{
String line = ""; String line = "";
if (ain instanceof VarInsnNode) { if (ain instanceof VarInsnNode) {
line = printVarInsnNode((VarInsnNode) ain); line = printVarInsnNode((VarInsnNode) ain);
@ -138,16 +123,22 @@ public class InstructionPrinter {
} else if (ain instanceof LineNumberNode) { } else if (ain instanceof LineNumberNode) {
line = printLineNumberNode((LineNumberNode) ain); line = printLineNumberNode((LineNumberNode) ain);
} else if (ain instanceof LabelNode) { } else if (ain instanceof LabelNode) {
if (firstLabel if (firstLabel && BytecodeViewer.viewer.appendBracketsToLabels.isSelected()) info.add("}");
&& BytecodeViewer.viewer.appendBracketsToLabels
.isSelected())
info.add("}");
line = printLabelnode((LabelNode) ain); LabelNode label = (LabelNode) ain;
if (mNode.tryCatchBlocks != null) {
List<TryCatchBlockNode> tcbs = mNode.tryCatchBlocks;
String starting = tcbs.stream().filter(tcb -> tcb.start == label).map(tcb -> "start TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
String ending = tcbs.stream().filter(tcb -> tcb.end == label).map(tcb -> "end TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
String handlers = tcbs.stream().filter(tcb -> tcb.handler == label).map(tcb -> "handler TCB" + tcbs.indexOf(tcb)).collect(Collectors.joining(", "));
if (!ending.isEmpty()) info.add("// " + ending);
if (!starting.isEmpty()) info.add("// " + starting);
if (!handlers.isEmpty()) info.add("// " + starting);
}
line = printLabelNode((LabelNode) ain);
if (BytecodeViewer.viewer.appendBracketsToLabels.isSelected()) { if (BytecodeViewer.viewer.appendBracketsToLabels.isSelected()) {
if (!firstLabel) if (!firstLabel) firstLabel = true;
firstLabel = true;
line += " {"; line += " {";
} }
} else if (ain instanceof TypeInsnNode) { } else if (ain instanceof TypeInsnNode) {
@ -165,8 +156,7 @@ public class InstructionPrinter {
} else if (ain instanceof MultiANewArrayInsnNode) { } else if (ain instanceof MultiANewArrayInsnNode) {
line = printMultiANewArrayInsNode((MultiANewArrayInsnNode) ain); line = printMultiANewArrayInsNode((MultiANewArrayInsnNode) ain);
} else { } else {
line += "UNADDED OPCODE: " + nameOpcode(ain.getOpcode()) + " " line += "UNADDED OPCODE: " + nameOpcode(ain.getOpcode()) + " " + ain;
+ ain;
} }
return line; return line;
@ -175,13 +165,13 @@ public class InstructionPrinter {
protected String printVarInsnNode(VarInsnNode vin) { protected String printVarInsnNode(VarInsnNode vin) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(nameOpcode(vin.getOpcode())); sb.append(nameOpcode(vin.getOpcode()));
sb.append(" ");
sb.append(vin.var); sb.append(vin.var);
if (BytecodeViewer.viewer.debugHelpers.isSelected()) { if (BytecodeViewer.viewer.debugHelpers.isSelected()) {
if (vin.var == 0 && !Modifier.isStatic(mNode.access)) { if (vin.var == 0 && !Modifier.isStatic(mNode.access)) {
sb.append(" // reference to self"); sb.append(" // reference to self");
} else { } else {
final int refIndex = vin.var final int refIndex = vin.var - (Modifier.isStatic(mNode.access) ? 0 : 1);
- (Modifier.isStatic(mNode.access) ? 0 : 1);
if (refIndex >= 0 && refIndex < args.length - 1) { if (refIndex >= 0 && refIndex < args.length - 1) {
sb.append(" // reference to ").append(args[refIndex].name); sb.append(" // reference to ").append(args[refIndex].name);
} }
@ -197,10 +187,8 @@ public class InstructionPrinter {
protected String printFieldInsnNode(FieldInsnNode fin) { protected String printFieldInsnNode(FieldInsnNode fin) {
String desc = Type.getType(fin.desc).getClassName(); String desc = Type.getType(fin.desc).getClassName();
if (desc.equals("null")) if (desc.equals("null")) desc = fin.desc;
desc = fin.desc; return nameOpcode(fin.getOpcode()) + " " + fin.owner + "." + fin.name + ":" + desc;
return nameOpcode(fin.getOpcode()) + " " + fin.owner + "." + fin.name
+ ":" + desc;
} }
protected String printMethodInsnNode(MethodInsnNode min) { protected String printMethodInsnNode(MethodInsnNode min) {
@ -209,16 +197,14 @@ public class InstructionPrinter {
String desc = min.desc; String desc = min.desc;
try { try {
if (Type.getType(min.desc) != null) if (Type.getType(min.desc) != null) desc = Type.getType(min.desc).getClassName();
desc = Type.getType(min.desc).getClassName();
} catch (java.lang.AssertionError e) { } catch (java.lang.AssertionError e) {
//e.printStackTrace(); //e.printStackTrace();
} catch (java.lang.Exception e) { } catch (java.lang.Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
if (desc == null || desc.equals("null")) if (desc == null || desc.equals("null")) desc = min.desc;
desc = min.desc;
sb.append(desc); sb.append(desc);
@ -227,13 +213,9 @@ public class InstructionPrinter {
protected String printLdcInsnNode(LdcInsnNode ldc) { protected String printLdcInsnNode(LdcInsnNode ldc) {
if (ldc.cst instanceof String) if (ldc.cst instanceof String)
return nameOpcode(ldc.getOpcode()) + " \"" return nameOpcode(ldc.getOpcode()) + " \"" + StringEscapeUtils.escapeJava(ldc.cst.toString()) + "\" (" + ldc.cst.getClass().getCanonicalName() + ")";
+ StringEscapeUtils.escapeJava(ldc.cst.toString()) + "\" ("
+ ldc.cst.getClass().getCanonicalName() + ")";
return nameOpcode(ldc.getOpcode()) + " " return nameOpcode(ldc.getOpcode()) + " " + StringEscapeUtils.escapeJava(ldc.cst.toString()) + " (" + ldc.cst.getClass().getCanonicalName() + ")";
+ StringEscapeUtils.escapeJava(ldc.cst.toString()) + " ("
+ ldc.cst.getClass().getCanonicalName() + ")";
} }
protected String printInsnNode(InsnNode in) { protected String printInsnNode(InsnNode in) {
@ -241,15 +223,14 @@ public class InstructionPrinter {
} }
protected String printJumpInsnNode(JumpInsnNode jin) { protected String printJumpInsnNode(JumpInsnNode jin) {
return nameOpcode(jin.getOpcode()) + " L" return nameOpcode(jin.getOpcode()) + " L" + resolveLabel(jin.label);
+ resolveLabel(jin.label);
} }
protected String printLineNumberNode(LineNumberNode lnn) { protected String printLineNumberNode(LineNumberNode lnn) {
return "// line " + lnn.line; return "// line " + lnn.line;
} }
protected String printLabelnode(LabelNode label) { protected String printLabelNode(LabelNode label) {
return "L" + resolveLabel(label); return "L" + resolveLabel(label);
} }
@ -257,11 +238,9 @@ public class InstructionPrinter {
try { try {
String desc = tin.desc; String desc = tin.desc;
try { try {
if (Type.getType(tin.desc) != null) if (Type.getType(tin.desc) != null) desc = Type.getType(tin.desc).getClassName();
desc = Type.getType(tin.desc).getClassName();
if (desc.equals("null")) if (desc.equals("null")) desc = tin.desc;
desc = tin.desc;
} catch (java.lang.ArrayIndexOutOfBoundsException ignored) { } catch (java.lang.ArrayIndexOutOfBoundsException ignored) {
} }
@ -280,8 +259,7 @@ public class InstructionPrinter {
List<?> labels = tin.labels; List<?> labels = tin.labels;
int count = 0; int count = 0;
for (int i = tin.min; i < tin.max + 1; i++) { for (int i = tin.min; i < tin.max + 1; i++) {
line.append(" val: ").append(i).append(" -> ").append("L") line.append(" val: ").append(i).append(" -> ").append("L").append(resolveLabel((LabelNode) labels.get(count++))).append("\n");
.append(resolveLabel((LabelNode) labels.get(count++))).append("\n");
} }
line.append(" default" + " -> L").append(resolveLabel(tin.dflt)); line.append(" default" + " -> L").append(resolveLabel(tin.dflt));
return line.toString(); return line.toString();
@ -295,8 +273,7 @@ public class InstructionPrinter {
for (int i = 0; i < keys.size(); i++) { for (int i = 0; i < keys.size(); i++) {
int key = (Integer) keys.get(i); int key = (Integer) keys.get(i);
LabelNode label = (LabelNode) labels.get(i); LabelNode label = (LabelNode) labels.get(i);
line.append(" val: ").append(key).append(" -> ").append("L") line.append(" val: ").append(key).append(" -> ").append("L").append(resolveLabel(label)).append("\n");
.append(resolveLabel(label)).append("\n");
} }
line.append(" default" + " -> L").append(resolveLabel(lin.dflt)); line.append(" default" + " -> L").append(resolveLabel(lin.dflt));
@ -305,9 +282,7 @@ public class InstructionPrinter {
protected String printInvokeDynamicInsNode(InvokeDynamicInsnNode idin) { protected String printInvokeDynamicInsNode(InvokeDynamicInsnNode idin) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(nameOpcode(idin.getOpcode())).append(" ").append(idin.bsm.getOwner()).append('.') sb.append(nameOpcode(idin.getOpcode())).append(" ").append(idin.bsm.getOwner()).append('.').append(idin.bsm.getName()).append(idin.bsm.getDesc()).append(" : ").append(idin.name).append(idin.desc);
.append(idin.bsm.getName()).append(idin.bsm.getDesc()).append(" : ")
.append(idin.name).append(idin.desc);
if (idin.bsmArgs != null) { if (idin.bsmArgs != null) {
for (Object o : idin.bsmArgs) { for (Object o : idin.bsmArgs) {
@ -325,45 +300,73 @@ public class InstructionPrinter {
private String printFrameNode(FrameNode frame) { private String printFrameNode(FrameNode frame) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(nameOpcode(frame.getOpcode())).append(" "); sb.append(nameFrameType(frame.type)).append(" ");
sb.append("(Locals"); sb.append("(Locals");
if (frame.local != null if (frame.local != null && !frame.local.isEmpty()) {
&& frame.local.size() > 0) { sb.append("[").append(frame.local.size()).append("]: ");
sb.append("[").append(frame.local.size()).append("]:"); sb.append(frame.local.stream().map(this::printFrameObject).collect(Collectors.joining(", ")));
sb.append(" ");
sb.append(frame.local.get(0).toString());
if (frame.local.size() > 1) {
for (int i = 1; i < frame.local.size(); i++) {
sb.append(", ");
sb.append(frame.local.get(i).toString());
}
}
} else { } else {
sb.append("[0]: null"); sb.append("[0]");
} }
sb.append(") "); sb.append(") ");
sb.append("(Stack"); sb.append("(Stack");
if (frame.stack != null if (frame.stack != null && !frame.stack.isEmpty()) {
&& frame.stack.size() > 0) { sb.append("[").append(frame.stack.size()).append("]: ");
sb.append("[").append(frame.stack.size()).append("]:"); sb.append(frame.stack.stream().map(this::printFrameObject).collect(Collectors.joining(", ")));
sb.append(" ");
sb.append(frame.stack.get(0).toString());
if (frame.stack.size() > 1) {
for (int i = 1; i < frame.stack.size(); i++) {
sb.append(", ");
sb.append(frame.stack.get(i).toString());
}
}
} else { } else {
sb.append("[0]: null"); sb.append("[0]");
} }
sb.append(")"); sb.append(") ");
return sb.toString(); return sb.toString();
} }
private String printFrameObject(Object obj) {
if (obj instanceof LabelNode) return "label [L" + resolveLabel((LabelNode) obj) + "]";
if (obj instanceof Integer) {
switch ((int) obj) {
case 0:
return "top";
case 1:
return "int";
case 2:
return "float";
case 3:
return "double";
case 4:
return "long";
case 5:
return "null";
case 6:
return "uninitialized this";
default:
return "unknown";
}
}
if (obj instanceof String) return "reference [" + obj + "]";
return "unknown [" + obj.toString() + "]";
}
private String nameFrameType(int type) {
switch (type) {
case F_NEW:
return " f_new";
case F_FULL:
return " f_full";
case F_APPEND:
return " f_append";
case F_CHOP:
return " f_chop";
case F_SAME:
return " f_same";
case F_SAME1:
return " f_same1";
default:
return " f_unknown" + type;
}
}
protected String nameOpcode(int opcode) { protected String nameOpcode(int opcode) {
return " " + OpcodeInfo.OPCODES.get(opcode).toLowerCase(); return " " + OpcodeInfo.OPCODES.get(opcode).toLowerCase();
} }
@ -372,15 +375,15 @@ public class InstructionPrinter {
if (labels.containsKey(label)) { if (labels.containsKey(label)) {
return labels.get(label); return labels.get(label);
} else { } else {
int newLabelIndex = labels.size() + 1; /*int newLabelIndex = labels.size() + 1;
labels.put(label, newLabelIndex); labels.put(label, newLabelIndex);
return newLabelIndex; return newLabelIndex;*/
throw new IllegalStateException("LabelNode index not found. (Label not in InsnList?)");
} }
} }
public static void saveTo(File file, InstructionPrinter printer) { public static void saveTo(File file, InstructionPrinter printer) {
try (FileWriter fw = new FileWriter(file); try (FileWriter fw = new FileWriter(file); BufferedWriter bw = new BufferedWriter(fw)) {
BufferedWriter bw = new BufferedWriter(fw)) {
for (String s : printer.createPrint()) { for (String s : printer.createPrint()) {
bw.write(s); bw.write(s);
bw.newLine(); bw.newLine();

View file

@ -57,6 +57,9 @@ public class MethodNodeDecompiler {
if (m.name.equals("<init>")) { if (m.name.equals("<init>")) {
sb.append(class_); sb.append(class_);
} else if (!m.name.equals("<clinit>")) { } else if (!m.name.equals("<clinit>")) {
Type returnType = Type.getReturnType(m.desc);
sb.append(returnType.getClassName());
sb.append(" ");
sb.append(m.name); sb.append(m.name);
} }