I dont know if this works or is correct but it runs?

This commit is contained in:
Adam
2015-08-01 21:35:02 -04:00
parent 7ce6cca104
commit 516fa7805f
10 changed files with 223 additions and 27 deletions

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.attributes.code.Instruction;
import java.util.List;
public interface JumpingInstruction public interface JumpingInstruction
{ {
public void buildJumpGraph(); public void buildJumpGraph();
List<Instruction> getJumps();
} }

View File

@@ -9,6 +9,8 @@ import info.sigterm.deob.execution.Frame;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class Goto extends Instruction implements JumpingInstruction public class Goto extends Instruction implements JumpingInstruction
{ {
@@ -71,4 +73,10 @@ public class Goto extends Instruction implements JumpingInstruction
if (to == oldi) if (to == oldi)
to = newi; to = newi;
} }
@Override
public List<Instruction> getJumps()
{
return Arrays.asList(to);
}
} }

View File

@@ -9,6 +9,8 @@ import info.sigterm.deob.execution.Frame;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class GotoW extends Instruction implements JumpingInstruction public class GotoW extends Instruction implements JumpingInstruction
{ {
@@ -61,4 +63,10 @@ public class GotoW extends Instruction implements JumpingInstruction
if (to == oldi) if (to == oldi)
to = newi; to = newi;
} }
@Override
public List<Instruction> getJumps()
{
return Arrays.asList(to);
}
} }

View File

@@ -13,6 +13,8 @@ import info.sigterm.deob.execution.StackContext;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class If extends Instruction implements JumpingInstruction, ComparisonInstruction public class If extends Instruction implements JumpingInstruction, ComparisonInstruction
{ {
@@ -71,8 +73,9 @@ public class If extends Instruction implements JumpingInstruction, ComparisonIns
to = newi; to = newi;
} }
public Instruction getTo() @Override
public List<Instruction> getJumps()
{ {
return to; return Arrays.asList(to);
} }
} }

View File

@@ -13,6 +13,8 @@ import info.sigterm.deob.execution.StackContext;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class If0 extends Instruction implements JumpingInstruction, ComparisonInstruction public class If0 extends Instruction implements JumpingInstruction, ComparisonInstruction
{ {
@@ -70,8 +72,9 @@ public class If0 extends Instruction implements JumpingInstruction, ComparisonIn
to = newi; to = newi;
} }
public Instruction getTo() @Override
public List<Instruction> getJumps()
{ {
return to; return Arrays.asList(to);
} }
} }

View File

@@ -13,6 +13,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
public class LookupSwitch extends Instruction implements JumpingInstruction public class LookupSwitch extends Instruction implements JumpingInstruction
@@ -132,4 +133,14 @@ public class LookupSwitch extends Instruction implements JumpingInstruction
if (branchi.get(i) == oldi) if (branchi.get(i) == oldi)
branchi.set(i, newi); branchi.set(i, newi);
} }
@Override
public List<Instruction> getJumps()
{
List<Instruction> list = new ArrayList<>();
for (Instruction i : branchi)
list.add(i);
list.add(defi);
return list;
}
} }

View File

@@ -129,4 +129,14 @@ public class TableSwitch extends Instruction implements JumpingInstruction
if (branchi.get(i) == oldi) if (branchi.get(i) == oldi)
branchi.set(i, newi); branchi.set(i, newi);
} }
@Override
public List<Instruction> getJumps()
{
List<Instruction> list = new ArrayList<>();
for (Instruction i : branchi)
list.add(i);
list.add(defi);
return list;
}
} }

View File

@@ -4,10 +4,13 @@ import info.sigterm.deob.ClassGroup;
import info.sigterm.deob.Deobfuscator; import info.sigterm.deob.Deobfuscator;
import info.sigterm.deob.Method; import info.sigterm.deob.Method;
import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.Instruction;
import info.sigterm.deob.attributes.code.Instructions;
import info.sigterm.deob.attributes.code.instruction.types.ComparisonInstruction; import info.sigterm.deob.attributes.code.instruction.types.ComparisonInstruction;
import info.sigterm.deob.attributes.code.instruction.types.InvokeInstruction; import info.sigterm.deob.attributes.code.instruction.types.InvokeInstruction;
import info.sigterm.deob.attributes.code.instruction.types.JumpingInstruction;
import info.sigterm.deob.attributes.code.instruction.types.LVTInstruction; 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.PushConstantInstruction;
import info.sigterm.deob.attributes.code.instructions.Goto;
import info.sigterm.deob.attributes.code.instructions.If; import info.sigterm.deob.attributes.code.instructions.If;
import info.sigterm.deob.attributes.code.instructions.If0; import info.sigterm.deob.attributes.code.instructions.If0;
import info.sigterm.deob.execution.Execution; import info.sigterm.deob.execution.Execution;
@@ -16,8 +19,11 @@ import info.sigterm.deob.execution.InstructionContext;
import info.sigterm.deob.execution.StackContext; import info.sigterm.deob.execution.StackContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
@@ -85,6 +91,7 @@ class MethodGroup
public class ConstantParameter implements Deobfuscator public class ConstantParameter implements Deobfuscator
{ {
private List<ConstantMethodParameter> parameters = new ArrayList<>(); private List<ConstantMethodParameter> parameters = new ArrayList<>();
private MultiValueMap<Method, Integer> nonconst = new MultiValueMap<>(); // methods with non const parameters
//private MultiValueMap<Method, ConstantMethodParameter> parameters = new MultiValueMap<>(); //private MultiValueMap<Method, ConstantMethodParameter> parameters = new MultiValueMap<>();
// methods can be in more than one group because of multiple inheritance with interfaces // methods can be in more than one group because of multiple inheritance with interfaces
//private MultiValueMap<Method, MethodGroup> methodGroups = new MultiValueMap<>(); //private MultiValueMap<Method, MethodGroup> methodGroups = new MultiValueMap<>();
@@ -142,8 +149,28 @@ public class ConstantParameter implements Deobfuscator
if (c.equals(cmp)) if (c.equals(cmp))
continue outer; continue outer;
if (method.getMethods().getClassFile().getName().equals("gy") && method.getName().equals("y"))
{
int i = 5;
}
parameters.add(cmp); parameters.add(cmp);
} }
else
{
nonconst.put(method, parameterIndex);
// remove from parameters as is not always const
for (Iterator<ConstantMethodParameter> it = parameters.iterator(); it.hasNext();)
{
ConstantMethodParameter c = it.next();
if (c.methods.equals(methods) && c.lvtIndex == lvtOffset)
{
it.remove();;
}
}
}
} }
} }
@@ -247,9 +274,37 @@ public class ConstantParameter implements Deobfuscator
} }
} }
private boolean isLogicallyDead(Execution execution, Method method, int paramIndex, int lvtIndex, Object value) private static class LogicallyDeadOp
{
InstructionContext compCtx; // logically dead comparison
boolean branch; // branch which is always taken
@Override
public boolean equals(Object obj)
{
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final LogicallyDeadOp other = (LogicallyDeadOp) obj;
if (!Objects.equals(this.compCtx.getInstruction(), other.compCtx.getInstruction())) {
return false;
}
if (this.branch != other.branch) {
return false;
}
return true;
}
}
private List<LogicallyDeadOp> isLogicallyDead(Execution execution, Method method, int lvtIndex, Object value)
{ {
Boolean branch = null; Boolean branch = null;
List<LogicallyDeadOp> ops = new ArrayList<>();
// find if instruction // find if instruction
// one side must be constant, other must be parameterIndex // one side must be constant, other must be parameterIndex
@@ -263,6 +318,7 @@ public class ConstantParameter implements Deobfuscator
for (InstructionContext ins : frame.getInstructions()) for (InstructionContext ins : frame.getInstructions())
{ {
// XXX this should look for field accesses and see hwats done with it.
// if (ins.getInstruction() instanceof LVTInstruction) // if (ins.getInstruction() instanceof LVTInstruction)
// { // {
// LVTInstruction lvtins = (LVTInstruction) ins.getInstruction(); // LVTInstruction lvtins = (LVTInstruction) ins.getInstruction();
@@ -296,14 +352,17 @@ public class ConstantParameter implements Deobfuscator
// find if one is a lvt ins // find if one is a lvt ins
LVTInstruction lvt = null; LVTInstruction lvt = null;
StackContext other = null;
if (one.getPushed().getInstruction() instanceof LVTInstruction) if (one.getPushed().getInstruction() instanceof LVTInstruction)
{ {
lvt = (LVTInstruction) one.getPushed().getInstruction(); lvt = (LVTInstruction) one.getPushed().getInstruction();
other = two;
} }
else if (two != null && two.getPushed().getInstruction() instanceof LVTInstruction) else if (two != null && two.getPushed().getInstruction() instanceof LVTInstruction)
{ {
lvt = (LVTInstruction) two.getPushed().getInstruction(); lvt = (LVTInstruction) two.getPushed().getInstruction();
other = one;
} }
assert lvt == null || !lvt.store(); assert lvt == null || !lvt.store();
@@ -315,43 +374,94 @@ public class ConstantParameter implements Deobfuscator
if (two != null) // two is null for if0 if (two != null) // two is null for if0
{ {
if (!(two.getPushed().getInstruction() instanceof PushConstantInstruction)) if (!(other.getPushed().getInstruction() instanceof PushConstantInstruction))
continue; continue;
PushConstantInstruction pc = (PushConstantInstruction) two.getPushed().getInstruction(); PushConstantInstruction pc = (PushConstantInstruction) other.getPushed().getInstruction();
otherValue = pc.getConstant().getObject(); otherValue = pc.getConstant().getObject();
} }
// results must all be the same // the result of the comparison doesn't matter, only that it always goes the same direction for every invocation
boolean logicallyDead = doLogicalComparison(value, comp, otherValue); boolean result = doLogicalComparison(value, comp, otherValue);
if (branch == null) /*if (branch == null)
branch = logicallyDead; branch = result;
else if (branch != logicallyDead) else if (branch != result)
return false; return null;*/
LogicallyDeadOp deadOp = new LogicallyDeadOp();
deadOp.compCtx = ins;
deadOp.branch = result;
ops.add(deadOp);
//if (!logicallyDead) //if (!logicallyDead)
// return false; // if one frame finds it not logically dead, then stop // return false; // if one frame finds it not logically dead, then stop
} }
} }
return branch != null ? true /* always logically taking the same branch */ : false /* totally unused XXX */; return ops;
//return branch != null ? true /* always logically taking the same branch */ : false /* totally unused XXX */;
//return true; //return true;
} }
private void removeLogicallyDead(Execution execution, Method method, int lvtIndex)
{
}
private Map<Method, List<LogicallyDeadOp> > deadops = new HashMap<>();
private Set<Method> invalidDeadops = new HashSet<>();
private void findLogicallyDeadOperations(Execution execution) private void findLogicallyDeadOperations(Execution execution)
{ {
outer: outer:
for (ConstantMethodParameter cmp : parameters) for (ConstantMethodParameter cmp : parameters)
{ {
// Method method2 = cmp.methods.get(0);
// if (method2.getMethods().getClassFile().getName().equals("gy") && method2.getName().equals("y"))
// {
// int i = 5;
// }
for (Method method : cmp.methods) for (Method method : cmp.methods)
{ {
boolean isDead = isLogicallyDead(execution, method, cmp.paramIndex, cmp.lvtIndex, cmp.value); if (invalidDeadops.contains(method))
if (!isDead) continue;
continue outer;
// the dead comparisons must be the same and branch the same way for every call to this method.
List<LogicallyDeadOp> deadOps = isLogicallyDead(execution, method, cmp.lvtIndex, cmp.value);
List<LogicallyDeadOp> existing = deadops.get(method);
if (existing != null)
if (!existing.equals(deadOps))
{
deadops.remove(method);
invalidDeadops.add(method);
continue;
}
else
{
continue;
}
deadops.put(method, deadOps);
//if (deadOps == null)
//continue;
//if (isDead == null || !isDead)
// continue outer;
} }
// param is logically dead for all possible methods // param is logically dead for all possible methods
Method method = cmp.methods.get(0); //Method method = cmp.methods.get(0);
System.out.println(method.getMethods().getClassFile().getName() + "." + method.getName() + " has dead param " + cmp.paramIndex); //System.out.println(method.getMethods().getClassFile().getName() + "." + method.getName() + " has dead param " + cmp.paramIndex);
for (Method method : cmp.methods)
{
// remove dead parameter.
// I already have an unused parameter deob which detects them and removes them, so don't have to clean up those.
// Additionally there is an unused block deob which can remove unused blocks of code, so
// remove conditional jump, insert goto?
//removeLogicallyDead(execution, method, cmp.lvtIndex);
}
} }
// for (MethodGroup group : methodGroups) // for (MethodGroup group : methodGroups)
// //for (Object ogroup : methodGroups.values()) // //for (Object ogroup : methodGroups.values())
@@ -395,6 +505,43 @@ public class ConstantParameter implements Deobfuscator
// } // }
} }
private void removeDeadOperations()
{
for (Method method : deadops.keySet())
{
List<LogicallyDeadOp> ops = deadops.get(method);
for (LogicallyDeadOp op : ops)
{
InstructionContext ctx = op.compCtx; // comparison
boolean branch = op.branch;
Instructions instructions = ctx.getInstruction().getInstructions();
// remove the if
if (ctx.getInstruction() instanceof If)
ctx.removeStack(1);
ctx.removeStack(0);
int idx = instructions.getInstructions().indexOf(ctx.getInstruction());
if (idx == -1)
continue; // already removed?
JumpingInstruction jumpIns = (JumpingInstruction) ctx.getInstruction();
assert jumpIns.getJumps().size() == 1;
Instruction to = jumpIns.getJumps().get(0);
instructions.remove(ctx.getInstruction());
if (branch)
{
// insert goto
instructions.getInstructions().add(idx, new Goto(instructions, to));
}
}
}
}
@Override @Override
public void run(ClassGroup group) public void run(ClassGroup group)
{ {
@@ -406,6 +553,9 @@ public class ConstantParameter implements Deobfuscator
findParameters(execution); findParameters(execution);
findLogicallyDeadOperations(execution); findLogicallyDeadOperations(execution);
removeDeadOperations();
//System.out.println(deadops.size() + " deadops");
// System.out.println(parameters.size() + " params"); // System.out.println(parameters.size() + " params");
// for (ConstantMethodParameter p : parameters) // for (ConstantMethodParameter p : parameters)

View File

@@ -9,6 +9,8 @@ import info.sigterm.deob.Method;
import info.sigterm.deob.attributes.Code; import info.sigterm.deob.attributes.Code;
import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.Instruction;
import info.sigterm.deob.attributes.code.Instructions; import info.sigterm.deob.attributes.code.Instructions;
import info.sigterm.deob.attributes.code.instruction.types.ComparisonInstruction;
import info.sigterm.deob.attributes.code.instruction.types.JumpingInstruction;
import info.sigterm.deob.attributes.code.instructions.AThrow; import info.sigterm.deob.attributes.code.instructions.AThrow;
import info.sigterm.deob.attributes.code.instructions.Goto; import info.sigterm.deob.attributes.code.instructions.Goto;
import info.sigterm.deob.attributes.code.instructions.If; import info.sigterm.deob.attributes.code.instructions.If;
@@ -43,7 +45,7 @@ public class IllegalStateExceptions implements Deobfuscator
{ {
Instruction ins = ilist.get(i); Instruction ins = ilist.get(i);
if (!(ins instanceof If) && !(ins instanceof If0)) if (!(ins instanceof ComparisonInstruction))
continue; continue;
Instruction ins2 = ilist.get(i + 1); Instruction ins2 = ilist.get(i + 1);
@@ -55,11 +57,9 @@ public class IllegalStateExceptions implements Deobfuscator
if (!clazz.getName().equals("java/lang/IllegalStateException")) if (!clazz.getName().equals("java/lang/IllegalStateException"))
continue; continue;
Instruction to = null; JumpingInstruction jumpIns = (JumpingInstruction) ins;
if (ins instanceof If) assert jumpIns.getJumps().size() == 1;
to = ((If) ins).getTo(); Instruction to = jumpIns.getJumps().get(0);
else if (ins instanceof If0)
to = ((If0) ins).getTo();
// remove stack of if. // remove stack of if.
boolean found = false; boolean found = false;

View File

@@ -50,8 +50,6 @@ public class Execution
public void run() public void run()
{ {
// XXX update pc? some instructiosn rely on it still.
int count = 0, fcount = 0; int count = 0, fcount = 0;
while (!pendingMethods.isEmpty()) while (!pendingMethods.isEmpty())
{ {