Doesn't execute all paths correctly
This commit is contained in:
@@ -33,7 +33,7 @@ public class Deob
|
||||
|
||||
execute(group);
|
||||
}
|
||||
|
||||
|
||||
private static void execute(ClassGroup group) throws IOException
|
||||
{
|
||||
ClassFile cf = group.findClass("client");
|
||||
|
||||
@@ -39,7 +39,7 @@ public abstract class Instruction
|
||||
|
||||
public String getDesc(Frame frame)
|
||||
{
|
||||
return type.getName();
|
||||
return type.getName() + " at pc " + frame.getPc() + " in " + frame.getMethod().getName() + " " + frame.getMethod().getDescriptor() + " class " + frame.getMethod().getCode().getAttributes().getClassFile().getName();
|
||||
}
|
||||
|
||||
protected void addJump(int offset)
|
||||
|
||||
@@ -22,6 +22,9 @@ public class AALoad extends Instruction
|
||||
int index = (int) stack.pop();
|
||||
ArrayInstance array = (ArrayInstance) stack.pop();
|
||||
|
||||
stack.push(this, array.get(index));
|
||||
if (index >= 0 && index < array.getLength())
|
||||
stack.push(this, array.get(index));
|
||||
else
|
||||
frame.getPath().throwException(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class ALoad_0 extends Instruction
|
||||
public void execute(Frame frame)
|
||||
{
|
||||
Object obj = frame.getVariables().get(0);
|
||||
assert obj != null;
|
||||
frame.getStack().push(this, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class ALoad_3 extends Instruction
|
||||
public void execute(Frame frame)
|
||||
{
|
||||
Object obj = frame.getVariables().get(3);
|
||||
assert obj != null;
|
||||
frame.getStack().push(this, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class AStore_0 extends Instruction
|
||||
public void execute(Frame frame)
|
||||
{
|
||||
Object obj = frame.getStack().pop();
|
||||
assert obj != null;
|
||||
frame.getVariables().set(0, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class AStore_3 extends Instruction
|
||||
public void execute(Frame frame)
|
||||
{
|
||||
Object obj = frame.getStack().pop();
|
||||
assert obj != null;
|
||||
frame.getVariables().set(3, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class ILoad extends Instruction
|
||||
@Override
|
||||
public void execute(Frame frame)
|
||||
{
|
||||
int i = (int) frame.getVariables().get(index);
|
||||
Object i = frame.getVariables().get(index);
|
||||
frame.getStack().push(this, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class ILoad_1 extends Instruction
|
||||
public void execute(Frame frame)
|
||||
{
|
||||
Object obj = frame.getVariables().get(1);
|
||||
assert obj instanceof Integer;
|
||||
frame.getStack().push(this, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ public class IMul extends Instruction
|
||||
Integer two = (Integer) stack.pop();
|
||||
Integer one = (Integer) stack.pop();
|
||||
|
||||
stack.push(this, one * two);
|
||||
if (one == null || two == null)
|
||||
stack.push(this, 0);
|
||||
else
|
||||
stack.push(this, one * two);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ public class IStore extends Instruction
|
||||
public void execute(Frame frame)
|
||||
{
|
||||
Object obj = frame.getStack().pop();
|
||||
assert obj instanceof Integer;
|
||||
frame.getVariables().set(index, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class InvokeSpecial extends Instruction
|
||||
|
||||
if (object == null)
|
||||
{
|
||||
System.out.println("invokespecial for nonexistant function " + method.getNameAndType().getName() + " " + method.getNameAndType().getDescriptor() + " on " + method.getClassEntry().getName() + " (void: " + !method.getNameAndType().isNonVoid() + ")");
|
||||
//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;
|
||||
|
||||
@@ -42,8 +42,9 @@ public class InvokeStatic extends Instruction
|
||||
|
||||
if (otherClass == null)
|
||||
{
|
||||
System.out.println("invokestatic for nonexistant class " + clazz.getName());
|
||||
e.getStack().push(this, null);
|
||||
//System.out.println("invokestatic for nonexistant class " + clazz.getName());
|
||||
if (method.getNameAndType().isNonVoid())
|
||||
e.getStack().push(this, null);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class InvokeVirtual extends Instruction
|
||||
ObjectInstance object = (ObjectInstance) e.getStack().pop();
|
||||
if (object == null)
|
||||
{
|
||||
System.out.println("invokevirtual on null object for method " + method.getNameAndType().getName() + " " + method.getNameAndType().getDescriptor() + " on " + method.getClassEntry().getName());
|
||||
//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;
|
||||
}
|
||||
@@ -54,8 +54,9 @@ public class InvokeVirtual extends Instruction
|
||||
info.sigterm.deob.Method meth = objectType.getClassFile().findMethod(method.getNameAndType());
|
||||
if (meth == null)
|
||||
{
|
||||
System.out.println("Unknown method " + method.getNameAndType().getName() + " " + method.getNameAndType().getDescriptor() + " in " + objectType.getClassFile().getName());
|
||||
e.getStack().push(this, null);
|
||||
//System.out.println("Unknown method " + method.getNameAndType().getName() + " " + method.getNameAndType().getDescriptor() + " in " + objectType.getClassFile().getName());
|
||||
if (method.getNameAndType().isNonVoid())
|
||||
e.getStack().push(this, null);
|
||||
return;
|
||||
}
|
||||
e.getPath().invoke(meth, args);
|
||||
|
||||
@@ -4,6 +4,7 @@ import info.sigterm.deob.attributes.code.Instruction;
|
||||
import info.sigterm.deob.attributes.code.InstructionType;
|
||||
import info.sigterm.deob.attributes.code.Instructions;
|
||||
import info.sigterm.deob.execution.Frame;
|
||||
import info.sigterm.deob.execution.Path;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -51,15 +52,15 @@ public class LookupSwitch extends Instruction
|
||||
@Override
|
||||
public void execute(Frame e)
|
||||
{
|
||||
int key = (int) e.getStack().pop();
|
||||
e.getStack().pop();
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (match[i] == key)
|
||||
{
|
||||
e.jump(branch[i]);
|
||||
return;
|
||||
}
|
||||
for (int i : branch)
|
||||
{
|
||||
Path p = e.getPath().dup();
|
||||
p.getCurrentFrame().jump(i);
|
||||
}
|
||||
|
||||
e.jump(def);
|
||||
Path p = e.getPath().dup();
|
||||
p.getCurrentFrame().jump(def);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@ public class PutField extends Instruction
|
||||
ObjectInstance object = (ObjectInstance) e.getStack().pop();
|
||||
Object value = e.getStack().pop();
|
||||
|
||||
if (object == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FieldInstance field = object.getField(nat);
|
||||
field.setValue(value);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import info.sigterm.deob.attributes.code.Instruction;
|
||||
import info.sigterm.deob.attributes.code.InstructionType;
|
||||
import info.sigterm.deob.attributes.code.Instructions;
|
||||
import info.sigterm.deob.execution.Frame;
|
||||
import info.sigterm.deob.execution.Path;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -49,11 +50,15 @@ public class TableSwitch extends Instruction
|
||||
@Override
|
||||
public void execute(Frame e)
|
||||
{
|
||||
int index = (int) e.getStack().pop();
|
||||
e.getStack().pop();
|
||||
|
||||
if (index < low || index > high)
|
||||
e.jump(def);
|
||||
else
|
||||
e.jump(jumps[index - low]);
|
||||
for (int i : jumps)
|
||||
{
|
||||
Path p = e.getPath().dup();
|
||||
p.getCurrentFrame().jump(i);
|
||||
}
|
||||
|
||||
Path p = e.getPath().dup();
|
||||
p.getCurrentFrame().jump(def);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,15 @@ import info.sigterm.deob.ClassGroup;
|
||||
import info.sigterm.deob.Method;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
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 Execution(ClassGroup group)
|
||||
{
|
||||
@@ -22,13 +26,50 @@ public class Execution
|
||||
ClassInstance instance = p.getClassInstance(cf);
|
||||
ObjectInstance object = p.createObject(instance);
|
||||
|
||||
int count = 1;
|
||||
p.invoke(method, object);
|
||||
|
||||
//process();
|
||||
while (!paths.isEmpty())
|
||||
{
|
||||
p = paths.remove(0);
|
||||
++count;
|
||||
try
|
||||
{
|
||||
System.out.println("Resuming path with " + paths.size() + " remaining");
|
||||
p.resume();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package info.sigterm.deob.execution;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import info.sigterm.deob.Method;
|
||||
import info.sigterm.deob.attributes.Code;
|
||||
@@ -47,6 +48,11 @@ public class Frame
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
public int getPc()
|
||||
{
|
||||
return pc;
|
||||
}
|
||||
|
||||
public Stack getStack()
|
||||
{
|
||||
@@ -67,6 +73,12 @@ public class Frame
|
||||
|
||||
Instruction i = ins.findInstruction(pc);
|
||||
|
||||
if (i == null)
|
||||
{
|
||||
System.err.println("Cant find ins at pc " + pc + " in method " + method.getName() + " in " + method.getCode().getAttributes().getClassFile().getName());
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
i.execute(this);
|
||||
@@ -74,7 +86,7 @@ public class Frame
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
System.err.println("Error executing instruction " + i.getDesc(this) + " in " + method.getName() + " " + method.getDescriptor() + " in class " + method.getMethods().getClassFile().getName() + " at pc " + pc);
|
||||
System.err.println("Error executing instruction " + i.getDesc(this));
|
||||
System.err.println("Frame stack (grows downward):");
|
||||
while (stack.getSize() > 0)
|
||||
{
|
||||
@@ -87,8 +99,8 @@ public class Frame
|
||||
}
|
||||
System.err.println("end of stack");
|
||||
ex.printStackTrace();
|
||||
System.exit(-1);
|
||||
//throw ex;
|
||||
//System.exit(-1);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (oldPc == pc)
|
||||
@@ -102,15 +114,39 @@ public class Frame
|
||||
}
|
||||
}
|
||||
|
||||
public void resume()
|
||||
{
|
||||
execute();
|
||||
}
|
||||
|
||||
public void skip()
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
public void jump(int offset)
|
||||
{
|
||||
assert offset != 0;
|
||||
pc += offset;
|
||||
checkLoop();
|
||||
}
|
||||
|
||||
public void jumpAbsolute(int pc)
|
||||
{
|
||||
this.pc = pc;
|
||||
checkLoop();
|
||||
}
|
||||
|
||||
public Collection<Exception> getExceptionHandlers()
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ObjectInstance extends ObjectInstanceBase
|
||||
Attributes attributes = field.getAttributes();
|
||||
ConstantValue cv = (ConstantValue) attributes.findType(AttributeType.CONSTANT_VALUE);
|
||||
|
||||
FieldInstance fi = new FieldInstance(this, field, cv.getValue().getObject());
|
||||
FieldInstance fi = new FieldInstance(this, field, cv != null ? cv.getValue().getObject() : null);
|
||||
this.fields.add(fi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,20 +90,42 @@ public class Path
|
||||
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);
|
||||
|
||||
while (!frames.isEmpty())
|
||||
{
|
||||
f = frames.peek();
|
||||
f.execute();
|
||||
frames.pop();
|
||||
}
|
||||
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)
|
||||
@@ -144,5 +166,9 @@ public class Path
|
||||
/* handler pc is absolute from the beginning instruction */
|
||||
other.getCurrentFrame().jumpAbsolute(handler.getHandlerPc());
|
||||
}
|
||||
|
||||
/* this path stops executing */
|
||||
for (Frame f : frames)
|
||||
f.executing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,8 @@ public class NameAndType extends PoolEntry
|
||||
public boolean isNonVoid()
|
||||
{
|
||||
java.lang.String methodRefType = this.getDescriptor();
|
||||
if (this.getName().equals("<init>"))
|
||||
return true;
|
||||
return !methodRefType.endsWith(")V");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user