mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-24 23:00:46 +00:00
AS3 deobfuscation
This commit is contained in:
@@ -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++) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user