From e38b4c521258c590f0c401fbddbe46870308c11a Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 1 Feb 2015 17:49:33 -0500 Subject: [PATCH] More execution work --- .../attributes/code/instructions/AAStore.java | 5 +++- .../attributes/code/instructions/AStore.java | 1 - .../code/instructions/InvokeSpecial.java | 19 +++++++++++- .../code/instructions/InvokeVirtual.java | 3 +- .../sigterm/deob/execution/ArrayInstance.java | 22 +++++++++++--- .../sigterm/deob/execution/ClassInstance.java | 8 +++++ .../sigterm/deob/execution/FieldInstance.java | 7 +++++ .../info/sigterm/deob/execution/Frame.java | 25 +++++++++++++++- .../deob/execution/ObjectInstance.java | 15 ++++++++++ .../deob/execution/ObjectInstanceBase.java | 2 ++ .../info/sigterm/deob/execution/Path.java | 29 ++++++++++++++----- .../info/sigterm/deob/execution/Stack.java | 22 ++++++++++++++ .../deob/execution/StaticFieldInstance.java | 7 +++++ .../sigterm/deob/execution/Variables.java | 7 +++++ .../info/sigterm/deob/pool/NameAndType.java | 6 ++++ 15 files changed, 161 insertions(+), 17 deletions(-) diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/AAStore.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/AAStore.java index 1ef8809557..0c294cff2f 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/AAStore.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/AAStore.java @@ -20,10 +20,13 @@ public class AAStore extends Instruction { Stack stack = frame.getStack(); - ObjectInstance value = (ObjectInstance) stack.pop(); // Strings are objects too, so this cast fails + Object value = stack.pop(); int index = (int) stack.pop(); ArrayInstance array = (ArrayInstance) stack.pop(); + if (array == null) + return; + array.put(value, index); } } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/AStore.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/AStore.java index 6398a2f66b..cf7b1ceddc 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/AStore.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/AStore.java @@ -25,7 +25,6 @@ public class AStore extends Instruction public void execute(Frame frame) { Object obj = frame.getStack().pop(); - assert obj != null; frame.getVariables().set(index, obj); } } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeSpecial.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeSpecial.java index e03e4e012f..1baaf3e494 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeSpecial.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeSpecial.java @@ -9,6 +9,7 @@ import info.sigterm.deob.execution.ClassInstance; import info.sigterm.deob.execution.Frame; import info.sigterm.deob.execution.ObjectInstance; import info.sigterm.deob.pool.Method; +import info.sigterm.deob.pool.PoolEntry; import java.io.DataInputStream; import java.io.IOException; @@ -36,15 +37,31 @@ public class InvokeSpecial extends Instruction int count = method.getNameAndType().getNumberOfArgs(); ObjectInstance object = (ObjectInstance) e.getStack().pop(); - ClassInstance objectType = object.getType(); Object[] args = new Object[count + 1]; args[0] = object; for (int i = 1; i < count + 1; ++i) args[i] = e.getStack().pop(); + if (object == null) + { + System.out.println("invokespecial for nonexistant function " + method.getNameAndType().getName() + " " + method.getNameAndType().getDescriptor() + " on " + method.getClassEntry().getName() + " (void: " + !method.getNameAndType().isNonVoid() + ")"); + if (method.getNameAndType().isNonVoid()) + e.getStack().push(this, null); + return; + } + + ClassInstance objectType = object.getType(); info.sigterm.deob.Method meth = objectType.getClassFile().findMethod(method.getNameAndType()); e.getPath().invoke(meth, args); } + @Override + public String getDesc(Frame frame) + { + ClassFile thisClass = this.getInstructions().getCode().getAttributes().getClassFile(); + Method method = (Method) thisClass.getPool().getEntry(index); + + return "invokespecial " + method.getNameAndType().getDescriptor() + " on " + method.getClassEntry().getName(); + } } diff --git a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeVirtual.java b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeVirtual.java index 7ae4248dc8..2a52d11cb3 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeVirtual.java +++ b/src/main/java/info/sigterm/deob/attributes/code/instructions/InvokeVirtual.java @@ -42,7 +42,7 @@ public class InvokeVirtual extends Instruction ObjectInstance object = (ObjectInstance) e.getStack().pop(); if (object == null) { - System.out.println("Invoke on a null object"); + System.out.println("invokevirtual on null object for method " + method.getNameAndType().getName() + " " + method.getNameAndType().getDescriptor() + " on " + method.getClassEntry().getName()); e.getStack().push(this, null); return; } @@ -56,7 +56,6 @@ public class InvokeVirtual extends Instruction { System.out.println("Unknown method " + method.getNameAndType().getName() + " " + method.getNameAndType().getDescriptor() + " in " + objectType.getClassFile().getName()); e.getStack().push(this, null); - //meth.getDescriptor() return; } e.getPath().invoke(meth, args); diff --git a/src/main/java/info/sigterm/deob/execution/ArrayInstance.java b/src/main/java/info/sigterm/deob/execution/ArrayInstance.java index 4e0976b318..e61c4e73a0 100644 --- a/src/main/java/info/sigterm/deob/execution/ArrayInstance.java +++ b/src/main/java/info/sigterm/deob/execution/ArrayInstance.java @@ -1,22 +1,30 @@ package info.sigterm.deob.execution; +import java.util.Arrays; + public class ArrayInstance extends ObjectInstanceBase { - private ObjectInstance[] array; + private Object[] array; public ArrayInstance(Path path, ClassInstance type, int len) { super(path, type); - this.array = new ObjectInstance[len]; + this.array = new Object[len]; } - public void put(ObjectInstance obj, int idx) + private ArrayInstance(ArrayInstance other, Path path, ClassInstance type) + { + super(path, type); + this.array = Arrays.copyOf(other.array, other.array.length); + } + + public void put(Object obj, int idx) { array[idx] = obj; } - public ObjectInstance get(int idx) + public Object get(int idx) { return array[idx]; } @@ -25,4 +33,10 @@ public class ArrayInstance extends ObjectInstanceBase { return array.length; } + + @Override + public ObjectInstanceBase dup(Path path, ClassInstance type) + { + return new ArrayInstance(this, path, type); + } } diff --git a/src/main/java/info/sigterm/deob/execution/ClassInstance.java b/src/main/java/info/sigterm/deob/execution/ClassInstance.java index 36de83c86d..dd724f080d 100644 --- a/src/main/java/info/sigterm/deob/execution/ClassInstance.java +++ b/src/main/java/info/sigterm/deob/execution/ClassInstance.java @@ -33,6 +33,14 @@ public class ClassInstance this.fields.add(fi); } } + + protected ClassInstance(Path path, ClassInstance other) + { + this.path = path; + this.clazz = other.clazz; + for (StaticFieldInstance f : other.fields) + this.fields.add(new StaticFieldInstance(other, f)); + } public Path getPath() { diff --git a/src/main/java/info/sigterm/deob/execution/FieldInstance.java b/src/main/java/info/sigterm/deob/execution/FieldInstance.java index be641674ab..2f1235ec78 100644 --- a/src/main/java/info/sigterm/deob/execution/FieldInstance.java +++ b/src/main/java/info/sigterm/deob/execution/FieldInstance.java @@ -15,6 +15,13 @@ public class FieldInstance this.value = value; } + protected FieldInstance(ObjectInstance object, FieldInstance other) + { + this.object = object; + this.field = other.field; + this.value = other.value; + } + public Field getField() { return field; diff --git a/src/main/java/info/sigterm/deob/execution/Frame.java b/src/main/java/info/sigterm/deob/execution/Frame.java index 1dee9cfca8..fcf1b99dca 100644 --- a/src/main/java/info/sigterm/deob/execution/Frame.java +++ b/src/main/java/info/sigterm/deob/execution/Frame.java @@ -24,6 +24,16 @@ public class Frame stack = new Stack(code.getMaxStack()); variables = new Variables(code.getMaxLocals()); } + + protected Frame(Path path, Frame other) + { + this.path = path; + this.method = other.method; + this.executing = other.executing; + this.pc = other.pc; + this.stack = new Stack(other.stack); + this.variables = new Variables(other.variables); + } public Path getPath() { @@ -60,7 +70,20 @@ public class Frame catch (Throwable ex) { System.err.println("Error executing instruction in " + method.getName() + " " + method.getDescriptor() + " in class " + method.getMethods().getClassFile().getName() + " at pc " + pc); - throw ex; + System.err.println("Frame stack (grows downward):"); + while (stack.getSize() > 0) + { + Instruction stacki = stack.getIns(); + Object obj = stack.pop(); + if (obj != null) + System.err.println(" " + obj + " (class " + obj.getClass().getName() + ") pushed by instruction " + stacki + " at pc " + stacki.getPc()); + else + System.err.println(" " + obj + " pushed by instruction " + stacki + " at pc " + stacki.getPc()); + } + System.err.println("end of stack"); + ex.printStackTrace(); + System.exit(-1); + //throw ex; } if (oldPc == pc) diff --git a/src/main/java/info/sigterm/deob/execution/ObjectInstance.java b/src/main/java/info/sigterm/deob/execution/ObjectInstance.java index 0963f7c560..dc3882f8e1 100644 --- a/src/main/java/info/sigterm/deob/execution/ObjectInstance.java +++ b/src/main/java/info/sigterm/deob/execution/ObjectInstance.java @@ -32,6 +32,15 @@ public class ObjectInstance extends ObjectInstanceBase } } + private ObjectInstance(ObjectInstance other, Path path, ClassInstance type) + { + super(path, type); + + /* copy fields */ + for (FieldInstance field : other.fields) + this.fields.add(new FieldInstance(this, field)); + } + public FieldInstance getField(NameAndType nat) { for (FieldInstance f : fields) @@ -39,4 +48,10 @@ public class ObjectInstance extends ObjectInstanceBase return f; return null; } + + @Override + public ObjectInstanceBase dup(Path path, ClassInstance type) + { + return new ObjectInstance(this, path, type); + } } diff --git a/src/main/java/info/sigterm/deob/execution/ObjectInstanceBase.java b/src/main/java/info/sigterm/deob/execution/ObjectInstanceBase.java index 96092011d4..5f93402ac7 100644 --- a/src/main/java/info/sigterm/deob/execution/ObjectInstanceBase.java +++ b/src/main/java/info/sigterm/deob/execution/ObjectInstanceBase.java @@ -16,4 +16,6 @@ public abstract class ObjectInstanceBase { return type; } + + public abstract ObjectInstanceBase dup(Path path, ClassInstance type); } diff --git a/src/main/java/info/sigterm/deob/execution/Path.java b/src/main/java/info/sigterm/deob/execution/Path.java index 11a13d4bff..f8ea47774d 100644 --- a/src/main/java/info/sigterm/deob/execution/Path.java +++ b/src/main/java/info/sigterm/deob/execution/Path.java @@ -5,12 +5,13 @@ import info.sigterm.deob.Method; import info.sigterm.deob.attributes.code.Instruction; import java.util.ArrayList; +import java.util.HashMap; public class Path { private Execution execution; private ArrayList classes = new ArrayList(); - private ArrayList objects = new ArrayList(); + private ArrayList objects = new ArrayList(); private java.util.Stack frames = new java.util.Stack(); // current execution frames public Path(Execution execution) @@ -20,11 +21,23 @@ public class Path private Path(Path other) { + HashMap classmap = new HashMap(); + this.execution = other.execution; - this.classes = new ArrayList(other.classes); - this.objects = new ArrayList(other.objects); - this.frames = new java.util.Stack(); - this.frames.addAll(other.frames); + + for (ClassInstance c : other.classes) + { + ClassInstance newclass = new ClassInstance(this, c); + classmap.put(c, newclass); + this.classes.add(newclass); + } + + for (ObjectInstanceBase o : other.objects) + o.dup(this, classmap.get(o.getType())); + + /* iteration order of a Stack is in reverse */ + for (Frame f : other.frames) + frames.push(new Frame(this, f)); } public Execution getExecution() @@ -58,7 +71,9 @@ public class Path public ArrayInstance createArray(ClassInstance type, int len) { - return new ArrayInstance(this, type, len); + ArrayInstance arr = new ArrayInstance(this, type, len); + objects.add(arr); + return arr; } public Frame getCurrentFrame() @@ -99,7 +114,7 @@ public class Path public void throwException(ObjectInstance exception) { - System.out.println("throw " + exception); + System.out.println("XXX throw " + exception); //XXX } } diff --git a/src/main/java/info/sigterm/deob/execution/Stack.java b/src/main/java/info/sigterm/deob/execution/Stack.java index ed7f61bb2c..cac95df88a 100644 --- a/src/main/java/info/sigterm/deob/execution/Stack.java +++ b/src/main/java/info/sigterm/deob/execution/Stack.java @@ -1,5 +1,7 @@ package info.sigterm.deob.execution; +import java.util.Arrays; + import info.sigterm.deob.attributes.code.Instruction; public class Stack @@ -13,6 +15,13 @@ public class Stack stack = new Object[sz]; ins = new Instruction[sz]; } + + protected Stack(Stack other) + { + this.size = other.size; + this.stack = Arrays.copyOf(other.stack, other.stack.length); + this.ins = Arrays.copyOf(other.ins, other.ins.length); + } public void push(Instruction i, Object obj) { @@ -24,6 +33,14 @@ public class Stack ++size; } + + public Instruction getIns() + { + if (size <= 0) + throw new RuntimeException("Stack underflow"); + + return ins[size - 1]; + } public Object pop() { @@ -32,4 +49,9 @@ public class Stack return stack[--size]; } + + public int getSize() + { + return size; + } } diff --git a/src/main/java/info/sigterm/deob/execution/StaticFieldInstance.java b/src/main/java/info/sigterm/deob/execution/StaticFieldInstance.java index 74f4ad7832..e7f3583990 100644 --- a/src/main/java/info/sigterm/deob/execution/StaticFieldInstance.java +++ b/src/main/java/info/sigterm/deob/execution/StaticFieldInstance.java @@ -16,6 +16,13 @@ public class StaticFieldInstance if (value != null) this.value = value.getValue().getObject(); } + + protected StaticFieldInstance(ClassInstance clazz, StaticFieldInstance other) + { + this.clazz = clazz; + this.field = other.field; + this.value = other.value; + } public Field getField() { diff --git a/src/main/java/info/sigterm/deob/execution/Variables.java b/src/main/java/info/sigterm/deob/execution/Variables.java index f96e479356..23e4c62081 100644 --- a/src/main/java/info/sigterm/deob/execution/Variables.java +++ b/src/main/java/info/sigterm/deob/execution/Variables.java @@ -1,5 +1,7 @@ package info.sigterm.deob.execution; +import java.util.Arrays; + public class Variables { private Object[] variables; @@ -8,6 +10,11 @@ public class Variables { variables = new Object[sz]; } + + protected Variables(Variables other) + { + this.variables = Arrays.copyOf(other.variables, other.variables.length); + } public void set(int index, Object value) { diff --git a/src/main/java/info/sigterm/deob/pool/NameAndType.java b/src/main/java/info/sigterm/deob/pool/NameAndType.java index 051ce976f9..650a6532ff 100644 --- a/src/main/java/info/sigterm/deob/pool/NameAndType.java +++ b/src/main/java/info/sigterm/deob/pool/NameAndType.java @@ -79,4 +79,10 @@ public class NameAndType extends PoolEntry return count; } + + public boolean isNonVoid() + { + java.lang.String methodRefType = this.getDescriptor(); + return !methodRefType.endsWith(")V"); + } }