mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-06 04:45:54 +00:00
AS2 deobfuscation fixes
This commit is contained in:
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.action;
|
||||
import com.jpexs.decompiler.flash.AppResources;
|
||||
import com.jpexs.decompiler.flash.BaseLocalData;
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.model.ActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.ConstantPool;
|
||||
@@ -54,7 +55,9 @@ import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.ecma.Null;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.CodeFormatting;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.HilightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.NulWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
@@ -391,6 +394,23 @@ public class Action implements GraphSourceItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts list of actions to ASM source
|
||||
*
|
||||
* @param listeners
|
||||
* @param address
|
||||
* @param list List of actions
|
||||
* @param version SWF version
|
||||
* @param exportMode PCode or hex?
|
||||
* @return source ASM
|
||||
*
|
||||
*/
|
||||
public static String actionsToString(List<DisassemblyListener> listeners, long address, ActionList list, int version, ScriptExportMode exportMode) {
|
||||
HilightedTextWriter writer = new HilightedTextWriter(new CodeFormatting(), false);
|
||||
actionsToString(listeners, address, list, version, exportMode, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts list of actions to ASM source
|
||||
*
|
||||
@@ -671,6 +691,21 @@ public class Action implements GraphSourceItem {
|
||||
return actionsToTree(new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>(), actions, version, staticOperation, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts list of actions to ActionScript source code
|
||||
*
|
||||
* @param asm
|
||||
* @param actions List of actions
|
||||
* @param path
|
||||
* @return source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
public static String actionsToSource(final ASMSource asm, final List<Action> actions, final String path) throws InterruptedException {
|
||||
HilightedTextWriter writer = new HilightedTextWriter(new CodeFormatting(), false);
|
||||
actionsToSource(asm, actions, path, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts list of actions to ActionScript source code
|
||||
*
|
||||
@@ -685,12 +720,13 @@ public class Action implements GraphSourceItem {
|
||||
List<GraphTargetItem> tree = null;
|
||||
Throwable convertException = null;
|
||||
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
|
||||
final int version = asm == null ? SWF.DEFAULT_VERSION : asm.getSwf().version;
|
||||
try {
|
||||
tree = CancellableWorker.call(new Callable<List<GraphTargetItem>>() {
|
||||
@Override
|
||||
public List<GraphTargetItem> call() throws Exception {
|
||||
int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC;
|
||||
List<GraphTargetItem> tree = actionsToTree(new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>(), actions, asm.getSwf().version, staticOperation, path);
|
||||
List<GraphTargetItem> tree = actionsToTree(new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>(), actions, version, staticOperation, path);
|
||||
Graph.graphToString(tree, new NulWriter(), new LocalData());
|
||||
return tree;
|
||||
}
|
||||
@@ -707,7 +743,9 @@ public class Action implements GraphSourceItem {
|
||||
}
|
||||
writer.continueMeasure();
|
||||
|
||||
asm.getActionSourcePrefix(writer);
|
||||
if (asm != null) {
|
||||
asm.getActionSourcePrefix(writer);
|
||||
}
|
||||
if (convertException == null) {
|
||||
Graph.graphToString(tree, writer, new LocalData());
|
||||
} else if (convertException instanceof TimeoutException) {
|
||||
@@ -717,7 +755,9 @@ public class Action implements GraphSourceItem {
|
||||
Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error in: " + path, convertException);
|
||||
Helper.appendErrorComment(writer, convertException);
|
||||
}
|
||||
asm.getActionSourceSuffix(writer);
|
||||
if (asm != null) {
|
||||
asm.getActionSourceSuffix(writer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -186,4 +186,17 @@ public class ActionList extends ArrayList<Action> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Action.actionsToString(new ArrayList<DisassemblyListener>(), 0, this, SWF.DEFAULT_VERSION, ScriptExportMode.PCODE);
|
||||
}
|
||||
|
||||
public String toSource() {
|
||||
try {
|
||||
return Action.actionsToSource(null, this, "");
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(ActionList.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,11 +49,15 @@ import com.jpexs.decompiler.flash.action.swf5.ActionBitRShift;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitXor;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionCallFunction;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDecrement;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionModulo;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionReturn;
|
||||
import com.jpexs.decompiler.flash.action.swf6.ActionGreater;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
@@ -215,9 +219,10 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
ActionConstantPool cPool = getConstantPool(actions);
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
executeActions(actions, i, actions.size() - 1, result, fakeFunctions);
|
||||
executeActions(actions, i, actions.size() - 1, cPool, result, fakeFunctions);
|
||||
|
||||
if (result.idx != -1) {
|
||||
int newIstructionCount = 1; // jump
|
||||
@@ -285,12 +290,26 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void executeActions(ActionList actions, int idx, int endIdx, ExecutionResult result, Map<String, Object> fakeFunctions) {
|
||||
private ActionConstantPool getConstantPool(ActionList actions) {
|
||||
ActionConstantPool cPool = null;
|
||||
for (Action action : actions) {
|
||||
if (action instanceof ActionConstantPool) {
|
||||
if (cPool != null) {
|
||||
// there are multiple constant pools
|
||||
return null;
|
||||
}
|
||||
cPool = (ActionConstantPool) action;
|
||||
}
|
||||
}
|
||||
return cPool;
|
||||
}
|
||||
|
||||
private void executeActions(ActionList actions, int idx, int endIdx, ActionConstantPool constantPool, ExecutionResult result, Map<String, Object> fakeFunctions) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
ActionLocalData localData = new ActionLocalData();
|
||||
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack();
|
||||
int instructionsProcessed = 0;
|
||||
ActionConstantPool constantPool = null;
|
||||
ActionConstantPool lastConstantPool = null;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
@@ -311,7 +330,7 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
}
|
||||
System.out.println();*/
|
||||
if (action instanceof ActionConstantPool) {
|
||||
constantPool = (ActionConstantPool) action;
|
||||
lastConstantPool = (ActionConstantPool) action;
|
||||
}
|
||||
|
||||
if (action instanceof ActionDefineLocal) {
|
||||
@@ -348,6 +367,8 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
|| action instanceof ActionPushDuplicate
|
||||
|| action instanceof ActionAdd
|
||||
|| action instanceof ActionAdd2
|
||||
|| action instanceof ActionIncrement
|
||||
|| action instanceof ActionDecrement
|
||||
|| action instanceof ActionSubtract
|
||||
|| action instanceof ActionModulo
|
||||
|| action instanceof ActionMultiply
|
||||
@@ -361,6 +382,8 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
|| action instanceof ActionGetVariable
|
||||
|| action instanceof ActionSetVariable
|
||||
|| action instanceof ActionEquals
|
||||
|| action instanceof ActionEquals2
|
||||
|| action instanceof ActionGreater
|
||||
|| action instanceof ActionNot
|
||||
|| action instanceof ActionIf
|
||||
|| action instanceof ActionConstantPool
|
||||
@@ -374,7 +397,7 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
ActionPush push = (ActionPush) action;
|
||||
boolean ok = true;
|
||||
for (Object value : push.values) {
|
||||
if (value instanceof ConstantIndex || value instanceof RegisterNumber) {
|
||||
if ((constantPool == null && value instanceof ConstantIndex) || value instanceof RegisterNumber) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
@@ -418,7 +441,7 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
if (/*localData.variables.size() == 1 && */stack.allItemsFixed() || action instanceof ActionEnd) {
|
||||
result.idx = idx == actions.size() ? idx - 1 : idx;
|
||||
result.instructionsProcessed = instructionsProcessed;
|
||||
result.constantPool = constantPool;
|
||||
result.constantPool = lastConstantPool;
|
||||
result.variables.clear();
|
||||
for (String variableName : localData.variables.keySet()) {
|
||||
Object value = localData.variables.get(variableName).getResult();
|
||||
@@ -458,7 +481,7 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
List<Action> lastActions = actions.getContainerLastActions(action);
|
||||
int lastActionIdx = actions.indexOf(lastActions.get(0));
|
||||
executeActions(actions, i + 1, lastActionIdx, result, null);
|
||||
executeActions(actions, i + 1, lastActionIdx, null, result, null);
|
||||
if (result.resultValue != null) {
|
||||
results.put(def.functionName, result.resultValue);
|
||||
for (int j = i; j <= lastActionIdx; j++) {
|
||||
|
||||
@@ -60,7 +60,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase {
|
||||
List<Action> actions = par.actionsFromString(str);
|
||||
byte[] hex = Action.actionsToBytes(actions, true, SWF.DEFAULT_VERSION);
|
||||
ActionList list = ActionListReader.readActionListTimeout(new ArrayList<DisassemblyListener>(), new SWFInputStream(swf,hex), SWF.DEFAULT_VERSION, 0, hex.length, "");
|
||||
Action.actionsToSource(getFirstActionTag(), list,"", writer);
|
||||
Action.actionsToSource(null, list, "", writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@@ -80,12 +80,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase {
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
//TODO: use this to make better deobfuscator:
|
||||
|
||||
|
||||
|
||||
@Test(dataProvider = "provideBasicTrueExpressions")
|
||||
// todo: honfika @Test(dataProvider = "provideBasicTrueExpressions")
|
||||
public void testRemoveBasicTrueExpressions(String expression) throws ActionParseException, IOException, CompilationException, InterruptedException, TimeoutException{
|
||||
String res = recompile("if("+expression+"){"+
|
||||
"trace(\"OK\");"+
|
||||
@@ -100,7 +95,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "provideBasicFalseExpressions")
|
||||
// todo: honfika @Test(dataProvider = "provideBasicFalseExpressions")
|
||||
public void testRemoveBasicFalseExpressions(String expression) throws Exception {
|
||||
String res = recompile("if("+expression+"){"+
|
||||
"trace(\"FAIL\");"+
|
||||
@@ -116,7 +111,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
// todo: honfika @Test
|
||||
public void testRemoveKnownVariables() throws Exception{
|
||||
String res = recompile("var a = true; var b = false;"
|
||||
+ "if(a){"
|
||||
@@ -149,7 +144,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
// todo: honfika @Test
|
||||
public void testNotRemoveParams() throws Exception {
|
||||
String res = recompile("function tst(p1,p2){"
|
||||
+ "var a = 2;"
|
||||
@@ -182,7 +177,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase {
|
||||
|
||||
@Test
|
||||
public void testEvailExpressionAfterWhile() throws Exception {
|
||||
String res = "var a = 5;"
|
||||
String res = recompile("var a = 5;"
|
||||
+ "while(true){"
|
||||
+ "if(a==73){"
|
||||
+ "a = 15;"
|
||||
@@ -212,7 +207,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase {
|
||||
+ "trace(\"OK\");"
|
||||
+ "}else{"
|
||||
+ "trace(\"FAIL3\");"
|
||||
+ "}";
|
||||
+ "}");
|
||||
if(res.contains("\"FAIL1\"")){
|
||||
fail("unreachable if onTrue not removed");
|
||||
}
|
||||
@@ -226,7 +221,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase {
|
||||
fail("reachable of onTrue removed");
|
||||
}
|
||||
}
|
||||
//*/
|
||||
|
||||
@Test
|
||||
public void testRemoveJumpsToTheNextAction() {
|
||||
String actionsString = "ConstantPool \"a\" \"b\" \"c\"\n"
|
||||
|
||||
Reference in New Issue
Block a user