From 246c08a8f4a8059f81bac7b880a65238e0f8e155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 5 Jul 2015 16:45:21 +0200 Subject: [PATCH] Issue #942 timeout optimisation --- .../decompiler/flash/abc/avm2/AVM2Code.java | 100 +++++++------ .../AVM2DeobfuscatorRegisters.java | 134 ++++++++++++++---- .../deobfuscation/AVM2DeobfuscatorSimple.java | 4 + 3 files changed, 166 insertions(+), 72 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 516769410..52a1e401e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -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> refs) throws InterruptedException { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } - while (ip < code.size()) { - if (!refs.containsKey(ip)) { - refs.put(ip, new ArrayList<>()); + List toVisit = new ArrayList<>(); + List 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++; }; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java index 3af7fd656..d90586129 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java @@ -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 singleRegisters = getSingleUseRegisters(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body); - replaceSingleUseRegisters(singleRegisters, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body); + + Map outFirstAssigned = new HashMap<>(); + Map outFirstAssignments = new HashMap<>(); + Map outAssignCount1 = new HashMap<>(); + Map outAssignCount2 = new HashMap<>(); + + Map singleRegisters = new HashMap<>(); + + List ignored = new ArrayList<>(); + Map 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 singleRegisters, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) { + private void replaceSingleUseRegisters(Map singleRegisters, List 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 getSingleUseRegisters(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) { + private void getFirstRegistersUsage(Map outAssignCount, Map outFirstAssigned, Map outFirstAssignments, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body, List ignoredAss, Map registers) { AVM2Code code = body.getCode(); Map 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 getSingleUseRegisters(int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) { + AVM2Code code = body.getCode(); + Map ret = new HashMap<>(); - private void visitCode(Set 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 visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, ExecutionResult result, Map registers, List ignoredAss) { List 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 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 assignCount = new HashMap<>(); public Map lastAssigned = new HashMap<>(); + public Map firstAssigned = new HashMap<>(); + public Map firstAssignInstruction = new HashMap<>(); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java index 653efad41..b89363cc5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java @@ -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); }