From 0b65cb3c6b6b0d90483066649e572efda690a341 Mon Sep 17 00:00:00 2001 From: MultiplyByZer0 Date: Sat, 11 Feb 2017 21:33:51 -0500 Subject: [PATCH 1/2] 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. --- .../deobfuscation/AVM2DeobfuscatorSimple.java | 35 +++++++++++++++++++ .../AVM2DeobfuscatorSimpleOld.java | 35 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java index 5b389e12f..a900c705b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java @@ -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 { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java index 11ded804a..1052b5e81 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java @@ -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 { From e8e598dc6c6441feacdd4c0b71fd292a87e77b1d Mon Sep 17 00:00:00 2001 From: MultiplyByZer0 Date: Tue, 28 Feb 2017 15:49:21 -0500 Subject: [PATCH 2/2] Correct deobfuscation for labels The deobfuscator will no longer incorrectly remove the following code: pushtrue label1:pop --- .../flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java | 2 ++ .../abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java | 3 +++ 2 files changed, 5 insertions(+) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java index a900c705b..145c51fa3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java @@ -155,9 +155,11 @@ public class AVM2DeobfuscatorSimple extends SWFDecompilerAdapter { boolean result = false; // Deliberately skip over instruction zero for(int i = 1; i < code.code.size(); i++) { + Set offsets = code.getImportantOffsets(body, true); AVM2Instruction ins1 = code.code.get(i - 1); AVM2Instruction ins2 = code.code.get(i); if(ins2.definition instanceof PopIns && + !offsets.contains(ins2.getAddress()) && (ins1.definition instanceof PushByteIns || ins1.definition instanceof PushDoubleIns || ins1.definition instanceof PushFalseIns || diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java index 1052b5e81..1e8e925d2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java @@ -105,6 +105,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; /** * @@ -210,9 +211,11 @@ public class AVM2DeobfuscatorSimpleOld extends SWFDecompilerAdapter { boolean result = false; // Deliberately skip over instruction zero for(int i = 1; i < code.code.size(); i++) { + Set offsets = code.getImportantOffsets(body, true); AVM2Instruction ins1 = code.code.get(i - 1); AVM2Instruction ins2 = code.code.get(i); if(ins2.definition instanceof PopIns && + !offsets.contains(ins2.getAddress()) && (ins1.definition instanceof PushByteIns || ins1.definition instanceof PushDoubleIns || ins1.definition instanceof PushFalseIns ||