Issue #939 AS3 Correct deobfuscate pop

AS3 Improved P-code reading - Ignoring jumps in unreachable code
This commit is contained in:
Jindra Petřík
2015-07-05 20:41:12 +02:00
parent 1a90ab026d
commit 1caf4e4856
4 changed files with 49 additions and 28 deletions

View File

@@ -777,6 +777,8 @@ public class AVM2Code implements Cloneable {
Map<Long, AVM2Instruction> codeMap = new TreeMap<>();
DumpInfo diParent = ais.dumpInfo;
List<Long> addresses = new ArrayList<>();
//Do not add new jumps when processing these addresses (unreachable code,etc.)
List<Long> unAdresses = new ArrayList<>();
//Handle lookupswitches at the end - they can be invalid. Handle other instruction first so we can decide lookupswitch to be invalid based on other instructions inside it
//Flashplayer does not check casecount in lookupswitch instruction so the instruction can "be" long and over other instructions
List<Long> switchAddresses = new ArrayList<>();
@@ -789,14 +791,18 @@ public class AVM2Code implements Cloneable {
addresses.add(startPos);
loopaddr:
while (!addresses.isEmpty() || !switchAddresses.isEmpty()) {
while (!addresses.isEmpty() || !switchAddresses.isEmpty() || !unAdresses.isEmpty()) {
long address;
boolean isSwitch = false;
boolean handleJumps = true;
if (!addresses.isEmpty()) {
address = addresses.remove(0);
} else {
} else if (!switchAddresses.isEmpty()) {
address = switchAddresses.remove(0);
isSwitch = true;
} else {
address = unAdresses.remove(0);
handleJumps = false;
}
if (codeMap.containsKey(address) && !(codeMap.get(address).definition instanceof NopIns)) {
continue;
@@ -805,6 +811,7 @@ public class AVM2Code implements Cloneable {
{
continue;
}
boolean afterExit = false;
try {
ais.seek(address);
while (ais.available() > 0) {
@@ -847,7 +854,6 @@ public class AVM2Code implements Cloneable {
if (afterCasePos > totalBytes) {
invalidSwitch = true;
}
if (invalidSwitch) {
continue loopaddr;
} else {
@@ -889,28 +895,33 @@ public class AVM2Code implements Cloneable {
ais.endDumpLevel(instr.instructionCode);
if ((instr instanceof IfTypeIns)) {
long target = ais.getPosition() + actualOperands[0];
addresses.add(target);
//addresses.add(ais.getPosition());
if (handleJumps) {
if ((instr instanceof IfTypeIns)) {
long target = ais.getPosition() + actualOperands[0];
addresses.add(target);
//addresses.add(ais.getPosition());
}
if (instr instanceof JumpIns) {
long target = ais.getPosition() + actualOperands[0];
addresses.add(target);
unAdresses.add(ais.getPosition());
continue loopaddr;
}
if (instr.isExitInstruction()) { //do not process jumps if there is return/throw instruction
unAdresses.add(ais.getPosition());
continue loopaddr;
}
if (instr instanceof LookupSwitchIns) {
addresses.add(beforeSwitchPos + actualOperands[0]);
for (int c = 2; c < actualOperands.length; c++) {
addresses.add(beforeSwitchPos + actualOperands[c]);
}
continue loopaddr;
}
}
/*if (instr instanceof JumpIns) {
long target = ais.getPosition() + actualOperands[0];
addresses.add(target);
continue loopaddr;
}
if (instr.isExitInstruction()) { //do not process jumps if there is return/throw instruction
continue loopaddr;
}
if (instr instanceof LookupSwitchIns) {
addresses.add(beforeSwitchPos + actualOperands[0]);
for (int c = 2; c < actualOperands.length; c++) {
addresses.add(beforeSwitchPos + actualOperands[c]);
}
continue loopaddr;
}*/
} else {
ais.endDumpLevel();
break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions)

View File

@@ -367,6 +367,8 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
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);
//Some IfType instructions need more than 1 operand, we must pop out all of them
int stackCount = -action.definition.getStackDelta(action, abc);
if (EcmaScript.toBoolean(res)) {
//System.err.println("replacing " + action + " on " + idx + " with jump");
@@ -374,13 +376,17 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
//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.getBytesLength());
code.insertInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), true, body);
for (int s = 0; s < stackCount; s++) {
code.insertInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), true, body);
}
idx = code.adr2pos(jumpIns.offset + jumpIns.getBytesLength() + jumpIns.operands[0]);
} else {
//System.err.println("replacing " + action + " on " + idx + " with pop");
code.replaceInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), body);
for (int s = 1 /*first is replaced*/; s < stackCount; s++) {
code.insertInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), true, body);
}
//action.definition = new DeobfuscatePopIns();
idx++;
}

View File

@@ -93,7 +93,7 @@ public class InstructionDefinition implements Serializable {
protected FullMultinameAVM2Item resolveMultiname(TranslateStack stack, AVM2ConstantPool constants, int multinameIndex, AVM2Instruction ins) {
GraphTargetItem ns = null;
GraphTargetItem name = null;
if (multinameIndex < constants.constant_multiname.size()) {
if (multinameIndex > 0 && multinameIndex < constants.constant_multiname.size()) {
if (constants.getMultiname(multinameIndex).needsName()) {
name = stack.pop();
}

View File

@@ -96,7 +96,11 @@ public class FullMultinameAVM2Item extends AVM2Item {
} else {
AVM2ConstantPool constants = localData.constantsAvm2;
List<String> fullyQualifiedNames = localData.fullyQualifiedNames;
writer.append(constants.getMultiname(multinameIndex).getName(constants, fullyQualifiedNames, false));
if (multinameIndex > 0 && multinameIndex < constants.constant_multiname.size()) {
writer.append(constants.getMultiname(multinameIndex).getName(constants, fullyQualifiedNames, false));
} else {
writer.append("§§unknown_multiname");
}
}
return writer;
}