Start of constant parameter stuff
This commit is contained in:
@@ -20,6 +20,7 @@ import info.sigterm.deob.attributes.code.instructions.Goto;
|
||||
import info.sigterm.deob.attributes.code.instructions.GotoW;
|
||||
import info.sigterm.deob.attributes.code.instructions.Return;
|
||||
import info.sigterm.deob.block.Block;
|
||||
import info.sigterm.deob.deobfuscators.ConstantParameter;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
@@ -43,31 +44,54 @@ public class Deob
|
||||
|
||||
ClassGroup group = loadJar(args[0]);
|
||||
|
||||
new RenameUnique().run(group);
|
||||
|
||||
// remove except RuntimeException
|
||||
new RuntimeExceptions().run(group);
|
||||
// the blocks of runtime exceptions may contain interesting things like other obfuscations we identify later, but now that
|
||||
// it can't be reached by the execution phase, those things become confused. so remove blocks here.
|
||||
new UnusedBlocks().run(group);
|
||||
new ConstantParameter().run(group);
|
||||
|
||||
// remove unused methods
|
||||
new UnusedMethods().run(group);
|
||||
|
||||
// remove illegal state exceptions, frees up some parameters
|
||||
new IllegalStateExceptions().run(group);
|
||||
|
||||
// remove unhit blocks
|
||||
new UnusedBlocks().run(group);
|
||||
|
||||
// remove unused parameters
|
||||
new UnusedParameters().run(group);
|
||||
// long bstart = System.currentTimeMillis();
|
||||
// new RenameUnique().run(group);
|
||||
// long bdur = System.currentTimeMillis() - bstart;
|
||||
// System.out.println("rename unique took " + bdur/1000L + " seconds");
|
||||
//
|
||||
// // remove except RuntimeException
|
||||
// bstart = System.currentTimeMillis();
|
||||
// new RuntimeExceptions().run(group);
|
||||
// // the blocks of runtime exceptions may contain interesting things like other obfuscations we identify later, but now that
|
||||
// // it can't be reached by the execution phase, those things become confused. so remove blocks here.
|
||||
// new UnusedBlocks().run(group);
|
||||
// bdur = System.currentTimeMillis() - bstart;
|
||||
// System.out.println("runtime exception took " + bdur/1000L + " seconds");
|
||||
//
|
||||
// // remove unused methods
|
||||
// bstart = System.currentTimeMillis();
|
||||
// new UnusedMethods().run(group);
|
||||
// bdur = System.currentTimeMillis() - bstart;
|
||||
// System.out.println("unused methods took " + bdur/1000L + " seconds");
|
||||
//
|
||||
// // remove illegal state exceptions, frees up some parameters
|
||||
// bstart = System.currentTimeMillis();
|
||||
// new IllegalStateExceptions().run(group);
|
||||
// bdur = System.currentTimeMillis() - bstart;
|
||||
// System.out.println("illegal state exception took " + bdur/1000L + " seconds");
|
||||
//
|
||||
// // remove unhit blocks
|
||||
// bstart = System.currentTimeMillis();
|
||||
// new UnusedBlocks().run(group);
|
||||
// bdur = System.currentTimeMillis() - bstart;
|
||||
// System.out.println("unused blocks took " + bdur/1000L + " seconds");
|
||||
//
|
||||
// // remove unused parameters
|
||||
// bstart = System.currentTimeMillis();
|
||||
// new UnusedParameters().run(group);
|
||||
// bdur = System.currentTimeMillis() - bstart;
|
||||
// System.out.println("unused blocks took " + bdur/1000L + " seconds");
|
||||
|
||||
// remove jump obfuscation
|
||||
//new Jumps().run(group);
|
||||
|
||||
// remove unused fields
|
||||
new UnusedFields().run(group);
|
||||
// bstart = System.currentTimeMillis();
|
||||
// new UnusedFields().run(group);
|
||||
// bdur = System.currentTimeMillis() - bstart;
|
||||
// System.out.println("unused fields took " + bdur/1000L + " seconds");
|
||||
|
||||
//new ModularArithmeticDeobfuscation().run(group);
|
||||
|
||||
|
||||
@@ -10,4 +10,6 @@ public interface InvokeInstruction
|
||||
public void removeParameter(int idx);
|
||||
|
||||
public PoolEntry getMethod();
|
||||
|
||||
public List<Method> getMethods();
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ public class InvokeInterface extends Instruction implements InvokeInstruction
|
||||
out.writeByte(0);
|
||||
}
|
||||
|
||||
private List<info.sigterm.deob.Method> getMethods()
|
||||
@Override
|
||||
public List<info.sigterm.deob.Method> getMethods()
|
||||
{
|
||||
ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup();
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction
|
||||
out.writeShort(this.getPool().make(method));
|
||||
}
|
||||
|
||||
private List<info.sigterm.deob.Method> getMethods()
|
||||
@Override
|
||||
public List<info.sigterm.deob.Method> getMethods()
|
||||
{
|
||||
ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup();
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
|
||||
out.writeShort(this.getPool().make(method));
|
||||
}
|
||||
|
||||
private List<info.sigterm.deob.Method> getMethods()
|
||||
@Override
|
||||
public List<info.sigterm.deob.Method> getMethods()
|
||||
{
|
||||
ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup();
|
||||
|
||||
|
||||
@@ -83,7 +83,8 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
|
||||
// find the possible methods this instruction might be invoking. we can't know for sure
|
||||
// which method is being invoked without tracking the types of objects in fields and when
|
||||
// passed in parameters/return values.
|
||||
private List<info.sigterm.deob.Method> getMethods()
|
||||
@Override
|
||||
public List<info.sigterm.deob.Method> getMethods()
|
||||
{
|
||||
ClassGroup group = this.getInstructions().getCode().getAttributes().getClassFile().getGroup();
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package info.sigterm.deob.deobfuscators;
|
||||
|
||||
import info.sigterm.deob.ClassGroup;
|
||||
import info.sigterm.deob.Deobfuscator;
|
||||
import info.sigterm.deob.Method;
|
||||
import info.sigterm.deob.attributes.code.instruction.types.InvokeInstruction;
|
||||
import info.sigterm.deob.attributes.code.instruction.types.PushConstantInstruction;
|
||||
import info.sigterm.deob.execution.Execution;
|
||||
import info.sigterm.deob.execution.Frame;
|
||||
import info.sigterm.deob.execution.InstructionContext;
|
||||
import info.sigterm.deob.execution.StackContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.map.MultiValueMap;
|
||||
|
||||
class ConstantMethodParameter
|
||||
{
|
||||
public Method method;
|
||||
public int paramNum;
|
||||
public Object value;
|
||||
}
|
||||
|
||||
class MethodGroup
|
||||
{
|
||||
public List<Method> methods; // methods that can be invoked
|
||||
public Collection<Integer> constantParameters; // parameters which are always constant for all invocations
|
||||
public List<ConstantMethodParameter> cmps = new ArrayList<>(); // cmps for all methods in the group, which hold the values.
|
||||
}
|
||||
|
||||
public class ConstantParameter implements Deobfuscator
|
||||
{
|
||||
private MultiValueMap<Method, ConstantMethodParameter> parameters = new MultiValueMap<>();
|
||||
// methods can be in more than one group because of multiple inheritance with interfaces
|
||||
private MultiValueMap<Method, MethodGroup> methodGroups = new MultiValueMap<>();
|
||||
|
||||
private void findConstantParameter(Execution execution, Method method, InstructionContext invokeCtx)
|
||||
{
|
||||
List<StackContext> pops = invokeCtx.getPops();
|
||||
for (int i = 0; i < method.getDescriptor().size(); ++i)
|
||||
{
|
||||
// object is poped first
|
||||
|
||||
int offset = method.isStatic() ? 0 : 1;
|
||||
|
||||
StackContext ctx = pops.get(offset + i);
|
||||
if (ctx.getPushed().getInstruction() instanceof PushConstantInstruction)
|
||||
{
|
||||
PushConstantInstruction pc = (PushConstantInstruction) ctx.getPushed().getInstruction();
|
||||
|
||||
if (!(pc.getConstant().getObject() instanceof Integer))
|
||||
continue;
|
||||
|
||||
ConstantMethodParameter cmp = new ConstantMethodParameter();
|
||||
cmp.method = method;
|
||||
cmp.paramNum = i;
|
||||
cmp.value = pc.getConstant().getObject();
|
||||
|
||||
parameters.put(method, cmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<Integer> getParametersFor(Method method)
|
||||
{
|
||||
Collection<ConstantMethodParameter> params = parameters.getCollection(method);
|
||||
Collection<Integer> out = new ArrayList<>();
|
||||
|
||||
if (params != null)
|
||||
for (ConstantMethodParameter p : params)
|
||||
out.add(p.paramNum);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private void findParameters(Execution execution)
|
||||
{
|
||||
for (Frame frame : execution.processedFrames)
|
||||
for (InstructionContext ins : frame.getInstructions())
|
||||
{
|
||||
if (!(ins.getInstruction() instanceof InvokeInstruction))
|
||||
continue;
|
||||
|
||||
List<Method> methods = ((InvokeInstruction) ins.getInstruction()).getMethods();
|
||||
for (Method m : methods)
|
||||
findConstantParameter(execution, m, ins);
|
||||
|
||||
// get common constant indexes from all methods that can possibly be called
|
||||
Collection<Integer> parameterIndexes = null;
|
||||
for (Method m : methods)
|
||||
{
|
||||
Collection<Integer> idxs = getParametersFor(m);
|
||||
|
||||
if (parameterIndexes == null)
|
||||
parameterIndexes = idxs;
|
||||
else
|
||||
parameterIndexes = CollectionUtils.intersection(parameterIndexes, idxs);
|
||||
}
|
||||
|
||||
MethodGroup group = new MethodGroup();
|
||||
group.methods = methods;
|
||||
group.constantParameters = parameterIndexes;
|
||||
|
||||
// build constant method parameters
|
||||
for (Method m : methods)
|
||||
{
|
||||
Collection<ConstantMethodParameter> params = parameters.getCollection(m);
|
||||
if (params != null)
|
||||
group.cmps.addAll(params);
|
||||
}
|
||||
|
||||
// insert
|
||||
for (Method m : methods)
|
||||
methodGroups.put(m, group);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ClassGroup group)
|
||||
{
|
||||
group.buildClassGraph(); // required for getMethods in the invoke stuff
|
||||
|
||||
Execution execution = new Execution(group);
|
||||
execution.populateInitialMethods();
|
||||
execution.run();
|
||||
|
||||
findParameters(execution);
|
||||
|
||||
System.out.println("finished with " + methodGroups.size() + " groups");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,4 +54,10 @@ public class Double extends PoolEntry
|
||||
{
|
||||
out.writeDouble(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,4 +48,10 @@ public class Float extends PoolEntry
|
||||
{
|
||||
out.writeFloat(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,10 @@ public class Integer extends PoolEntry
|
||||
{
|
||||
out.writeInt(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,10 @@ public class Long extends PoolEntry
|
||||
{
|
||||
out.writeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,4 +45,9 @@ public abstract class PoolEntry
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public Object getObject()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,4 +61,10 @@ public class String extends PoolEntry
|
||||
{
|
||||
out.writeShort(stringIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject()
|
||||
{
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,10 @@ public class UTF8 extends PoolEntry
|
||||
java.lang.String s = getValue();
|
||||
out.writeUTF(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject()
|
||||
{
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user