AS3 deobfuscation from commandline.

Separated deobfuscation settings
This commit is contained in:
Jindra Petřík
2015-07-06 11:36:36 +02:00
parent 9fcc4fa394
commit cc475e9781
5 changed files with 129 additions and 17 deletions

View File

@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.ClassPath;
import com.jpexs.decompiler.flash.abc.RenameType;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.action.Action;
@@ -2859,4 +2860,19 @@ public final class SWF implements SWFContainerItem, Timelined {
public String toString() {
return getShortFileName();
}
public void deobfuscate(DeobfuscationLevel level) throws InterruptedException {
List<ABCContainerTag> atags = getAbcList();
for (ABCContainerTag tag : atags) {
if (level == DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE) {
tag.getABC().removeDeadCode();
} else if (level == DeobfuscationLevel.LEVEL_REMOVE_TRAPS) {
tag.getABC().removeTraps();
} else if (level == DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW) {
tag.getABC().removeTraps();
tag.getABC().restoreControlFlow();
}
}
}
}

View File

@@ -0,0 +1,22 @@
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
/**
*
* @author JPEXS
*/
public enum DeobfuscationLevel {
LEVEL_REMOVE_DEAD_CODE(1),
LEVEL_REMOVE_TRAPS(2),
LEVEL_RESTORE_CONTROL_FLOW(3);
private final int level;
public int getLevel() {
return level;
}
DeobfuscationLevel(int level) {
this.level = level;
}
}

View File

@@ -29,6 +29,7 @@ import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.RenameType;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException;
import com.jpexs.decompiler.flash.abc.avm2.parser.pcode.ASM3Parser;
import com.jpexs.decompiler.flash.abc.avm2.parser.pcode.MissingSymbolHandler;
@@ -314,6 +315,10 @@ public class CommandLineArgumentParser {
out.println(" " + (cnt++) + ") -replace <infile> <outfile> (<characterId1>|<scriptName1>) <importDataFile1> [methodBodyIndex1] [(<characterId2>|<scriptName2>) <importDataFile2> [methodBodyIndex2]]...");
out.println(" ...replaces the data of the specified BinaryData, Image, DefineSound tag or Script");
out.println(" ...methodBodyIndexN parameter should be specified if and only if the imported entity is an AS3 P-Code");
out.println(" " + (cnt++) + ") -deobfuscate <level> <infile> <outfile>");
out.println(" ...Deobfuscates AS3 P-code in <infile> and saves result to <outfile>");
out.println(" ...<level> can be one of: controlflow/3/max, traps/2, deadcode/1");
out.println(" ...WARNING: The deobfuscation result is still probably far enough to be openable by other decompilers.");
printCmdLineUsageExamples(out);
}
@@ -329,11 +334,12 @@ public class CommandLineArgumentParser {
out.println("java -jar ffdec.jar -format script:pcode,text:plain -export script,text,image \"C:\\decompiled\" myfile.swf");
out.println("java -jar ffdec.jar -format fla:cs5.5 -export fla \"C:\\sources\\myfile.fla\" myfile.swf");
out.println("java -jar ffdec.jar -dumpSWF myfile.swf");
out.println("java -jar ffdec.jar -compress myfile.swf myfiledec.swf");
out.println("java -jar ffdec.jar -decompress myfiledec.swf myfile.swf");
out.println("java -jar ffdec.jar -compress myfile.swf myfilecomp.swf");
out.println("java -jar ffdec.jar -decompress myfile.swf myfiledec.swf");
out.println("java -jar ffdec.jar -onerror ignore -export script \"C:\\decompiled\" myfile.swf");
out.println("java -jar ffdec.jar -onerror retry 5 -export script \"C:\\decompiled\" myfile.swf");
out.println("java -jar ffdec.jar -config autoDeobfuscate=1,parallelSpeedUp=0 -export script \"C:\\decompiled\" myfile.swf");
out.println("java -jar ffdec.jar -deobfuscate max myas3file_secure.swf myas3file.swf");
out.println("");
out.println("Instead of \"java -jar ffdec.jar\" you can use ffdec.bat on Windows, ffdec.sh on Linux/MacOs");
}
@@ -470,6 +476,8 @@ public class CommandLineArgumentParser {
parseXml2Swf(args);
} else if (command.equals("extract")) {
parseExtract(args);
} else if (command.equals("deobfuscate")) {
parseDeobfuscate(args);
} else if (command.equals("renameinvalididentifiers")) {
parseRenameInvalidIdentifiers(args);
} else if (command.equals("dumpswf")) {
@@ -1317,6 +1325,75 @@ public class CommandLineArgumentParser {
}
}
private static void parseDeobfuscate(Stack<String> args) {
if (args.size() < 3) {
badArguments();
}
String mode = args.pop();
DeobfuscationLevel lev = null;
switch (mode) {
case "controlflow":
case "max":
case "3":
lev = DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW;
break;
case "traps":
case "2":
lev = DeobfuscationLevel.LEVEL_REMOVE_TRAPS;
break;
case "deadcode":
case "1":
lev = DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE;
break;
default:
System.err.println("Invalid level, must be one of: controlflow,traps,deadcode or 1,2, 3/max");
System.exit(1);
break;
}
File inFile = new File(args.pop());
File outFile = new File(args.pop());
File tmpFile = null;
if (inFile.equals(outFile)) {
try {
tmpFile = File.createTempFile("ffdec_deobf_", ".swf");
outFile = tmpFile;
} catch (IOException ex) {
System.err.println("Unable to create temp file");
System.exit(1);
}
}
try (FileInputStream is = new FileInputStream(inFile);
FileOutputStream fos = new FileOutputStream(outFile)) {
SWF swf = new SWF(is, Configuration.parallelSpeedUp.get());
if (!swf.isAS3()) {
System.out.println("Warning: The file is not AS3. Only AS3 deobfuscation from commandline is available.");
System.exit(0);
}
swf.deobfuscate(lev);
swf.saveTo(fos);
if (tmpFile != null) {
inFile.delete();
tmpFile.renameTo(inFile);
tmpFile = null;
System.out.println("" + inFile + " overwritten.");
}
System.out.println("OK");
} catch (FileNotFoundException ex) {
System.err.println("File not found.");
System.exit(1);
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
System.exit(1);
} catch (IOException ex) {
Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, "Error", ex);
System.exit(1);
} finally {
if (tmpFile != null && tmpFile.exists()) {
tmpFile.delete();
}
}
}
private static void parseCompress(Stack<String> args) {
if (args.size() < 2) {
badArguments();

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.RenameType;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.configuration.ConfigurationItem;
@@ -2222,11 +2223,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
ABCPanel aBCPanel = getABCPanel();
if (deobfuscationDialog.processAllCheckbox.isSelected()) {
for (ABCContainerTag tag : abcPanel.getAbcList()) {
if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_REMOVE_DEAD_CODE) {
if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE.getLevel()) {
tag.getABC().removeDeadCode();
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_REMOVE_TRAPS) {
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationLevel.LEVEL_REMOVE_TRAPS.getLevel()) {
tag.getABC().removeTraps();
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_RESTORE_CONTROL_FLOW) {
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW.getLevel()) {
tag.getABC().removeTraps();
tag.getABC().restoreControlFlow();
}
@@ -2237,11 +2238,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
Trait t = abcPanel.decompiledTextArea.getCurrentTrait();
ABC abc = abcPanel.abc;
if (bi != -1) {
if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_REMOVE_DEAD_CODE) {
if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE.getLevel()) {
abc.bodies.get(bi).removeDeadCode(abc.constants, t, abc.method_info.get(abc.bodies.get(bi).method_info));
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_REMOVE_TRAPS) {
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationLevel.LEVEL_REMOVE_TRAPS.getLevel()) {
abc.bodies.get(bi).removeTraps(abc.constants, abc, t, decompiledTextArea.getScriptLeaf().scriptIndex, decompiledTextArea.getClassIndex(), decompiledTextArea.getIsStatic(), ""/*FIXME*/);
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_RESTORE_CONTROL_FLOW) {
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW.getLevel()) {
abc.bodies.get(bi).removeTraps(abc.constants, abc, t, decompiledTextArea.getScriptLeaf().scriptIndex, decompiledTextArea.getClassIndex(), decompiledTextArea.getIsStatic(), ""/*FIXME*/);
abc.bodies.get(bi).restoreControlFlow(abc.constants, t, abc.method_info.get(abc.bodies.get(bi).method_info));
}

View File

@@ -16,6 +16,8 @@
*/
package com.jpexs.decompiler.flash.gui.abc;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
import com.jpexs.decompiler.flash.gui.AppDialog;
import com.jpexs.decompiler.flash.gui.View;
import java.awt.Component;
@@ -43,12 +45,6 @@ public class DeobfuscationDialog extends AppDialog {
private int result = ERROR_OPTION;
public static final int LEVEL_REMOVE_DEAD_CODE = 1;
public static final int LEVEL_REMOVE_TRAPS = 2;
public static final int LEVEL_RESTORE_CONTROL_FLOW = 3;
@SuppressWarnings("unchecked")
public DeobfuscationDialog() {
setDefaultCloseOperation(HIDE_ON_CLOSE);
@@ -68,9 +64,9 @@ public class DeobfuscationDialog extends AppDialog {
Hashtable<Integer, JLabel> labelTable = new Hashtable<>();
//labelTable.put(LEVEL_NONE, new JLabel("None"));
labelTable.put(LEVEL_REMOVE_DEAD_CODE, new JLabel(translate("deobfuscation.removedeadcode")));
labelTable.put(LEVEL_REMOVE_TRAPS, new JLabel(translate("deobfuscation.removetraps")));
labelTable.put(LEVEL_RESTORE_CONTROL_FLOW, new JLabel(translate("deobfuscation.restorecontrolflow")));
labelTable.put(DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE.getLevel(), new JLabel(translate("deobfuscation.removedeadcode")));
labelTable.put(DeobfuscationLevel.LEVEL_REMOVE_TRAPS.getLevel(), new JLabel(translate("deobfuscation.removetraps")));
labelTable.put(DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW.getLevel(), new JLabel(translate("deobfuscation.restorecontrolflow")));
codeProcessingLevel.setLabelTable(labelTable);
codeProcessingLevel.setPaintLabels(true);