AS3: Jump deobfuscation improved

This commit is contained in:
Jindra Petřík
2015-06-21 14:40:00 +02:00
parent 18c295010a
commit 1747d06edf
7 changed files with 194 additions and 39 deletions

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.action.ActionList;
import java.util.List;
import java.util.Map;
/**
*
* AVM2 Deobfuscator removing single assigned local registers.
*
* Example: var a = true; var b = false; ... if(a){ ...ok }else{ not executed }
*
* @author JPEXS
*/
public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple {
//private final int executionLimit = 30000;
@Override
public void actionListParsed(ActionList actions, SWF swf) {
}
@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();
//removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
AVM2Code code = body.getCode();
boolean found;
do {
found = false;
Map<Integer, List<Integer>> refs = body.getCode().visitCode(body);
loopi:
for (int i = 0; i < code.code.size(); i++) {
AVM2Instruction ins = code.code.get(i);
if (ins.definition instanceof JumpIns) {
long targetAddr = ins.offset + ins.operands[0] + ins.getBytes().length;
{
for (int r : refs.get(i)) {
if (r >= 0) { //Not Exception start/end
AVM2Instruction srcIns = code.code.get(r);
if ((srcIns.definition instanceof JumpIns) || ((srcIns.definition instanceof IfTypeIns) && (r != i - 1))) {
{
int oldop = srcIns.operands[0];
srcIns.operands[0] = (int) (targetAddr - (srcIns.offset + srcIns.getBytes().length));
if (srcIns.operands[0] != oldop) {
found = true;
System.err.println("found");
}
}
}
}
}
}
}
}
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
} while (found);
}
}

View File

@@ -14,12 +14,14 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2;
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2GraphSource;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
@@ -139,13 +141,6 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
AVM2Instruction action = code.code.get(idx);
instructionsProcessed++;
/*if (action.definition instanceof GetLocalTypeIns) {
int regId = ((GetLocalTypeIns) action.definition).getRegisterId(action);//stack.peek().getResult().toString();
if (!localData.localRegs.containsKey(regId)) {
break;
}
}*/
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
InstructionDefinition def = action.definition;

View File

@@ -14,11 +14,14 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2;
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.FixItemCounterTranslateStack;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
@@ -37,6 +40,11 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterEqualsIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
@@ -311,7 +319,14 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
EqualsIns.class,
NotIns.class,
IfTypeIns.class,
JumpIns.class
JumpIns.class,
EqualsIns.class,
LessEqualsIns.class,
GreaterEqualsIns.class,
GreaterThanIns.class,
LessThanIns.class,
StrictEqualsIns.class,
PopIns.class
};
boolean ok = false;

View File

@@ -20,10 +20,11 @@ import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ABCInputStream;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.AVM2DeobfuscatorRegisters;
import com.jpexs.decompiler.flash.abc.avm2.AVM2DeobfuscatorSimple;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorRegisters;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorSimple;
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorJumps;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.configuration.Configuration;
@@ -203,7 +204,7 @@ public final class MethodBody implements Cloneable {
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
} else {
//if (!path.contains("@")) {
//if (!path.contains("RemoveAllPopup")) {
if (!Configuration.decompile.get()) {
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
return;
@@ -247,7 +248,7 @@ public final class MethodBody implements Cloneable {
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
} else {
//if (!path.contains("@")) {
//if (!path.contains("RemoveAllPopup")) {
if (!Configuration.decompile.get()) {
//writer.startMethod(this.method_info);
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
@@ -291,6 +292,8 @@ public final class MethodBody implements Cloneable {
} else {
new AVM2DeobfuscatorSimple().deobfuscate(path, classIndex, isStatic, scriptIndex, abc, constants, trait, method_info.get(this.method_info), b);
new AVM2DeobfuscatorRegisters().deobfuscate(path, classIndex, isStatic, scriptIndex, abc, constants, trait, method_info.get(this.method_info), b);
new AVM2DeobfuscatorJumps().deobfuscate(path, classIndex, isStatic, scriptIndex, abc, constants, trait, method_info.get(this.method_info), b);
}
}

View File

@@ -49,7 +49,7 @@ public class MethodInfo {
}
}
public int[] param_types;
public int[] param_types = new int[]{};
public int ret_type;
@@ -74,9 +74,9 @@ public class MethodInfo {
public int flags;
public ValueKind[] optional;
public ValueKind[] optional = new ValueKind[0];
public int[] paramNames;
public int[] paramNames = new int[0];
private MethodBody body;

View File

@@ -431,11 +431,12 @@ public class Graph {
TranslateStack stack = new TranslateStack(path);
List<Loop> loops = new ArrayList<>();
getLoops(localData, heads.get(0), loops, null);
/*System.out.println("<loops>");
/*1
System.err.println("<loops>");
for (Loop el : loops) {
System.out.println(el);
System..println(el);
}
System.out.println("</loops>");*/
System.err.println("</loops>");*/
getPrecontinues(path, localData, null, heads.get(0), allParts, loops, null);
/*System.err.println("<loopspre>");
for (Loop el : loops) {
@@ -1378,7 +1379,7 @@ public class Graph {
}
if (el.phase != 1) {
if (debugMode) {
//System.err.println("ignoring loop "+el);
System.err.println("ignoring loop " + el);
}
continue;
}
@@ -1418,18 +1419,9 @@ public class Graph {
if (currentLoop != null) {
currentLoop.phase = 0;
}
/*switch (part.stopPartType) {
case AND_OR:
part.setAndOrStack(stack); //Save stack for later use
break;
case COMMONPART:
part.setCommonPartStack(stack); //Save stack for later use
break;
case NONE:
break;
}*/
if (debugMode) {
System.err.println("Stopped on part " + part);
}
return ret;
}
@@ -1562,19 +1554,19 @@ public class Graph {
List<GraphPart> nps;
nps = part.nextParts;
boolean isEmpty = nps.get(0) == nps.get(1);
GraphPart next = getCommonPart(localData, nps, loops);
TranslateStack trueStack = (TranslateStack) stack.clone();
TranslateStack falseStack = (TranslateStack) stack.clone();
trueStack.clear();
falseStack.clear();
/*int trueStackSizeBefore = trueStack.size();
int falseStackSizeBefore = falseStack.size();
*/
boolean isEmpty = nps.get(0) == nps.get(1);
if (isEmpty) {
next = nps.get(0);
}
boolean hasOntrue = nps.get(1) != next;
boolean hasOnFalse = nps.get(0) != next;
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
@@ -1583,12 +1575,12 @@ public class Graph {
}
List<GraphTargetItem> onTrue = new ArrayList<>();
if (!isEmpty) {
if (!isEmpty && hasOntrue) {
onTrue = printGraph(visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
}
List<GraphTargetItem> onFalse = new ArrayList<>();
if (!isEmpty) {
if (!isEmpty && hasOnFalse) {
onFalse = printGraph(visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
}
//List<GraphTargetItem> out2 = new ArrayList<>();