From 738b26ccc1df3a6db56449e5d7a1ad84b7c87013 Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Sat, 4 Jul 2015 14:23:37 +0200 Subject: [PATCH] AS3 deobfuscation fix (jumps after the end), faster instruction length calculation --- .../decompiler/flash/abc/ABCOutputStream.java | 591 ++--- .../decompiler/flash/abc/avm2/AVM2Code.java | 71 +- .../deobfuscation/AVM2DeobfuscatorJumps.java | 5 +- .../AVM2DeobfuscatorRegisters.java | 2 +- .../deobfuscation/AVM2DeobfuscatorSimple.java | 14 +- .../flash/abc/avm2/graph/AVM2Graph.java | 8 +- .../avm2/instructions/AVM2Instruction.java | 46 +- .../abc/avm2/parser/pcode/ASM3Parser.java | 1980 ++++++++--------- .../parser/script/AVM2SourceGenerator.java | 16 +- .../script/ExceptionMarkAVM2Instruction.java | 5 + .../flash/abc/types/MethodBody.java | 6 +- .../jpexs/decompiler/flash/ABCStreamTest.java | 84 +- .../flash/ActionScript3DeobfuscatorTest.java | 3 +- 13 files changed, 1487 insertions(+), 1344 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABCOutputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABCOutputStream.java index cdbb29b7a..a37781707 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABCOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABCOutputStream.java @@ -1,285 +1,306 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ -package com.jpexs.decompiler.flash.abc; - -import com.jpexs.decompiler.flash.abc.types.Decimal; -import com.jpexs.decompiler.flash.abc.types.InstanceInfo; -import com.jpexs.decompiler.flash.abc.types.MethodInfo; -import com.jpexs.decompiler.flash.abc.types.Multiname; -import com.jpexs.decompiler.flash.abc.types.Namespace; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.abc.types.traits.TraitClass; -import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; -import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; -import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; -import com.jpexs.decompiler.flash.abc.types.traits.Traits; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.IOException; -import java.io.OutputStream; - -public class ABCOutputStream extends OutputStream { - - private final OutputStream os; - - public ABCOutputStream(OutputStream os) { - this.os = os; - } - - @Override - public void write(int b) throws IOException { - os.write(b); - } - - public void writeU30(long value) throws IOException { - writeS32(value); - /*boolean loop = true; - boolean underZero=value<0; - - if(underZero){ - value = value & 0xFFFFFFFF; - }else{ - value = value & 0x7FFFFFFF; - } - do { - int ret = (int) (value & 0x7F); - if (value < 0x80) { - loop = false; - } - if (value > 0x7F) { - ret += 0x80; - } - write(ret); - value = value >> 7; - } while (loop); - */ - } - - public void writeU32(long value) throws IOException { - boolean loop = true; - value &= 0xFFFFFFFF; - do { - int ret = (int) (value & 0x7F); - if (value < 0x80) { - loop = false; - } - if (value > 0x7F) { - ret += 0x80; - } - write(ret); - value >>= 7; - } while (loop); - } - - public void writeS24(long value) throws IOException { - int ret = (int) (value & 0xff); - write(ret); - value >>= 8; - ret = (int) (value & 0xff); - write(ret); - value >>= 8; - ret = (int) (value & 0xff); - write(ret); - } - - public void writeS32(long value) throws IOException { - boolean belowZero = value < 0; - /*if (belowZero) { - value = -value; - }*/ - int bitcount = 0; - boolean loop = true; - //value = value & 0xFFFFFFFF; - do { - bitcount += 7; - int ret = (int) (value & 0x7F); - if (value < 0x80) { - if (belowZero) { //&& bitcount < 35 - ret += 0x80; - } else { - loop = false; - } - } else { - ret += 0x80; - } - - if (bitcount == 35) { - ret &= 0xf; - } - write(ret); - if (bitcount == 35) { - break; - } - value >>= 7; - } while (loop); - } - - public void writeLong(long value) throws IOException { - byte[] writeBuffer = new byte[8]; - writeBuffer[7] = (byte) (value >>> 56); - writeBuffer[6] = (byte) (value >>> 48); - writeBuffer[5] = (byte) (value >>> 40); - writeBuffer[4] = (byte) (value >>> 32); - writeBuffer[3] = (byte) (value >>> 24); - writeBuffer[2] = (byte) (value >>> 16); - writeBuffer[1] = (byte) (value >>> 8); - writeBuffer[0] = (byte) (value); - write(writeBuffer); - } - - public void writeDouble(double value) throws IOException { - writeLong(Double.doubleToLongBits(value)); - } - - public void writeU8(int value) throws IOException { - write(value); - } - - public void writeU16(int value) throws IOException { - write(value & 0xff); - write((value >> 8) & 0xff); - } - - public void writeString(String s) throws IOException { - byte[] sbytes = Utf8Helper.getBytes(s); - writeU30(sbytes.length); - write(sbytes); - } - - public void writeNamespace(Namespace ns) throws IOException { - write(ns.kind); - boolean found = false; - for (int k = 0; k < Namespace.nameSpaceKinds.length; k++) { - if (Namespace.nameSpaceKinds[k] == ns.kind) { - writeU30(ns.name_index); - found = true; - break; - } - } - if (!found) { - throw new RuntimeException("Invalid ns kind:" + ns.kind); - } - } - - public void writeMultiname(Multiname m) throws IOException { - writeU8(m.kind); - if ((m.kind == 7) || (m.kind == 0xd)) { // CONSTANT_QName and CONSTANT_QNameA. - writeU30(m.namespace_index); - writeU30(m.name_index); - } - if ((m.kind == 9) || (m.kind == 0xe)) { // CONSTANT_Multiname and CONSTANT_MultinameA. - writeU30(m.name_index); - writeU30(m.namespace_set_index); - } - if ((m.kind == 0xf) || (m.kind == 0x10)) { // CONSTANT_RTQName and CONSTANT_RTQNameA - writeU30(m.name_index); - } - if ((m.kind == 0x1B) || (m.kind == 0x1C)) { // CONSTANT_MultinameL and CONSTANT_MultinameLA - writeU30(m.namespace_set_index); - } - if (m.kind == 0x1D) { - writeU30(m.qname_index); - writeU30(m.params.size()); - for (int i = 0; i < m.params.size(); i++) { - writeU30(m.params.get(i)); - } - } - // kind==0x11,0x12 nothing CONSTANT_RTQNameL and CONSTANT_RTQNameLA. - } - - public void writeMethodInfo(MethodInfo mi) throws IOException { - writeU30(mi.param_types.length); - writeU30(mi.ret_type); - for (int i = 0; i < mi.param_types.length; i++) { - writeU30(mi.param_types[i]); - } - writeU30(mi.name_index); - write(mi.flags); - if ((mi.flags & 8) == 8) { - writeU30(mi.optional.length); - for (int i = 0; i < mi.optional.length; i++) { - writeU30(mi.optional[i].value_index); - write(mi.optional[i].value_kind); - } - } - - if ((mi.flags & 128) == 128) { // if has_paramnames - for (int i = 0; i < mi.paramNames.length; i++) { - writeU30(mi.paramNames[i]); - } - } - } - - public void writeTrait(Trait t) throws IOException { - writeU30(t.name_index); - write((t.kindFlags << 4) + t.kindType); - if (t instanceof TraitSlotConst) { - TraitSlotConst t1 = (TraitSlotConst) t; - writeU30(t1.slot_id); - writeU30(t1.type_index); - writeU30(t1.value_index); - if (t1.value_index != 0) { - write(t1.value_kind); - } - } - if (t instanceof TraitMethodGetterSetter) { - TraitMethodGetterSetter t2 = (TraitMethodGetterSetter) t; - writeU30(t2.disp_id); - writeU30(t2.method_info); - } - if (t instanceof TraitClass) { - TraitClass t3 = (TraitClass) t; - writeU30(t3.slot_id); - writeU30(t3.class_info); - } - if (t instanceof TraitFunction) { - TraitFunction t4 = (TraitFunction) t; - writeU30(t4.slot_id); - writeU30(t4.method_info); - } - if ((t.kindFlags & 4) == 4) { - writeU30(t.metadata.length); - for (int i = 0; i < t.metadata.length; i++) { - writeU30(t.metadata[i]); - } - } - } - - public void writeTraits(Traits t) throws IOException { - writeU30(t.traits.size()); - for (int i = 0; i < t.traits.size(); i++) { - writeTrait(t.traits.get(i)); - } - } - - public void writeInstanceInfo(InstanceInfo ii) throws IOException { - writeU30(ii.name_index); - writeU30(ii.super_index); - write(ii.flags); - if ((ii.flags & 8) == 8) { - writeU30(ii.protectedNS); - } - writeU30(ii.interfaces.length); - for (int i = 0; i < ii.interfaces.length; i++) { - writeU30(ii.interfaces[i]); - } - writeU30(ii.iinit_index); - writeTraits(ii.instance_traits); - } - - public void writeDecimal(Decimal value) throws IOException { - write(value.data); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc; + +import com.jpexs.decompiler.flash.abc.types.Decimal; +import com.jpexs.decompiler.flash.abc.types.InstanceInfo; +import com.jpexs.decompiler.flash.abc.types.MethodInfo; +import com.jpexs.decompiler.flash.abc.types.Multiname; +import com.jpexs.decompiler.flash.abc.types.Namespace; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.abc.types.traits.TraitClass; +import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; +import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; +import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; +import com.jpexs.decompiler.flash.abc.types.traits.Traits; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.IOException; +import java.io.OutputStream; + +public class ABCOutputStream extends OutputStream { + + private final OutputStream os; + + public ABCOutputStream(OutputStream os) { + this.os = os; + } + + @Override + public void write(int b) throws IOException { + os.write(b); + } + + public void writeU30(long value) throws IOException { + writeS32(value); + /*boolean loop = true; + boolean underZero=value<0; + + if(underZero){ + value = value & 0xFFFFFFFF; + }else{ + value = value & 0x7FFFFFFF; + } + do { + int ret = (int) (value & 0x7F); + if (value < 0x80) { + loop = false; + } + if (value > 0x7F) { + ret += 0x80; + } + write(ret); + value = value >> 7; + } while (loop); + */ + } + + public void writeU32(long value) throws IOException { + boolean loop = true; + value &= 0xFFFFFFFF; + do { + int ret = (int) (value & 0x7F); + if (value < 0x80) { + loop = false; + } + if (value > 0x7F) { + ret += 0x80; + } + write(ret); + value >>= 7; + } while (loop); + } + + public void writeS24(long value) throws IOException { + int ret = (int) (value & 0xff); + write(ret); + value >>= 8; + ret = (int) (value & 0xff); + write(ret); + value >>= 8; + ret = (int) (value & 0xff); + write(ret); + } + + public void writeS32(long value) throws IOException { + boolean belowZero = value < 0; + /*if (belowZero) { + value = -value; + }*/ + int bitcount = 0; + boolean loop = true; + //value = value & 0xFFFFFFFF; + do { + bitcount += 7; + int ret = (int) (value & 0x7F); + if (value < 0x80) { + if (belowZero) { //&& bitcount < 35 + ret += 0x80; + } else { + loop = false; + } + } else { + ret += 0x80; + } + + if (bitcount == 35) { + ret &= 0xf; + } + write(ret); + if (bitcount == 35) { + break; + } + value >>= 7; + } while (loop); + } + + public void writeLong(long value) throws IOException { + byte[] writeBuffer = new byte[8]; + writeBuffer[7] = (byte) (value >>> 56); + writeBuffer[6] = (byte) (value >>> 48); + writeBuffer[5] = (byte) (value >>> 40); + writeBuffer[4] = (byte) (value >>> 32); + writeBuffer[3] = (byte) (value >>> 24); + writeBuffer[2] = (byte) (value >>> 16); + writeBuffer[1] = (byte) (value >>> 8); + writeBuffer[0] = (byte) (value); + write(writeBuffer); + } + + public void writeDouble(double value) throws IOException { + writeLong(Double.doubleToLongBits(value)); + } + + public void writeU8(int value) throws IOException { + write(value); + } + + public void writeU16(int value) throws IOException { + write(value & 0xff); + write((value >> 8) & 0xff); + } + + public void writeString(String s) throws IOException { + byte[] sbytes = Utf8Helper.getBytes(s); + writeU30(sbytes.length); + write(sbytes); + } + + public void writeNamespace(Namespace ns) throws IOException { + write(ns.kind); + boolean found = false; + for (int k = 0; k < Namespace.nameSpaceKinds.length; k++) { + if (Namespace.nameSpaceKinds[k] == ns.kind) { + writeU30(ns.name_index); + found = true; + break; + } + } + if (!found) { + throw new RuntimeException("Invalid ns kind:" + ns.kind); + } + } + + public void writeMultiname(Multiname m) throws IOException { + writeU8(m.kind); + if ((m.kind == 7) || (m.kind == 0xd)) { // CONSTANT_QName and CONSTANT_QNameA. + writeU30(m.namespace_index); + writeU30(m.name_index); + } + if ((m.kind == 9) || (m.kind == 0xe)) { // CONSTANT_Multiname and CONSTANT_MultinameA. + writeU30(m.name_index); + writeU30(m.namespace_set_index); + } + if ((m.kind == 0xf) || (m.kind == 0x10)) { // CONSTANT_RTQName and CONSTANT_RTQNameA + writeU30(m.name_index); + } + if ((m.kind == 0x1B) || (m.kind == 0x1C)) { // CONSTANT_MultinameL and CONSTANT_MultinameLA + writeU30(m.namespace_set_index); + } + if (m.kind == 0x1D) { + writeU30(m.qname_index); + writeU30(m.params.size()); + for (int i = 0; i < m.params.size(); i++) { + writeU30(m.params.get(i)); + } + } + // kind==0x11,0x12 nothing CONSTANT_RTQNameL and CONSTANT_RTQNameLA. + } + + public void writeMethodInfo(MethodInfo mi) throws IOException { + writeU30(mi.param_types.length); + writeU30(mi.ret_type); + for (int i = 0; i < mi.param_types.length; i++) { + writeU30(mi.param_types[i]); + } + writeU30(mi.name_index); + write(mi.flags); + if ((mi.flags & 8) == 8) { + writeU30(mi.optional.length); + for (int i = 0; i < mi.optional.length; i++) { + writeU30(mi.optional[i].value_index); + write(mi.optional[i].value_kind); + } + } + + if ((mi.flags & 128) == 128) { // if has_paramnames + for (int i = 0; i < mi.paramNames.length; i++) { + writeU30(mi.paramNames[i]); + } + } + } + + public void writeTrait(Trait t) throws IOException { + writeU30(t.name_index); + write((t.kindFlags << 4) + t.kindType); + if (t instanceof TraitSlotConst) { + TraitSlotConst t1 = (TraitSlotConst) t; + writeU30(t1.slot_id); + writeU30(t1.type_index); + writeU30(t1.value_index); + if (t1.value_index != 0) { + write(t1.value_kind); + } + } + if (t instanceof TraitMethodGetterSetter) { + TraitMethodGetterSetter t2 = (TraitMethodGetterSetter) t; + writeU30(t2.disp_id); + writeU30(t2.method_info); + } + if (t instanceof TraitClass) { + TraitClass t3 = (TraitClass) t; + writeU30(t3.slot_id); + writeU30(t3.class_info); + } + if (t instanceof TraitFunction) { + TraitFunction t4 = (TraitFunction) t; + writeU30(t4.slot_id); + writeU30(t4.method_info); + } + if ((t.kindFlags & 4) == 4) { + writeU30(t.metadata.length); + for (int i = 0; i < t.metadata.length; i++) { + writeU30(t.metadata[i]); + } + } + } + + public void writeTraits(Traits t) throws IOException { + writeU30(t.traits.size()); + for (int i = 0; i < t.traits.size(); i++) { + writeTrait(t.traits.get(i)); + } + } + + public void writeInstanceInfo(InstanceInfo ii) throws IOException { + writeU30(ii.name_index); + writeU30(ii.super_index); + write(ii.flags); + if ((ii.flags & 8) == 8) { + writeU30(ii.protectedNS); + } + writeU30(ii.interfaces.length); + for (int i = 0; i < ii.interfaces.length; i++) { + writeU30(ii.interfaces[i]); + } + writeU30(ii.iinit_index); + writeTraits(ii.instance_traits); + } + + public void writeDecimal(Decimal value) throws IOException { + write(value.data); + } + + public static int getU30ByteLength(long value) { + boolean belowZero = value < 0; + int bitcount = 0; + int result = 0; + boolean loop = true; + do { + bitcount += 7; + if (value < 0x80 && !belowZero) { + loop = false; + } + + result++; + if (bitcount == 35) { + break; + } + value >>= 7; + } while (loop); + return result; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index d24538a44..d9dbd24a4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -712,14 +712,14 @@ public class AVM2Code implements Cloneable { } if (ins.definition instanceof JumpIns) { try { - pos = adr2pos(pos2adr(pos) + ins.getBytes().length + ins.operands[0]); + pos = adr2pos(pos2adr(pos) + ins.getBytesLength() + ins.operands[0]); continue; } catch (ConvertException ex) { return false; } } else if (ins.definition instanceof IfTypeIns) { try { - int newpos = adr2pos(pos2adr(pos) + ins.getBytes().length + ins.operands[0]); + int newpos = adr2pos(pos2adr(pos) + ins.getBytesLength() + ins.operands[0]); calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen); } catch (ConvertException ex) { return false; @@ -1115,7 +1115,7 @@ public class AVM2Code implements Cloneable { writer.appendNoHilight(new DeobfuscatePopIns().instructionName).newLine(); } if (fixBranch == 0) { // jump - writer.appendNoHilight(new JumpIns().instructionName + " ofs" + Helper.formatAddress(ofs + ins.getBytes().length + ins.operands[0])); + writer.appendNoHilight(new JumpIns().instructionName + " ofs" + Helper.formatAddress(ofs + ins.getBytesLength() + ins.operands[0])); } else { // nojump, ignore } @@ -1150,7 +1150,7 @@ public class AVM2Code implements Cloneable { long a = 0; for (int i = 0; i < code.size(); i++) { posCache.add(a); - a += code.get(i).getBytes().length; + a += code.get(i).getBytesLength(); } posCache.add(a); cacheActual = true; @@ -1801,7 +1801,7 @@ public class AVM2Code implements Cloneable { }*/ //Faster, but not so universal if ((ins.definition instanceof JumpIns) || (ins.definition instanceof IfTypeIns)) { - long target = ins.offset + ins.getBytes().length + ins.operands[0]; + long target = ins.offset + ins.getBytesLength() + ins.operands[0]; ins.operands[0] = updater.updateOperandOffset(ins.offset, target, ins.operands[0]); } } @@ -1815,13 +1815,34 @@ public class AVM2Code implements Cloneable { } } + public void fixJumps(MethodBody body) { + AVM2Instruction lastInstuction = code.get(code.size() - 1); + final long endOffset = lastInstuction.offset + lastInstuction.getBytesLength(); + updateOffsets(new OffsetUpdater() { + + @Override + public long updateInstructionOffset(long address) { + return address; + } + + @Override + public int updateOperandOffset(long insAddr, long targetAddress, int offset) { + if (targetAddress > endOffset) { + return (int) (offset - targetAddress + endOffset); + } + return offset; + } + + }, body); + } + private void checkValidOffsets(MethodBody body) { updateOffsets(new OffsetUpdater() { @Override - public long updateInstructionOffset(long offset) { - adr2pos(offset); - return offset; + public long updateInstructionOffset(long address) { + adr2pos(address); + return address; } @Override @@ -1840,7 +1861,7 @@ public class AVM2Code implements Cloneable { checkValidOffsets(body); AVM2Instruction ins = code.get(pos); final long remOffset = ins.offset; - final int byteCount = ins.getBytes().length; + final int byteCount = ins.getBytesLength(); updateOffsets(new OffsetUpdater() { @Override public long updateInstructionOffset(long address) { @@ -1898,19 +1919,19 @@ public class AVM2Code implements Cloneable { pos = code.size(); } instruction.offset = code.get(pos).offset; - int oldByteCount = code.get(pos).getBytes().length; - int newByteCount = instruction.getBytes().length; + int oldByteCount = code.get(pos).getBytesLength(); + int newByteCount = instruction.getBytesLength(); int byteDelta = newByteCount - oldByteCount; if (byteDelta != 0) { updateOffsets(new OffsetUpdater() { @Override - public long updateInstructionOffset(long addr) { - if (addr > instruction.offset) { - return addr + byteDelta; + public long updateInstructionOffset(long address) { + if (address > instruction.offset) { + return address + byteDelta; } - return addr; + return address; } @Override @@ -1949,9 +1970,9 @@ public class AVM2Code implements Cloneable { if (pos > code.size()) { pos = code.size(); } - final int byteCount = instruction.getBytes().length; + final int byteCount = instruction.getBytesLength(); if (pos == code.size()) { - instruction.offset = code.get(pos - 1).offset + code.get(pos - 1).getBytes().length; + instruction.offset = code.get(pos - 1).offset + code.get(pos - 1).getBytesLength(); } else { instruction.offset = code.get(pos).offset; } @@ -2108,14 +2129,14 @@ public class AVM2Code implements Cloneable { } if (ins.definition instanceof JumpIns) { try { - pos = adr2pos(pos2adr(pos) + ins.getBytes().length + ins.operands[0]); + pos = adr2pos(pos2adr(pos) + ins.getBytesLength() + ins.operands[0]); continue; } catch (ConvertException ex) { return false; } } else if (ins.definition instanceof IfTypeIns) { try { - int newpos = adr2pos(pos2adr(pos) + ins.getBytes().length + ins.operands[0]); + int newpos = adr2pos(pos2adr(pos) + ins.getBytesLength() + ins.operands[0]); walkCode(stats, newpos, stack, scope, abc); } catch (ConvertException ex) { return false; @@ -2236,14 +2257,14 @@ public class AVM2Code implements Cloneable { } if (ins.definition instanceof JumpIns) { try { - ip = adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]); + ip = adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]); continue; } catch (ConvertException ex) { logger.log(Level.FINE, null, ex); } } else if (ins.definition instanceof IfTypeIns) { try { - visitCode(adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]), ip, refs); + visitCode(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]), ip, refs); } catch (ConvertException ex) { logger.log(Level.FINE, null, ex); } @@ -2304,7 +2325,7 @@ public class AVM2Code implements Cloneable { } if (ins.definition instanceof JumpIns) { try { - ip = adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]); + ip = adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]); prev2 = prev; prev = ins; continue; @@ -2373,7 +2394,7 @@ public class AVM2Code implements Cloneable { } } try { - ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]), visited, prev, prev2); + ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]), visited, prev, prev2); } catch (ConvertException ex) { logger.log(Level.FINE, null, ex); } @@ -2616,7 +2637,7 @@ public class AVM2Code implements Cloneable { int csize = code.size(); for (int i = 0; i < csize; i++) { AVM2Instruction ins = code.get(i); - int insLen = code.get(i).getBytes().length; + int insLen = code.get(i).getBytesLength(); int ofs = pos2adr(i); if (ins.definition instanceof JumpIns) { int targetOfs = ofs + insLen + ins.operands[0]; @@ -2650,7 +2671,7 @@ public class AVM2Code implements Cloneable { int ofs = 0; for (int i = 0; i < code.size(); i++) { code.get(i).mappedOffset = ofs; - ofs += code.get(i).getBytes().length; + ofs += code.get(i).getBytesLength(); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java index 827c0a93b..aecf84b8f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java @@ -61,7 +61,7 @@ public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple { for (int i = 0; i < code.code.size(); i++) { AVM2Instruction ins = code.code.get(i); if (ins.definition instanceof JumpIns) { - long targetAddr = ins.offset + ins.operands[0] + ins.getBytes().length; + long targetAddr = ins.offset + ins.operands[0] + ins.getBytesLength(); { for (int r : refs.get(i)) { if (r >= 0) { //Not Exception start/end @@ -70,7 +70,7 @@ public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple { if ((srcIns.definition instanceof JumpIns) || ((srcIns.definition instanceof IfTypeIns) && (r != i - 1))) { { int oldop = srcIns.operands[0]; - srcIns.operands[0] = (int) (targetAddr - (srcIns.offset + srcIns.getBytes().length)); + srcIns.operands[0] = (int) (targetAddr - (srcIns.offset + srcIns.getBytesLength())); if (srcIns.operands[0] != oldop) { found = true; } @@ -85,5 +85,4 @@ public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple { } while (found); } - } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java index ab35f1e90..c78c7561e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java @@ -164,7 +164,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { if (action.definition instanceof JumpIns) { - long address = action.offset + action.getBytes().length + action.operands[0]; + long address = action.offset + action.getBytesLength() + action.operands[0]; idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address)); if (idx == -1) { throw new TranslateException("Jump target not found: " + address); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java index d412b70c7..4cd6dfab6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java @@ -324,7 +324,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { boolean ifed = false; if (def instanceof JumpIns) { //ActionJump jump = (ActionJump) action; - long address = action.offset + action.getBytes().length + action.operands[0]; + long address = action.offset + action.getBytesLength() + action.operands[0]; idx = code.adr2pos(address); if (idx == -1) { @@ -334,7 +334,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { //ActionIf aif = (ActionIf) action; GraphTargetItem top = stack.pop(); Object res = top.getResult(); - long address = action.offset + action.getBytes().length + action.operands[0]; + long address = action.offset + action.getBytesLength() + action.operands[0]; int nidx = code.adr2pos(address);//code.indexOf(code.getByAddress(address)); AVM2Instruction tarIns = code.code.get(nidx); @@ -345,11 +345,11 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { AVM2Instruction jumpIns = new AVM2Instruction(0, new JumpIns(), new int[]{0}); //jumpIns.operands[0] = action.operands[0] /*- action.getBytes().length*/ + jumpIns.getBytes().length; code.replaceInstruction(idx, jumpIns, body); - jumpIns.operands[0] = (int) (tarIns.offset - jumpIns.offset - jumpIns.getBytes().length); + jumpIns.operands[0] = (int) (tarIns.offset - jumpIns.offset - jumpIns.getBytesLength()); code.insertInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), true, body); - idx = code.adr2pos(jumpIns.offset + jumpIns.getBytes().length + jumpIns.operands[0]); + idx = code.adr2pos(jumpIns.offset + jumpIns.getBytesLength() + jumpIns.operands[0]); } else { code.replaceInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), body); //action.definition = new DeobfuscatePopIns(); @@ -399,9 +399,11 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { } public void deobfuscate(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException { - removeUnreachableActions(body.getCode(), cpool, trait, minfo, body); + AVM2Code code = body.getCode(); + code.fixJumps(body); + removeUnreachableActions(code, cpool, trait, minfo, body); removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body); - removeZeroJumps(body.getCode(), body); + removeZeroJumps(code, body); } class ExecutionResult { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 2d9a0c447..380a3b540 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -36,7 +36,6 @@ import com.jpexs.decompiler.flash.abc.avm2.model.HasNextAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.InAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NextNameAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NextValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; @@ -71,7 +70,6 @@ import com.jpexs.decompiler.graph.model.IfItem; import com.jpexs.decompiler.graph.model.LoopItem; import com.jpexs.decompiler.graph.model.NotItem; import com.jpexs.decompiler.graph.model.PopItem; -import com.jpexs.decompiler.graph.model.PushItem; import com.jpexs.decompiler.graph.model.SwitchItem; import com.jpexs.decompiler.graph.model.WhileItem; import java.util.ArrayList; @@ -231,7 +229,7 @@ public class AVM2Graph extends Graph { AVM2Instruction jmpIns = this.avm2code.code.get(code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end))); if (jmpIns.definition instanceof JumpIns) { - finStart = code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytes().length + jmpIns.operands[0]); + finStart = code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytesLength() + jmpIns.operands[0]); GraphPart fpart = null; for (GraphPart p : allParts) { @@ -247,7 +245,7 @@ public class AVM2Graph extends Graph { if (this.avm2code.code.get(f).definition instanceof LookupSwitchIns) { AVM2Instruction swins = this.avm2code.code.get(f); if (swins.operands.length >= 3) { - if (swins.operands[0] == swins.getBytes().length) { + if (swins.operands[0] == swins.getBytesLength()) { if (code.adr2pos(code.pos2adr(f) + swins.operands[2]) < finStart) { //st.push(new ExceptionAVM2Item(body.exceptions[e])); GraphPart fepart = null; @@ -694,7 +692,7 @@ public class AVM2Graph extends Graph { if (true) { //afterCatchPos + 1 == code.adr2pos(this.code.fixAddrAfterDebugLine(body.exceptions[e].end))) { AVM2Instruction jmpIns = this.avm2code.code.get(avm2code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end))); if (jmpIns.definition instanceof JumpIns) { - int finStart = avm2code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytes().length + jmpIns.operands[0]); + int finStart = avm2code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytesLength() + jmpIns.operands[0]); if (!finallyJumps.containsKey(e)) { finallyJumps.put(e, new ArrayList<>()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java index f313852f7..1262b316a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java @@ -92,11 +92,11 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { aos.writeU8(0xff & operands[i]); break; case AVM2Code.OPT_CASE_OFFSETS: - aos.writeU30(operands[i]); //case count for (int j = i + 1; j < operands.length; j++) { aos.writeS24(operands[j]); } + break; } } @@ -106,6 +106,40 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { return bos.toByteArray(); } + public int getBytesLength() { + int refCnt = getBytes().length; + int cnt = 1; + for (int i = 0; i < definition.operands.length; i++) { + int opt = definition.operands[i] & 0xff00; + switch (opt) { + case AVM2Code.OPT_S24: + cnt += 3; + break; + case AVM2Code.OPT_U30: + cnt += ABCOutputStream.getU30ByteLength(operands[i]); + break; + case AVM2Code.OPT_U8: + cnt++; + break; + case AVM2Code.OPT_BYTE: + cnt++; + break; + case AVM2Code.OPT_CASE_OFFSETS: + cnt += ABCOutputStream.getU30ByteLength(operands[i]); //case count + for (int j = i + 1; j < operands.length; j++) { + cnt += 3; + } + + break; + } + } + + if (refCnt != cnt) { + throw new Error("aaa"); + } + return cnt; + } + @Override public String toString() { StringBuilder s = new StringBuilder(); @@ -125,7 +159,7 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { for (int i = 0; i < definition.operands.length; i++) { switch (definition.operands[i]) { case AVM2Code.DAT_OFFSET: - ret.add(offset + operands[i] + getBytes().length); + ret.add(offset + operands[i] + getBytesLength()); break; case AVM2Code.DAT_CASE_BASEOFFSET: ret.add(offset + operands[i]); @@ -161,7 +195,7 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { s.add(constants.getDouble(operands[i])); break; case AVM2Code.DAT_OFFSET: - s.add(offset + operands[i] + getBytes().length); + s.add(offset + operands[i] + getBytesLength()); break; case AVM2Code.DAT_CASE_BASEOFFSET: s.add(offset + operands[i]); @@ -243,7 +277,7 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { case AVM2Code.DAT_OFFSET: s.append(" "); s.append("ofs"); - s.append(Helper.formatAddress(offset + operands[i] + getBytes().length)); + s.append(Helper.formatAddress(offset + operands[i] + getBytesLength())); break; case AVM2Code.DAT_CASE_BASEOFFSET: s.append(" "); @@ -338,11 +372,11 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { if (definition instanceof IfTypeIns) { if (fixedBranch == -1 || fixedBranch == 0) { - ret.add(code.adr2pos(offset + getBytes().length + operands[0])); + ret.add(code.adr2pos(offset + getBytesLength() + operands[0])); } if (!(definition instanceof JumpIns)) { if (fixedBranch == -1 || fixedBranch == 1) { - ret.add(code.adr2pos(offset + getBytes().length)); + ret.add(code.adr2pos(offset + getBytesLength())); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/pcode/ASM3Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/pcode/ASM3Parser.java index 11049f10e..8d718c00b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/pcode/ASM3Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/pcode/ASM3Parser.java @@ -1,990 +1,990 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.abc.avm2.parser.pcode; - -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; -import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; -import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; -import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns; -import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException; -import com.jpexs.decompiler.flash.abc.types.ABCException; -import com.jpexs.decompiler.flash.abc.types.MethodBody; -import com.jpexs.decompiler.flash.abc.types.MethodInfo; -import com.jpexs.decompiler.flash.abc.types.Multiname; -import com.jpexs.decompiler.flash.abc.types.Namespace; -import com.jpexs.decompiler.flash.abc.types.NamespaceSet; -import com.jpexs.decompiler.flash.abc.types.ValueKind; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; -import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; -import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; -import com.jpexs.decompiler.flash.configuration.Configuration; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - -public class ASM3Parser { - - private static class OffsetItem { - - public String label = ""; - - public long insPosition; - - public int insOperandIndex; - - public OffsetItem(String label, long insOffset, int insOperandIndex) { - this.label = label; - this.insPosition = insOffset; - this.insOperandIndex = insOperandIndex; - } - } - - private static class CaseOffsetItem extends OffsetItem { - - public CaseOffsetItem(String label, long insOffset, int insOperandIndex) { - super(label, insOffset, insOperandIndex); - } - } - - private static class LabelItem { - - public String label = ""; - - public int offset; - - public LabelItem(String label, int offset) { - this.label = label; - this.offset = offset; - } - } - - public static AVM2Code parse(Reader reader, AVM2ConstantPool constants, Trait trait, MethodBody body, MethodInfo info) throws IOException, AVM2ParseException, InterruptedException { - return parse(reader, constants, trait, null, body, info); - } - - private static int checkMultinameIndex(AVM2ConstantPool constants, int index, int line) throws AVM2ParseException { - if ((index < 0) || (index >= constants.getMultinameCount())) { - throw new AVM2ParseException("Invalid multiname index", line); - } - return index; - } - - private static void expected(int type, String expStr, Flasm3Lexer lexer) throws IOException, AVM2ParseException { - ParsedSymbol s = lexer.lex(); - if (s.type != type) { - throw new AVM2ParseException(expStr + " expected", lexer.yyline()); - } - } - - private static void expected(ParsedSymbol s, int type, String expStr) throws IOException, AVM2ParseException { - if (s.type != type) { - throw new AVM2ParseException(expStr + " expected", 0); - } - } - - public static boolean parseSlotConst(Reader reader, AVM2ConstantPool constants, TraitSlotConst tsc) throws IOException, AVM2ParseException { - Flasm3Lexer lexer = new Flasm3Lexer(reader); - expected(ParsedSymbol.TYPE_KEYWORD_TRAIT, "trait", lexer); - int name_index = parseMultiName(constants, lexer); - - ParsedSymbol symb = lexer.lex(); - - int flags = 0; - while (symb.type == ParsedSymbol.TYPE_KEYWORD_FLAG) { - symb = lexer.lex(); - switch (symb.type) { - case ParsedSymbol.TYPE_KEYWORD_FINAL: - flags |= Trait.ATTR_Final; - break; - case ParsedSymbol.TYPE_KEYWORD_OVERRIDE: - flags |= Trait.ATTR_Override; - break; - case ParsedSymbol.TYPE_KEYWORD_METADATA: - flags |= Trait.ATTR_Metadata; - break; - default: - throw new AVM2ParseException("Invalid trait flag", lexer.yyline()); - } - symb = lexer.lex(); - } - - switch (symb.type) { - case ParsedSymbol.TYPE_KEYWORD_SLOT: - case ParsedSymbol.TYPE_KEYWORD_CONST: - expected(ParsedSymbol.TYPE_KEYWORD_SLOTID, "slotid", lexer); - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); - int slotid = (int) (long) (Long) symb.value; - expected(ParsedSymbol.TYPE_KEYWORD_TYPE, "type", lexer); - int type = parseMultiName(constants, lexer); - expected(ParsedSymbol.TYPE_KEYWORD_VALUE, "value", lexer); - ValueKind val = parseValue(constants, lexer); - tsc.slot_id = slotid; - tsc.type_index = type; - tsc.value_kind = val.value_kind; - tsc.value_index = val.value_index; - tsc.kindFlags = flags; - break; - /*case ParsedSymbol.TYPE_KEYWORD_CLASS: - break; - case ParsedSymbol.TYPE_KEYWORD_FUNCTION: - break; - case ParsedSymbol.TYPE_KEYWORD_METHOD: - case ParsedSymbol.TYPE_KEYWORD_GETTER: - case ParsedSymbol.TYPE_KEYWORD_SETTER: - break;*/ - default: - throw new AVM2ParseException("Unexpected trait type", lexer.yyline()); - } - tsc.name_index = name_index; - return true; - } - - private static int parseNamespaceSet(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { - List namespaceList = new ArrayList<>(); - ParsedSymbol s = lexer.lex(); - if (s.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - return 0; - } - expected(s, ParsedSymbol.TYPE_BRACKET_OPEN, "["); - s = lexer.lex(); - if (s.type != ParsedSymbol.TYPE_BRACKET_CLOSE) { - lexer.pushback(s); - do { - namespaceList.add(parseNamespace(constants, lexer)); - s = lexer.lex(); - } while (s.type == ParsedSymbol.TYPE_COMMA); - expected(s, ParsedSymbol.TYPE_BRACKET_CLOSE, "]"); - } - loopn: - for (int n = 1; n < constants.getNamespaceSetCount(); n++) { - int[] nss = constants.getNamespaceSet(n).namespaces; - if (nss.length != namespaceList.size()) { - continue; - } - for (int i = 0; i < nss.length; i++) { - if (nss[i] != namespaceList.get(i)) { - continue loopn; - } - } - return n; - } - int[] nss = new int[namespaceList.size()]; - for (int i = 0; i < nss.length; i++) { - nss[i] = namespaceList.get(i); - } - return constants.addNamespaceSet(new NamespaceSet(nss)); - } - - private static int parseNamespace(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { - - ParsedSymbol type = lexer.lex(); - int kind = 0; - switch (type.type) { - case ParsedSymbol.TYPE_KEYWORD_NULL: - return 0; - case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: - kind = Namespace.KIND_NAMESPACE; - break; - case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: - kind = Namespace.KIND_PRIVATE; - break; - case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: - kind = Namespace.KIND_PACKAGE; - break; - case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: - kind = Namespace.KIND_PACKAGE_INTERNAL; - break; - case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: - kind = Namespace.KIND_PROTECTED; - break; - case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: - kind = Namespace.KIND_EXPLICIT; - break; - case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: - kind = Namespace.KIND_STATIC_PROTECTED; - break; - default: - throw new AVM2ParseException("Namespace kind expected", lexer.yyline()); - } - - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - ParsedSymbol name = lexer.lex(); - if (name.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - - } else if (name.type == ParsedSymbol.TYPE_STRING) { - - } else { - throw new AVM2ParseException("String or null expected", lexer.yyline()); - } - ParsedSymbol c = lexer.lex(); - int index = 0; - if (c.type == ParsedSymbol.TYPE_COMMA) { - ParsedSymbol extra = lexer.lex(); - expected(extra, ParsedSymbol.TYPE_STRING, "String"); - try { - index = Integer.parseInt((String) extra.value); - } catch (NumberFormatException nfe) { - throw new AVM2ParseException("Number expected", lexer.yyline()); - } - } else { - lexer.pushback(c); - } - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - - return constants.getNamespaceId(new Namespace(kind, name.type == ParsedSymbol.TYPE_KEYWORD_NULL ? 0 : constants.getStringId((String) name.value, true)), index, true); - } - - private static int parseMultiName(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { - ParsedSymbol s = lexer.lex(); - int kind = 0; - int name_index = 0; - int namespace_index = 0; - int namespace_set_index = 0; - int qname_index = 0; - List params = new ArrayList<>(); - - switch (s.type) { - case ParsedSymbol.TYPE_KEYWORD_NULL: - return 0; - case ParsedSymbol.TYPE_KEYWORD_QNAME: - kind = Multiname.QNAME; - break; - case ParsedSymbol.TYPE_KEYWORD_QNAMEA: - kind = Multiname.QNAMEA; - break; - case ParsedSymbol.TYPE_KEYWORD_RTQNAME: - kind = Multiname.RTQNAME; - break; - case ParsedSymbol.TYPE_KEYWORD_RTQNAMEA: - kind = Multiname.RTQNAMEA; - break; - case ParsedSymbol.TYPE_KEYWORD_RTQNAMEL: - kind = Multiname.RTQNAMEL; - break; - case ParsedSymbol.TYPE_KEYWORD_RTQNAMELA: - kind = Multiname.RTQNAMELA; - break; - case ParsedSymbol.TYPE_KEYWORD_MULTINAME: - kind = Multiname.MULTINAME; - break; - case ParsedSymbol.TYPE_KEYWORD_MULTINAMEA: - kind = Multiname.MULTINAMEA; - break; - case ParsedSymbol.TYPE_KEYWORD_MULTINAMEL: - kind = Multiname.MULTINAMEL; - break; - case ParsedSymbol.TYPE_KEYWORD_MULTINAMELA: - kind = Multiname.MULTINAMELA; - break; - case ParsedSymbol.TYPE_KEYWORD_TYPENAME: - kind = Multiname.TYPENAME; - break; - default: - throw new AVM2ParseException("Name expected", lexer.yyline()); - } - - switch (s.type) { - case ParsedSymbol.TYPE_KEYWORD_QNAME: - case ParsedSymbol.TYPE_KEYWORD_QNAMEA: - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - namespace_index = parseNamespace(constants, lexer); - expected(ParsedSymbol.TYPE_COMMA, ",", lexer); - ParsedSymbol name = lexer.lex(); - if (name.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - name_index = 0; - } else { - expected(name, ParsedSymbol.TYPE_STRING, "String"); - name_index = constants.getStringId((String) name.value, true); - } - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - case ParsedSymbol.TYPE_KEYWORD_RTQNAME: - case ParsedSymbol.TYPE_KEYWORD_RTQNAMEA: - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - ParsedSymbol rtqName = lexer.lex(); - if (rtqName.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - name_index = 0; - } else { - expected(rtqName, ParsedSymbol.TYPE_STRING, "String"); - name_index = constants.getStringId((String) rtqName.value, true); - } - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - case ParsedSymbol.TYPE_KEYWORD_RTQNAMEL: - case ParsedSymbol.TYPE_KEYWORD_RTQNAMELA: - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - case ParsedSymbol.TYPE_KEYWORD_MULTINAME: - case ParsedSymbol.TYPE_KEYWORD_MULTINAMEA: - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - ParsedSymbol mName = lexer.lex(); - if (mName.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - name_index = 0; - } else { - expected(mName, ParsedSymbol.TYPE_STRING, "String"); - name_index = constants.getStringId((String) mName.value, true); - } - expected(ParsedSymbol.TYPE_COMMA, ",", lexer); - namespace_set_index = parseNamespaceSet(constants, lexer); - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - case ParsedSymbol.TYPE_KEYWORD_MULTINAMEL: - case ParsedSymbol.TYPE_KEYWORD_MULTINAMELA: - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - namespace_set_index = parseNamespaceSet(constants, lexer); - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - case ParsedSymbol.TYPE_KEYWORD_TYPENAME: - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - qname_index = parseMultiName(constants, lexer); - expected(ParsedSymbol.TYPE_LOWERTHAN, "<", lexer); - params.add(parseMultiName(constants, lexer)); - ParsedSymbol nt = lexer.lex(); - while (nt.type == ParsedSymbol.TYPE_COMMA) { - params.add(parseMultiName(constants, lexer)); - nt = lexer.lex(); - } - expected(nt, ParsedSymbol.TYPE_GREATERTHAN, ">"); - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - } - - return constants.getMultinameId(new Multiname(kind, name_index, namespace_index, namespace_set_index, qname_index, params), true); - } - - public static ValueKind parseValue(AVM2ConstantPool constants, Flasm3Lexer lexer) throws IOException, AVM2ParseException { - ParsedSymbol type = lexer.lex(); - ParsedSymbol value; - int value_index = 0; - int value_kind = 0; - switch (type.type) { - case ParsedSymbol.TYPE_KEYWORD_INTEGER: - value_kind = ValueKind.CONSTANT_Int; - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - value = lexer.lex(); - if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - value_index = 0; - } else { - expected(value, ParsedSymbol.TYPE_INTEGER, "Integer or null"); - value_index = constants.getIntId((Long) value.value, true); - } - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - case ParsedSymbol.TYPE_KEYWORD_UINTEGER: - value_kind = ValueKind.CONSTANT_UInt; - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - value = lexer.lex(); - if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - value_index = 0; - } else { - expected(value, ParsedSymbol.TYPE_INTEGER, "UInteger"); - value_index = constants.getUIntId((Long) value.value, true); - } - - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - case ParsedSymbol.TYPE_KEYWORD_DOUBLE: - value_kind = ValueKind.CONSTANT_Double; - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - value = lexer.lex(); - if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - value_index = 0; - } else { - expected(value, ParsedSymbol.TYPE_FLOAT, "Double or null"); - value_index = constants.getDoubleId((Double) value.value, true); - } - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - break; - /*case ParsedSymbol.TYPE_KEYWORD_DECIMAL: - value_kind = ValueKind.CONSTANT_Decimal; - break;*/ - case ParsedSymbol.TYPE_INTEGER: - value_kind = ValueKind.CONSTANT_Int; - value_index = constants.getIntId((Long) type.value, true); - break; - case ParsedSymbol.TYPE_FLOAT: - value_kind = ValueKind.CONSTANT_Double; - value_index = constants.getDoubleId((Double) type.value, true); - break; - case ParsedSymbol.TYPE_STRING: - value_kind = ValueKind.CONSTANT_Utf8; - value_index = constants.getStringId((String) type.value, true); - break; - case ParsedSymbol.TYPE_KEYWORD_UTF8: - value_kind = ValueKind.CONSTANT_Utf8; - expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); - value = lexer.lex(); - if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - value_index = 0; - } else { - expected(value, ParsedSymbol.TYPE_STRING, "String or null"); - expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); - value_index = constants.getStringId((String) value.value, true); - } - break; - case ParsedSymbol.TYPE_KEYWORD_TRUE: - value_kind = ValueKind.CONSTANT_True; - break; - case ParsedSymbol.TYPE_KEYWORD_FALSE: - value_kind = ValueKind.CONSTANT_False; - break; - case ParsedSymbol.TYPE_KEYWORD_NULL: - value_kind = ValueKind.CONSTANT_Null; - break; - case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: - case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: - case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: - case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: - case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: - case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: - case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: - - switch (type.type) { - case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: - value_kind = ValueKind.CONSTANT_Namespace; - break; - case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: - value_kind = ValueKind.CONSTANT_PackageInternalNs; - break; - case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: - value_kind = ValueKind.CONSTANT_ProtectedNamespace; - break; - case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: - value_kind = ValueKind.CONSTANT_ExplicitNamespace; - break; - case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: - value_kind = ValueKind.CONSTANT_StaticProtectedNs; - break; - case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: - value_kind = ValueKind.CONSTANT_PrivateNs; - break; - case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: - value_kind = ValueKind.CONSTANT_PackageNamespace; - break; - } - lexer.pushback(type); - value_index = parseNamespace(constants, lexer); - break; - default: - if (Configuration.debugMode.get()) { - throw new AVM2ParseException("Not supported valueType.", lexer.yyline()); - } - } - return new ValueKind(value_index, value_kind); - } - - public static AVM2Code parse(Reader reader, AVM2ConstantPool constants, Trait trait, MissingSymbolHandler missingHandler, MethodBody body, MethodInfo info) throws IOException, AVM2ParseException, InterruptedException { - AVM2Code code = new AVM2Code(); - - List offsetItems = new ArrayList<>(); - List labelItems = new ArrayList<>(); - List exceptions = new ArrayList<>(); - List exceptionIndices = new ArrayList<>(); - int offset = 0; - - Flasm3Lexer lexer = new Flasm3Lexer(reader); - - ParsedSymbol symb; - AVM2Instruction lastIns = null; - List exceptionsFrom = new ArrayList<>(); - List exceptionsTo = new ArrayList<>(); - List exceptionsTargets = new ArrayList<>(); - info.flags = 0; - info.name_index = 0; - List paramTypes = new ArrayList<>(); - List paramNames = new ArrayList<>(); - List optional = new ArrayList<>(); - do { - symb = lexer.lex(); - if (Arrays.asList(ParsedSymbol.TYPE_KEYWORD_BODY, ParsedSymbol.TYPE_KEYWORD_CODE, ParsedSymbol.TYPE_KEYWORD_METHOD).contains(symb.type)) { - continue; - } - if (symb.type == ParsedSymbol.TYPE_KEYWORD_TRAIT) { - if (trait == null) { - throw new AVM2ParseException("No trait expected", lexer.yyline()); - } - symb = lexer.lex(); - switch (symb.type) { - case ParsedSymbol.TYPE_KEYWORD_METHOD: - case ParsedSymbol.TYPE_KEYWORD_GETTER: - case ParsedSymbol.TYPE_KEYWORD_SETTER: - if (!(trait instanceof TraitMethodGetterSetter)) { - throw new AVM2ParseException("Unxpected trait type", lexer.yyline()); - } - TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait; - switch (symb.type) { - case ParsedSymbol.TYPE_KEYWORD_METHOD: - tm.kindType = Trait.TRAIT_METHOD; - break; - case ParsedSymbol.TYPE_KEYWORD_GETTER: - tm.kindType = Trait.TRAIT_GETTER; - break; - case ParsedSymbol.TYPE_KEYWORD_SETTER: - tm.kindType = Trait.TRAIT_SETTER; - break; - } - tm.name_index = parseMultiName(constants, lexer); - expected(ParsedSymbol.TYPE_KEYWORD_DISPID, "dispid", lexer); - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); - tm.disp_id = (int) (long) (Long) symb.value; - - break; - case ParsedSymbol.TYPE_KEYWORD_FUNCTION: - if (!(trait instanceof TraitFunction)) { - throw new AVM2ParseException("Unxpected trait type", lexer.yyline()); - } - break; - - } - continue; - } - if (symb.type == ParsedSymbol.TYPE_KEYWORD_NAME) { - symb = lexer.lex(); - if (symb.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - info.name_index = 0; - } else { - expected(symb, ParsedSymbol.TYPE_STRING, "String or null"); - info.name_index = constants.getStringId((String) symb.value, true); - } - continue; - } - if (symb.type == ParsedSymbol.TYPE_KEYWORD_PARAM) { - paramTypes.add(parseMultiName(constants, lexer)); - continue; - } - if (symb.type == ParsedSymbol.TYPE_KEYWORD_PARAMNAME) { - symb = lexer.lex(); - if (symb.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - paramNames.add(0); - } else { - expected(symb, ParsedSymbol.TYPE_STRING, "String or null"); - paramNames.add(constants.getStringId((String) symb.value, true)); - } - continue; - } - - if (symb.type == ParsedSymbol.TYPE_KEYWORD_OPTIONAL) { - optional.add(parseValue(constants, lexer)); - continue; - } - - if (symb.type == ParsedSymbol.TYPE_KEYWORD_MAXSTACK) { - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); - body.max_stack = (int) (long) (Long) symb.value; - continue; - } - - if (symb.type == ParsedSymbol.TYPE_KEYWORD_LOCALCOUNT) { - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); - body.max_regs = (int) (long) (Long) symb.value; - continue; - } - - if (symb.type == ParsedSymbol.TYPE_KEYWORD_INITSCOPEDEPTH) { - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); - body.init_scope_depth = (int) (long) (Long) symb.value; - continue; - } - - if (symb.type == ParsedSymbol.TYPE_KEYWORD_MAXSCOPEDEPTH) { - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); - body.max_scope_depth = (int) (long) (Long) symb.value; - continue; - } - - if (symb.type == ParsedSymbol.TYPE_KEYWORD_RETURNS) { - info.ret_type = parseMultiName(constants, lexer); - continue; - } - - if (symb.type == ParsedSymbol.TYPE_KEYWORD_FLAG) { - symb = lexer.lex(); - switch (symb.type) { - case ParsedSymbol.TYPE_KEYWORD_EXPLICIT: - info.setFlagExplicit(); - break; - case ParsedSymbol.TYPE_KEYWORD_HAS_OPTIONAL: - info.setFlagHas_optional(); - break; - case ParsedSymbol.TYPE_KEYWORD_HAS_PARAM_NAMES: - info.setFlagHas_paramnames(); - break; - case ParsedSymbol.TYPE_KEYWORD_IGNORE_REST: - info.setFlagIgnore_Rest(); - break; - case ParsedSymbol.TYPE_KEYWORD_NEED_ACTIVATION: - info.setFlagNeed_activation(); - break; - case ParsedSymbol.TYPE_KEYWORD_NEED_ARGUMENTS: - info.setFlagNeed_Arguments(); - break; - case ParsedSymbol.TYPE_KEYWORD_NEED_REST: - info.setFlagNeed_rest(); - break; - case ParsedSymbol.TYPE_KEYWORD_SET_DXNS: - info.setFlagSetsdxns(); - break; - } - continue; - } - if (symb.type == ParsedSymbol.TYPE_KEYWORD_TRY) { - expected(ParsedSymbol.TYPE_KEYWORD_FROM, "From", lexer); - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); - exceptionsFrom.add((String) symb.value); - expected(ParsedSymbol.TYPE_KEYWORD_TO, "To", lexer); - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); - exceptionsTo.add((String) symb.value); - expected(ParsedSymbol.TYPE_KEYWORD_TARGET, "Target", lexer); - symb = lexer.lex(); - expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); - exceptionsTargets.add((String) symb.value); - expected(ParsedSymbol.TYPE_KEYWORD_TYPE, "Type", lexer); - ABCException ex = new ABCException(); - ex.type_index = parseMultiName(constants, lexer); - expected(ParsedSymbol.TYPE_KEYWORD_NAME, "Name", lexer); - ex.name_index = parseMultiName(constants, lexer); - exceptions.add(ex); - continue; - } - if (symb.type == ParsedSymbol.TYPE_EXCEPTION_START) { - int exIndex = (Integer) symb.value; - int listIndex = exceptionIndices.indexOf(exIndex); - if (listIndex == -1) { - throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); - } - exceptions.get(listIndex).start = offset; - continue; - } - if (symb.type == ParsedSymbol.TYPE_EXCEPTION_END) { - int exIndex = (Integer) symb.value; - int listIndex = exceptionIndices.indexOf(exIndex); - if (listIndex == -1) { - throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); - } - exceptions.get(listIndex).end = offset; - continue; - } - if (symb.type == ParsedSymbol.TYPE_EXCEPTION_TARGET) { - int exIndex = (Integer) symb.value; - int listIndex = exceptionIndices.indexOf(exIndex); - if (listIndex == -1) { - throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); - } - exceptions.get(listIndex).target = offset; - continue; - } - if (symb.type == ParsedSymbol.TYPE_EOF) { - break; - } - if (symb.type == ParsedSymbol.TYPE_COMMENT) { - if (lastIns != null) { - lastIns.comment = (String) symb.value; - } - continue; - } - if (symb.type == ParsedSymbol.TYPE_INSTRUCTION_NAME) { - if (((String) symb.value).toLowerCase(Locale.ENGLISH).equals("exception")) { - ParsedSymbol exIndex = lexer.lex(); - if (exIndex.type != ParsedSymbol.TYPE_INTEGER) { - throw new AVM2ParseException("Index expected", lexer.yyline()); - } - ParsedSymbol exName = lexer.lex(); - if (exName.type != ParsedSymbol.TYPE_MULTINAME) { - throw new AVM2ParseException("Multiname expected", lexer.yyline()); - } - ParsedSymbol exType = lexer.lex(); - if (exType.type != ParsedSymbol.TYPE_MULTINAME) { - throw new AVM2ParseException("Multiname expected", lexer.yyline()); - } - ABCException ex = new ABCException(); - - ex.name_index = checkMultinameIndex(constants, (int) (long) (Long) exName.value, lexer.yyline()); - ex.type_index = checkMultinameIndex(constants, (int) (long) (Long) exType.value, lexer.yyline()); - exceptions.add(ex); - exceptionIndices.add((int) (long) (Long) exIndex.value); - continue; - } - boolean insFound = false; - for (InstructionDefinition def : AVM2Code.instructionSet) { - if (def != null && def.instructionName.equals((String) symb.value)) { - insFound = true; - List operandsList = new ArrayList<>(); - - for (int i = 0; i < def.operands.length; i++) { - ParsedSymbol parsedOperand = lexer.lex(); - switch (def.operands[i]) { - case AVM2Code.DAT_MULTINAME_INDEX: - lexer.pushback(parsedOperand); - operandsList.add(parseMultiName(constants, lexer)); - /*if (parsedOperand.type == ParsedSymbol.TYPE_MULTINAME) { - operandsList.add(checkMultinameIndex(constants, (int) (long) (Long) parsedOperand.value, lexer.yyline())); - } else { - throw new ParseException("Multiname expected", lexer.yyline()); - }*/ - break; - case AVM2Code.DAT_STRING_INDEX: - if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - operandsList.add(0); - } else { - if (parsedOperand.type == ParsedSymbol.TYPE_STRING) { - int sid = constants.getStringId((String) parsedOperand.value); - if (sid == 0) { - if ((missingHandler != null) && (missingHandler.missingString((String) parsedOperand.value))) { - sid = constants.addString((String) parsedOperand.value); - } else { - throw new AVM2ParseException("Unknown String", lexer.yyline()); - } - } - operandsList.add(sid); - } else { - throw new AVM2ParseException("String or null expected", lexer.yyline()); - } - } - break; - case AVM2Code.DAT_INT_INDEX: - - if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - operandsList.add(0); - } else { - if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { - long intVal = (Long) parsedOperand.value; - int iid = constants.getIntId(intVal); - if (iid == 0) { - if ((missingHandler != null) && (missingHandler.missingInt(intVal))) { - iid = constants.addInt(intVal); - } else { - throw new AVM2ParseException("Unknown int", lexer.yyline()); - } - } - operandsList.add(iid); - } else { - throw new AVM2ParseException("Integer or null expected", lexer.yyline()); - } - } - break; - case AVM2Code.DAT_UINT_INDEX: - if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - operandsList.add(0); - } else { - if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { - long intVal = (Long) parsedOperand.value; - int iid = constants.getUIntId(intVal); - if (iid == 0) { - if ((missingHandler != null) && (missingHandler.missingUInt(intVal))) { - iid = constants.addUInt(intVal); - } else { - throw new AVM2ParseException("Unknown uint", lexer.yyline()); - } - } - operandsList.add(iid); - } else { - throw new AVM2ParseException("Integer or null expected", lexer.yyline()); - } - } - break; - case AVM2Code.DAT_DOUBLE_INDEX: - if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { - operandsList.add(0); - } else { - if ((parsedOperand.type == ParsedSymbol.TYPE_INTEGER) || (parsedOperand.type == ParsedSymbol.TYPE_FLOAT)) { - - double doubleVal = 0; - if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { - doubleVal = (Long) parsedOperand.value; - } - if (parsedOperand.type == ParsedSymbol.TYPE_FLOAT) { - doubleVal = (Double) parsedOperand.value; - } - int did = constants.getDoubleId(doubleVal); - if (did == 0) { - if ((missingHandler != null) && (missingHandler.missingDouble(doubleVal))) { - did = constants.addDouble(doubleVal); - } else { - throw new AVM2ParseException("Unknown double", lexer.yyline()); - } - } - operandsList.add(did); - } else { - throw new AVM2ParseException("Float or null expected", lexer.yyline()); - } - } - break; - case AVM2Code.DAT_OFFSET: - if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { - offsetItems.add(new OffsetItem((String) parsedOperand.value, code.code.size(), i)); - operandsList.add(0); - } else { - throw new AVM2ParseException("Offset expected", lexer.yyline()); - } - break; - case AVM2Code.DAT_CASE_BASEOFFSET: - if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { - offsetItems.add(new CaseOffsetItem((String) parsedOperand.value, code.code.size(), i)); - operandsList.add(0); - } else { - throw new AVM2ParseException("Offset expected", lexer.yyline()); - } - break; - case AVM2Code.OPT_CASE_OFFSETS: - - if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { - int patCount = (int) (long) (Long) parsedOperand.value; - operandsList.add(patCount); - - for (int c = 0; c <= patCount; c++) { - parsedOperand = lexer.lex(); - if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { - offsetItems.add(new CaseOffsetItem((String) parsedOperand.value, code.code.size(), i + (c + 1))); - operandsList.add(0); - } else { - throw new AVM2ParseException("Offset expected", lexer.yyline()); - } - } - } else { - throw new AVM2ParseException("Case count expected", lexer.yyline()); - } - break; - case AVM2Code.OPT_BYTE: - if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { - long val = (long) (Long) parsedOperand.value; - if (val < Byte.MIN_VALUE || val > Byte.MAX_VALUE) { - throw new AVM2ParseException("Byte value expected (" + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE + "). Use pushshort or pushint to push larger values", lexer.yyline()); - } - operandsList.add((int) val); - } else { - throw new AVM2ParseException("Integer expected", lexer.yyline()); - } - break; - default: - if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { - long val = (long) (Long) parsedOperand.value; - if (def instanceof PushShortIns) { - if (val < Short.MIN_VALUE || val > Short.MAX_VALUE) { - throw new AVM2ParseException("Short value expected (" + Short.MIN_VALUE + " to " + Short.MAX_VALUE + "). Use pushint to push larger values", lexer.yyline()); - } - } - operandsList.add((int) val); - } else { - throw new AVM2ParseException("Integer expected", lexer.yyline()); - } - } - } - - int[] operands = new int[operandsList.size()]; - for (int i = 0; i < operandsList.size(); i++) { - operands[i] = operandsList.get(i); - } - lastIns = new AVM2Instruction(offset, def, operands); - code.code.add(lastIns); - offset += lastIns.getBytes().length; - break; - } - } - if (symb.value.toString().toLowerCase().equals("ffdec_deobfuscatepop")) { - lastIns = new AVM2Instruction(offset, new DeobfuscatePopIns(), null); - code.code.add(lastIns); - offset += lastIns.getBytes().length; - insFound = true; - } - if (!insFound) { - throw new AVM2ParseException("Invalid instruction name:" + (String) symb.value, lexer.yyline()); - } - } else if (symb.type == ParsedSymbol.TYPE_LABEL) { - labelItems.add(new LabelItem((String) symb.value, offset)); - - } else { - throw new AVM2ParseException("Unexpected symbol", lexer.yyline()); - } - } while (symb.type != ParsedSymbol.TYPE_EOF); - - code.compact(); - for (LabelItem li : labelItems) { - int ind; - ind = exceptionsFrom.indexOf(li.label); - if (ind > -1) { - exceptions.get(ind).start = li.offset; - } - - ind = exceptionsTo.indexOf(li.label); - if (ind > -1) { - exceptions.get(ind).end = li.offset; - } - - ind = exceptionsTargets.indexOf(li.label); - if (ind > -1) { - exceptions.get(ind).target = li.offset; - } - } - - for (OffsetItem oi : offsetItems) { - for (LabelItem li : labelItems) { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } - if (oi.label.equals(li.label)) { - AVM2Instruction ins = code.code.get((int) oi.insPosition); - int relOffset; - if (oi instanceof CaseOffsetItem) { - relOffset = li.offset - (int) ins.offset; - } else { - relOffset = li.offset - ((int) ins.offset + ins.getBytes().length); - } - ins.operands[oi.insOperandIndex] = relOffset; - } - } - } - body.exceptions = new ABCException[exceptions.size()]; - for (int e = 0; e < exceptions.size(); e++) { - body.exceptions[e] = exceptions.get(e); - } - - info.param_types = new int[paramTypes.size()]; - for (int i = 0; i < paramTypes.size(); i++) { - info.param_types[i] = paramTypes.get(i); - } - - if (info.flagHas_paramnames()) { - info.paramNames = new int[paramNames.size()]; - for (int i = 0; i < paramNames.size(); i++) { - info.paramNames[i] = paramNames.get(i); - } - } - - if (info.flagHas_optional()) { - info.optional = new ValueKind[optional.size()]; - for (int i = 0; i < optional.size(); i++) { - info.optional[i] = optional.get(i); - } - } - return code; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc.avm2.parser.pcode; + +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns; +import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException; +import com.jpexs.decompiler.flash.abc.types.ABCException; +import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.MethodInfo; +import com.jpexs.decompiler.flash.abc.types.Multiname; +import com.jpexs.decompiler.flash.abc.types.Namespace; +import com.jpexs.decompiler.flash.abc.types.NamespaceSet; +import com.jpexs.decompiler.flash.abc.types.ValueKind; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; +import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; +import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; +import com.jpexs.decompiler.flash.configuration.Configuration; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class ASM3Parser { + + private static class OffsetItem { + + public String label = ""; + + public long insPosition; + + public int insOperandIndex; + + public OffsetItem(String label, long insOffset, int insOperandIndex) { + this.label = label; + this.insPosition = insOffset; + this.insOperandIndex = insOperandIndex; + } + } + + private static class CaseOffsetItem extends OffsetItem { + + public CaseOffsetItem(String label, long insOffset, int insOperandIndex) { + super(label, insOffset, insOperandIndex); + } + } + + private static class LabelItem { + + public String label = ""; + + public int offset; + + public LabelItem(String label, int offset) { + this.label = label; + this.offset = offset; + } + } + + public static AVM2Code parse(Reader reader, AVM2ConstantPool constants, Trait trait, MethodBody body, MethodInfo info) throws IOException, AVM2ParseException, InterruptedException { + return parse(reader, constants, trait, null, body, info); + } + + private static int checkMultinameIndex(AVM2ConstantPool constants, int index, int line) throws AVM2ParseException { + if ((index < 0) || (index >= constants.getMultinameCount())) { + throw new AVM2ParseException("Invalid multiname index", line); + } + return index; + } + + private static void expected(int type, String expStr, Flasm3Lexer lexer) throws IOException, AVM2ParseException { + ParsedSymbol s = lexer.lex(); + if (s.type != type) { + throw new AVM2ParseException(expStr + " expected", lexer.yyline()); + } + } + + private static void expected(ParsedSymbol s, int type, String expStr) throws IOException, AVM2ParseException { + if (s.type != type) { + throw new AVM2ParseException(expStr + " expected", 0); + } + } + + public static boolean parseSlotConst(Reader reader, AVM2ConstantPool constants, TraitSlotConst tsc) throws IOException, AVM2ParseException { + Flasm3Lexer lexer = new Flasm3Lexer(reader); + expected(ParsedSymbol.TYPE_KEYWORD_TRAIT, "trait", lexer); + int name_index = parseMultiName(constants, lexer); + + ParsedSymbol symb = lexer.lex(); + + int flags = 0; + while (symb.type == ParsedSymbol.TYPE_KEYWORD_FLAG) { + symb = lexer.lex(); + switch (symb.type) { + case ParsedSymbol.TYPE_KEYWORD_FINAL: + flags |= Trait.ATTR_Final; + break; + case ParsedSymbol.TYPE_KEYWORD_OVERRIDE: + flags |= Trait.ATTR_Override; + break; + case ParsedSymbol.TYPE_KEYWORD_METADATA: + flags |= Trait.ATTR_Metadata; + break; + default: + throw new AVM2ParseException("Invalid trait flag", lexer.yyline()); + } + symb = lexer.lex(); + } + + switch (symb.type) { + case ParsedSymbol.TYPE_KEYWORD_SLOT: + case ParsedSymbol.TYPE_KEYWORD_CONST: + expected(ParsedSymbol.TYPE_KEYWORD_SLOTID, "slotid", lexer); + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); + int slotid = (int) (long) (Long) symb.value; + expected(ParsedSymbol.TYPE_KEYWORD_TYPE, "type", lexer); + int type = parseMultiName(constants, lexer); + expected(ParsedSymbol.TYPE_KEYWORD_VALUE, "value", lexer); + ValueKind val = parseValue(constants, lexer); + tsc.slot_id = slotid; + tsc.type_index = type; + tsc.value_kind = val.value_kind; + tsc.value_index = val.value_index; + tsc.kindFlags = flags; + break; + /*case ParsedSymbol.TYPE_KEYWORD_CLASS: + break; + case ParsedSymbol.TYPE_KEYWORD_FUNCTION: + break; + case ParsedSymbol.TYPE_KEYWORD_METHOD: + case ParsedSymbol.TYPE_KEYWORD_GETTER: + case ParsedSymbol.TYPE_KEYWORD_SETTER: + break;*/ + default: + throw new AVM2ParseException("Unexpected trait type", lexer.yyline()); + } + tsc.name_index = name_index; + return true; + } + + private static int parseNamespaceSet(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { + List namespaceList = new ArrayList<>(); + ParsedSymbol s = lexer.lex(); + if (s.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + return 0; + } + expected(s, ParsedSymbol.TYPE_BRACKET_OPEN, "["); + s = lexer.lex(); + if (s.type != ParsedSymbol.TYPE_BRACKET_CLOSE) { + lexer.pushback(s); + do { + namespaceList.add(parseNamespace(constants, lexer)); + s = lexer.lex(); + } while (s.type == ParsedSymbol.TYPE_COMMA); + expected(s, ParsedSymbol.TYPE_BRACKET_CLOSE, "]"); + } + loopn: + for (int n = 1; n < constants.getNamespaceSetCount(); n++) { + int[] nss = constants.getNamespaceSet(n).namespaces; + if (nss.length != namespaceList.size()) { + continue; + } + for (int i = 0; i < nss.length; i++) { + if (nss[i] != namespaceList.get(i)) { + continue loopn; + } + } + return n; + } + int[] nss = new int[namespaceList.size()]; + for (int i = 0; i < nss.length; i++) { + nss[i] = namespaceList.get(i); + } + return constants.addNamespaceSet(new NamespaceSet(nss)); + } + + private static int parseNamespace(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { + + ParsedSymbol type = lexer.lex(); + int kind = 0; + switch (type.type) { + case ParsedSymbol.TYPE_KEYWORD_NULL: + return 0; + case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: + kind = Namespace.KIND_NAMESPACE; + break; + case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: + kind = Namespace.KIND_PRIVATE; + break; + case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: + kind = Namespace.KIND_PACKAGE; + break; + case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: + kind = Namespace.KIND_PACKAGE_INTERNAL; + break; + case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: + kind = Namespace.KIND_PROTECTED; + break; + case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: + kind = Namespace.KIND_EXPLICIT; + break; + case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: + kind = Namespace.KIND_STATIC_PROTECTED; + break; + default: + throw new AVM2ParseException("Namespace kind expected", lexer.yyline()); + } + + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + ParsedSymbol name = lexer.lex(); + if (name.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + + } else if (name.type == ParsedSymbol.TYPE_STRING) { + + } else { + throw new AVM2ParseException("String or null expected", lexer.yyline()); + } + ParsedSymbol c = lexer.lex(); + int index = 0; + if (c.type == ParsedSymbol.TYPE_COMMA) { + ParsedSymbol extra = lexer.lex(); + expected(extra, ParsedSymbol.TYPE_STRING, "String"); + try { + index = Integer.parseInt((String) extra.value); + } catch (NumberFormatException nfe) { + throw new AVM2ParseException("Number expected", lexer.yyline()); + } + } else { + lexer.pushback(c); + } + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + + return constants.getNamespaceId(new Namespace(kind, name.type == ParsedSymbol.TYPE_KEYWORD_NULL ? 0 : constants.getStringId((String) name.value, true)), index, true); + } + + private static int parseMultiName(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { + ParsedSymbol s = lexer.lex(); + int kind = 0; + int name_index = 0; + int namespace_index = 0; + int namespace_set_index = 0; + int qname_index = 0; + List params = new ArrayList<>(); + + switch (s.type) { + case ParsedSymbol.TYPE_KEYWORD_NULL: + return 0; + case ParsedSymbol.TYPE_KEYWORD_QNAME: + kind = Multiname.QNAME; + break; + case ParsedSymbol.TYPE_KEYWORD_QNAMEA: + kind = Multiname.QNAMEA; + break; + case ParsedSymbol.TYPE_KEYWORD_RTQNAME: + kind = Multiname.RTQNAME; + break; + case ParsedSymbol.TYPE_KEYWORD_RTQNAMEA: + kind = Multiname.RTQNAMEA; + break; + case ParsedSymbol.TYPE_KEYWORD_RTQNAMEL: + kind = Multiname.RTQNAMEL; + break; + case ParsedSymbol.TYPE_KEYWORD_RTQNAMELA: + kind = Multiname.RTQNAMELA; + break; + case ParsedSymbol.TYPE_KEYWORD_MULTINAME: + kind = Multiname.MULTINAME; + break; + case ParsedSymbol.TYPE_KEYWORD_MULTINAMEA: + kind = Multiname.MULTINAMEA; + break; + case ParsedSymbol.TYPE_KEYWORD_MULTINAMEL: + kind = Multiname.MULTINAMEL; + break; + case ParsedSymbol.TYPE_KEYWORD_MULTINAMELA: + kind = Multiname.MULTINAMELA; + break; + case ParsedSymbol.TYPE_KEYWORD_TYPENAME: + kind = Multiname.TYPENAME; + break; + default: + throw new AVM2ParseException("Name expected", lexer.yyline()); + } + + switch (s.type) { + case ParsedSymbol.TYPE_KEYWORD_QNAME: + case ParsedSymbol.TYPE_KEYWORD_QNAMEA: + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + namespace_index = parseNamespace(constants, lexer); + expected(ParsedSymbol.TYPE_COMMA, ",", lexer); + ParsedSymbol name = lexer.lex(); + if (name.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + name_index = 0; + } else { + expected(name, ParsedSymbol.TYPE_STRING, "String"); + name_index = constants.getStringId((String) name.value, true); + } + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + case ParsedSymbol.TYPE_KEYWORD_RTQNAME: + case ParsedSymbol.TYPE_KEYWORD_RTQNAMEA: + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + ParsedSymbol rtqName = lexer.lex(); + if (rtqName.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + name_index = 0; + } else { + expected(rtqName, ParsedSymbol.TYPE_STRING, "String"); + name_index = constants.getStringId((String) rtqName.value, true); + } + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + case ParsedSymbol.TYPE_KEYWORD_RTQNAMEL: + case ParsedSymbol.TYPE_KEYWORD_RTQNAMELA: + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + case ParsedSymbol.TYPE_KEYWORD_MULTINAME: + case ParsedSymbol.TYPE_KEYWORD_MULTINAMEA: + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + ParsedSymbol mName = lexer.lex(); + if (mName.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + name_index = 0; + } else { + expected(mName, ParsedSymbol.TYPE_STRING, "String"); + name_index = constants.getStringId((String) mName.value, true); + } + expected(ParsedSymbol.TYPE_COMMA, ",", lexer); + namespace_set_index = parseNamespaceSet(constants, lexer); + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + case ParsedSymbol.TYPE_KEYWORD_MULTINAMEL: + case ParsedSymbol.TYPE_KEYWORD_MULTINAMELA: + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + namespace_set_index = parseNamespaceSet(constants, lexer); + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + case ParsedSymbol.TYPE_KEYWORD_TYPENAME: + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + qname_index = parseMultiName(constants, lexer); + expected(ParsedSymbol.TYPE_LOWERTHAN, "<", lexer); + params.add(parseMultiName(constants, lexer)); + ParsedSymbol nt = lexer.lex(); + while (nt.type == ParsedSymbol.TYPE_COMMA) { + params.add(parseMultiName(constants, lexer)); + nt = lexer.lex(); + } + expected(nt, ParsedSymbol.TYPE_GREATERTHAN, ">"); + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + } + + return constants.getMultinameId(new Multiname(kind, name_index, namespace_index, namespace_set_index, qname_index, params), true); + } + + public static ValueKind parseValue(AVM2ConstantPool constants, Flasm3Lexer lexer) throws IOException, AVM2ParseException { + ParsedSymbol type = lexer.lex(); + ParsedSymbol value; + int value_index = 0; + int value_kind = 0; + switch (type.type) { + case ParsedSymbol.TYPE_KEYWORD_INTEGER: + value_kind = ValueKind.CONSTANT_Int; + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + value = lexer.lex(); + if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + value_index = 0; + } else { + expected(value, ParsedSymbol.TYPE_INTEGER, "Integer or null"); + value_index = constants.getIntId((Long) value.value, true); + } + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + case ParsedSymbol.TYPE_KEYWORD_UINTEGER: + value_kind = ValueKind.CONSTANT_UInt; + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + value = lexer.lex(); + if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + value_index = 0; + } else { + expected(value, ParsedSymbol.TYPE_INTEGER, "UInteger"); + value_index = constants.getUIntId((Long) value.value, true); + } + + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + case ParsedSymbol.TYPE_KEYWORD_DOUBLE: + value_kind = ValueKind.CONSTANT_Double; + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + value = lexer.lex(); + if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + value_index = 0; + } else { + expected(value, ParsedSymbol.TYPE_FLOAT, "Double or null"); + value_index = constants.getDoubleId((Double) value.value, true); + } + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + break; + /*case ParsedSymbol.TYPE_KEYWORD_DECIMAL: + value_kind = ValueKind.CONSTANT_Decimal; + break;*/ + case ParsedSymbol.TYPE_INTEGER: + value_kind = ValueKind.CONSTANT_Int; + value_index = constants.getIntId((Long) type.value, true); + break; + case ParsedSymbol.TYPE_FLOAT: + value_kind = ValueKind.CONSTANT_Double; + value_index = constants.getDoubleId((Double) type.value, true); + break; + case ParsedSymbol.TYPE_STRING: + value_kind = ValueKind.CONSTANT_Utf8; + value_index = constants.getStringId((String) type.value, true); + break; + case ParsedSymbol.TYPE_KEYWORD_UTF8: + value_kind = ValueKind.CONSTANT_Utf8; + expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); + value = lexer.lex(); + if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + value_index = 0; + } else { + expected(value, ParsedSymbol.TYPE_STRING, "String or null"); + expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); + value_index = constants.getStringId((String) value.value, true); + } + break; + case ParsedSymbol.TYPE_KEYWORD_TRUE: + value_kind = ValueKind.CONSTANT_True; + break; + case ParsedSymbol.TYPE_KEYWORD_FALSE: + value_kind = ValueKind.CONSTANT_False; + break; + case ParsedSymbol.TYPE_KEYWORD_NULL: + value_kind = ValueKind.CONSTANT_Null; + break; + case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: + case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: + case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: + case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: + case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: + case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: + case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: + + switch (type.type) { + case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: + value_kind = ValueKind.CONSTANT_Namespace; + break; + case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: + value_kind = ValueKind.CONSTANT_PackageInternalNs; + break; + case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: + value_kind = ValueKind.CONSTANT_ProtectedNamespace; + break; + case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: + value_kind = ValueKind.CONSTANT_ExplicitNamespace; + break; + case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: + value_kind = ValueKind.CONSTANT_StaticProtectedNs; + break; + case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: + value_kind = ValueKind.CONSTANT_PrivateNs; + break; + case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: + value_kind = ValueKind.CONSTANT_PackageNamespace; + break; + } + lexer.pushback(type); + value_index = parseNamespace(constants, lexer); + break; + default: + if (Configuration.debugMode.get()) { + throw new AVM2ParseException("Not supported valueType.", lexer.yyline()); + } + } + return new ValueKind(value_index, value_kind); + } + + public static AVM2Code parse(Reader reader, AVM2ConstantPool constants, Trait trait, MissingSymbolHandler missingHandler, MethodBody body, MethodInfo info) throws IOException, AVM2ParseException, InterruptedException { + AVM2Code code = new AVM2Code(); + + List offsetItems = new ArrayList<>(); + List labelItems = new ArrayList<>(); + List exceptions = new ArrayList<>(); + List exceptionIndices = new ArrayList<>(); + int offset = 0; + + Flasm3Lexer lexer = new Flasm3Lexer(reader); + + ParsedSymbol symb; + AVM2Instruction lastIns = null; + List exceptionsFrom = new ArrayList<>(); + List exceptionsTo = new ArrayList<>(); + List exceptionsTargets = new ArrayList<>(); + info.flags = 0; + info.name_index = 0; + List paramTypes = new ArrayList<>(); + List paramNames = new ArrayList<>(); + List optional = new ArrayList<>(); + do { + symb = lexer.lex(); + if (Arrays.asList(ParsedSymbol.TYPE_KEYWORD_BODY, ParsedSymbol.TYPE_KEYWORD_CODE, ParsedSymbol.TYPE_KEYWORD_METHOD).contains(symb.type)) { + continue; + } + if (symb.type == ParsedSymbol.TYPE_KEYWORD_TRAIT) { + if (trait == null) { + throw new AVM2ParseException("No trait expected", lexer.yyline()); + } + symb = lexer.lex(); + switch (symb.type) { + case ParsedSymbol.TYPE_KEYWORD_METHOD: + case ParsedSymbol.TYPE_KEYWORD_GETTER: + case ParsedSymbol.TYPE_KEYWORD_SETTER: + if (!(trait instanceof TraitMethodGetterSetter)) { + throw new AVM2ParseException("Unxpected trait type", lexer.yyline()); + } + TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait; + switch (symb.type) { + case ParsedSymbol.TYPE_KEYWORD_METHOD: + tm.kindType = Trait.TRAIT_METHOD; + break; + case ParsedSymbol.TYPE_KEYWORD_GETTER: + tm.kindType = Trait.TRAIT_GETTER; + break; + case ParsedSymbol.TYPE_KEYWORD_SETTER: + tm.kindType = Trait.TRAIT_SETTER; + break; + } + tm.name_index = parseMultiName(constants, lexer); + expected(ParsedSymbol.TYPE_KEYWORD_DISPID, "dispid", lexer); + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); + tm.disp_id = (int) (long) (Long) symb.value; + + break; + case ParsedSymbol.TYPE_KEYWORD_FUNCTION: + if (!(trait instanceof TraitFunction)) { + throw new AVM2ParseException("Unxpected trait type", lexer.yyline()); + } + break; + + } + continue; + } + if (symb.type == ParsedSymbol.TYPE_KEYWORD_NAME) { + symb = lexer.lex(); + if (symb.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + info.name_index = 0; + } else { + expected(symb, ParsedSymbol.TYPE_STRING, "String or null"); + info.name_index = constants.getStringId((String) symb.value, true); + } + continue; + } + if (symb.type == ParsedSymbol.TYPE_KEYWORD_PARAM) { + paramTypes.add(parseMultiName(constants, lexer)); + continue; + } + if (symb.type == ParsedSymbol.TYPE_KEYWORD_PARAMNAME) { + symb = lexer.lex(); + if (symb.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + paramNames.add(0); + } else { + expected(symb, ParsedSymbol.TYPE_STRING, "String or null"); + paramNames.add(constants.getStringId((String) symb.value, true)); + } + continue; + } + + if (symb.type == ParsedSymbol.TYPE_KEYWORD_OPTIONAL) { + optional.add(parseValue(constants, lexer)); + continue; + } + + if (symb.type == ParsedSymbol.TYPE_KEYWORD_MAXSTACK) { + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); + body.max_stack = (int) (long) (Long) symb.value; + continue; + } + + if (symb.type == ParsedSymbol.TYPE_KEYWORD_LOCALCOUNT) { + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); + body.max_regs = (int) (long) (Long) symb.value; + continue; + } + + if (symb.type == ParsedSymbol.TYPE_KEYWORD_INITSCOPEDEPTH) { + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); + body.init_scope_depth = (int) (long) (Long) symb.value; + continue; + } + + if (symb.type == ParsedSymbol.TYPE_KEYWORD_MAXSCOPEDEPTH) { + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); + body.max_scope_depth = (int) (long) (Long) symb.value; + continue; + } + + if (symb.type == ParsedSymbol.TYPE_KEYWORD_RETURNS) { + info.ret_type = parseMultiName(constants, lexer); + continue; + } + + if (symb.type == ParsedSymbol.TYPE_KEYWORD_FLAG) { + symb = lexer.lex(); + switch (symb.type) { + case ParsedSymbol.TYPE_KEYWORD_EXPLICIT: + info.setFlagExplicit(); + break; + case ParsedSymbol.TYPE_KEYWORD_HAS_OPTIONAL: + info.setFlagHas_optional(); + break; + case ParsedSymbol.TYPE_KEYWORD_HAS_PARAM_NAMES: + info.setFlagHas_paramnames(); + break; + case ParsedSymbol.TYPE_KEYWORD_IGNORE_REST: + info.setFlagIgnore_Rest(); + break; + case ParsedSymbol.TYPE_KEYWORD_NEED_ACTIVATION: + info.setFlagNeed_activation(); + break; + case ParsedSymbol.TYPE_KEYWORD_NEED_ARGUMENTS: + info.setFlagNeed_Arguments(); + break; + case ParsedSymbol.TYPE_KEYWORD_NEED_REST: + info.setFlagNeed_rest(); + break; + case ParsedSymbol.TYPE_KEYWORD_SET_DXNS: + info.setFlagSetsdxns(); + break; + } + continue; + } + if (symb.type == ParsedSymbol.TYPE_KEYWORD_TRY) { + expected(ParsedSymbol.TYPE_KEYWORD_FROM, "From", lexer); + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); + exceptionsFrom.add((String) symb.value); + expected(ParsedSymbol.TYPE_KEYWORD_TO, "To", lexer); + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); + exceptionsTo.add((String) symb.value); + expected(ParsedSymbol.TYPE_KEYWORD_TARGET, "Target", lexer); + symb = lexer.lex(); + expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); + exceptionsTargets.add((String) symb.value); + expected(ParsedSymbol.TYPE_KEYWORD_TYPE, "Type", lexer); + ABCException ex = new ABCException(); + ex.type_index = parseMultiName(constants, lexer); + expected(ParsedSymbol.TYPE_KEYWORD_NAME, "Name", lexer); + ex.name_index = parseMultiName(constants, lexer); + exceptions.add(ex); + continue; + } + if (symb.type == ParsedSymbol.TYPE_EXCEPTION_START) { + int exIndex = (Integer) symb.value; + int listIndex = exceptionIndices.indexOf(exIndex); + if (listIndex == -1) { + throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); + } + exceptions.get(listIndex).start = offset; + continue; + } + if (symb.type == ParsedSymbol.TYPE_EXCEPTION_END) { + int exIndex = (Integer) symb.value; + int listIndex = exceptionIndices.indexOf(exIndex); + if (listIndex == -1) { + throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); + } + exceptions.get(listIndex).end = offset; + continue; + } + if (symb.type == ParsedSymbol.TYPE_EXCEPTION_TARGET) { + int exIndex = (Integer) symb.value; + int listIndex = exceptionIndices.indexOf(exIndex); + if (listIndex == -1) { + throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); + } + exceptions.get(listIndex).target = offset; + continue; + } + if (symb.type == ParsedSymbol.TYPE_EOF) { + break; + } + if (symb.type == ParsedSymbol.TYPE_COMMENT) { + if (lastIns != null) { + lastIns.comment = (String) symb.value; + } + continue; + } + if (symb.type == ParsedSymbol.TYPE_INSTRUCTION_NAME) { + if (((String) symb.value).toLowerCase(Locale.ENGLISH).equals("exception")) { + ParsedSymbol exIndex = lexer.lex(); + if (exIndex.type != ParsedSymbol.TYPE_INTEGER) { + throw new AVM2ParseException("Index expected", lexer.yyline()); + } + ParsedSymbol exName = lexer.lex(); + if (exName.type != ParsedSymbol.TYPE_MULTINAME) { + throw new AVM2ParseException("Multiname expected", lexer.yyline()); + } + ParsedSymbol exType = lexer.lex(); + if (exType.type != ParsedSymbol.TYPE_MULTINAME) { + throw new AVM2ParseException("Multiname expected", lexer.yyline()); + } + ABCException ex = new ABCException(); + + ex.name_index = checkMultinameIndex(constants, (int) (long) (Long) exName.value, lexer.yyline()); + ex.type_index = checkMultinameIndex(constants, (int) (long) (Long) exType.value, lexer.yyline()); + exceptions.add(ex); + exceptionIndices.add((int) (long) (Long) exIndex.value); + continue; + } + boolean insFound = false; + for (InstructionDefinition def : AVM2Code.instructionSet) { + if (def != null && def.instructionName.equals((String) symb.value)) { + insFound = true; + List operandsList = new ArrayList<>(); + + for (int i = 0; i < def.operands.length; i++) { + ParsedSymbol parsedOperand = lexer.lex(); + switch (def.operands[i]) { + case AVM2Code.DAT_MULTINAME_INDEX: + lexer.pushback(parsedOperand); + operandsList.add(parseMultiName(constants, lexer)); + /*if (parsedOperand.type == ParsedSymbol.TYPE_MULTINAME) { + operandsList.add(checkMultinameIndex(constants, (int) (long) (Long) parsedOperand.value, lexer.yyline())); + } else { + throw new ParseException("Multiname expected", lexer.yyline()); + }*/ + break; + case AVM2Code.DAT_STRING_INDEX: + if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + operandsList.add(0); + } else { + if (parsedOperand.type == ParsedSymbol.TYPE_STRING) { + int sid = constants.getStringId((String) parsedOperand.value); + if (sid == 0) { + if ((missingHandler != null) && (missingHandler.missingString((String) parsedOperand.value))) { + sid = constants.addString((String) parsedOperand.value); + } else { + throw new AVM2ParseException("Unknown String", lexer.yyline()); + } + } + operandsList.add(sid); + } else { + throw new AVM2ParseException("String or null expected", lexer.yyline()); + } + } + break; + case AVM2Code.DAT_INT_INDEX: + + if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + operandsList.add(0); + } else { + if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { + long intVal = (Long) parsedOperand.value; + int iid = constants.getIntId(intVal); + if (iid == 0) { + if ((missingHandler != null) && (missingHandler.missingInt(intVal))) { + iid = constants.addInt(intVal); + } else { + throw new AVM2ParseException("Unknown int", lexer.yyline()); + } + } + operandsList.add(iid); + } else { + throw new AVM2ParseException("Integer or null expected", lexer.yyline()); + } + } + break; + case AVM2Code.DAT_UINT_INDEX: + if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + operandsList.add(0); + } else { + if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { + long intVal = (Long) parsedOperand.value; + int iid = constants.getUIntId(intVal); + if (iid == 0) { + if ((missingHandler != null) && (missingHandler.missingUInt(intVal))) { + iid = constants.addUInt(intVal); + } else { + throw new AVM2ParseException("Unknown uint", lexer.yyline()); + } + } + operandsList.add(iid); + } else { + throw new AVM2ParseException("Integer or null expected", lexer.yyline()); + } + } + break; + case AVM2Code.DAT_DOUBLE_INDEX: + if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { + operandsList.add(0); + } else { + if ((parsedOperand.type == ParsedSymbol.TYPE_INTEGER) || (parsedOperand.type == ParsedSymbol.TYPE_FLOAT)) { + + double doubleVal = 0; + if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { + doubleVal = (Long) parsedOperand.value; + } + if (parsedOperand.type == ParsedSymbol.TYPE_FLOAT) { + doubleVal = (Double) parsedOperand.value; + } + int did = constants.getDoubleId(doubleVal); + if (did == 0) { + if ((missingHandler != null) && (missingHandler.missingDouble(doubleVal))) { + did = constants.addDouble(doubleVal); + } else { + throw new AVM2ParseException("Unknown double", lexer.yyline()); + } + } + operandsList.add(did); + } else { + throw new AVM2ParseException("Float or null expected", lexer.yyline()); + } + } + break; + case AVM2Code.DAT_OFFSET: + if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { + offsetItems.add(new OffsetItem((String) parsedOperand.value, code.code.size(), i)); + operandsList.add(0); + } else { + throw new AVM2ParseException("Offset expected", lexer.yyline()); + } + break; + case AVM2Code.DAT_CASE_BASEOFFSET: + if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { + offsetItems.add(new CaseOffsetItem((String) parsedOperand.value, code.code.size(), i)); + operandsList.add(0); + } else { + throw new AVM2ParseException("Offset expected", lexer.yyline()); + } + break; + case AVM2Code.OPT_CASE_OFFSETS: + + if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { + int patCount = (int) (long) (Long) parsedOperand.value; + operandsList.add(patCount); + + for (int c = 0; c <= patCount; c++) { + parsedOperand = lexer.lex(); + if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { + offsetItems.add(new CaseOffsetItem((String) parsedOperand.value, code.code.size(), i + (c + 1))); + operandsList.add(0); + } else { + throw new AVM2ParseException("Offset expected", lexer.yyline()); + } + } + } else { + throw new AVM2ParseException("Case count expected", lexer.yyline()); + } + break; + case AVM2Code.OPT_BYTE: + if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { + long val = (long) (Long) parsedOperand.value; + if (val < Byte.MIN_VALUE || val > Byte.MAX_VALUE) { + throw new AVM2ParseException("Byte value expected (" + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE + "). Use pushshort or pushint to push larger values", lexer.yyline()); + } + operandsList.add((int) val); + } else { + throw new AVM2ParseException("Integer expected", lexer.yyline()); + } + break; + default: + if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { + long val = (long) (Long) parsedOperand.value; + if (def instanceof PushShortIns) { + if (val < Short.MIN_VALUE || val > Short.MAX_VALUE) { + throw new AVM2ParseException("Short value expected (" + Short.MIN_VALUE + " to " + Short.MAX_VALUE + "). Use pushint to push larger values", lexer.yyline()); + } + } + operandsList.add((int) val); + } else { + throw new AVM2ParseException("Integer expected", lexer.yyline()); + } + } + } + + int[] operands = new int[operandsList.size()]; + for (int i = 0; i < operandsList.size(); i++) { + operands[i] = operandsList.get(i); + } + lastIns = new AVM2Instruction(offset, def, operands); + code.code.add(lastIns); + offset += lastIns.getBytesLength(); + break; + } + } + if (symb.value.toString().toLowerCase().equals("ffdec_deobfuscatepop")) { + lastIns = new AVM2Instruction(offset, new DeobfuscatePopIns(), null); + code.code.add(lastIns); + offset += lastIns.getBytesLength(); + insFound = true; + } + if (!insFound) { + throw new AVM2ParseException("Invalid instruction name:" + (String) symb.value, lexer.yyline()); + } + } else if (symb.type == ParsedSymbol.TYPE_LABEL) { + labelItems.add(new LabelItem((String) symb.value, offset)); + + } else { + throw new AVM2ParseException("Unexpected symbol", lexer.yyline()); + } + } while (symb.type != ParsedSymbol.TYPE_EOF); + + code.compact(); + for (LabelItem li : labelItems) { + int ind; + ind = exceptionsFrom.indexOf(li.label); + if (ind > -1) { + exceptions.get(ind).start = li.offset; + } + + ind = exceptionsTo.indexOf(li.label); + if (ind > -1) { + exceptions.get(ind).end = li.offset; + } + + ind = exceptionsTargets.indexOf(li.label); + if (ind > -1) { + exceptions.get(ind).target = li.offset; + } + } + + for (OffsetItem oi : offsetItems) { + for (LabelItem li : labelItems) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + if (oi.label.equals(li.label)) { + AVM2Instruction ins = code.code.get((int) oi.insPosition); + int relOffset; + if (oi instanceof CaseOffsetItem) { + relOffset = li.offset - (int) ins.offset; + } else { + relOffset = li.offset - ((int) ins.offset + ins.getBytesLength()); + } + ins.operands[oi.insOperandIndex] = relOffset; + } + } + } + body.exceptions = new ABCException[exceptions.size()]; + for (int e = 0; e < exceptions.size(); e++) { + body.exceptions[e] = exceptions.get(e); + } + + info.param_types = new int[paramTypes.size()]; + for (int i = 0; i < paramTypes.size(); i++) { + info.param_types[i] = paramTypes.get(i); + } + + if (info.flagHas_paramnames()) { + info.paramNames = new int[paramNames.size()]; + for (int i = 0; i < paramNames.size(); i++) { + info.paramNames[i] = paramNames.get(i); + } + } + + if (info.flagHas_optional()) { + info.optional = new ValueKind[optional.size()]; + for (int i = 0; i < optional.size(); i++) { + info.optional[i] = optional.get(i); + } + } + return code; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java index 37c42df8c..3ac417bcb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java @@ -394,7 +394,7 @@ public class AVM2SourceGenerator implements SourceGenerator { int pos = 0; for (int a = 0; a < code.size(); a++) { AVM2Instruction ins = code.get(a); - pos += ins.getBytes().length; + pos += ins.getBytesLength(); if (ins.definition instanceof JumpIns) { if (ins.definition instanceof ContinueJumpIns) { if (continueOffset != Integer.MAX_VALUE) { @@ -924,7 +924,7 @@ public class AVM2SourceGenerator implements SourceGenerator { List finallySwitchCmds = new ArrayList<>(); finSwitch = new AVM2Instruction(0, new LookupSwitchIns(), new int[1 + 1 + 1]); - finSwitch.operands[0] = finSwitch.getBytes().length; + finSwitch.operands[0] = finSwitch.getBytesLength(); finSwitch.operands[1] = 0; //switch cnt List preFinallySwitch = new ArrayList<>(); @@ -1004,7 +1004,7 @@ public class AVM2SourceGenerator implements SourceGenerator { continue; } } - pos += ins.getBytes().length; + pos += ins.getBytesLength(); } } @@ -1028,13 +1028,13 @@ public class AVM2SourceGenerator implements SourceGenerator { if (wasDef) { ins.operands[0] = 0; } else { - ins.operands[0] = finallyPos - (pos + ins.getBytes().length); + ins.operands[0] = finallyPos - (pos + ins.getBytesLength()); } ins.definition = new JumpIns(); - switchLoc.add(pos + ins.getBytes().length + betLen - switchPos); + switchLoc.add(pos + ins.getBytesLength() + betLen - switchPos); } } - pos += ins.getBytes().length; + pos += ins.getBytesLength(); } if (defPos == switchLoc.size() - 1) { switchLoc.add(defLoc); @@ -1043,7 +1043,7 @@ public class AVM2SourceGenerator implements SourceGenerator { } finSwitch.operands = new int[1 + 1 + switchLoc.size()]; pushDefIns.operands[0] = defPos + 1; - int afterLoc = finSwitch.getBytes().length; + int afterLoc = finSwitch.getBytesLength(); finSwitch.operands[0] = afterLoc; finSwitch.operands[1] = switchLoc.size() - 1; for (int j = 0; j < switchLoc.size(); j++) { @@ -1806,7 +1806,7 @@ public class AVM2SourceGenerator implements SourceGenerator { i--; continue; } - offset += ins.getBytes().length; + offset += ins.getBytesLength(); } mbody.markOffsets(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ExceptionMarkAVM2Instruction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ExceptionMarkAVM2Instruction.java index 8ca8ea88c..a592f9160 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ExceptionMarkAVM2Instruction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ExceptionMarkAVM2Instruction.java @@ -40,4 +40,9 @@ public class ExceptionMarkAVM2Instruction extends AVM2Instruction { public byte[] getBytes() { return new byte[0]; } + + @Override + public int getBytesLength() { + return 0; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index 4be2e5b15..2114c6df1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -146,7 +146,7 @@ public final class MethodBody implements Cloneable { long offset = 0; for (int i = 0; i < getCode().code.size(); i++) { getCode().code.get(i).offset = offset; - offset += getCode().code.get(i).getBytes().length; + offset += getCode().code.get(i).getBytesLength(); } } @@ -241,7 +241,7 @@ public final class MethodBody implements Cloneable { } public void convert(final String path, ScriptExportMode exportMode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final AVM2ConstantPool constants, final List method_info, final ScopeStack scopeStack, final boolean isStaticInitializer, final GraphTextWriter writer, final List fullyQualifiedNames, final Traits initTraits, boolean firstLevel) throws InterruptedException { - /*if (!path.contains("testCatchFinally")) { + /*if (!path.contains("forcedWidth")) { return; }*/ if (debugMode) { @@ -290,7 +290,7 @@ public final class MethodBody implements Cloneable { } public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final AVM2ConstantPool constants, final List method_info, final GraphTextWriter writer, final List fullyQualifiedNames) throws InterruptedException { - /*if (!path.contains("testCatchFinally")) { + /*if (!path.contains("forcedWidth")) { return writer; }*/ if (exportMode != ScriptExportMode.AS) { diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ABCStreamTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ABCStreamTest.java index f8e50109f..5eabe771f 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ABCStreamTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ABCStreamTest.java @@ -21,6 +21,8 @@ import com.jpexs.decompiler.flash.abc.ABCOutputStream; import com.jpexs.helpers.MemoryInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; import org.testng.annotations.BeforeClass; @@ -37,20 +39,80 @@ public class ABCStreamTest { //Main.initLogging(false); } + private List getTestNumebers(long min, long max) { + List res = new ArrayList<>(); + addWhenBetween(res, 1531, min, max); + long x = 1; + for (int i = 0; i < 32; i++) { + x <<= 1; + addWhenBetween(res, x - 1, min, max); + addWhenBetween(res, x, min, max); + addWhenBetween(res, x + 1, min, max); + addWhenBetween(res, -(x - 1), min, max); + addWhenBetween(res, -x, min, max); + addWhenBetween(res, -(x + 1), min, max); + } + + return res; + } + + private void addWhenBetween(List list, long num, long min, long max) { + if (num >= min && num <= max) { + list.add(num); + } + } + @Test public void testU30() { - try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ABCOutputStream aos = new ABCOutputStream(baos);) { - long number = 1531; - aos.writeU30(number); - aos.close(); - try (MemoryInputStream mis = new MemoryInputStream(baos.toByteArray()); - ABCInputStream ais = new ABCInputStream(mis);) { - assertEquals(number, ais.readU30("test")); - assertEquals(0, mis.available()); + for (long number : getTestNumebers(0, (1L << 30) - 1)) { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ABCOutputStream aos = new ABCOutputStream(baos);) { + aos.writeU30(number); + aos.close(); + try (MemoryInputStream mis = new MemoryInputStream(baos.toByteArray()); + ABCInputStream ais = new ABCInputStream(mis);) { + assertEquals(number, ais.readU30("test")); + assertEquals(0, mis.available()); + } + } catch (IOException ex) { + fail(); + } + } + } + + @Test + public void testU32() { + for (long number : getTestNumebers(0, (1L << 32) - 1)) { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ABCOutputStream aos = new ABCOutputStream(baos);) { + aos.writeU32(number); + aos.close(); + try (MemoryInputStream mis = new MemoryInputStream(baos.toByteArray()); + ABCInputStream ais = new ABCInputStream(mis);) { + assertEquals(number, ais.readU32("test")); + assertEquals(0, mis.available()); + } + } catch (IOException ex) { + fail(); + } + } + } + + @Test + public void testS32() { + for (long number : getTestNumebers(-(1L << 31), (1 << 31) - 1)) { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ABCOutputStream aos = new ABCOutputStream(baos);) { + aos.writeU32(number); + aos.close(); + try (MemoryInputStream mis = new MemoryInputStream(baos.toByteArray()); + ABCInputStream ais = new ABCInputStream(mis);) { + assertEquals(number, ais.readS32("test")); + assertEquals(0, mis.available()); + } + } catch (IOException ex) { + fail(); } - } catch (IOException ex) { - fail(); } } } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java index e9e1073fb..178887af7 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java @@ -53,6 +53,7 @@ public class ActionScript3DeobfuscatorTest extends ActionStript2TestBase { //Main.initLogging(false); Configuration.autoDeobfuscate.set(true); Configuration.deobfuscationMode.set(1); + Configuration.decimalAddress.set(false); swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as3/as3.swf")), false); } @@ -225,7 +226,7 @@ public class ActionScript3DeobfuscatorTest extends ActionStript2TestBase { public void testJumps() throws Exception { String res = recompilePCode("pushbyte 3\r\n" + "pushbyte 4\r\n" - + "ifeq a\r\n" //should change to ifeq c + + "ifeq a\r\n" //should change to ifeq c + "jump b\r\n" //should not change + "a:jump c\r\n" + "c:pushbyte 4\r\n"