Issue #691 AS3 P-code reading/saving fix

This commit is contained in:
Jindra Petřík
2014-09-23 19:26:13 +02:00
parent a431639521
commit b211d3b8cf
2 changed files with 53 additions and 63 deletions

View File

@@ -661,14 +661,14 @@ public class ABC {
aos.writeTraits(si.traits);
}
aos.writeU30(bodies.size());
aos.writeU30(bodies.size());
for (MethodBody mb : bodies) {
aos.writeU30(mb.method_info);
aos.writeU30(mb.max_stack);
aos.writeU30(mb.max_regs);
aos.writeU30(mb.init_scope_depth);
aos.writeU30(mb.max_scope_depth);
byte[] codeBytes = mb.getCode().getBytes();
byte[] codeBytes = mb.getCode().getBytes();
aos.writeU30(codeBytes.length);
aos.write(codeBytes);
aos.writeU30(mb.exceptions.length);

View File

@@ -784,75 +784,62 @@ public class AVM2Code implements Cloneable {
return null;
}
public AVM2Code(ABCInputStream ais) throws IOException {
public AVM2Code(ABCInputStream ais) throws IOException {
//Note: special jump handling like in AS1/2 is not needed as code must pass FlashPlayer verification
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;
}
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("operand");
}
} 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.readU8("operand");
break;
case OPT_BYTE:
actualOperands[op] = (byte) ais.read("operand");
break;
case OPT_S24:
actualOperands[op] = ais.readS24("operand");
break;
}
}
}
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);
}
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)
}
} catch (EndOfStreamException ex) {
// lookupswitch obfuscation, ignore
ais.endDumpLevelUntil(diParent);
}
} catch (EndOfStreamException ex) {
ais.endDumpLevelUntil(diParent);
}
code.addAll(codeMap.values());
@@ -1599,6 +1586,7 @@ public class AVM2Code implements Cloneable {
prev = ins;
}
return ret;
}
private class Slot {
@@ -2256,6 +2244,7 @@ public class AVM2Code implements Cloneable {
prev = ins;
};
return ret;
}
private static class ControlFlowTag {
@@ -2483,6 +2472,7 @@ public class AVM2Code implements Cloneable {
for (int i = 0; i < code.size(); i++) {
code.get(i).mappedOffset = ofs;
ofs += code.get(i).getBytes().length;
}
}