Undefined registers handling (some obfuscators use getlocal_x when there is no selocal before)

Issue #941 index out of bounds fix
This commit is contained in:
Jindra Petřík
2015-07-05 20:07:08 +02:00
parent bda1e29fa9
commit 1a90ab026d
4 changed files with 80 additions and 30 deletions

View File

@@ -247,6 +247,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.ReturnVoidAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item;
@@ -1516,7 +1517,12 @@ public class AVM2Code implements Cloneable {
} else if (ins.definition instanceof DupIns) {
int nextPos;
do {
AVM2Instruction insAfter = code.get(ip + 1);
AVM2Instruction insAfter = ip + 1 < code.size() ? code.get(ip + 1) : null;
if (insAfter == null) {
ins.definition.translate(isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, constants, ins, method_info, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this);
ip++;
break;
}
AVM2Instruction insBefore = ins;
if (ip - 1 >= start) {
insBefore = code.get(ip - 1);
@@ -1813,6 +1819,9 @@ public class AVM2Code implements Cloneable {
HashMap<Integer, GraphTargetItem> localRegs = new HashMap<>();
int regCount = getRegisterCount();
for (int i = 0; i < regCount; i++) {
localRegs.put(0, new UndefinedAVM2Item(null));
}
//try {
list = AVM2Graph.translateViaGraph(path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs);

View File

@@ -71,8 +71,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
@Override
public void deobfuscate(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody abody) throws InterruptedException {
MethodBody body = abody.clone();
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
removeUnreachableActions(abody.getCode(), cpool, trait, minfo, abody);
Map<Integer, GraphTargetItem> outFirstAssigned = new HashMap<>();
Map<Integer, AVM2Instruction> outFirstAssignments = new HashMap<>();
@@ -83,29 +82,46 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
List<AVM2Instruction> ignored = new ArrayList<>();
Map<Integer, GraphTargetItem> registers = new HashMap<>();
getFirstRegistersUsage(outAssignCount1, outFirstAssigned, outFirstAssignments, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body, ignored, registers);
ignored.addAll(outFirstAssignments.values());
registers.putAll(outFirstAssigned);
replaceSingleUseRegisters(registers, ignored, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
boolean extended = true;
super.deobfuscate(path, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
MethodBody body = abody;
//second pass - ignore all first assignments
registers.clear();
ignored.clear();
outFirstAssignments.clear();
getFirstRegistersUsage(outAssignCount2, new HashMap<>(), outFirstAssignments, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body, ignored, registers);
if (extended) {
body = abody.clone();
getFirstRegistersUsage(outAssignCount1, outFirstAssigned, outFirstAssignments, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body, ignored, registers);
ignored.addAll(outFirstAssignments.values());
registers.putAll(outFirstAssigned);
for (int regId : outAssignCount1.keySet()) {
int ac = outAssignCount2.containsKey(regId) ? outAssignCount2.get(regId) : 0;
if (ac == 0) {
singleRegisters.put(regId, outFirstAssigned.get(regId));
replaceSingleUseRegisters(registers, ignored, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
super.deobfuscate(path, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);
//second pass - ignore all first assignments
registers.clear();
ignored.clear();
outFirstAssignments.clear();
getFirstRegistersUsage(outAssignCount2, new HashMap<>(), outFirstAssignments, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body, ignored, registers);
for (int regId : outAssignCount1.keySet()) {
int ac = outAssignCount2.containsKey(regId) ? outAssignCount2.get(regId) : 0;
if (ac == 0) {
singleRegisters.put(regId, outFirstAssigned.get(regId));
}
}
body = abody;
} else {
getFirstRegistersUsage(outAssignCount1, outFirstAssigned, outFirstAssignments, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body, ignored, registers);
for (int regId : outAssignCount1.keySet()) {
int ac = outAssignCount1.get(regId);
if (ac == 1) {
singleRegisters.put(regId, outFirstAssigned.get(regId));
}
}
}
body = abody;
//body.max_regs
replaceSingleUseRegisters(singleRegisters, null, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
super.deobfuscate(path, classIndex, isStatic, scriptIndex, abc, cpool, trait, minfo, body);
removeUnreachableActions(body.getCode(), cpool, trait, minfo, body);

View File

@@ -45,7 +45,9 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIn
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
@@ -60,6 +62,8 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns;
import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item;
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.NewFunctionAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
@@ -233,6 +237,9 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
localData.isStatic = isStatic;
localData.classIndex = classIndex;
localData.localRegs = new HashMap<>();
for (int i = 0; i < body.max_regs; i++) {
localData.localRegs.put(i, new UndefinedAVM2Item(null));
}
localData.scopeStack = new ScopeStack(true);
localData.constants = cpool;
localData.methodInfo = abc.method_info;
@@ -270,7 +277,17 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
}
AVM2Instruction action = code.code.get(idx);
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
if (action.definition instanceof NewFunctionIns) {
if (idx + 1 < code.code.size()) {
if (code.code.get(idx + 1).definition instanceof PopIns) {
code.removeInstruction(idx + 1, body);
code.removeInstruction(idx, body);
continue;
}
}
} else {
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
}
InstructionDefinition def = action.definition;
Class allowedDefs[] = new Class[]{
@@ -307,7 +324,9 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
GreaterThanIns.class,
LessThanIns.class,
StrictEqualsIns.class,
PopIns.class
PopIns.class,
GetLocalTypeIns.class,
NewFunctionIns.class
};
boolean ok = false;
@@ -321,6 +340,17 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
break;
}
if (def instanceof GetLocalTypeIns) {
int regId = ((GetLocalTypeIns) def).getRegisterId(action);
if (regId > 0 && localData.localRegs.get(regId) instanceof UndefinedAVM2Item) {
//System.err.println(""+);
stack.pop();
stack.push(new UndefinedAVM2Item(action));
} else {
break;
}
}
boolean ifed = false;
if (def instanceof JumpIns) {
//ActionJump jump = (ActionJump) action;
@@ -339,9 +369,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
AVM2Instruction tarIns = code.code.get(nidx);
if (EcmaScript.toBoolean(res)) {
/*if (nidx == -1) {
throw new TranslateException("If target not found: " + address);
}*/
//System.err.println("replacing " + action + " on " + idx + " with jump");
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);
@@ -351,6 +379,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
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);
//action.definition = new DeobfuscatePopIns();
idx++;

View File

@@ -81,16 +81,12 @@ public class LocalRegAVM2Item extends AVM2Item {
@Override
public Object getResult() {
if (computedResult == null) {
return new Undefined();
}
return computedResult;
return computedValue.getResult();
}
@Override
public boolean isCompileTime(Set<GraphTargetItem> dependencies) {
return false; //isCT;
return computedValue instanceof UndefinedAVM2Item;
}
@Override