diff --git a/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index db7459cdc..efc408535 100644 --- a/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -1,253 +1,247 @@ -/* - * Copyright (C) 2010-2014 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.decompiler.flash.abc.types; - -import com.jpexs.decompiler.flash.AppStrings; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.avm2.CodeStats; -import com.jpexs.decompiler.flash.abc.avm2.ConstantPool; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.abc.types.traits.Traits; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.graph.Graph; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.model.LocalData; -import com.jpexs.helpers.CancellableWorker; -import com.jpexs.helpers.Helper; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Stack; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class MethodBody implements Cloneable, Serializable { - - public boolean deleted; - boolean debugMode = false; - public int method_info; - public int max_stack; - public int max_regs; - public int init_scope_depth; - public int max_scope_depth; - public byte[] codeBytes; - public AVM2Code code; - public ABCException[] exceptions = new ABCException[0]; - public Traits traits = new Traits(); - public transient List convertedItems; - public transient Exception convertException; - - public List getExceptionEntries() { - List ret = new ArrayList<>(); - for (ABCException e : exceptions) { - ret.add(code.adr2pos(e.start)); - ret.add(code.adr2pos(e.end)); - ret.add(code.adr2pos(e.target)); - } - return ret; - } - - public void markOffsets() { - long offset = 0; - for (int i = 0; i < code.code.size(); i++) { - code.code.get(i).offset = offset; - offset += code.code.get(i).getBytes().length; - } - } - - @Override - public String toString() { - String s = ""; - s += "method_info=" + method_info + " max_stack=" + max_stack + " max_regs=" + max_regs + " scope_depth=" + init_scope_depth + " max_scope=" + max_scope_depth; - s += "\r\nCode:\r\n" + code.toString(); - return s; - } - - public int removeDeadCode(ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException { - return code.removeDeadCode(constants, trait, info, this); - } - - public void restoreControlFlow(ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException { - code.restoreControlFlow(constants, trait, info, this); - } - - public int removeTraps(ConstantPool constants, ABC abc, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { - return code.removeTraps(constants, trait, abc.method_info.get(method_info), this, abc, scriptIndex, classIndex, isStatic, path); - } - - public HashMap getLocalRegNames(ABC abc) { - HashMap ret = new HashMap<>(); - for (int i = 1; i <= abc.method_info.get(this.method_info).param_types.length; i++) { - String paramName = "param" + i; - if (abc.method_info.get(this.method_info).flagHas_paramnames() && Configuration.paramNamesEnable.get()) { - paramName = abc.constants.getString(abc.method_info.get(this.method_info).paramNames[i - 1]); - } - ret.put(i, paramName); - } - int pos = abc.method_info.get(this.method_info).param_types.length + 1; - if (abc.method_info.get(this.method_info).flagNeed_arguments()) { - ret.put(pos, "arguments"); - pos++; - } - if (abc.method_info.get(this.method_info).flagNeed_rest()) { - ret.put(pos, "rest"); - pos++; - } - - HashMap debugRegNames = code.getLocalRegNamesFromDebug(abc); - for (int k : debugRegNames.keySet()) { - ret.put(k, debugRegNames.get(k)); - } - return ret; - } - - public void convert(final String path, ScriptExportMode exportMode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ConstantPool constants, final List method_info, final Stack scopeStack, final boolean isStaticInitializer, final GraphTextWriter writer, final List fullyQualifiedNames, final Traits initTraits, boolean firstLevel) throws InterruptedException { - if (debugMode) { - System.err.println("Decompiling " + path); - } - if (exportMode != ScriptExportMode.AS) { - code.toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer); - } else { - if (!Configuration.decompile.get()) { - writer.appendNoHilight("//" + AppStrings.translate("decompilation.skipped")).newLine(); - return; - } - int timeout = Configuration.decompilationTimeoutSingleMethod.get(); - try { - Callable callable = new Callable() { - @Override - public Void call() throws InterruptedException { - MethodBody converted = convertMethodBody(path, isStatic, scriptIndex, classIndex, abc, trait, constants, method_info, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits); - HashMap localRegNames = getLocalRegNames(abc); - convertedItems = converted.code.toGraphTargetItems(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, converted, localRegNames, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap(), converted.code.visitCode(converted)); - Graph.graphToString(convertedItems, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames)); - return null; - } - }; - if (firstLevel) { - CancellableWorker.call(callable, timeout, TimeUnit.SECONDS); - } else { - callable.call(); - } - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", ex); - convertException = ex; - if (ex instanceof ExecutionException && ex.getCause() instanceof Exception) { - convertException = (Exception) ex.getCause(); - } - } - } - } - - public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ConstantPool constants, final List method_info, final Stack scopeStack, final boolean isStaticInitializer, final GraphTextWriter writer, final List fullyQualifiedNames, final Traits initTraits) throws InterruptedException { - if (exportMode != ScriptExportMode.AS) { - writer.indent(); - code.toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer); - writer.unindent(); - } else { - if (!Configuration.decompile.get()) { - writer.indent(); - writer.startMethod(this.method_info); - writer.appendNoHilight("//" + AppStrings.translate("decompilation.skipped")).newLine(); - writer.endMethod(); - writer.unindent(); - return writer; - } - writer.indent(); - int timeout = Configuration.decompilationTimeoutSingleMethod.get(); - - if (convertException == null) { - HashMap localRegNames = getLocalRegNames(abc); - writer.startMethod(this.method_info); - Graph.graphToString(convertedItems, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames)); - writer.endMethod(); - } else if (convertException instanceof TimeoutException) { - Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", convertException); - Helper.appendTimeoutComment(writer, timeout); - } else { - Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", convertException); - Helper.appendErrorComment(writer, convertException); - } - writer.unindent(); - } - return writer; - } - - public MethodBody convertMethodBody(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, ConstantPool constants, List method_info, Stack scopeStack, boolean isStaticInitializer, List fullyQualifiedNames, Traits initTraits) throws InterruptedException { - MethodBody b = Helper.deepCopy(this); - AVM2Code deobfuscated = b.code; - deobfuscated.markMappedOffsets(); - if (Configuration.autoDeobfuscate.get()) { - try { - deobfuscated.removeTraps(constants, trait, method_info.get(this.method_info), b, abc, scriptIndex, classIndex, isStatic, path); - } catch (StackOverflowError ex) { - Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex); - } - } - //deobfuscated.restoreControlFlow(constants, b); - - return b; - } - - @Override - public Object clone() throws CloneNotSupportedException { - MethodBody ret = new MethodBody(); - ret.code = code; - ret.codeBytes = codeBytes; - ret.exceptions = exceptions; - ret.max_regs = max_regs; - ret.max_scope_depth = max_scope_depth; - ret.max_stack = max_stack; - ret.method_info = method_info; - ret.init_scope_depth = init_scope_depth; - ret.traits = traits; //maybe deep clone - return ret; - } - - public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) { - //System.out.println("--------------"); - CodeStats stats = code.getStats(abc, this, initScope); - if (stats == null) { - return false; - } - if (stats.has_activation) { - initScope++; - } - max_stack = stats.maxstack; - max_scope_depth = stats.maxscope + (stats.has_activation ? 1 : 0); - max_regs = stats.maxlocal; - init_scope_depth = initScope; - abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns); - abc.method_info.get(method_info).setFlagNeed_activation(stats.has_activation); - MethodInfo mi = abc.method_info.get(method_info); - int min_regs = mi.param_types.length + (hasThis ? 1 : 0) + (mi.flagNeed_rest() ? 1 : 0); - if (max_regs < min_regs) { - max_regs = min_regs; - } - return true; - } -} +/* + * Copyright (C) 2010-2014 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.decompiler.flash.abc.types; + +import com.jpexs.decompiler.flash.AppStrings; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.CodeStats; +import com.jpexs.decompiler.flash.abc.avm2.ConstantPool; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.abc.types.traits.Traits; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.Graph; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.model.LocalData; +import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Stack; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class MethodBody implements Cloneable, Serializable { + + public boolean deleted; + boolean debugMode = false; + public int method_info; + public int max_stack; + public int max_regs; + public int init_scope_depth; + public int max_scope_depth; + public byte[] codeBytes; + public AVM2Code code; + public ABCException[] exceptions = new ABCException[0]; + public Traits traits = new Traits(); + public transient List convertedItems; + public transient Exception convertException; + + public List getExceptionEntries() { + List ret = new ArrayList<>(); + for (ABCException e : exceptions) { + ret.add(code.adr2pos(e.start)); + ret.add(code.adr2pos(e.end)); + ret.add(code.adr2pos(e.target)); + } + return ret; + } + + public void markOffsets() { + long offset = 0; + for (int i = 0; i < code.code.size(); i++) { + code.code.get(i).offset = offset; + offset += code.code.get(i).getBytes().length; + } + } + + @Override + public String toString() { + String s = ""; + s += "method_info=" + method_info + " max_stack=" + max_stack + " max_regs=" + max_regs + " scope_depth=" + init_scope_depth + " max_scope=" + max_scope_depth; + s += "\r\nCode:\r\n" + code.toString(); + return s; + } + + public int removeDeadCode(ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException { + return code.removeDeadCode(constants, trait, info, this); + } + + public void restoreControlFlow(ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException { + code.restoreControlFlow(constants, trait, info, this); + } + + public int removeTraps(ConstantPool constants, ABC abc, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { + return code.removeTraps(constants, trait, abc.method_info.get(method_info), this, abc, scriptIndex, classIndex, isStatic, path); + } + + public HashMap getLocalRegNames(ABC abc) { + HashMap ret = new HashMap<>(); + for (int i = 1; i <= abc.method_info.get(this.method_info).param_types.length; i++) { + String paramName = "param" + i; + if (abc.method_info.get(this.method_info).flagHas_paramnames() && Configuration.paramNamesEnable.get()) { + paramName = abc.constants.getString(abc.method_info.get(this.method_info).paramNames[i - 1]); + } + ret.put(i, paramName); + } + int pos = abc.method_info.get(this.method_info).param_types.length + 1; + if (abc.method_info.get(this.method_info).flagNeed_arguments()) { + ret.put(pos, "arguments"); + pos++; + } + if (abc.method_info.get(this.method_info).flagNeed_rest()) { + ret.put(pos, "rest"); + pos++; + } + + HashMap debugRegNames = code.getLocalRegNamesFromDebug(abc); + for (int k : debugRegNames.keySet()) { + ret.put(k, debugRegNames.get(k)); + } + return ret; + } + + public void convert(final String path, ScriptExportMode exportMode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ConstantPool constants, final List method_info, final Stack scopeStack, final boolean isStaticInitializer, final GraphTextWriter writer, final List fullyQualifiedNames, final Traits initTraits, boolean firstLevel) throws InterruptedException { + if (debugMode) { + System.err.println("Decompiling " + path); + } + if (exportMode != ScriptExportMode.AS) { + code.toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer); + } else { + if (!Configuration.decompile.get()) { + writer.appendNoHilight("//" + AppStrings.translate("decompilation.skipped")).newLine(); + return; + } + int timeout = Configuration.decompilationTimeoutSingleMethod.get(); + try { + Callable callable = new Callable() { + @Override + public Void call() throws InterruptedException { + MethodBody converted = convertMethodBody(path, isStatic, scriptIndex, classIndex, abc, trait, constants, method_info, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits); + HashMap localRegNames = getLocalRegNames(abc); + convertedItems = converted.code.toGraphTargetItems(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, converted, localRegNames, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap(), converted.code.visitCode(converted)); + Graph.graphToString(convertedItems, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames)); + return null; + } + }; + if (firstLevel) { + CancellableWorker.call(callable, timeout, TimeUnit.SECONDS); + } else { + callable.call(); + } + } catch (InterruptedException ex) { + throw ex; + } catch (Exception ex) { + Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", ex); + convertException = ex; + if (ex instanceof ExecutionException && ex.getCause() instanceof Exception) { + convertException = (Exception) ex.getCause(); + } + } + } + } + + public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ConstantPool constants, final List method_info, final Stack scopeStack, final boolean isStaticInitializer, final GraphTextWriter writer, final List fullyQualifiedNames, final Traits initTraits) throws InterruptedException { + if (exportMode != ScriptExportMode.AS) { + code.toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer); + } else { + if (!Configuration.decompile.get()) { + writer.startMethod(this.method_info); + writer.appendNoHilight("//" + AppStrings.translate("decompilation.skipped")).newLine(); + writer.endMethod(); + return writer; + } + int timeout = Configuration.decompilationTimeoutSingleMethod.get(); + + if (convertException == null) { + HashMap localRegNames = getLocalRegNames(abc); + writer.startMethod(this.method_info); + Graph.graphToString(convertedItems, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames)); + writer.endMethod(); + } else if (convertException instanceof TimeoutException) { + Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", convertException); + Helper.appendTimeoutComment(writer, timeout); + } else { + Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", convertException); + Helper.appendErrorComment(writer, convertException); + } + } + return writer; + } + + public MethodBody convertMethodBody(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, ConstantPool constants, List method_info, Stack scopeStack, boolean isStaticInitializer, List fullyQualifiedNames, Traits initTraits) throws InterruptedException { + MethodBody b = Helper.deepCopy(this); + AVM2Code deobfuscated = b.code; + deobfuscated.markMappedOffsets(); + if (Configuration.autoDeobfuscate.get()) { + try { + deobfuscated.removeTraps(constants, trait, method_info.get(this.method_info), b, abc, scriptIndex, classIndex, isStatic, path); + } catch (StackOverflowError ex) { + Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex); + } + } + //deobfuscated.restoreControlFlow(constants, b); + + return b; + } + + @Override + public Object clone() throws CloneNotSupportedException { + MethodBody ret = new MethodBody(); + ret.code = code; + ret.codeBytes = codeBytes; + ret.exceptions = exceptions; + ret.max_regs = max_regs; + ret.max_scope_depth = max_scope_depth; + ret.max_stack = max_stack; + ret.method_info = method_info; + ret.init_scope_depth = init_scope_depth; + ret.traits = traits; //maybe deep clone + return ret; + } + + public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) { + //System.out.println("--------------"); + CodeStats stats = code.getStats(abc, this, initScope); + if (stats == null) { + return false; + } + if (stats.has_activation) { + initScope++; + } + max_stack = stats.maxstack; + max_scope_depth = stats.maxscope + (stats.has_activation ? 1 : 0); + max_regs = stats.maxlocal; + init_scope_depth = initScope; + abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns); + abc.method_info.get(method_info).setFlagNeed_activation(stats.has_activation); + MethodInfo mi = abc.method_info.get(method_info); + int min_regs = mi.param_types.length + (hasThis ? 1 : 0) + (mi.flagNeed_rest() ? 1 : 0); + if (max_regs < min_regs) { + max_regs = min_regs; + } + return true; + } +} diff --git a/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java b/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java index 14bf711e2..64a259e70 100644 --- a/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java +++ b/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java @@ -133,12 +133,10 @@ public abstract class Trait implements Serializable { Namespace ns = abc.constants.getMultiname(name_index).getNamespace(abc.constants); if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) { String nsname = ns.getName(abc.constants); - writer.appendNoHilight("package " + nsname).newLine(); //assume not null name - writer.appendNoHilight("{").newLine(); - writer.indent(); + writer.appendNoHilight("package " + nsname); //assume not null name + writer.startBlock(); toString(parent, path, abcTags, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); - writer.unindent(); - writer.appendNoHilight("}"); + writer.endBlock(); writer.newLine(); } return writer;