Issue #942 timeout optimisation

This commit is contained in:
Jindra Petřík
2015-07-05 16:45:21 +02:00
parent 5553d3f046
commit 246c08a8f4
3 changed files with 166 additions and 72 deletions
@@ -2078,7 +2078,7 @@ public class AVM2Code implements Cloneable {
}
code.set(pos, instruction);
invalidateCache();
checkValidOffsets(body);
//checkValidOffsets(body);
}
/**
@@ -2353,53 +2353,65 @@ public class AVM2Code implements Cloneable {
}
private void visitCode(int ip, int lastIp, HashMap<Integer, List<Integer>> refs) throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
while (ip < code.size()) {
if (!refs.containsKey(ip)) {
refs.put(ip, new ArrayList<>());
List<Integer> toVisit = new ArrayList<>();
List<Integer> toVisitLast = new ArrayList<>();
toVisit.add(ip);
toVisitLast.add(lastIp);
while (!toVisit.isEmpty()) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
refs.get(ip).add(lastIp);
lastIp = ip;
if (refs.get(ip).size() > 1) {
break;
}
AVM2Instruction ins = code.get(ip);
if (ins.definition instanceof ThrowIns) {
break;
}
if (ins.definition instanceof ReturnValueIns) {
break;
}
if (ins.definition instanceof ReturnVoidIns) {
break;
}
if (ins.definition instanceof LookupSwitchIns) {
try {
for (int i = 2; i < ins.operands.length; i++) {
visitCode(adr2pos(pos2adr(ip) + ins.operands[i]), ip, refs);
ip = toVisit.remove(0);
lastIp = toVisitLast.remove(0);
while (ip < code.size()) {
if (!refs.containsKey(ip)) {
refs.put(ip, new ArrayList<>());
}
refs.get(ip).add(lastIp);
lastIp = ip;
if (refs.get(ip).size() > 1) {
break;
}
AVM2Instruction ins = code.get(ip);
if (ins.definition instanceof ThrowIns) {
break;
}
if (ins.definition instanceof ReturnValueIns) {
break;
}
if (ins.definition instanceof ReturnVoidIns) {
break;
}
if (ins.definition instanceof LookupSwitchIns) {
try {
for (int i = 2; i < ins.operands.length; i++) {
toVisit.add(adr2pos(pos2adr(ip) + ins.operands[i]));
toVisitLast.add(ip);
//visitCode(, ip, refs);
}
ip = adr2pos(pos2adr(ip) + ins.operands[0]);
continue;
} catch (ConvertException ex) {
}
ip = adr2pos(pos2adr(ip) + ins.operands[0]);
continue;
} catch (ConvertException ex) {
}
if (ins.definition instanceof JumpIns) {
try {
ip = adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]);
continue;
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
} else if (ins.definition instanceof IfTypeIns) {
try {
toVisit.add(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]));
toVisitLast.add(ip);
//visitCode(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]), ip, refs);
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
}
ip++;
}
if (ins.definition instanceof JumpIns) {
try {
ip = adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]);
continue;
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
} else if (ins.definition instanceof IfTypeIns) {
try {
visitCode(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]), ip, refs);
} catch (ConvertException ex) {
logger.log(Level.FINE, null, ex);
}
}
ip++;
};
}
@@ -69,23 +69,66 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
}
@Override
public void deobfuscate(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
body.getCode().markMappedOffsets();
public void deobfuscate(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody abody) throws InterruptedException {
MethodBody body = abody.clone();
System.err.println("A");
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
Map<Integer, GraphTargetItem> singleRegisters = getSingleUseRegisters(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
replaceSingleUseRegisters(singleRegisters, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
Map<Integer, GraphTargetItem> outFirstAssigned = new HashMap<>();
Map<Integer, AVM2Instruction> outFirstAssignments = new HashMap<>();
Map<Integer, Integer> outAssignCount1 = new HashMap<>();
Map<Integer, Integer> outAssignCount2 = new HashMap<>();
Map<Integer, GraphTargetItem> singleRegisters = new HashMap<>();
List<AVM2Instruction> ignored = new ArrayList<>();
Map<Integer, GraphTargetItem> registers = new HashMap<>();
System.err.println("B");
getFirstRegistersUsage(outAssignCount1, outFirstAssigned, outFirstAssignments, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body, ignored, registers);
ignored.addAll(outFirstAssignments.values());
registers.putAll(outFirstAssigned);
System.err.println("C");
replaceSingleUseRegisters(registers, ignored, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
System.err.println("C1");
super.deobfuscate(path, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
System.err.println("C2");
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
System.err.println("D");
//second pass - ignore all first assignments
registers.clear();
ignored.clear();
outFirstAssignments.clear();
getFirstRegistersUsage(outAssignCount2, new HashMap<>(), outFirstAssignments, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body, ignored, registers);
System.err.println("E");
for (int regId : outAssignCount1.keySet()) {
int ac = outAssignCount2.containsKey(regId) ? outAssignCount2.get(regId) : 0;
if (ac == 0) {
singleRegisters.put(regId, outFirstAssigned.get(regId));
}
}
body = abody;
replaceSingleUseRegisters(singleRegisters, null, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
System.err.println("F");
super.deobfuscate(path, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
System.err.println("G");
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
System.err.println("H");
}
private void replaceSingleUseRegisters(Map<Integer, GraphTargetItem> singleRegisters, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) {
private void replaceSingleUseRegisters(Map<Integer, GraphTargetItem> singleRegisters, List<AVM2Instruction> setInss, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) {
AVM2Code code = body.getCode();
for (int i = 0; i < code.code.size(); i++) {
System.err.println("replacesingle: " + i + "/" + code.code.size());
AVM2Instruction ins = code.code.get(i);
if (ins.definition instanceof SetLocalTypeIns) {
if (((setInss == null) || setInss.contains(ins)) && (ins.definition instanceof SetLocalTypeIns)) {
SetLocalTypeIns slt = (SetLocalTypeIns) ins.definition;
int regId = slt.getRegisterId(ins);
if (singleRegisters.containsKey(regId)) {
@@ -102,30 +145,48 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
}
}
private Map<Integer, GraphTargetItem> getSingleUseRegisters(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) {
private void getFirstRegistersUsage(Map<Integer, Integer> outAssignCount, Map<Integer, GraphTargetItem> outFirstAssigned, Map<Integer, AVM2Instruction> outFirstAssignments, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body, List<AVM2Instruction> ignoredAss, Map<Integer, GraphTargetItem> registers) {
AVM2Code code = body.getCode();
Map<Integer, GraphTargetItem> ret = new HashMap<>();
if (code.code.isEmpty()) {
return ret;
return;
}
ExecutionResult res = new ExecutionResult();
visitCode(new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, res);
visitCode(new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, res, registers, ignoredAss);
for (int reg : res.assignCount.keySet()) {
if (res.assignCount.get(reg) == 1) {
ret.put(reg, res.lastAssigned.get(reg));
if (res.firstAssigned.get(reg) != null && res.firstAssigned.get(reg).isCompileTime()) {
outAssignCount.put(reg, res.assignCount.get(reg));
outFirstAssigned.put(reg, res.firstAssigned.get(reg));
outFirstAssignments.put(reg, res.firstAssignInstruction.get(reg));
}
}
return ret;
}
/*
private Map<Integer, GraphTargetItem> getSingleUseRegisters(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) {
AVM2Code code = body.getCode();
Map<Integer, GraphTargetItem> ret = new HashMap<>();
private void visitCode(Set<Integer> visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, ExecutionResult result) {
if (code.code.isEmpty()) {
return ret;
}
ExecutionResult res = new ExecutionResult();
visitCode(new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, res);
for (int reg : res.assignCount.keySet()) {
if (res.assignCount.get(reg) == 1) {
ret.put(reg, res.lastAssigned.get(reg));
}
}
return ret;
}*/
private void visitCode(Set<Integer> visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, ExecutionResult result, Map<Integer, GraphTargetItem> registers, List<AVM2Instruction> ignoredAss) {
List<GraphTargetItem> output = new ArrayList<>();
AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex);
localData.localRegs.put(0, new NullAVM2Item(null));//this
int instructionsProcessed = 0;
List<Integer> toVisit = new ArrayList<>();
toVisit.add(idx);
@@ -145,27 +206,42 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
visited.add(idx);
AVM2Instruction action = code.code.get(idx);
instructionsProcessed++;
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
InstructionDefinition def = action.definition;
if (def instanceof SetLocalTypeIns) {
//System.err.println("" + idx + ": " + action + " stack:" + stack.size());
if (action.definition instanceof GetLocalTypeIns) {
stack.push(registers.get(((GetLocalTypeIns) action.definition).getRegisterId(action)));
} else if (action.definition instanceof SetLocalTypeIns) {
SetLocalTypeIns slt = (SetLocalTypeIns) def;
GraphTargetItem regVal = stack.pop();//localData.localRegs.get(regId);
int regId = slt.getRegisterId(action);
if (!result.assignCount.containsKey(regId)) {
result.assignCount.put(regId, 0);
}
result.assignCount.put(regId, result.assignCount.get(regId) + 1);
GraphTargetItem regVal = localData.localRegs.get(regId);
if (regVal == null || !regVal.getNotCoerced().isCompileTime()) {
result.assignCount.put(regId, Integer.MAX_VALUE);
boolean isIgnored = false;
for (AVM2Instruction ins : ignoredAss) {
if (action == ins) {
isIgnored = true;
break;
}
}
if (isIgnored) {
} else {
result.lastAssigned.put(regId, regVal.getNotCoerced());
result.assignCount.put(regId, result.assignCount.get(regId) + 1);
//GraphTargetItem regVal = localData.localRegs.get(regId);
if (regVal == null || !regVal.getNotCoerced().isCompileTime()) {
result.assignCount.put(regId, Integer.MAX_VALUE);
} else {
if (result.assignCount.get(regId) == 1) {
result.firstAssigned.put(regId, regVal.getNotCoerced());
result.firstAssignInstruction.put(regId, action);
}
result.lastAssigned.put(regId, regVal.getNotCoerced());
}
}
//assignCount
} else {
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
}
idx++;
@@ -255,5 +331,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
public Map<Integer, Integer> assignCount = new HashMap<>();
public Map<Integer, GraphTargetItem> lastAssigned = new HashMap<>();
public Map<Integer, GraphTargetItem> firstAssigned = new HashMap<>();
public Map<Integer, AVM2Instruction> firstAssignInstruction = new HashMap<>();
}
}
@@ -398,9 +398,13 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
public void deobfuscate(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
AVM2Code code = body.getCode();
System.err.println("1");
code.fixJumps(body);
System.err.println("2");
removeUnreachableActions(code, cpool, trait, minfo, body);
System.err.println("3");
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
System.err.println("4");
removeZeroJumps(code, body);
}