avm2 instruction is not serializable anymore, AS2 swf in AS3 binarydata fix

This commit is contained in:
honfika@gmail.com
2014-09-07 00:15:01 +02:00
parent 334e6be6db
commit 946018749e
8 changed files with 161 additions and 134 deletions

View File

@@ -12,14 +12,17 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash;
import java.io.IOException;
/**
*
* @author JPEXS
*/
*/
public class EndOfStreamException extends IOException {
public EndOfStreamException() {
super("Premature end of the stream reached");

View File

@@ -983,7 +983,7 @@ public class SWFInputStream implements AutoCloseable {
dumpInfo.name = t.getName();
}
return t;
} catch (EndOfStreamException ex) {
} catch (Exception ex) {
tag.getDataStream().endDumpLevelUntil(di);
logger.log(Level.SEVERE, null, ex);
return tag;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc;
import com.jpexs.decompiler.flash.EndOfStreamException;
import com.jpexs.decompiler.flash.abc.types.Decimal;
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
@@ -103,6 +105,9 @@ public class ABCInputStream implements AutoCloseable {
private int readInternal() throws IOException {
bytesRead++;
int i = is.read();
if (i == -1) {
throw new EndOfStreamException();
}
if (DEBUG_READ) {
System.out.println("Read:0x" + Integer.toHexString(i));
}

View File

@@ -16,6 +16,7 @@
*/
package com.jpexs.decompiler.flash.abc.avm2;
import com.jpexs.decompiler.flash.EndOfStreamException;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ABCInputStream;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
@@ -234,10 +235,7 @@ import com.jpexs.helpers.Helper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
@@ -248,9 +246,8 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AVM2Code implements Serializable {
public class AVM2Code implements Cloneable {
public static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(AVM2Code.class.getName());
private static final boolean DEBUG_MODE = false;
public static int toSourceLimit = -1;
@@ -787,54 +784,58 @@ public class AVM2Code implements Serializable {
}
public AVM2Code(ABCInputStream ais) throws IOException {
while (ais.available() > 0) {
DumpInfo di = ais.newDumpLevel("instruction", "instruction");
long startOffset = ais.getPosition();
int instructionCode = ais.read("instructionCode");
InstructionDefinition instr = instructionSetByCode[instructionCode];
if (di != null) {
di.name = instr.instructionName;
}
if (instr != null) {
int[] actualOperands = null;
if (instructionCode == 0x1b) { //switch
int firstOperand = ais.readS24("firstOperand");
int case_count = ais.readU30("case_count");
actualOperands = new int[case_count + 3];
actualOperands[0] = firstOperand;
actualOperands[1] = case_count;
for (int c = 0; c < case_count + 1; c++) {
actualOperands[2 + c] = ais.readS24("actualOperand");
}
} else {
if (instr.operands.length > 0) {
actualOperands = new int[instr.operands.length];
for (int op = 0; op < instr.operands.length; op++) {
switch (instr.operands[op] & 0xff00) {
case OPT_U30:
actualOperands[op] = ais.readU30("operand");
break;
case OPT_U8:
actualOperands[op] = ais.read("operand");
break;
case OPT_BYTE:
actualOperands[op] = (byte) ais.read("operand");
break;
case OPT_S24:
actualOperands[op] = ais.readS24("operand");
break;
try {
while (ais.available() > 0) {
DumpInfo di = ais.newDumpLevel("instruction", "instruction");
long startOffset = ais.getPosition();
int instructionCode = ais.read("instructionCode");
InstructionDefinition instr = instructionSetByCode[instructionCode];
if (di != null) {
di.name = instr.instructionName;
}
if (instr != null) {
int[] actualOperands = null;
if (instructionCode == 0x1b) { //switch
int firstOperand = ais.readS24("default_offset");
int case_count = ais.readU30("case_count");
actualOperands = new int[case_count + 3];
actualOperands[0] = firstOperand;
actualOperands[1] = case_count;
for (int c = 0; c < case_count + 1; c++) {
actualOperands[2 + c] = ais.readS24("actualOperand");
}
} else {
if (instr.operands.length > 0) {
actualOperands = new int[instr.operands.length];
for (int op = 0; op < instr.operands.length; op++) {
switch (instr.operands[op] & 0xff00) {
case OPT_U30:
actualOperands[op] = ais.readU30("operand");
break;
case OPT_U8:
actualOperands[op] = ais.read("operand");
break;
case OPT_BYTE:
actualOperands[op] = (byte) ais.read("operand");
break;
case OPT_S24:
actualOperands[op] = ais.readS24("operand");
break;
}
}
}
}
}
code.add(new AVM2Instruction(startOffset, instr, actualOperands));
ais.endDumpLevel(instr.instructionCode);
} else {
ais.endDumpLevel();
break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions)
//throw new UnknownInstructionCode(instructionCode);
code.add(new AVM2Instruction(startOffset, instr, actualOperands));
ais.endDumpLevel(instr.instructionCode);
} else {
ais.endDumpLevel();
break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions)
//throw new UnknownInstructionCode(instructionCode);
}
}
} catch (EndOfStreamException ex) {
// lookupswitch obfuscation, ignore
}
}
@@ -2433,24 +2434,6 @@ public class AVM2Code implements Serializable {
}
}
public AVM2Code deepCopy() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(this);
oos.flush();
}
AVM2Code copy;
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
copy = (AVM2Code) ois.readObject();
}
return copy;
} catch (IOException | ClassNotFoundException ex) {
logger.log(Level.SEVERE, "Error during deepCopy", ex);
return null;
}
}
private static class Decision {
public boolean jumpUsed = false;
@@ -2890,4 +2873,18 @@ public class AVM2Code implements Serializable {
AVM2Graph.translateViaGraph(localData, "", code, new ArrayList<Integer>(), Graph.SOP_REMOVE_STATIC);
return 1;
}*/
@SuppressWarnings("unchecked")
@Override
public Object clone() throws CloneNotSupportedException {
AVM2Code ret = (AVM2Code) super.clone();
if (code != null) {
List<AVM2Instruction> codeCopy = new ArrayList<>(code.size());
for (AVM2Instruction ins : code) {
codeCopy.add((AVM2Instruction) ins.clone());
}
ret.code = codeCopy;
}
return ret;
}
}

View File

@@ -35,13 +35,12 @@ import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.helpers.Helper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AVM2Instruction implements Serializable, GraphSourceItem {
public class AVM2Instruction implements Cloneable, GraphSourceItem {
public static final long serialVersionUID = 1L;
public InstructionDefinition definition;
public int[] operands;
public long offset;
@@ -360,4 +359,13 @@ public class AVM2Instruction implements Serializable, GraphSourceItem {
public boolean isDeobfuscatePop() {
return definition instanceof DeobfuscatePopIns;
}
@Override
public Object clone() throws CloneNotSupportedException {
AVM2Instruction ret = (AVM2Instruction) super.clone();
if (operands != null) {
ret.operands = Arrays.copyOf(operands, operands.length);
}
return ret;
}
}

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
@@ -100,7 +101,7 @@ public abstract class AssignableAVM2Item extends AVM2Item {
ret.add(ins(new KillIns(), register.getVal()));
return ret;
}*/
}*/
public static List<GraphSourceItem> killTemp(SourceGeneratorLocalData localData, SourceGenerator generator, List<Reference<Integer>> registers) {
List<GraphSourceItem> ret = new ArrayList<>();
for (Reference<Integer> register : registers) {

View File

@@ -35,7 +35,6 @@ import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -46,7 +45,7 @@ import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MethodBody implements Cloneable, Serializable {
public class MethodBody implements Cloneable {
public boolean deleted;
boolean debugMode = false;
@@ -221,7 +220,7 @@ public class MethodBody implements Cloneable, Serializable {
}
public MethodBody convertMethodBody(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, AVM2ConstantPool constants, List<MethodInfo> method_info, ScopeStack scopeStack, boolean isStaticInitializer, List<String> fullyQualifiedNames, Traits initTraits) throws InterruptedException {
MethodBody b = Helper.deepCopy(this);
MethodBody b = (MethodBody) clone();
AVM2Code deobfuscated = b.getCode();
deobfuscated.markMappedOffsets();
if (Configuration.autoDeobfuscate.get()) {
@@ -237,18 +236,25 @@ public class MethodBody implements Cloneable, Serializable {
}
@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 Object clone() {
try {
MethodBody ret = (MethodBody) super.clone();
if (code != null) {
ret.code = (AVM2Code) code.clone();
}
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;
} catch (CloneNotSupportedException ex) {
Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) {