AS3 deobfuscation

This commit is contained in:
Jindra Pet��k
2013-01-28 22:34:00 +01:00
parent fa9ced470b
commit c26a46139e
8 changed files with 393 additions and 84 deletions
+6
View File
@@ -86,6 +86,12 @@ public class ABC {
return rem;
}
public void restoreControlFlow() {
for(MethodBody body:bodies){
body.restoreControlFlow(constants);
}
}
public int deobfuscateIdentifiers() {
int ret = 0;
for (int i = 1; i < instance_info.length; i++) {
+104 -77
View File
@@ -59,6 +59,7 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.Highlighter;
import com.jpexs.asdec.abc.avm2.instructions.TagInstruction;
public class AVM2Code {
@@ -718,7 +719,9 @@ public class AVM2Code {
}
long ofs = 0;
for (AVM2Instruction ins : code) {
if (offsets.contains(ofs)) {
if (ins.labelname != null) {
ret += ins.labelname + ":";
} else if (offsets.contains(ofs)) {
ret += "ofs" + Helper.formatAddress(ofs) + ":";
}
for (int e = 0; e < body.exceptions.length; e++) {
@@ -737,8 +740,13 @@ public class AVM2Code {
if (ins2.isIgnored()) {
continue;
}
if (ins2.definition instanceof JumpIns) {
ret += "jump ofs" + Helper.formatAddress(pos2adr(ins2.operands[0])) + "\n";
if (ins2.definition instanceof TagInstruction) {
if (ins2.definition.instructionName.equals("appendjump")) {
ret += "jump ofs" + Helper.formatAddress(pos2adr(ins2.operands[0])) + "\n";
}
if (ins2.definition.instructionName.equals("mark")) {
ret += "ofs" + Helper.formatAddress(pos2adr(ins2.operands[0])) + ":";
}
} else {
ret += Highlighting.hilighOffset("", ofs) + ins2.toStringNoAddress(constants, new ArrayList<String>()) + "\n";
}
@@ -1734,7 +1742,7 @@ public class AVM2Code {
if (ex instanceof UnknownJumpException) {
throw (UnknownJumpException) ex;
}
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
throw new ConvertException(ex.getClass().getSimpleName(), ip);
}
}
@@ -1933,7 +1941,7 @@ public class AVM2Code {
s = listToString(list, constants, localRegNames, fullyQualifiedNames);
} catch (Exception ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
s = "/*\r\n * Decompilation error\r\n * Code may be obfuscated\r\n * Error Message: " + ex.getMessage() + "\r\n */";
return s;
}
@@ -2175,8 +2183,6 @@ public class AVM2Code {
code.add(pos, instruction);
}
public int removePushTrueFalseTraps(ConstantPool constants, MethodBody body) throws ConvertException {
removeDeadCode(constants, body);
boolean isSecure = true;
@@ -2328,8 +2334,8 @@ public class AVM2Code {
}
}
}
int ret=isSecure ? 1 : 0;
ret+=visitCodeTrap(body, new int[code.size()]);
int ret = isSecure ? 1 : 0;
ret += visitCodeTrap(body, new int[code.size()]);
removeIgnored(body);
return ret;
}
@@ -2358,11 +2364,11 @@ public class AVM2Code {
int ret = 0;
try {
ret += removePushByteTraps(constants, body);
ret += removePushTrueFalseTraps(constants, body);
ret += removePushTrueFalseTraps(constants, body);
} catch (ConvertException ex) {
ex.printStackTrace();
}
restoreControlFlow(constants, body);
return ret;
}
@@ -2462,10 +2468,11 @@ public class AVM2Code {
return stats;
}
private void visitCode(int ip, int visited[]) {
while (ip < visited.length) {
visited[ip]++;
if (visited[ip] > 1) {
private void visitCode(int ip, int lastIp, HashMap<Integer, List<Integer>> refs) {
while (ip < code.size()) {
refs.get(ip).add(lastIp);
lastIp = ip;
if (refs.get(ip).size() > 1) {
break;
}
AVM2Instruction ins = code.get(ip);
@@ -2481,7 +2488,7 @@ public class AVM2Code {
if (ins.definition instanceof LookupSwitchIns) {
try {
for (int i = 2; i < ins.operands.length; i++) {
visitCode(adr2pos(pos2adr(ip) + ins.operands[i]), visited);
visitCode(adr2pos(pos2adr(ip) + ins.operands[i]), ip, refs);
}
ip = adr2pos(pos2adr(ip) + ins.operands[0]);
continue;
@@ -2493,36 +2500,36 @@ public class AVM2Code {
ip = adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]);
continue;
} catch (ConvertException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
}
} else if (ins.definition instanceof IfTypeIns) {
try {
visitCode(adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]), visited);
visitCode(adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]), ip, refs);
} catch (ConvertException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
}
}
ip++;
};
}
private void visitCode(MethodBody body, int visited[]) {
for (int i = 0; i < visited.length; i++) {
visited[i] = 0;
private void visitCode(MethodBody body, HashMap<Integer, List<Integer>> refs) {
for (int i = 0; i < code.size(); i++) {
refs.put(i, new ArrayList<Integer>());
}
visitCode(0, visited);
visitCode(0, 0, refs);
for (ABCException e : body.exceptions) {
try {
visitCode(adr2pos(e.start), visited);
visitCode(adr2pos(e.target), visited);
visitCode(adr2pos(e.start), adr2pos(e.start), refs);
visitCode(adr2pos(e.target), adr2pos(e.target), refs);
} catch (ConvertException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
}
}
}
private int visitCodeTrap(int ip, int visited[],AVM2Instruction prev) {
int ret=0;
private int visitCodeTrap(int ip, int visited[], AVM2Instruction prev) {
int ret = 0;
while (ip < visited.length) {
visited[ip]++;
if (visited[ip] > 1) {
@@ -2541,10 +2548,10 @@ public class AVM2Code {
if (ins.definition instanceof LookupSwitchIns) {
try {
for (int i = 2; i < ins.operands.length; i++) {
ret+=visitCodeTrap(adr2pos(pos2adr(ip) + ins.operands[i]), visited,prev);
ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.operands[i]), visited, prev);
}
ip = adr2pos(pos2adr(ip) + ins.operands[0]);
prev=ins;
prev = ins;
continue;
} catch (ConvertException ex) {
}
@@ -2552,10 +2559,10 @@ public class AVM2Code {
if (ins.definition instanceof JumpIns) {
try {
ip = adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]);
prev=ins;
prev = ins;
continue;
} catch (ConvertException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
}
} else if (ins.definition instanceof IfTypeIns) {
if ((prev != null) && ins.definition instanceof IfTrueIns) {
@@ -2587,66 +2594,67 @@ public class AVM2Code {
}
}
try {
ret+=visitCodeTrap(adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]), visited,prev);
ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]), visited, prev);
} catch (ConvertException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
}
}
ip++;
prev=ins;
prev = ins;
};
return ret;
}
private int visitCodeTrap(MethodBody body, int visited[]) {
int ret=0;
int ret = 0;
for (int i = 0; i < visited.length; i++) {
visited[i] = 0;
}
ret+=visitCodeTrap(0, visited,null);
ret += visitCodeTrap(0, visited, null);
for (ABCException e : body.exceptions) {
try {
ret+=visitCodeTrap(adr2pos(e.start), visited,null);
ret+=visitCodeTrap(adr2pos(e.target), visited,null);
ret += visitCodeTrap(adr2pos(e.start), visited, null);
ret += visitCodeTrap(adr2pos(e.target), visited, null);
} catch (ConvertException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
}
}
return ret;
}
public void restoreControlFlow(int ip, int visited[], int visited2[], HashMap<Integer, List<AVM2Instruction>> appended) throws ConvertException {
public void restoreControlFlow(int ip, HashMap<Integer, List<Integer>> refs, int visited2[], HashMap<Integer, List<AVM2Instruction>> appended) throws ConvertException {
List<AVM2Instruction> buf = new ArrayList<AVM2Instruction>();
boolean cont = false;
int continueip = 0;
AVM2Instruction prev = null;
for (; ip < visited.length; ip++) {
for (; ip < code.size(); ip++) {
AVM2Instruction ins = code.get(ip);
if (visited2[ip] > 0) {
break;
}
visited2[ip]++;
if (visited[ip] > 1) {
if ((refs.containsKey(ip) && refs.get(ip).size() > 1) || (visited2[ip] > 0)) {
if (cont) {
buf.add(new AVM2Instruction(0, new JumpIns(), new int[]{ip}, new byte[0]));
buf.add(new AVM2Instruction(0, new TagInstruction("appendjump"), new int[]{ip}, new byte[0]));
}
cont = false;
if (visited2[ip] > 0) {
break;
}
}
visited2[ip]++;
if (ins.definition instanceof LookupSwitchIns) {
if (cont) {
buf.add(new AVM2Instruction(0, new JumpIns(), new int[]{ip}, new byte[0]));
}
cont = false;
restoreControlFlow(adr2pos(pos2adr(ip) + ins.operands[0]), visited, visited2, appended);
restoreControlFlow(adr2pos(pos2adr(ip) + ins.operands[0]), refs, visited2, appended);
for (int i = 2; i < ins.operands.length; i++) {
restoreControlFlow(adr2pos(pos2adr(ip) + ins.operands[i]), visited, visited2, appended);
restoreControlFlow(adr2pos(pos2adr(ip) + ins.operands[i]), refs, visited2, appended);
}
break;
}
if (ins.definition instanceof JumpIns) {
int newip = adr2pos(pos2adr(ip + 1) + ins.operands[0]);
if ((newip < visited.length) && (visited[newip] == 1)) {
if ((newip < code.size()) && (refs.containsKey(newip) && refs.get(newip).size() == 1)) {
if (!cont) {
continueip = ip;
buf = new ArrayList<AVM2Instruction>();
@@ -2654,19 +2662,33 @@ public class AVM2Code {
}
cont = true;
} else {
if (cont) {
buf.add(new AVM2Instruction(0, new JumpIns(), new int[]{newip}, new byte[0]));
if (ip == code.size() - 1) {
continueip = ip;
buf = new ArrayList<AVM2Instruction>();
appended.put(continueip, buf);
for (int i : refs.get(newip)) {
if (i != ip) {
code.get(i).labelname = "nolabel" + ip;
}
}
refs.get(newip).clear();
buf.add(new AVM2Instruction(0, new TagInstruction("mark"), new int[]{newip}, new byte[0]));
cont = true;
} else {
if (cont) {
buf.add(new AVM2Instruction(0, new TagInstruction("appendjump"), new int[]{ip}, new byte[0]));
}
cont = false;
}
cont = false;
}
ip = newip - 1;
} else if (ins.definition instanceof IfTypeIns) {
} else if (ins.definition instanceof IfTypeIns) {
int newip = adr2pos(pos2adr(ip + 1) + ins.operands[0]);
if (cont) {
buf.add(new AVM2Instruction(0, new JumpIns(), new int[]{ip}, new byte[0]));
buf.add(new AVM2Instruction(0, new TagInstruction("appendjump"), new int[]{ip}, new byte[0]));
}
cont = false;
restoreControlFlow(newip, visited, visited2, appended);
restoreControlFlow(newip, refs, visited2, appended);
} else if ((ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ThrowIns)) {
if (cont) {
buf.add(ins);
@@ -2680,19 +2702,23 @@ public class AVM2Code {
}
public void restoreControlFlow(ConstantPool constants, MethodBody body) {
private void restoreControlFlowPass(ConstantPool constants, MethodBody body, boolean secondpass) {
try {
int visited[] = new int[code.size()];
HashMap<Integer, List<Integer>> refs = new HashMap<Integer, List<Integer>>();
int visited2[] = new int[code.size()];
visitCode(body, visited);
visitCode(body, refs);
HashMap<Integer, List<AVM2Instruction>> appended = new HashMap<Integer, List<AVM2Instruction>>();
restoreControlFlow(0, visited, visited2, appended);
for (ABCException e : body.exceptions) {
try {
restoreControlFlow(adr2pos(e.start), visited, visited2, appended);
restoreControlFlow(adr2pos(e.target), visited, visited2, appended);
} catch (ConvertException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
if (secondpass) {
restoreControlFlow(code.size() - 1, refs, visited2, appended);
} else {
restoreControlFlow(0, refs, visited2, appended);
for (ABCException e : body.exceptions) {
try {
restoreControlFlow(adr2pos(e.start), refs, visited2, appended);
restoreControlFlow(adr2pos(e.target), refs, visited2, appended);
} catch (ConvertException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
}
}
}
for (int ip : appended.keySet()) {
@@ -2702,20 +2728,22 @@ public class AVM2Code {
}
try {
String src = Highlighting.stripHilights(toASMSource(constants, body));
FileOutputStream fos = new FileOutputStream("src.txt");
fos.write(src.getBytes());
fos.close();
AVM2Code acode = ASM3Parser.parse(new ByteArrayInputStream(src.getBytes()), constants, null, body);
this.code = acode.code;
} catch (IOException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
} catch (ParseException ex) {
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex);
}
invalidateCache();
removeDeadCode(constants, body);
}
public void restoreControlFlow(ConstantPool constants, MethodBody body) {
restoreControlFlowPass(constants, body, false);
restoreControlFlowPass(constants, body, true);
}
private void removeIgnored(MethodBody body) {
for (int rem = code.size() - 1; rem >= 0; rem--) {
if (code.get(rem).ignored) {
@@ -2725,12 +2753,11 @@ public class AVM2Code {
}
public int removeDeadCode(ConstantPool constants, MethodBody body) {
int visited[] = new int[code.size()];
visitCode(body, visited);
HashMap<Integer, List<Integer>> refs = new HashMap<Integer, List<Integer>>();
visitCode(body, refs);
int cnt = 0;
for (int i = visited.length - 1; i >= 0; i--) {
if (visited[i] == 0) {
for (int i = code.size() - 1; i >= 0; i--) {
if (refs.get(i).isEmpty()) {
removeInstruction(i, body);
cnt++;
}
@@ -33,6 +33,7 @@ public class AVM2Instruction {
public byte bytes[];
public String comment;
public boolean ignored = false;
public String labelname;
public AVM2Instruction(long offset, InstructionDefinition definition, int[] operands, byte bytes[]) {
this.definition = definition;
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2010-2013 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.asdec.abc.avm2.instructions;
/**
*
* @author JPEXS
*/
public class TagInstruction extends InstructionDefinition {
public TagInstruction(String tagName) {
super(-1, tagName, new int[0]);
}
}
@@ -42,7 +42,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener {
public ABC abc;
public List<DoABCTag> list;
public JComboBox abcComboBox;
public int listIndex = 0;
public int listIndex = -1;
public DecompiledEditorPane decompiledTextArea;
public JScrollPane decompiledScrollPane;
public JSplitPane splitPaneDecompiledVSDetail;
@@ -175,7 +175,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener {
this.list = list;
if (list.size() > 0) {
this.abc = list.get(listIndex).abc;
this.abc = list.get(0).abc;
}
setLayout(new BorderLayout());
@@ -0,0 +1,144 @@
/*
* Copyright (C) 2010-2013 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.asdec.abc.gui;
import com.jpexs.asdec.gui.View;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
/**
*
* @author JPEXS
*/
public class DeobfuscationDialog extends JDialog implements ActionListener {
public JCheckBox renameIdentifiersCheckbox = new JCheckBox("Rename identifiers");
public JCheckBox processAllCheckbox = new JCheckBox("Process all classes");
public JSlider codeProcessingLevel;
public boolean ok = false;
public static final int LEVEL_NONE = 0;
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;
public DeobfuscationDialog() {
setDefaultCloseOperation(HIDE_ON_CLOSE);
setSize(new Dimension(300, 270));
setTitle("About");
Container cp = getContentPane();
cp.setLayout(null);
codeProcessingLevel = new JSlider(JSlider.VERTICAL, 0, 3, 3);
codeProcessingLevel.setMajorTickSpacing(1);
codeProcessingLevel.setPaintTicks(true);
codeProcessingLevel.setMinorTickSpacing(1);
codeProcessingLevel.setSnapToTicks(true);
JLabel lab1=new JLabel("Code deobfuscation level:");
lab1.setBounds(30, 0, getWidth()-60, 25);
cp.add(lab1);
Hashtable labelTable = new Hashtable();
labelTable.put(new Integer(LEVEL_NONE), new JLabel("None"));
labelTable.put(new Integer(LEVEL_REMOVE_DEAD_CODE), new JLabel("Remove dead code"));
labelTable.put(new Integer(LEVEL_REMOVE_TRAPS), new JLabel("Remove traps"));
labelTable.put(new Integer(LEVEL_RESTORE_CONTROL_FLOW), new JLabel("Restore control flow"));
codeProcessingLevel.setLabelTable(labelTable);
codeProcessingLevel.setPaintLabels(true);
codeProcessingLevel.setAlignmentX(Component.CENTER_ALIGNMENT);
codeProcessingLevel.setSize(300, 200);
renameIdentifiersCheckbox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (renameIdentifiersCheckbox.isSelected()) {
processAllCheckbox.setSelected(true);
}
}
});
processAllCheckbox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(!processAllCheckbox.isSelected()){
renameIdentifiersCheckbox.setSelected(false);
}
}
});
codeProcessingLevel.setBounds(30,25,getWidth()-60,125);
add(codeProcessingLevel);
processAllCheckbox.setBounds(50, 150, getWidth()-100, 25);
add(processAllCheckbox);
renameIdentifiersCheckbox.setBounds(50, 175, getWidth()-100, 25);
add(renameIdentifiersCheckbox);
processAllCheckbox.setSelected(true);
renameIdentifiersCheckbox.setSelected(true);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(this);
cancelButton.setActionCommand("CANCEL");
JButton okButton = new JButton("OK");
okButton.addActionListener(this);
okButton.setActionCommand("OK");
okButton.setBounds(50, 200, 75, 25);
cancelButton.setBounds(145, 200, 75, 25);
cp.add(okButton);
cp.add(cancelButton);
setModal(true);
View.centerScreen(this);
View.setWindowIcon(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("OK")) {
ok = true;
setVisible(false);
}
if (e.getActionCommand().equals("CANCEL")) {
ok = false;
setVisible(false);
}
}
@Override
public void setVisible(boolean b) {
if(b){
ok=false;
}
super.setVisible(b);
}
}
@@ -51,6 +51,9 @@ public class MethodBody implements Cloneable {
public int removeDeadCode(ConstantPool constants){
return code.removeDeadCode(constants,this);
}
public void restoreControlFlow(ConstantPool constants) {
code.restoreControlFlow(constants, this);
}
public int removeTraps(ConstantPool constants){
return code.removeTraps(constants, this);
+102 -5
View File
@@ -20,6 +20,7 @@ import com.jpexs.asdec.Configuration;
import com.jpexs.asdec.Main;
import com.jpexs.asdec.SWF;
import com.jpexs.asdec.abc.gui.ABCPanel;
import com.jpexs.asdec.abc.gui.DeobfuscationDialog;
import com.jpexs.asdec.abc.gui.TreeLeafScript;
import com.jpexs.asdec.action.gui.ActionPanel;
import com.jpexs.asdec.tags.DefineBitsJPEG2Tag;
@@ -95,6 +96,7 @@ public class MainFrame extends JFrame implements ActionListener {
public JLabel statusLabel = new JLabel("");
public JPanel statusPanel = new JPanel();
public JProgressBar progressBar = new JProgressBar(0, 100);
private DeobfuscationDialog deobfuscationDialog;
public void setPercent(int percent) {
progressBar.setValue(percent);
@@ -220,6 +222,14 @@ public class MainFrame extends JFrame implements ActionListener {
menuFile.add(miClose);
menuBar.add(menuFile);
JMenu menuDeobfuscation = new JMenu("Deobfuscation");
JMenuItem miDeobfuscation = new JMenuItem("Deobfuscation...");
miDeobfuscation.setActionCommand("DEOBFUSCATE");
miDeobfuscation.addActionListener(this);
JCheckBoxMenuItem miSubLimiter = new JCheckBoxMenuItem("Enable sub limiter");
miSubLimiter.setActionCommand("SUBLIMITER");
miSubLimiter.addActionListener(this);
@@ -244,14 +254,26 @@ public class MainFrame extends JFrame implements ActionListener {
miTrapsAll.setActionCommand("REMOVETRAPSALL");
miTrapsAll.addActionListener(this);
menuDeobfuscation.add(miSubLimiter);
JMenuItem miControlFlow = new JMenuItem("Restore control flow");
miControlFlow.setActionCommand("RESTORECONTROLFLOW");
miControlFlow.addActionListener(this);
JMenuItem miControlFlowAll = new JMenuItem("Restore all control flow");
miControlFlowAll.setActionCommand("RESTORECONTROLFLOWALL");
miControlFlowAll.addActionListener(this);
//menuDeobfuscation.add(miSubLimiter);
//menuDeobfuscation.add(miDeobfuscate);
/*menuDeobfuscation.add(miDeobfuscate);
menuDeobfuscation.addSeparator();
menuDeobfuscation.add(miRenameIdentifiers);
menuDeobfuscation.add(miRemoveDeadCode);
menuDeobfuscation.add(miRemoveDeadCodeAll);
menuDeobfuscation.add(miTraps);
menuDeobfuscation.add(miTrapsAll);
menuDeobfuscation.add(miControlFlow);
menuDeobfuscation.add(miControlFlowAll);
*/
JMenu menuTools = new JMenu("Tools");
JMenuItem miProxy = new JMenuItem("Proxy");
miProxy.setActionCommand("SHOWPROXY");
@@ -259,7 +281,8 @@ public class MainFrame extends JFrame implements ActionListener {
miProxy.addActionListener(this);
menuTools.add(miProxy);
menuTools.add(menuDeobfuscation);
//menuTools.add(menuDeobfuscation);
menuTools.add(miDeobfuscation);
menuBar.add(menuTools);
JMenu menuHelp = new JMenu("Help");
@@ -305,7 +328,7 @@ public class MainFrame extends JFrame implements ActionListener {
if (actionPanel.tagTree.getRowCount() > 1) {
addTab(tabPane, actionPanel, "ActionScript", new ImageIcon(this.getClass().getClassLoader().getResource("com/jpexs/asdec/gui/graphics/as16.png")));
}
menuDeobfuscation.setEnabled(false);
miDeobfuscation.setEnabled(false);
}
if (!shapes.isEmpty()) {
@@ -737,6 +760,34 @@ public class MainFrame extends JFrame implements ActionListener {
}
}
if (e.getActionCommand().startsWith("RESTORECONTROLFLOW")) {
Main.startWork("Restoring control flow...");
final boolean all = e.getActionCommand().endsWith("ALL");
if ((!all) || confirmExperimental()) {
new SwingWorker() {
@Override
protected Object doInBackground() throws Exception {
int cnt = 0;
if (all) {
for (DoABCTag tag : abcPanel.list) {
tag.abc.restoreControlFlow();
}
} else {
int bi = abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getBodyIndex();
if (bi != -1) {
abcPanel.abc.bodies[bi].restoreControlFlow(abcPanel.abc.constants);
}
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setBodyIndex(bi, abcPanel.abc);
}
Main.stopWork();
JOptionPane.showMessageDialog(null, "Control flow restored");
abcPanel.reload();
return true;
}
}.execute();
}
}
if (e.getActionCommand().startsWith("REMOVETRAPS")) {
Main.startWork("Removing traps...");
final boolean all = e.getActionCommand().endsWith("ALL");
@@ -815,5 +866,51 @@ public class MainFrame extends JFrame implements ActionListener {
}
}
if (e.getActionCommand().startsWith("DEOBFUSCATE")) {
if(deobfuscationDialog==null){
deobfuscationDialog = new DeobfuscationDialog();
}
deobfuscationDialog.setVisible(true);
if (deobfuscationDialog.ok) {
Main.startWork("Deobfuscating...");
new SwingWorker() {
@Override
protected Object doInBackground() throws Exception {
if (deobfuscationDialog.processAllCheckbox.isSelected()) {
for (DoABCTag tag : abcPanel.list) {
if (deobfuscationDialog.renameIdentifiersCheckbox.isSelected()) {
tag.abc.deobfuscateIdentifiers();
}
if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_REMOVE_DEAD_CODE) {
tag.abc.removeDeadCode();
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_REMOVE_TRAPS) {
tag.abc.removeTraps();
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_RESTORE_CONTROL_FLOW) {
tag.abc.removeTraps();
tag.abc.restoreControlFlow();
}
}
} else {
int bi = abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getBodyIndex();
if (bi != -1) {
if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_REMOVE_DEAD_CODE) {
abcPanel.abc.bodies[bi].removeDeadCode(abcPanel.abc.constants);
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_REMOVE_TRAPS) {
abcPanel.abc.bodies[bi].removeTraps(abcPanel.abc.constants);
} else if (deobfuscationDialog.codeProcessingLevel.getValue() == DeobfuscationDialog.LEVEL_RESTORE_CONTROL_FLOW) {
abcPanel.abc.bodies[bi].removeTraps(abcPanel.abc.constants);
abcPanel.abc.bodies[bi].restoreControlFlow(abcPanel.abc.constants);
}
}
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setBodyIndex(bi, abcPanel.abc);
}
Main.stopWork();
JOptionPane.showMessageDialog(null, "Deobfuscation complete");
abcPanel.reload();
return true;
}
}.execute();
}
}
}
}