debugging, idr, exception handler execution support

This commit is contained in:
Adam
2015-06-13 21:51:06 -04:00
parent 6cac8c1cc9
commit db6269ba7e
13 changed files with 289 additions and 33 deletions

View File

@@ -52,10 +52,6 @@ public class Deob
// remove jump obfuscation // remove jump obfuscation
new Jumps().run(group); new Jumps().run(group);
//group.buildClassGraph();
//group.buildInstructionGraph();
//group.buildCallGraph();
saveJar(group, args[1]); saveJar(group, args[1]);
} }

View File

@@ -11,6 +11,7 @@ import info.sigterm.deob.execution.Execution;
import info.sigterm.deob.execution.Frame; import info.sigterm.deob.execution.Frame;
import info.sigterm.deob.execution.InstructionContext; import info.sigterm.deob.execution.InstructionContext;
import info.sigterm.deob.pool.NameAndType; import info.sigterm.deob.pool.NameAndType;
import info.sigterm.deob.pool.PoolEntry;
import info.sigterm.deob.signature.Signature; import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
@@ -72,11 +73,13 @@ public class Method
Method caller = n.from; Method caller = n.from;
// find frames on the caller // find frames on the caller
boolean found = false;
for (Frame f : execution.processedFrames) for (Frame f : execution.processedFrames)
if (f.getMethod() == caller) if (f.getMethod() == caller)
for (InstructionContext ins : f.getInstructions()) for (InstructionContext ins : f.getInstructions())
if (ins.getInstruction() == n.ins) // this instruction invokes the function we're removing a parameter from if (ins.getInstruction() == n.ins) // this instruction invokes the function we're removing a parameter from
{ {
found = true;
if (done.contains(ins.getInstruction())) if (done.contains(ins.getInstruction()))
continue; continue;
@@ -88,8 +91,54 @@ public class Method
done.add(ins.getInstruction()); done.add(ins.getInstruction());
} }
if (found == false)
{
System.err.println("Method " + caller.getName() + " in " + caller.getMethods().getClassFile().getName() + " calls " + this.getName() + " in " + this.getMethods().getClassFile().getName() + ", but was unable to find any execution frame doing this");
assert false;
}
} }
// this double checks that all calls to this have been located
for (ClassFile cf : methods.getClassFile().getGroup().getClasses())
for (Method m : cf.getMethods().getMethods())
{
Code c = m.getCode();
if (c == null)
continue;
for (Instruction i : c.getInstructions().getInstructions())
{
if (i instanceof InvokeInstruction)
{
InvokeInstruction ii = (InvokeInstruction) i;
PoolEntry pool = ii.getMethod();
if (pool instanceof info.sigterm.deob.pool.Method)
{
info.sigterm.deob.pool.Method pm = (info.sigterm.deob.pool.Method) pool;
if (pm.getClassEntry().getName().equals(this.getMethods().getClassFile().getName()) && pm.getNameAndType().equals(this.getNameAndType()) && !done.contains(i))
{
// for some reason this wasn't removed above?
System.err.println("Method " + m.getName() + " in " + cf.getName() + " calls " + pm.getNameAndType().getName() + " in " + pm.getClassEntry().getName() + " at " + i.getPc() + ", but this instruction was not found during execution");
//assert false;
}
}
else if (pool instanceof info.sigterm.deob.pool.InterfaceMethod)
{
info.sigterm.deob.pool.InterfaceMethod pm = (info.sigterm.deob.pool.InterfaceMethod) pool;
if (pm.getClassEntry().getName().equals(this.getMethods().getClassFile().getName()) && pm.getNameAndType().equals(this.getNameAndType()) && !done.contains(i))
{
// for some reason this wasn't removed above?
System.err.println("Method " + m.getName() + " in " + cf.getName() + " calls " + pm.getNameAndType().getName() + " in " + pm.getClassEntry().getName() + " at " + i.getPc() + ", but this instruction was not found during execution");
//assert false;
}
}
}
}
}
// adjust lvt indexes to get rid of idx in the method // adjust lvt indexes to get rid of idx in the method
for (Instruction ins : new ArrayList<>(getCode().getInstructions().getInstructions())) for (Instruction ins : new ArrayList<>(getCode().getInstructions().getInstructions()))
{ {

View File

@@ -1,6 +1,11 @@
package info.sigterm.deob.attributes.code.instruction.types; package info.sigterm.deob.attributes.code.instruction.types;
import info.sigterm.deob.Method;
import info.sigterm.deob.pool.PoolEntry;
public interface InvokeInstruction public interface InvokeInstruction
{ {
public void removeParameter(int idx); public void removeParameter(int idx);
public PoolEntry getMethod();
} }

View File

@@ -6,7 +6,11 @@ import info.sigterm.deob.attributes.code.Instructions;
import info.sigterm.deob.execution.Frame; import info.sigterm.deob.execution.Frame;
import info.sigterm.deob.execution.InstructionContext; import info.sigterm.deob.execution.InstructionContext;
import info.sigterm.deob.execution.Stack; import info.sigterm.deob.execution.Stack;
import info.sigterm.deob.execution.StackContext;
import info.sigterm.deob.execution.Type;
import java.io.IOException; import java.io.IOException;
import java.util.List;
public class AThrow extends Instruction public class AThrow extends Instruction
{ {
@@ -21,13 +25,38 @@ public class AThrow extends Instruction
InstructionContext ins = new InstructionContext(this, frame); InstructionContext ins = new InstructionContext(this, frame);
Stack stack = frame.getStack(); Stack stack = frame.getStack();
// XXX this actually clears the stack and puts only the value on, after jumping to the handler // get exception
//StackContext value = stack.pop(); StackContext exception = stack.pop();
//ins.pop(value); ins.pop(exception);
// Clear stack
while (stack.getSize() > 0)
{
StackContext value = stack.pop();
ins.pop(value);
}
// push exception back
exception = new StackContext(ins, exception.getType());
stack.push(exception);
// jump to instruction handlers that can catch exceptions here
for (info.sigterm.deob.attributes.code.Exception e : this.getInstructions().getCode().getExceptions().getExceptions())
{
Instruction start = e.getStart(),
end = e.getEnd();
// [start, end)
if (this.getPc() >= start.getPc() && this.getPc() < end.getPc())
{
Frame f = frame.dup();
f.jumpAbsolute(e.getHandler().getPc());
}
}
frame.addInstructionContext(ins); frame.addInstructionContext(ins);
frame.throwException(null);//value.getType()); frame.stop();
} }
@Override @Override

View File

@@ -36,17 +36,35 @@ public class CheckCast extends Instruction
@Override @Override
public void execute(Frame frame) public void execute(Frame frame)
{ {
Frame other = frame.dup(); // jump to instruction handlers that can catch exceptions here
Stack stack = other.getStack(); for (info.sigterm.deob.attributes.code.Exception e : this.getInstructions().getCode().getExceptions().getExceptions())
{
InstructionContext ins = new InstructionContext(this, other); Instruction start = e.getStart(),
end = e.getEnd();
StackContext what = stack.pop();
// [start, end)
ins.pop(what); if (this.getPc() >= start.getPc() && this.getPc() < end.getPc())
{
other.throwException(new Type("java.lang.ClassCastException")); Frame f = frame.dup();
Stack stack = f.getStack();
InstructionContext ins = new InstructionContext(this, f);
while (stack.getSize() > 0)
{
StackContext what = stack.pop();
ins.pop(what);
}
// push exception back
StackContext exception = new StackContext(ins, new Type("java/lang/Exception"));
stack.push(exception);
f.addInstructionContext(ins);
f.jumpAbsolute(e.getHandler().getPc());
}
}
} }
} }

View File

@@ -56,6 +56,8 @@ public class If0 extends Instruction implements JumpingInstruction
ins.pop(one); ins.pop(one);
frame.addInstructionContext(ins);
Frame other = frame.dup(); Frame other = frame.dup();
other.jump(offset); other.jump(offset);
} }

View File

@@ -13,6 +13,7 @@ import info.sigterm.deob.execution.Type;
import info.sigterm.deob.pool.InterfaceMethod; import info.sigterm.deob.pool.InterfaceMethod;
import info.sigterm.deob.pool.Method; import info.sigterm.deob.pool.Method;
import info.sigterm.deob.pool.NameAndType; import info.sigterm.deob.pool.NameAndType;
import info.sigterm.deob.pool.PoolEntry;
import info.sigterm.deob.signature.Signature; import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
@@ -77,6 +78,8 @@ public class InvokeInterface extends Instruction implements InvokeInstruction
StackContext object = stack.pop(); StackContext object = stack.pop();
ins.pop(object); ins.pop(object);
handleExceptions(frame);
if (!method.getNameAndType().isVoid()) if (!method.getNameAndType().isVoid())
{ {
StackContext ctx = new StackContext(ins, new Type(method.getNameAndType().getDescriptor().getReturnValue()).toStackType()); StackContext ctx = new StackContext(ins, new Type(method.getNameAndType().getDescriptor().getReturnValue()).toStackType());
@@ -85,6 +88,32 @@ public class InvokeInterface extends Instruction implements InvokeInstruction
frame.addInstructionContext(ins); frame.addInstructionContext(ins);
} }
private void handleExceptions(Frame frame)
{
// jump to instruction handlers that can catch exceptions here
for (info.sigterm.deob.attributes.code.Exception e : this.getInstructions().getCode().getExceptions().getExceptions())
{
Instruction start = e.getStart(),
end = e.getEnd();
// [start, end)
if (this.getPc() >= start.getPc() && this.getPc() < end.getPc())
{
Frame f = frame.dup();
Stack stack = f.getStack();
while (stack.getSize() > 0)
stack.pop();
InstructionContext ins = new InstructionContext(this, f);
StackContext ctx = new StackContext(ins, new Type("java/lang/Exception"));
stack.push(ctx);
f.jumpAbsolute(e.getHandler().getPc());
}
}
}
@Override @Override
public void removeParameter(int idx) public void removeParameter(int idx)
@@ -99,4 +128,10 @@ public class InvokeInterface extends Instruction implements InvokeInstruction
// create new method pool object // create new method pool object
method = new InterfaceMethod(method.getPool(), clazz, new NameAndType(nat.getPool(), nat.getName(), sig)); method = new InterfaceMethod(method.getPool(), clazz, new NameAndType(nat.getPool(), nat.getName(), sig));
} }
@Override
public PoolEntry getMethod()
{
return method;
}
} }

View File

@@ -12,6 +12,7 @@ import info.sigterm.deob.execution.StackContext;
import info.sigterm.deob.execution.Type; import info.sigterm.deob.execution.Type;
import info.sigterm.deob.pool.Method; import info.sigterm.deob.pool.Method;
import info.sigterm.deob.pool.NameAndType; import info.sigterm.deob.pool.NameAndType;
import info.sigterm.deob.pool.PoolEntry;
import info.sigterm.deob.signature.Signature; import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
@@ -72,6 +73,8 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction
StackContext object = stack.pop(); StackContext object = stack.pop();
ins.pop(object); ins.pop(object);
handleExceptions(frame);
if (!method.getNameAndType().isVoid()) if (!method.getNameAndType().isVoid())
{ {
StackContext ctx = new StackContext(ins, new Type(method.getNameAndType().getDescriptor().getReturnValue()).toStackType()); StackContext ctx = new StackContext(ins, new Type(method.getNameAndType().getDescriptor().getReturnValue()).toStackType());
@@ -80,6 +83,32 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction
frame.addInstructionContext(ins); frame.addInstructionContext(ins);
} }
private void handleExceptions(Frame frame)
{
// jump to instruction handlers that can catch exceptions here
for (info.sigterm.deob.attributes.code.Exception e : this.getInstructions().getCode().getExceptions().getExceptions())
{
Instruction start = e.getStart(),
end = e.getEnd();
// [start, end)
if (this.getPc() >= start.getPc() && this.getPc() < end.getPc())
{
Frame f = frame.dup();
Stack stack = f.getStack();
while (stack.getSize() > 0)
stack.pop();
InstructionContext ins = new InstructionContext(this, f);
StackContext ctx = new StackContext(ins, new Type("java/lang/Exception"));
stack.push(ctx);
f.jumpAbsolute(e.getHandler().getPc());
}
}
}
@Override @Override
public String getDesc(Frame frame) public String getDesc(Frame frame)
@@ -100,4 +129,10 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction
// create new method pool object // create new method pool object
method = new Method(method.getPool(), clazz, new NameAndType(nat.getPool(), nat.getName(), sig)); method = new Method(method.getPool(), clazz, new NameAndType(nat.getPool(), nat.getName(), sig));
} }
@Override
public PoolEntry getMethod()
{
return method;
}
} }

View File

@@ -12,6 +12,7 @@ import info.sigterm.deob.execution.StackContext;
import info.sigterm.deob.execution.Type; import info.sigterm.deob.execution.Type;
import info.sigterm.deob.pool.Method; import info.sigterm.deob.pool.Method;
import info.sigterm.deob.pool.NameAndType; import info.sigterm.deob.pool.NameAndType;
import info.sigterm.deob.pool.PoolEntry;
import info.sigterm.deob.signature.Signature; import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
@@ -69,6 +70,8 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
ins.pop(arg); ins.pop(arg);
} }
handleExceptions(frame);
if (!method.getNameAndType().isVoid()) if (!method.getNameAndType().isVoid())
{ {
StackContext ctx = new StackContext(ins, new Type(method.getNameAndType().getDescriptor().getReturnValue()).toStackType()); StackContext ctx = new StackContext(ins, new Type(method.getNameAndType().getDescriptor().getReturnValue()).toStackType());
@@ -78,6 +81,32 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
frame.addInstructionContext(ins); frame.addInstructionContext(ins);
} }
private void handleExceptions(Frame frame)
{
// jump to instruction handlers that can catch exceptions here
for (info.sigterm.deob.attributes.code.Exception e : this.getInstructions().getCode().getExceptions().getExceptions())
{
Instruction start = e.getStart(),
end = e.getEnd();
// [start, end)
if (this.getPc() >= start.getPc() && this.getPc() < end.getPc())
{
Frame f = frame.dup();
Stack stack = f.getStack();
while (stack.getSize() > 0)
stack.pop();
InstructionContext ins = new InstructionContext(this, f);
StackContext ctx = new StackContext(ins, new Type("java/lang/Exception"));
stack.push(ctx);
f.jumpAbsolute(e.getHandler().getPc());
}
}
}
@Override @Override
public String getDesc(Frame frame) public String getDesc(Frame frame)
{ {
@@ -97,4 +126,10 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
// create new method pool object // create new method pool object
method = new Method(method.getPool(), clazz, new NameAndType(nat.getPool(), nat.getName(), sig)); method = new Method(method.getPool(), clazz, new NameAndType(nat.getPool(), nat.getName(), sig));
} }
@Override
public PoolEntry getMethod()
{
return method;
}
} }

View File

@@ -12,6 +12,7 @@ import info.sigterm.deob.execution.StackContext;
import info.sigterm.deob.execution.Type; import info.sigterm.deob.execution.Type;
import info.sigterm.deob.pool.Method; import info.sigterm.deob.pool.Method;
import info.sigterm.deob.pool.NameAndType; import info.sigterm.deob.pool.NameAndType;
import info.sigterm.deob.pool.PoolEntry;
import info.sigterm.deob.signature.Signature; import info.sigterm.deob.signature.Signature;
import java.io.DataInputStream; import java.io.DataInputStream;
@@ -73,6 +74,8 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
StackContext object = stack.pop(); StackContext object = stack.pop();
ins.pop(object); ins.pop(object);
handleExceptions(frame);
if (!method.getNameAndType().isVoid()) if (!method.getNameAndType().isVoid())
{ {
StackContext ctx = new StackContext(ins, new Type(method.getNameAndType().getDescriptor().getReturnValue()).toStackType()); StackContext ctx = new StackContext(ins, new Type(method.getNameAndType().getDescriptor().getReturnValue()).toStackType());
@@ -82,6 +85,32 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
frame.addInstructionContext(ins); frame.addInstructionContext(ins);
} }
private void handleExceptions(Frame frame)
{
// jump to instruction handlers that can catch exceptions here
for (info.sigterm.deob.attributes.code.Exception e : this.getInstructions().getCode().getExceptions().getExceptions())
{
Instruction start = e.getStart(),
end = e.getEnd();
// [start, end)
if (this.getPc() >= start.getPc() && this.getPc() < end.getPc())
{
Frame f = frame.dup();
Stack stack = f.getStack();
while (stack.getSize() > 0)
stack.pop();
InstructionContext ins = new InstructionContext(this, f);
StackContext ctx = new StackContext(ins, new Type("java/lang/Exception"));
stack.push(ctx);
f.jumpAbsolute(e.getHandler().getPc());
}
}
}
@Override @Override
public void removeParameter(int idx) public void removeParameter(int idx)
{ {
@@ -95,4 +124,10 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
// create new method pool object // create new method pool object
method = new Method(method.getPool(), clazz, new NameAndType(nat.getPool(), nat.getName(), sig)); method = new Method(method.getPool(), clazz, new NameAndType(nat.getPool(), nat.getName(), sig));
} }
@Override
public PoolEntry getMethod()
{
return method;
}
} }

View File

@@ -21,6 +21,9 @@ public class UnusedParameters
int count = 0; int count = 0;
int collide = 0; int collide = 0;
int overrides = 0; int overrides = 0;
group.buildCallGraph(); // method.removeParameter uses the callgraph
for (ClassFile cf : group.getClasses()) for (ClassFile cf : group.getClasses())
{ {
for (Method m : cf.getMethods().getMethods()) for (Method m : cf.getMethods().getMethods())

View File

@@ -3,6 +3,7 @@ package info.sigterm.deob.execution;
import info.sigterm.deob.ClassFile; import info.sigterm.deob.ClassFile;
import info.sigterm.deob.ClassGroup; import info.sigterm.deob.ClassGroup;
import info.sigterm.deob.Method; import info.sigterm.deob.Method;
import info.sigterm.deob.attributes.code.Exceptions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -26,8 +27,10 @@ public class Execution
{ {
if (method.getCode() == null) if (method.getCode() == null)
continue; continue;
Frame f = new Frame(this, method); Frame f = new Frame(this, method);
frames.add(f); frames.add(f);
fcount += this.runFrames(); fcount += this.runFrames();
++count; ++count;
} }

View File

@@ -23,7 +23,7 @@ public class Frame
private Stack stack; private Stack stack;
private Variables variables; private Variables variables;
private List<InstructionContext> instructions = new ArrayList<>(); // instructions executed in this frame private List<InstructionContext> instructions = new ArrayList<>(); // instructions executed in this frame
private Map<Instruction, Instruction> visited; // shared private Map<Instruction, List<Instruction>> visited; // shared
public Frame(Execution execution, Method method) public Frame(Execution execution, Method method)
{ {
@@ -73,11 +73,6 @@ public class Frame
executing = false; executing = false;
} }
public void throwException(Type type)
{
executing = false; // XXX
}
public Method getMethod() public Method getMethod()
{ {
return method; return method;
@@ -154,17 +149,33 @@ public class Frame
private void doJump(Instruction from, Instruction to) private void doJump(Instruction from, Instruction to)
{ {
visited.put(from, to); List<Instruction> l = visited.get(from);
if (l == null)
{
List<Instruction> l2 = new ArrayList<>();
l2.add(to);
visited.put(from, l2);
}
else
{
l.add(to);
}
} }
private boolean hasJumped(Instruction from, Instruction to) private boolean hasJumped(Instruction from, Instruction to)
{ {
Instruction i = visited.get(from); List<Instruction> i = visited.get(from);
if (from instanceof TableSwitch || from instanceof LookupSwitch) // XXX magic instructions which jump to multiple different places if (i != null && i.contains(to))
if (i != null) return true;
return true;
assert i == null || i == to; if (i == null)
return i == to; {
i = new ArrayList<>();
visited.put(from, i);
}
i.add(to);
return false;
} }
public void jump(int offset) public void jump(int offset)