new execute stuff
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
public class ArrayInstance extends ObjectInstanceBase
|
||||
{
|
||||
private Object[] array;
|
||||
|
||||
public ArrayInstance(Path path, ClassInstance type, int len)
|
||||
{
|
||||
super(path, type);
|
||||
this.array = new Object[len];
|
||||
}
|
||||
|
||||
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 Object get(int idx)
|
||||
{
|
||||
return array[idx];
|
||||
}
|
||||
|
||||
public int getLength()
|
||||
{
|
||||
return array.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstanceBase dup(Path path, ClassInstance type)
|
||||
{
|
||||
return new ArrayInstance(this, path, type);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import info.sigterm.deob.ClassFile;
|
||||
import info.sigterm.deob.Field;
|
||||
import info.sigterm.deob.Fields;
|
||||
import info.sigterm.deob.attributes.AttributeType;
|
||||
import info.sigterm.deob.attributes.Attributes;
|
||||
import info.sigterm.deob.attributes.ConstantValue;
|
||||
import info.sigterm.deob.pool.NameAndType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ClassInstance
|
||||
{
|
||||
private Path path;
|
||||
private ClassFile clazz;
|
||||
private ArrayList<StaticFieldInstance> fields = new ArrayList<StaticFieldInstance>();
|
||||
|
||||
public ClassInstance(Path path, ClassFile clazz)
|
||||
{
|
||||
this.path = path;
|
||||
this.clazz = clazz;
|
||||
|
||||
/* initialize static fields */
|
||||
Fields fields = clazz.getFields();
|
||||
for (Field field : fields.getFields())
|
||||
if ((field.getAccessFlags() & Field.ACC_STATIC) != 0)
|
||||
{
|
||||
Attributes attributes = field.getAttributes();
|
||||
ConstantValue cv = (ConstantValue) attributes.findType(AttributeType.CONSTANT_VALUE);
|
||||
|
||||
StaticFieldInstance fi = new StaticFieldInstance(this, field, cv);
|
||||
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()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
public ClassFile getClassFile()
|
||||
{
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public StaticFieldInstance findStaticField(NameAndType nat)
|
||||
{
|
||||
for (StaticFieldInstance f : fields)
|
||||
if (f.getField().getName().equals(nat.getName()) && f.getField().getType().equals(nat.getDescriptorType()))
|
||||
return f;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -7,69 +7,30 @@ import info.sigterm.deob.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class Execution
|
||||
{
|
||||
private ClassGroup group;
|
||||
private ArrayList<Path> paths = new ArrayList<Path>(); // paths of execution
|
||||
private HashMap<Method, HashSet<Integer>> visited = new HashMap<Method, HashSet<Integer>>();
|
||||
//protected HashSet<Method> methods = new HashSet<Method>();
|
||||
public List<Frame> frames = new ArrayList<>();
|
||||
|
||||
public Execution(ClassGroup group)
|
||||
{
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public void run(ClassFile cf, Method method, Object... args)
|
||||
|
||||
public int run()
|
||||
{
|
||||
Path p = new Path(this);
|
||||
ClassInstance instance = p.getClassInstance(cf);
|
||||
ObjectInstance object = p.createObject(instance);
|
||||
int fcount = 0;
|
||||
|
||||
int count = 1;
|
||||
p.invoke(method, object);
|
||||
|
||||
while (!paths.isEmpty())
|
||||
while (!frames.isEmpty())
|
||||
{
|
||||
p = paths.remove(0);
|
||||
++count;
|
||||
try
|
||||
{
|
||||
System.out.println("Resuming path with " + paths.size() + " remaining");
|
||||
p.resume();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
Frame frame = frames.remove(0);
|
||||
System.out.println("Executing frame " + frame);
|
||||
++fcount;
|
||||
frame.execute();
|
||||
}
|
||||
|
||||
System.out.println("Done " + count + " paths");
|
||||
}
|
||||
|
||||
public void addPath(Path p)
|
||||
{
|
||||
paths.add(p);
|
||||
}
|
||||
|
||||
public boolean visit(Method m)
|
||||
{
|
||||
if (visited.containsKey(m))
|
||||
return false;
|
||||
|
||||
visited.put(m, new HashSet<Integer>());
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean visit(Method m, int pc)
|
||||
{
|
||||
HashSet<Integer> map = visited.get(m);
|
||||
if (map == null || !map.contains(pc))
|
||||
{
|
||||
map.add(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return fcount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import info.sigterm.deob.Field;
|
||||
|
||||
public class FieldInstance
|
||||
{
|
||||
private ObjectInstance object;
|
||||
private Field field;
|
||||
private Object value;
|
||||
|
||||
public FieldInstance(ObjectInstance object, Field field, Object value)
|
||||
{
|
||||
this.object = object;
|
||||
this.field = field;
|
||||
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;
|
||||
}
|
||||
|
||||
public Object getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object obj)
|
||||
{
|
||||
value = obj;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,84 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import info.sigterm.deob.Method;
|
||||
import info.sigterm.deob.attributes.Code;
|
||||
import info.sigterm.deob.attributes.code.Exception;
|
||||
import info.sigterm.deob.attributes.code.Instruction;
|
||||
import info.sigterm.deob.attributes.code.Instructions;
|
||||
import info.sigterm.deob.attributes.code.instructions.LookupSwitch;
|
||||
import info.sigterm.deob.attributes.code.instructions.TableSwitch;
|
||||
import info.sigterm.deob.pool.NameAndType;
|
||||
|
||||
public class Frame
|
||||
{
|
||||
private Path path;
|
||||
private Execution execution;
|
||||
private Method method;
|
||||
boolean executing = true;
|
||||
private boolean executing = true;
|
||||
private int pc;
|
||||
private Stack stack;
|
||||
private Variables variables;
|
||||
private List<InstructionContext> instructions = new ArrayList<>(); // instructions executed in this frame
|
||||
private Map<Instruction, Instruction> visited; // shared
|
||||
|
||||
public Frame(Path path, Method method)
|
||||
public Frame(Execution execution, Method method)
|
||||
{
|
||||
Code code = method.getCode();
|
||||
|
||||
this.path = path;
|
||||
this.execution = execution;
|
||||
this.method = method;
|
||||
|
||||
Code code = method.getCode();
|
||||
|
||||
stack = new Stack(code.getMaxStack());
|
||||
variables = new Variables(code.getMaxLocals());
|
||||
|
||||
visited = new HashMap<>();
|
||||
|
||||
// initialize LVT
|
||||
int pos = 0;
|
||||
if (!method.isStatic())
|
||||
variables.set(pos++, new VariableContext(null, new Type(method.getMethods().getClassFile().getName())));
|
||||
|
||||
NameAndType nat = method.getNameAndType();
|
||||
for (int i = 0; i < nat.getNumberOfArgs(); ++i)
|
||||
{
|
||||
variables.set(pos, new VariableContext(null, new Type(nat.getDescriptor().getTypeOfArg(i)).toStackType()));
|
||||
pos += nat.getDescriptor().getTypeOfArg(i).getSlots();
|
||||
}
|
||||
}
|
||||
|
||||
protected Frame(Path path, Frame other)
|
||||
protected Frame(Frame other)
|
||||
{
|
||||
this.path = path;
|
||||
this.execution = other.execution;
|
||||
this.method = other.method;
|
||||
this.executing = other.executing;
|
||||
this.pc = other.pc;
|
||||
this.stack = new Stack(other.stack);
|
||||
this.variables = new Variables(other.variables);
|
||||
this.visited = other.visited;
|
||||
}
|
||||
|
||||
public Path getPath()
|
||||
|
||||
public Frame dup()
|
||||
{
|
||||
return path;
|
||||
Frame other = new Frame(this);
|
||||
execution.frames.add(other);
|
||||
return other;
|
||||
}
|
||||
|
||||
public void stop()
|
||||
{
|
||||
executing = false;
|
||||
}
|
||||
|
||||
public void throwException(Type type)
|
||||
{
|
||||
executing = false; // XXX
|
||||
}
|
||||
|
||||
public Method getMethod()
|
||||
@@ -58,12 +95,17 @@ public class Frame
|
||||
{
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
||||
public Variables getVariables()
|
||||
{
|
||||
return variables;
|
||||
}
|
||||
|
||||
public void addInstructionContext(InstructionContext i)
|
||||
{
|
||||
instructions.add(i);
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
Instructions ins = method.getCode().getInstructions();
|
||||
@@ -90,16 +132,11 @@ public class Frame
|
||||
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());
|
||||
StackContext stacki = stack.pop();
|
||||
System.err.println(stacki);
|
||||
}
|
||||
System.err.println("end of stack");
|
||||
ex.printStackTrace();
|
||||
//System.exit(-1);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
@@ -114,39 +151,42 @@ public class Frame
|
||||
}
|
||||
}
|
||||
|
||||
public void resume()
|
||||
private void doJump(Instruction from, Instruction to)
|
||||
{
|
||||
execute();
|
||||
visited.put(from, to);
|
||||
}
|
||||
|
||||
public void skip()
|
||||
private boolean hasJumped(Instruction from, Instruction to)
|
||||
{
|
||||
/* for resume, skip current ins? */
|
||||
Instructions ins = method.getCode().getInstructions();
|
||||
Instruction i = ins.findInstruction(pc);
|
||||
pc += i.getLength();
|
||||
}
|
||||
|
||||
private void checkLoop()
|
||||
{
|
||||
if (!this.getPath().getExecution().visit(method, pc))
|
||||
{
|
||||
System.out.println("Ending frame " + this);
|
||||
executing = false;
|
||||
}
|
||||
Instruction i = visited.get(from);
|
||||
if (from instanceof TableSwitch || from instanceof LookupSwitch) // XXX magic instructions which jump to multiple different places
|
||||
if (i != null)
|
||||
return true;
|
||||
assert i == null || i == to;
|
||||
return i == to;
|
||||
}
|
||||
|
||||
public void jump(int offset)
|
||||
{
|
||||
assert offset != 0;
|
||||
pc += offset;
|
||||
checkLoop();
|
||||
jumpAbsolute(pc + offset);
|
||||
}
|
||||
|
||||
public void jumpAbsolute(int pc)
|
||||
{
|
||||
Instruction from = method.getCode().getInstructions().findInstruction(this.pc);
|
||||
Instruction to = method.getCode().getInstructions().findInstruction(pc);
|
||||
|
||||
assert from != null;
|
||||
assert to != null;
|
||||
|
||||
if (hasJumped(from, to))
|
||||
{
|
||||
executing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
doJump(from, to);
|
||||
this.pc = pc;
|
||||
checkLoop();
|
||||
}
|
||||
|
||||
public Collection<Exception> getExceptionHandlers()
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.sigterm.deob.attributes.code.Instruction;
|
||||
|
||||
public class InstructionContext
|
||||
{
|
||||
private Instruction ins;
|
||||
private Frame frame;
|
||||
private List<StackContext> pops = new ArrayList<>();
|
||||
private List<VariableContext> reads = new ArrayList<>(); // lvt reads
|
||||
|
||||
public InstructionContext(Instruction i, Frame f)
|
||||
{
|
||||
ins = i;
|
||||
frame = f;
|
||||
}
|
||||
|
||||
public void pop(StackContext... ctx)
|
||||
{
|
||||
for (StackContext c : ctx)
|
||||
pops.add(c);
|
||||
}
|
||||
|
||||
public void read(VariableContext... ctx)
|
||||
{
|
||||
for (VariableContext c : ctx)
|
||||
reads.add(c);
|
||||
}
|
||||
|
||||
public Instruction getInstruction()
|
||||
{
|
||||
return ins;
|
||||
}
|
||||
|
||||
public List<StackContext> getPops()
|
||||
{
|
||||
return pops;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import info.sigterm.deob.Field;
|
||||
import info.sigterm.deob.Fields;
|
||||
import info.sigterm.deob.attributes.AttributeType;
|
||||
import info.sigterm.deob.attributes.Attributes;
|
||||
import info.sigterm.deob.attributes.ConstantValue;
|
||||
import info.sigterm.deob.pool.NameAndType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ObjectInstance extends ObjectInstanceBase
|
||||
{
|
||||
private ArrayList<FieldInstance> fields = new ArrayList<FieldInstance>();
|
||||
|
||||
public ObjectInstance(Path path, ClassInstance type)
|
||||
{
|
||||
super(path, type);
|
||||
|
||||
/* create fields */
|
||||
Fields fields = type.getClassFile().getFields();
|
||||
for (Field field : fields.getFields())
|
||||
{
|
||||
if ((field.getAccessFlags() & Field.ACC_STATIC) != 0)
|
||||
continue;
|
||||
|
||||
Attributes attributes = field.getAttributes();
|
||||
ConstantValue cv = (ConstantValue) attributes.findType(AttributeType.CONSTANT_VALUE);
|
||||
|
||||
FieldInstance fi = new FieldInstance(this, field, cv != null ? cv.getValue().getObject() : null);
|
||||
this.fields.add(fi);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (f.getField().getName().equals(nat.getName()) && f.getField().getType().equals(nat.getDescriptorType()))
|
||||
return f;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstanceBase dup(Path path, ClassInstance type)
|
||||
{
|
||||
return new ObjectInstance(this, path, type);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
|
||||
public abstract class ObjectInstanceBase
|
||||
{
|
||||
private Path path;
|
||||
private ClassInstance type;
|
||||
|
||||
public ObjectInstanceBase(Path path, ClassInstance type)
|
||||
{
|
||||
this.path = path;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ClassInstance getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public abstract ObjectInstanceBase dup(Path path, ClassInstance type);
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import info.sigterm.deob.ClassFile;
|
||||
import info.sigterm.deob.Method;
|
||||
import info.sigterm.deob.attributes.code.Exception;
|
||||
import info.sigterm.deob.attributes.code.Instruction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Path
|
||||
{
|
||||
private Execution execution;
|
||||
private ArrayList<ClassInstance> classes = new ArrayList<ClassInstance>();
|
||||
private ArrayList<ObjectInstanceBase> objects = new ArrayList<ObjectInstanceBase>();
|
||||
private java.util.Stack<Frame> frames = new java.util.Stack<Frame>(); // current execution frames
|
||||
|
||||
public Path(Execution execution)
|
||||
{
|
||||
this.execution = execution;
|
||||
}
|
||||
|
||||
private Path(Path other)
|
||||
{
|
||||
HashMap<ClassInstance, ClassInstance> classmap = new HashMap<ClassInstance, ClassInstance>();
|
||||
|
||||
this.execution = other.execution;
|
||||
|
||||
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()
|
||||
{
|
||||
return execution;
|
||||
}
|
||||
|
||||
public ClassInstance getClassInstance(ClassFile clazz)
|
||||
{
|
||||
for (ClassInstance cl : classes)
|
||||
if (cl.getClassFile() == clazz)
|
||||
return cl;
|
||||
|
||||
/* load parent */
|
||||
ClassFile parent = clazz.getParent();
|
||||
if (parent != null)
|
||||
getClassInstance(parent);
|
||||
|
||||
ClassInstance cl = new ClassInstance(this, clazz);
|
||||
classes.add(cl);
|
||||
|
||||
return cl;
|
||||
}
|
||||
|
||||
public ObjectInstance createObject(ClassInstance type)
|
||||
{
|
||||
ObjectInstance obj = new ObjectInstance(this, type);
|
||||
objects.add(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public ArrayInstance createArray(ClassInstance type, int len)
|
||||
{
|
||||
ArrayInstance arr = new ArrayInstance(this, type, len);
|
||||
objects.add(arr);
|
||||
return arr;
|
||||
}
|
||||
|
||||
public Frame getCurrentFrame()
|
||||
{
|
||||
return frames.peek();
|
||||
}
|
||||
|
||||
public Path dup()
|
||||
{
|
||||
Path other = new Path(this);
|
||||
execution.addPath(other);
|
||||
return other;
|
||||
}
|
||||
|
||||
public void resume()
|
||||
{
|
||||
for (Frame f : frames)
|
||||
{
|
||||
/* top most is at the correct pc */
|
||||
if (f == frames.peek())
|
||||
break;
|
||||
|
||||
/* move pc past invoke function */
|
||||
f.skip();
|
||||
}
|
||||
|
||||
/* resume execution */
|
||||
while (!frames.isEmpty())
|
||||
{
|
||||
Frame top = frames.peek();
|
||||
top.resume();
|
||||
if (!frames.isEmpty() && frames.peek() == top)
|
||||
frames.pop(); // XXX throwing doesnt remove
|
||||
}
|
||||
}
|
||||
|
||||
public void invoke(Method method, Object... args)
|
||||
{
|
||||
if (!this.getExecution().visit(method))
|
||||
return;
|
||||
|
||||
Frame f = new Frame(this, method);
|
||||
Variables vars = f.getVariables();
|
||||
for (int i = 0; i < args.length; ++i)
|
||||
vars.set(i, args[i]);
|
||||
frames.push(f);
|
||||
System.out.println("Executing frame " + method.getName() + " " + method.getDescriptor());
|
||||
f.execute();
|
||||
if (frames.isEmpty() == false && frames.peek() == f)
|
||||
System.err.println("Unpopped frame post execute");
|
||||
}
|
||||
|
||||
public void returnFrame(Instruction i, Object value)
|
||||
{
|
||||
returnFrame();
|
||||
Frame prevFrame = getCurrentFrame();
|
||||
|
||||
prevFrame.getStack().push(i, value);
|
||||
}
|
||||
|
||||
public void returnFrame()
|
||||
{
|
||||
Frame currentFrame = frames.pop();
|
||||
currentFrame.executing = false;
|
||||
}
|
||||
|
||||
public void throwException(Instruction ins, ObjectInstance exception)
|
||||
{
|
||||
ArrayList<Exception> exceptions = new ArrayList<Exception>();
|
||||
|
||||
/* collect all existing exception handlers */
|
||||
for (Frame f : frames)
|
||||
{
|
||||
Collection<Exception> handlers = f.getExceptionHandlers();
|
||||
exceptions.addAll(handlers);
|
||||
}
|
||||
|
||||
for (Exception handler : exceptions)
|
||||
{
|
||||
/* jump to handler */
|
||||
Method handlerMethod = handler.getExceptions().getCode().getAttributes().getMethod();
|
||||
|
||||
Path other = this.dup();
|
||||
/* walk up the frames until we find the one which holds the exception handler */
|
||||
while (handlerMethod != other.getCurrentFrame().getMethod())
|
||||
other.returnFrame();
|
||||
|
||||
/* handler pc is absolute from the beginning instruction */
|
||||
other.getCurrentFrame().jumpAbsolute(handler.getHandlerPc());
|
||||
}
|
||||
|
||||
/* this path stops executing */
|
||||
for (Frame f : frames)
|
||||
f.executing = false;
|
||||
}
|
||||
}
|
||||
@@ -3,50 +3,59 @@ package info.sigterm.deob.execution;
|
||||
import java.util.Arrays;
|
||||
|
||||
import info.sigterm.deob.attributes.code.Instruction;
|
||||
import info.sigterm.deob.pool.Method;
|
||||
|
||||
public class Stack
|
||||
{
|
||||
private int size;
|
||||
private Object[] stack;
|
||||
private Instruction[] ins;
|
||||
private StackContext[] stack;
|
||||
|
||||
public Stack(int sz)
|
||||
{
|
||||
stack = new Object[sz];
|
||||
ins = new Instruction[sz];
|
||||
stack = new StackContext[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)
|
||||
{
|
||||
if (size == stack.length)
|
||||
throw new RuntimeException("Stack overflow");
|
||||
|
||||
stack[size] = obj;
|
||||
ins[size] = i;
|
||||
|
||||
++size;
|
||||
}
|
||||
|
||||
public Instruction getIns()
|
||||
private void printStack(StackContext ctx, int level)
|
||||
{
|
||||
if (size <= 0)
|
||||
throw new RuntimeException("Stack underflow");
|
||||
|
||||
return ins[size - 1];
|
||||
for (int i = 0; i < level; ++i)
|
||||
System.err.print(" ");
|
||||
System.err.println(ctx.getType().type + " pushed by " + ctx.getIns().getInstruction().getType().getName() + " at " + ctx.getIns().getInstruction().getPc());
|
||||
for (StackContext c : ctx.getIns().getPops())
|
||||
printStack(c, level + 2);
|
||||
}
|
||||
|
||||
public Object pop()
|
||||
public void push(StackContext i)
|
||||
{
|
||||
if (size == stack.length)
|
||||
{
|
||||
info.sigterm.deob.Method m = i.getIns().getInstruction().getInstructions().getCode().getAttributes().getMethod();
|
||||
System.err.println("in " + m.getMethods().getClassFile().getName() + " method " + m.getNameAndType().getName());
|
||||
for (int c = 0; c < stack.length; ++c)
|
||||
printStack(stack[c], 0);
|
||||
throw new RuntimeException("Stack overflow");
|
||||
}
|
||||
|
||||
assert !i.getType().type.equals("V");
|
||||
|
||||
System.out.println("PUSH context " + i.getType().type + " from + " + i.getIns().getInstruction());
|
||||
stack[size] = i;
|
||||
++size;
|
||||
}
|
||||
|
||||
public StackContext pop()
|
||||
{
|
||||
if (size <= 0)
|
||||
throw new RuntimeException("Stack underflow");
|
||||
|
||||
System.out.println("POP");
|
||||
if (size == 1)
|
||||
System.out.println("STACK SIZE IS NOW ZERO");
|
||||
return stack[--size];
|
||||
}
|
||||
|
||||
|
||||
35
src/main/java/info/sigterm/deob/execution/StackContext.java
Normal file
35
src/main/java/info/sigterm/deob/execution/StackContext.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
public class StackContext
|
||||
{
|
||||
private InstructionContext ic; // instruction which pushed this
|
||||
private Type type; // type of this
|
||||
|
||||
public StackContext(InstructionContext i, Type t)
|
||||
{
|
||||
ic = i;
|
||||
type = t;
|
||||
}
|
||||
|
||||
public StackContext(InstructionContext i, Class<?> c)
|
||||
{
|
||||
ic = i;
|
||||
type = new Type(c.getCanonicalName());
|
||||
}
|
||||
|
||||
public StackContext(InstructionContext i, info.sigterm.deob.pool.Class c)
|
||||
{
|
||||
ic = i;
|
||||
type = new Type(c.getName());
|
||||
}
|
||||
|
||||
public InstructionContext getIns()
|
||||
{
|
||||
return ic;
|
||||
}
|
||||
|
||||
public Type getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import info.sigterm.deob.Field;
|
||||
import info.sigterm.deob.attributes.ConstantValue;
|
||||
|
||||
public class StaticFieldInstance
|
||||
{
|
||||
private ClassInstance clazz;
|
||||
private Field field;
|
||||
private Object value;
|
||||
|
||||
public StaticFieldInstance(ClassInstance clazz, Field field, ConstantValue value)
|
||||
{
|
||||
this.clazz = clazz;
|
||||
this.field = field;
|
||||
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()
|
||||
{
|
||||
return field;
|
||||
}
|
||||
|
||||
public Object getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setField(Object obj)
|
||||
{
|
||||
value = obj;
|
||||
}
|
||||
}
|
||||
73
src/main/java/info/sigterm/deob/execution/Type.java
Normal file
73
src/main/java/info/sigterm/deob/execution/Type.java
Normal file
@@ -0,0 +1,73 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
public class Type
|
||||
{
|
||||
public String type;
|
||||
|
||||
public Type(String type)
|
||||
{
|
||||
if (type.startsWith("["))
|
||||
throw new IllegalStateException();
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Type(info.sigterm.deob.signature.Type t)
|
||||
{
|
||||
String before = t.getType();
|
||||
type = asmTypeToClass(t.getType());
|
||||
for (int i = 0; i < t.getArrayDims(); ++i)
|
||||
type = type + "[]";
|
||||
System.out.println(before + " -> " + type);
|
||||
}
|
||||
|
||||
public Type toStackType()
|
||||
{
|
||||
if (type.equals(byte.class.getCanonicalName()) || type.equals(char.class.getCanonicalName()) || type.equals(short.class.getCanonicalName())
|
||||
|| type.equals(boolean.class.getCanonicalName()))
|
||||
return new Type(int.class.getCanonicalName());
|
||||
return this;
|
||||
}
|
||||
|
||||
private static String asmTypeToClass(String type)
|
||||
{
|
||||
switch (type.toString())
|
||||
{
|
||||
case "B":
|
||||
return byte.class.getCanonicalName();
|
||||
case "C":
|
||||
return char.class.getCanonicalName();
|
||||
case "I":
|
||||
return int.class.getCanonicalName();
|
||||
case "S":
|
||||
return short.class.getCanonicalName();
|
||||
case "Z":
|
||||
return boolean.class.getCanonicalName();
|
||||
case "D":
|
||||
return double.class.getCanonicalName();
|
||||
case "F":
|
||||
return float.class.getCanonicalName();
|
||||
case "J":
|
||||
return long.class.getCanonicalName();
|
||||
default:
|
||||
return type.replace("/", ".");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other)
|
||||
{
|
||||
if (!(other instanceof Type))
|
||||
return false;
|
||||
|
||||
Type t = (Type) other;
|
||||
return type.equals(t.type);
|
||||
}
|
||||
|
||||
public Type getSubtype()
|
||||
{
|
||||
if (!type.endsWith("[]"))
|
||||
throw new IllegalStateException(type + " is not an array type");
|
||||
|
||||
return new Type(type.substring(0, type.length() - 2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
public class VariableContext
|
||||
{
|
||||
private InstructionContext ic;
|
||||
private Type type;
|
||||
|
||||
public VariableContext(InstructionContext i, Type t)
|
||||
{
|
||||
ic = i;
|
||||
type = t;
|
||||
}
|
||||
|
||||
public Type getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,28 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Variables
|
||||
{
|
||||
private Object[] variables;
|
||||
|
||||
public Variables(int 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)
|
||||
{
|
||||
variables[index] = value;
|
||||
}
|
||||
|
||||
public Object get(int index)
|
||||
{
|
||||
return variables[index];
|
||||
}
|
||||
}
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Variables
|
||||
{
|
||||
private VariableContext[] variables;
|
||||
|
||||
public Variables(int sz)
|
||||
{
|
||||
variables = new VariableContext[sz];
|
||||
}
|
||||
|
||||
protected Variables(Variables other)
|
||||
{
|
||||
this.variables = Arrays.copyOf(other.variables, other.variables.length);
|
||||
}
|
||||
|
||||
public void set(int index, VariableContext value)
|
||||
{
|
||||
variables[index] = value;
|
||||
}
|
||||
|
||||
public VariableContext get(int index)
|
||||
{
|
||||
return variables[index];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user