mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-13 13:18:23 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user