Deobfuscate no-op push instructions

Some obfuscators will scatter the instructions:

pushtrue
pop

or:

pushfalse
pop

randomly throughout the P-code. As any push instruction immediately followed by a pop instruction must be a no-op, they are removed.
This commit is contained in:
MultiplyByZer0
2017-02-11 21:33:51 -05:00
parent 3e99d19a1d
commit 0b65cb3c6b
2 changed files with 70 additions and 0 deletions

View File

@@ -64,11 +64,14 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntegerTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNanIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUIntIns;
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.instructions.types.CoerceOrConvertTypeIns;
@@ -148,6 +151,37 @@ public class AVM2DeobfuscatorSimple extends SWFDecompilerAdapter {
return result;
}
protected boolean removeNullPushes(AVM2Code code, MethodBody body) throws InterruptedException {
boolean result = false;
// Deliberately skip over instruction zero
for(int i = 1; i < code.code.size(); i++) {
AVM2Instruction ins1 = code.code.get(i - 1);
AVM2Instruction ins2 = code.code.get(i);
if(ins2.definition instanceof PopIns &&
(ins1.definition instanceof PushByteIns ||
ins1.definition instanceof PushDoubleIns ||
ins1.definition instanceof PushFalseIns ||
ins1.definition instanceof PushIntIns ||
ins1.definition instanceof PushIntegerTypeIns ||
ins1.definition instanceof PushNanIns ||
ins1.definition instanceof PushNullIns ||
ins1.definition instanceof PushShortIns ||
ins1.definition instanceof PushStringIns ||
ins1.definition instanceof PushTrueIns ||
ins1.definition instanceof PushUIntIns ||
ins1.definition instanceof PushUndefinedIns)
) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
code.removeInstruction(i - 1, body); i--;
code.removeInstruction(i, body); i--;
result = true;
}
} return result;
}
protected void initLocalRegs(LocalDataArea localData, int localReservedCount, int maxRegs, boolean executeFromFirst) {
for (int i = 0; i < localReservedCount; i++) {
localData.localRegisters.put(i, NotCompileTime.INSTANCE);
@@ -374,6 +408,7 @@ public class AVM2DeobfuscatorSimple extends SWFDecompilerAdapter {
code.removeDeadCode(body);
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, null);
removeZeroJumps(code, body);
removeNullPushes(code, body);
}
class ExecutionResult {

View File

@@ -68,11 +68,14 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntegerTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNanIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUIntIns;
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.instructions.types.CoerceOrConvertTypeIns;
@@ -203,6 +206,37 @@ public class AVM2DeobfuscatorSimpleOld extends SWFDecompilerAdapter {
return result;
}
protected boolean removeNullPushes(AVM2Code code, MethodBody body) throws InterruptedException {
boolean result = false;
// Deliberately skip over instruction zero
for(int i = 1; i < code.code.size(); i++) {
AVM2Instruction ins1 = code.code.get(i - 1);
AVM2Instruction ins2 = code.code.get(i);
if(ins2.definition instanceof PopIns &&
(ins1.definition instanceof PushByteIns ||
ins1.definition instanceof PushDoubleIns ||
ins1.definition instanceof PushFalseIns ||
ins1.definition instanceof PushIntIns ||
ins1.definition instanceof PushIntegerTypeIns ||
ins1.definition instanceof PushNanIns ||
ins1.definition instanceof PushNullIns ||
ins1.definition instanceof PushShortIns ||
ins1.definition instanceof PushStringIns ||
ins1.definition instanceof PushTrueIns ||
ins1.definition instanceof PushUIntIns ||
ins1.definition instanceof PushUndefinedIns)
) {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
code.removeInstruction(i - 1, body); i--;
code.removeInstruction(i, body); i--;
result = true;
}
} return result;
}
protected AVM2LocalData newLocalData(int scriptIndex, ABC abc, AVM2ConstantPool cpool, MethodBody body, boolean isStatic, int classIndex) {
AVM2LocalData localData = new AVM2LocalData();
localData.isStatic = isStatic;
@@ -475,6 +509,7 @@ public class AVM2DeobfuscatorSimpleOld extends SWFDecompilerAdapter {
code.removeDeadCode(body);
removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, new ArrayList<>());
removeZeroJumps(code, body);
removeNullPushes(code, body);
}
class ExecutionResult {