I think my invokevirtual execution is wrong because it doesn't actually

look for virtual methods on the type, which is why my unused method deob
does weird things. I am seeing methods that still exist after running it
that appear to be using non-inversible constants.
This commit is contained in:
Adam
2015-06-25 19:07:46 -04:00
parent 1eee5a48ae
commit 0543950013
7 changed files with 89 additions and 25 deletions

View File

@@ -0,0 +1,8 @@
package info.sigterm.deob.attributes.code.instruction.types;
import info.sigterm.deob.pool.Field;
public interface SetFieldInstruction
{
public Field getField();
}

View File

@@ -3,16 +3,18 @@ package info.sigterm.deob.attributes.code.instructions;
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.attributes.code.instruction.types.SetFieldInstruction;
import info.sigterm.deob.execution.Frame;
import info.sigterm.deob.execution.InstructionContext;
import info.sigterm.deob.execution.Stack;
import info.sigterm.deob.execution.StackContext;
import info.sigterm.deob.pool.Field;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class PutField extends Instruction
public class PutField extends Instruction implements SetFieldInstruction
{
private Field field;
@@ -45,4 +47,10 @@ public class PutField extends Instruction
frame.addInstructionContext(ins);
}
@Override
public Field getField()
{
return field;
}
}

View File

@@ -3,16 +3,18 @@ package info.sigterm.deob.attributes.code.instructions;
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.attributes.code.instruction.types.SetFieldInstruction;
import info.sigterm.deob.execution.Frame;
import info.sigterm.deob.execution.InstructionContext;
import info.sigterm.deob.execution.Stack;
import info.sigterm.deob.execution.StackContext;
import info.sigterm.deob.pool.Field;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class PutStatic extends Instruction
public class PutStatic extends Instruction implements SetFieldInstruction
{
private Field field;
@@ -44,4 +46,9 @@ public class PutStatic extends Instruction
frame.addInstructionContext(ins);
}
@Override
public Field getField()
{
return field;
}
}

View File

@@ -12,7 +12,9 @@ import info.sigterm.deob.attributes.Code;
import info.sigterm.deob.attributes.code.Instruction;
import info.sigterm.deob.attributes.code.Instructions;
import info.sigterm.deob.attributes.code.instruction.types.GetFieldInstruction;
import info.sigterm.deob.attributes.code.instruction.types.LVTInstruction;
import info.sigterm.deob.attributes.code.instruction.types.PushConstantInstruction;
import info.sigterm.deob.attributes.code.instruction.types.SetFieldInstruction;
import info.sigterm.deob.attributes.code.instructions.IMul;
import info.sigterm.deob.execution.Execution;
import info.sigterm.deob.execution.Frame;
@@ -67,8 +69,8 @@ public class ModularArithmeticDeobfuscation
continue;
// check for push constant and for get field instruction
Instruction one = ctx.getPops().get(0).getIns().getInstruction();
Instruction two = ctx.getPops().get(1).getIns().getInstruction();
Instruction one = ctx.getPops().get(0).getPushed().getInstruction();
Instruction two = ctx.getPops().get(1).getPushed().getInstruction();
PushConstantInstruction pc = null;
GetFieldInstruction gf = null;
@@ -86,14 +88,35 @@ public class ModularArithmeticDeobfuscation
if (pc == null)
continue;
int constant = Integer.parseInt(pc.getConstant().toString());
StackContext push = ctx.getPushes().get(0); // result of imul operation
InstructionContext popCtx = push.getPopped(); // instruction which popped the result
if (popCtx == null)
{
continue;
//System.err.println("Stack ctx never popped! Pushed by " + push.getPushed().getInstruction());
//int i = frame.getInstructions().indexOf(push.getPushed().getInstruction());
//System.err.println("next ins is " + frame.getInstructions().get(i + 1).getInstruction());
}
// XXX look only for setting to lvt.
if (!(popCtx.getInstruction() instanceof LVTInstruction))
continue;
LVTInstruction lvti = (LVTInstruction) popCtx.getInstruction();
if (!lvti.store())
continue;
try
{
int constant = Integer.parseInt(pc.getConstant().toString());
modInverse(constant);
}
catch (ArithmeticException ex)
{
continue;
System.err.println("Constant " + constant + " passed getter logic tests but is not inversable");
continue; // if the constant isn't inversable then it can't be the right one
}
Integer old = constants.get(gf.getField());
@@ -103,10 +126,9 @@ public class ModularArithmeticDeobfuscation
System.out.println("For " + gf.getField().getNameAndType().getName() + " in " + gf.getField().getClassEntry().getName() + " constant " + pc.getConstant().toString() + " mismatch on " + old);
constants.put(gf.getField(), newi);
// see what the result is used for?
}
}
System.out.println("Found " + constants.size() + " constants");
}
private static BigInteger modInverse(BigInteger val, int bits)

View File

@@ -22,7 +22,10 @@ public class InstructionContext
public void pop(StackContext... ctx)
{
for (StackContext c : ctx)
{
c.setPopped(this); // now we know which instruction popped this, record it
pops.add(c);
}
}
public void push(StackContext... ctx)
@@ -47,6 +50,11 @@ public class InstructionContext
return pops;
}
public List<StackContext> getPushes()
{
return pushes;
}
public void removeStack(int idx)
{
// idx 0 is top of the stack, 1 is one under

View File

@@ -22,8 +22,8 @@ public class Stack
{
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())
System.err.println(ctx.getType().type + " pushed by " + ctx.getPushed().getInstruction().getType().getName() + " at " + ctx.getPushed().getInstruction().getPc());
for (StackContext c : ctx.getPushed().getPops())
printStack(c, level + 2);
}
@@ -31,7 +31,7 @@ public class Stack
{
if (size == stack.length)
{
info.sigterm.deob.Method m = i.getIns().getInstruction().getInstructions().getCode().getAttributes().getMethod();
info.sigterm.deob.Method m = i.getPushed().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);

View File

@@ -2,32 +2,43 @@ package info.sigterm.deob.execution;
public class StackContext
{
private InstructionContext ic; // instruction which pushed this
private InstructionContext pushed; // instruction which pushed this
private InstructionContext popped; // instruction which popped this
private Type type; // type of this
public StackContext(InstructionContext i, Type t)
public StackContext(InstructionContext pushed, Type type)
{
ic = i;
type = t;
this.pushed = pushed;
this.type = type;
}
public StackContext(InstructionContext i, Class<?> c)
public StackContext(InstructionContext pushed, Class<?> clazz)
{
ic = i;
type = new Type(c.getCanonicalName());
this.pushed = pushed;
type = new Type(clazz.getCanonicalName());
}
public StackContext(InstructionContext i, info.sigterm.deob.pool.Class c)
public StackContext(InstructionContext pushed, info.sigterm.deob.pool.Class c)
{
ic = i;
this.pushed = pushed;
type = new Type(c.getName());
}
public InstructionContext getIns()
public InstructionContext getPushed()
{
return ic;
return pushed;
}
public InstructionContext getPopped()
{
return popped;
}
public void setPopped(InstructionContext popped)
{
this.popped = popped;
}
public Type getType()
{
return type;
@@ -37,13 +48,13 @@ public class StackContext
public void removeStack()
{
// remove the instruction which pushed this
if (!ic.getInstruction().removeStack())
if (!pushed.getInstruction().removeStack())
// dup will return false as the other objects on the stack below this are necessary
// for the other branch.
return;
// remove from the stack things this instruction read
for (StackContext ctx : ic.getPops())
for (StackContext ctx : pushed.getPops())
ctx.removeStack();
}
}