More execution work
This commit is contained in:
@@ -20,10 +20,13 @@ public class AAStore extends Instruction
|
|||||||
{
|
{
|
||||||
Stack stack = frame.getStack();
|
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();
|
int index = (int) stack.pop();
|
||||||
ArrayInstance array = (ArrayInstance) stack.pop();
|
ArrayInstance array = (ArrayInstance) stack.pop();
|
||||||
|
|
||||||
|
if (array == null)
|
||||||
|
return;
|
||||||
|
|
||||||
array.put(value, index);
|
array.put(value, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ public class AStore extends Instruction
|
|||||||
public void execute(Frame frame)
|
public void execute(Frame frame)
|
||||||
{
|
{
|
||||||
Object obj = frame.getStack().pop();
|
Object obj = frame.getStack().pop();
|
||||||
assert obj != null;
|
|
||||||
frame.getVariables().set(index, obj);
|
frame.getVariables().set(index, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import info.sigterm.deob.execution.ClassInstance;
|
|||||||
import info.sigterm.deob.execution.Frame;
|
import info.sigterm.deob.execution.Frame;
|
||||||
import info.sigterm.deob.execution.ObjectInstance;
|
import info.sigterm.deob.execution.ObjectInstance;
|
||||||
import info.sigterm.deob.pool.Method;
|
import info.sigterm.deob.pool.Method;
|
||||||
|
import info.sigterm.deob.pool.PoolEntry;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -36,15 +37,31 @@ public class InvokeSpecial extends Instruction
|
|||||||
int count = method.getNameAndType().getNumberOfArgs();
|
int count = method.getNameAndType().getNumberOfArgs();
|
||||||
|
|
||||||
ObjectInstance object = (ObjectInstance) e.getStack().pop();
|
ObjectInstance object = (ObjectInstance) e.getStack().pop();
|
||||||
ClassInstance objectType = object.getType();
|
|
||||||
|
|
||||||
Object[] args = new Object[count + 1];
|
Object[] args = new Object[count + 1];
|
||||||
args[0] = object;
|
args[0] = object;
|
||||||
for (int i = 1; i < count + 1; ++i)
|
for (int i = 1; i < count + 1; ++i)
|
||||||
args[i] = e.getStack().pop();
|
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());
|
info.sigterm.deob.Method meth = objectType.getClassFile().findMethod(method.getNameAndType());
|
||||||
e.getPath().invoke(meth, args);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class InvokeVirtual extends Instruction
|
|||||||
ObjectInstance object = (ObjectInstance) e.getStack().pop();
|
ObjectInstance object = (ObjectInstance) e.getStack().pop();
|
||||||
if (object == null)
|
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);
|
e.getStack().push(this, null);
|
||||||
return;
|
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());
|
System.out.println("Unknown method " + method.getNameAndType().getName() + " " + method.getNameAndType().getDescriptor() + " in " + objectType.getClassFile().getName());
|
||||||
e.getStack().push(this, null);
|
e.getStack().push(this, null);
|
||||||
//meth.getDescriptor()
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e.getPath().invoke(meth, args);
|
e.getPath().invoke(meth, args);
|
||||||
|
|||||||
@@ -1,22 +1,30 @@
|
|||||||
package info.sigterm.deob.execution;
|
package info.sigterm.deob.execution;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
public class ArrayInstance extends ObjectInstanceBase
|
public class ArrayInstance extends ObjectInstanceBase
|
||||||
{
|
{
|
||||||
private ObjectInstance[] array;
|
private Object[] array;
|
||||||
|
|
||||||
public ArrayInstance(Path path, ClassInstance type, int len)
|
public ArrayInstance(Path path, ClassInstance type, int len)
|
||||||
{
|
{
|
||||||
super(path, type);
|
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;
|
array[idx] = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectInstance get(int idx)
|
public Object get(int idx)
|
||||||
{
|
{
|
||||||
return array[idx];
|
return array[idx];
|
||||||
}
|
}
|
||||||
@@ -25,4 +33,10 @@ public class ArrayInstance extends ObjectInstanceBase
|
|||||||
{
|
{
|
||||||
return array.length;
|
return array.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectInstanceBase dup(Path path, ClassInstance type)
|
||||||
|
{
|
||||||
|
return new ArrayInstance(this, path, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,14 @@ public class ClassInstance
|
|||||||
this.fields.add(fi);
|
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()
|
public Path getPath()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ public class FieldInstance
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected FieldInstance(ObjectInstance object, FieldInstance other)
|
||||||
|
{
|
||||||
|
this.object = object;
|
||||||
|
this.field = other.field;
|
||||||
|
this.value = other.value;
|
||||||
|
}
|
||||||
|
|
||||||
public Field getField()
|
public Field getField()
|
||||||
{
|
{
|
||||||
return field;
|
return field;
|
||||||
|
|||||||
@@ -24,6 +24,16 @@ public class Frame
|
|||||||
stack = new Stack(code.getMaxStack());
|
stack = new Stack(code.getMaxStack());
|
||||||
variables = new Variables(code.getMaxLocals());
|
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()
|
public Path getPath()
|
||||||
{
|
{
|
||||||
@@ -60,7 +70,20 @@ public class Frame
|
|||||||
catch (Throwable ex)
|
catch (Throwable ex)
|
||||||
{
|
{
|
||||||
System.err.println("Error executing instruction in " + method.getName() + " " + method.getDescriptor() + " in class " + method.getMethods().getClassFile().getName() + " at pc " + pc);
|
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)
|
if (oldPc == pc)
|
||||||
|
|||||||
@@ -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)
|
public FieldInstance getField(NameAndType nat)
|
||||||
{
|
{
|
||||||
for (FieldInstance f : fields)
|
for (FieldInstance f : fields)
|
||||||
@@ -39,4 +48,10 @@ public class ObjectInstance extends ObjectInstanceBase
|
|||||||
return f;
|
return f;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectInstanceBase dup(Path path, ClassInstance type)
|
||||||
|
{
|
||||||
|
return new ObjectInstance(this, path, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,6 @@ public abstract class ObjectInstanceBase
|
|||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract ObjectInstanceBase dup(Path path, ClassInstance type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ import info.sigterm.deob.Method;
|
|||||||
import info.sigterm.deob.attributes.code.Instruction;
|
import info.sigterm.deob.attributes.code.Instruction;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class Path
|
public class Path
|
||||||
{
|
{
|
||||||
private Execution execution;
|
private Execution execution;
|
||||||
private ArrayList<ClassInstance> classes = new ArrayList<ClassInstance>();
|
private ArrayList<ClassInstance> classes = new ArrayList<ClassInstance>();
|
||||||
private ArrayList<ObjectInstance> objects = new ArrayList<ObjectInstance>();
|
private ArrayList<ObjectInstanceBase> objects = new ArrayList<ObjectInstanceBase>();
|
||||||
private java.util.Stack<Frame> frames = new java.util.Stack<Frame>(); // current execution frames
|
private java.util.Stack<Frame> frames = new java.util.Stack<Frame>(); // current execution frames
|
||||||
|
|
||||||
public Path(Execution execution)
|
public Path(Execution execution)
|
||||||
@@ -20,11 +21,23 @@ public class Path
|
|||||||
|
|
||||||
private Path(Path other)
|
private Path(Path other)
|
||||||
{
|
{
|
||||||
|
HashMap<ClassInstance, ClassInstance> classmap = new HashMap<ClassInstance, ClassInstance>();
|
||||||
|
|
||||||
this.execution = other.execution;
|
this.execution = other.execution;
|
||||||
this.classes = new ArrayList<ClassInstance>(other.classes);
|
|
||||||
this.objects = new ArrayList<ObjectInstance>(other.objects);
|
for (ClassInstance c : other.classes)
|
||||||
this.frames = new java.util.Stack<Frame>();
|
{
|
||||||
this.frames.addAll(other.frames);
|
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()
|
public Execution getExecution()
|
||||||
@@ -58,7 +71,9 @@ public class Path
|
|||||||
|
|
||||||
public ArrayInstance createArray(ClassInstance type, int len)
|
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()
|
public Frame getCurrentFrame()
|
||||||
@@ -99,7 +114,7 @@ public class Path
|
|||||||
|
|
||||||
public void throwException(ObjectInstance exception)
|
public void throwException(ObjectInstance exception)
|
||||||
{
|
{
|
||||||
System.out.println("throw " + exception);
|
System.out.println("XXX throw " + exception);
|
||||||
//XXX
|
//XXX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package info.sigterm.deob.execution;
|
package info.sigterm.deob.execution;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import info.sigterm.deob.attributes.code.Instruction;
|
import info.sigterm.deob.attributes.code.Instruction;
|
||||||
|
|
||||||
public class Stack
|
public class Stack
|
||||||
@@ -13,6 +15,13 @@ public class Stack
|
|||||||
stack = new Object[sz];
|
stack = new Object[sz];
|
||||||
ins = new Instruction[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)
|
public void push(Instruction i, Object obj)
|
||||||
{
|
{
|
||||||
@@ -24,6 +33,14 @@ public class Stack
|
|||||||
|
|
||||||
++size;
|
++size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Instruction getIns()
|
||||||
|
{
|
||||||
|
if (size <= 0)
|
||||||
|
throw new RuntimeException("Stack underflow");
|
||||||
|
|
||||||
|
return ins[size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
public Object pop()
|
public Object pop()
|
||||||
{
|
{
|
||||||
@@ -32,4 +49,9 @@ public class Stack
|
|||||||
|
|
||||||
return stack[--size];
|
return stack[--size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSize()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ public class StaticFieldInstance
|
|||||||
if (value != null)
|
if (value != null)
|
||||||
this.value = value.getValue().getObject();
|
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()
|
public Field getField()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package info.sigterm.deob.execution;
|
package info.sigterm.deob.execution;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class Variables
|
public class Variables
|
||||||
{
|
{
|
||||||
private Object[] variables;
|
private Object[] variables;
|
||||||
@@ -8,6 +10,11 @@ public class Variables
|
|||||||
{
|
{
|
||||||
variables = new Object[sz];
|
variables = new Object[sz];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Variables(Variables other)
|
||||||
|
{
|
||||||
|
this.variables = Arrays.copyOf(other.variables, other.variables.length);
|
||||||
|
}
|
||||||
|
|
||||||
public void set(int index, Object value)
|
public void set(int index, Object value)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -79,4 +79,10 @@ public class NameAndType extends PoolEntry
|
|||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNonVoid()
|
||||||
|
{
|
||||||
|
java.lang.String methodRefType = this.getDescriptor();
|
||||||
|
return !methodRefType.endsWith(")V");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user