mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-28 21:10:46 +00:00
AVM2 instruction reading fix, strongly typed Cache key
This commit is contained in:
@@ -42,7 +42,6 @@ public class ABCInputStream implements AutoCloseable {
|
||||
private static final int CLASS_PROTECTED_NS = 8;
|
||||
private static final int ATTR_METADATA = 4;
|
||||
private final MemoryInputStream is;
|
||||
private long bytesRead = 0;
|
||||
private ByteArrayOutputStream bufferOs = null;
|
||||
public static final boolean DEBUG_READ = false;
|
||||
public DumpInfo dumpInfo;
|
||||
@@ -102,8 +101,15 @@ public class ABCInputStream implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
public void endDumpLevelUntil(DumpInfo di) {
|
||||
if (di != null) {
|
||||
while (dumpInfo != null && dumpInfo != di) {
|
||||
endDumpLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int readInternal() throws IOException {
|
||||
bytesRead++;
|
||||
int i = is.read();
|
||||
if (i == -1) {
|
||||
throw new EndOfStreamException();
|
||||
@@ -128,7 +134,6 @@ public class ABCInputStream implements AutoCloseable {
|
||||
|
||||
private int read(byte[] b) throws IOException {
|
||||
int currBytesRead = is.read(b);
|
||||
bytesRead += currBytesRead;
|
||||
if (DEBUG_READ) {
|
||||
StringBuilder sb = new StringBuilder("Read[");
|
||||
sb.append(currBytesRead);
|
||||
@@ -478,7 +483,7 @@ public class ABCInputStream implements AutoCloseable {
|
||||
bytesRead=0;
|
||||
}*/
|
||||
public long getPosition() {
|
||||
return bytesRead;
|
||||
return is.getPos();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -243,6 +243,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -784,59 +785,77 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
|
||||
public AVM2Code(ABCInputStream ais) throws IOException {
|
||||
try {
|
||||
while (ais.available() > 0) {
|
||||
DumpInfo di = ais.newDumpLevel("instruction", "instruction");
|
||||
long startOffset = ais.getPosition();
|
||||
int instructionCode = ais.read("instructionCode");
|
||||
InstructionDefinition instr = instructionSetByCode[instructionCode];
|
||||
if (di != null) {
|
||||
di.name = instr.instructionName;
|
||||
}
|
||||
if (instr != null) {
|
||||
int[] actualOperands = null;
|
||||
if (instructionCode == 0x1b) { //switch
|
||||
int firstOperand = ais.readS24("default_offset");
|
||||
int case_count = ais.readU30("case_count");
|
||||
actualOperands = new int[case_count + 3];
|
||||
actualOperands[0] = firstOperand;
|
||||
actualOperands[1] = case_count;
|
||||
for (int c = 0; c < case_count + 1; c++) {
|
||||
actualOperands[2 + c] = ais.readS24("actualOperand");
|
||||
}
|
||||
} else {
|
||||
if (instr.operands.length > 0) {
|
||||
actualOperands = new int[instr.operands.length];
|
||||
for (int op = 0; op < instr.operands.length; op++) {
|
||||
switch (instr.operands[op] & 0xff00) {
|
||||
case OPT_U30:
|
||||
actualOperands[op] = ais.readU30("operand");
|
||||
break;
|
||||
case OPT_U8:
|
||||
actualOperands[op] = ais.read("operand");
|
||||
break;
|
||||
case OPT_BYTE:
|
||||
actualOperands[op] = (byte) ais.read("operand");
|
||||
break;
|
||||
case OPT_S24:
|
||||
actualOperands[op] = ais.readS24("operand");
|
||||
break;
|
||||
Map<Long, AVM2Instruction> codeMap = new TreeMap<>();
|
||||
DumpInfo diParent = ais.dumpInfo;
|
||||
List<Long> addresses = new ArrayList<>();
|
||||
addresses.add(ais.getPosition());
|
||||
while (!addresses.isEmpty()) {
|
||||
long address = addresses.remove(0);
|
||||
if (codeMap.containsKey(address)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
ais.seek(address);
|
||||
while (ais.available() > 0) {
|
||||
DumpInfo di = ais.newDumpLevel("instruction", "instruction");
|
||||
long startOffset = ais.getPosition();
|
||||
int instructionCode = ais.read("instructionCode");
|
||||
InstructionDefinition instr = instructionSetByCode[instructionCode];
|
||||
if (di != null) {
|
||||
di.name = instr.instructionName;
|
||||
}
|
||||
if (instr != null) {
|
||||
int[] actualOperands = null;
|
||||
if (instructionCode == 0x1b) { //switch
|
||||
int firstOperand = ais.readS24("default_offset");
|
||||
int case_count = ais.readU30("case_count");
|
||||
actualOperands = new int[case_count + 3];
|
||||
actualOperands[0] = firstOperand;
|
||||
actualOperands[1] = case_count;
|
||||
for (int c = 0; c < case_count + 1; c++) {
|
||||
actualOperands[2 + c] = ais.readS24("actualOperand");
|
||||
}
|
||||
} else {
|
||||
if (instr.operands.length > 0) {
|
||||
actualOperands = new int[instr.operands.length];
|
||||
for (int op = 0; op < instr.operands.length; op++) {
|
||||
switch (instr.operands[op] & 0xff00) {
|
||||
case OPT_U30:
|
||||
actualOperands[op] = ais.readU30("operand");
|
||||
break;
|
||||
case OPT_U8:
|
||||
actualOperands[op] = ais.read("operand");
|
||||
break;
|
||||
case OPT_BYTE:
|
||||
actualOperands[op] = (byte) ais.read("operand");
|
||||
break;
|
||||
case OPT_S24:
|
||||
actualOperands[op] = ais.readS24("operand");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code.add(new AVM2Instruction(startOffset, instr, actualOperands));
|
||||
ais.endDumpLevel(instr.instructionCode);
|
||||
} else {
|
||||
ais.endDumpLevel();
|
||||
break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions)
|
||||
//throw new UnknownInstructionCode(instructionCode);
|
||||
if (instr instanceof IfTypeIns) {
|
||||
long target = ais.getPosition() + actualOperands[0];
|
||||
addresses.add(target);
|
||||
}
|
||||
codeMap.put(startOffset, new AVM2Instruction(startOffset, instr, actualOperands));
|
||||
ais.endDumpLevel(instr.instructionCode);
|
||||
} else {
|
||||
ais.endDumpLevel();
|
||||
break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions)
|
||||
//throw new UnknownInstructionCode(instructionCode);
|
||||
}
|
||||
}
|
||||
} catch (EndOfStreamException ex) {
|
||||
// lookupswitch obfuscation, ignore
|
||||
ais.endDumpLevelUntil(diParent);
|
||||
}
|
||||
} catch (EndOfStreamException ex) {
|
||||
// lookupswitch obfuscation, ignore
|
||||
}
|
||||
|
||||
code.addAll(codeMap.values());
|
||||
}
|
||||
|
||||
public void compact() {
|
||||
@@ -1065,7 +1084,6 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
}
|
||||
}
|
||||
long ofs = 0;
|
||||
int ip = 0;
|
||||
int largeLimit = 20000;
|
||||
boolean markOffsets = code.size() <= largeLimit;
|
||||
@@ -1074,6 +1092,7 @@ public class AVM2Code implements Cloneable {
|
||||
Helper.byteArrayToHexWithHeader(writer, getBytes());
|
||||
} else {
|
||||
for (AVM2Instruction ins : code) {
|
||||
long ofs = ins.offset;
|
||||
if (exportMode == ScriptExportMode.PCODE_HEX) {
|
||||
writer.appendNoHilight("; ");
|
||||
writer.appendNoHilight(Helper.bytesToHexString(ins.getBytes()));
|
||||
@@ -1144,7 +1163,6 @@ public class AVM2Code implements Cloneable {
|
||||
outputMap.add(ip);
|
||||
}
|
||||
}
|
||||
ofs += ins.getBytes().length;
|
||||
ip++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import com.jpexs.decompiler.flash.abc.types.NamespaceSet;
|
||||
import com.jpexs.helpers.utf8.Utf8PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AVM2ConstantPool {
|
||||
|
||||
@@ -117,35 +119,75 @@ public class AVM2ConstantPool {
|
||||
}
|
||||
|
||||
public long getInt(int index) {
|
||||
return constant_int.get(index);
|
||||
try {
|
||||
return constant_int.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
Logger.getLogger(AVM2ConstantPool.class.getName()).log(Level.SEVERE, "Multiname not found. Index: " + index, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Namespace getNamespace(int index) {
|
||||
return constant_namespace.get(index);
|
||||
try {
|
||||
return constant_namespace.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
Logger.getLogger(AVM2ConstantPool.class.getName()).log(Level.SEVERE, "Multiname not found. Index: " + index, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public NamespaceSet getNamespaceSet(int index) {
|
||||
return constant_namespace_set.get(index);
|
||||
try {
|
||||
return constant_namespace_set.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
Logger.getLogger(AVM2ConstantPool.class.getName()).log(Level.SEVERE, "Multiname not found. Index: " + index, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Multiname getMultiname(int index) {
|
||||
return constant_multiname.get(index);
|
||||
try {
|
||||
return constant_multiname.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
Logger.getLogger(AVM2ConstantPool.class.getName()).log(Level.SEVERE, "Multiname not found. Index: " + index, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getUInt(int index) {
|
||||
return constant_uint.get(index);
|
||||
try {
|
||||
return constant_uint.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
Logger.getLogger(AVM2ConstantPool.class.getName()).log(Level.SEVERE, "Multiname not found. Index: " + index, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public double getDouble(int index) {
|
||||
return constant_double.get(index);
|
||||
try {
|
||||
return constant_double.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
Logger.getLogger(AVM2ConstantPool.class.getName()).log(Level.SEVERE, "Multiname not found. Index: " + index, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Decimal getDecimal(int index) {
|
||||
return constant_decimal.get(index);
|
||||
try {
|
||||
return constant_decimal.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
Logger.getLogger(AVM2ConstantPool.class.getName()).log(Level.SEVERE, "Multiname not found. Index: " + index, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getString(int index) {
|
||||
return constant_string.get(index);
|
||||
try {
|
||||
return constant_string.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
Logger.getLogger(AVM2ConstantPool.class.getName()).log(Level.SEVERE, "Multiname not found. Index: " + index, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getIntCount() {
|
||||
|
||||
+7
-1
@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
@@ -173,7 +174,12 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
s.append(" null");
|
||||
} else {
|
||||
s.append(" ");
|
||||
s.append(constants.getMultiname(operands[i]).toString(constants, fullyQualifiedNames));
|
||||
Multiname multiname = constants.getMultiname(operands[i]);
|
||||
if (multiname != null) {
|
||||
s.append(multiname.toString(constants, fullyQualifiedNames));
|
||||
} else {
|
||||
s.append("Multiname not found.");
|
||||
}
|
||||
}
|
||||
/*s.append(" m[");
|
||||
s.append(operands[i]);
|
||||
|
||||
Reference in New Issue
Block a user