diff --git a/trunk/src/com/jpexs/asdec/abc/ABC.java b/trunk/src/com/jpexs/asdec/abc/ABC.java index 5ede0e26c..6e1420000 100644 --- a/trunk/src/com/jpexs/asdec/abc/ABC.java +++ b/trunk/src/com/jpexs/asdec/abc/ABC.java @@ -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++) { diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/AVM2Code.java b/trunk/src/com/jpexs/asdec/abc/avm2/AVM2Code.java index 108f304f4..cbda1becc 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/AVM2Code.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/AVM2Code.java @@ -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()) + "\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> 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> refs) { + for (int i = 0; i < code.size(); i++) { + refs.put(i, new ArrayList()); } - 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> appended) throws ConvertException { + public void restoreControlFlow(int ip, HashMap> refs, int visited2[], HashMap> appended) throws ConvertException { List buf = new ArrayList(); 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(); @@ -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(); + 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> refs = new HashMap>(); int visited2[] = new int[code.size()]; - visitCode(body, visited); + visitCode(body, refs); HashMap> appended = new HashMap>(); - 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> refs = new HashMap>(); + 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++; } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/AVM2Instruction.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/AVM2Instruction.java index 0fc3ae3ea..6b82ebb95 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/AVM2Instruction.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/AVM2Instruction.java @@ -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; diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/TagInstruction.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/TagInstruction.java new file mode 100644 index 000000000..07ffe0b0f --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/TagInstruction.java @@ -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 . + */ +package com.jpexs.asdec.abc.avm2.instructions; + +/** + * + * @author JPEXS + */ +public class TagInstruction extends InstructionDefinition { + + public TagInstruction(String tagName) { + super(-1, tagName, new int[0]); + } + + + +} diff --git a/trunk/src/com/jpexs/asdec/abc/gui/ABCPanel.java b/trunk/src/com/jpexs/asdec/abc/gui/ABCPanel.java index 053367257..fdb1303d1 100644 --- a/trunk/src/com/jpexs/asdec/abc/gui/ABCPanel.java +++ b/trunk/src/com/jpexs/asdec/abc/gui/ABCPanel.java @@ -42,7 +42,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener { public ABC abc; public List 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()); diff --git a/trunk/src/com/jpexs/asdec/abc/gui/DeobfuscationDialog.java b/trunk/src/com/jpexs/asdec/abc/gui/DeobfuscationDialog.java new file mode 100644 index 000000000..ed2d6bc8b --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/gui/DeobfuscationDialog.java @@ -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 . + */ +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); + } + + +} diff --git a/trunk/src/com/jpexs/asdec/abc/types/MethodBody.java b/trunk/src/com/jpexs/asdec/abc/types/MethodBody.java index 5a1036420..480b0ae0b 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/MethodBody.java +++ b/trunk/src/com/jpexs/asdec/abc/types/MethodBody.java @@ -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); diff --git a/trunk/src/com/jpexs/asdec/gui/MainFrame.java b/trunk/src/com/jpexs/asdec/gui/MainFrame.java index 5abbd39a4..9ec37b251 100644 --- a/trunk/src/com/jpexs/asdec/gui/MainFrame.java +++ b/trunk/src/com/jpexs/asdec/gui/MainFrame.java @@ -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(); + } + } } }