wwh1004 发表于 2018-11-11 10:24

[.NET] 超难控制流混淆UnpackMe

本UnpackMe真的只有一个控制流混淆,而且还是原版ConfuserEx加的,只不过用了点技巧
加壳后:

加壳前:

非常简单吧,就一个方法需要反混淆,就看哪位大牛可以搞定(现有工具都不行的){:301_988:}

Ravey 发表于 2018-11-15 01:12

wwh1004 发表于 2018-11-14 22:16
厉害,自己写的工具么?

应该不算全是,因为还要依赖 de4dot 和 dnlib

附上代码吧,见笑了,我是看到这个帖子才刚开始学 dnlib ,C#也不是太熟
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using de4dot.blocks;
using de4dot.blocks.cflow;
using dnlib.DotNet;
using dnlib.DotNet.Emit;

namespace de4dot.code.deobfuscators.ConfuserEX {
        class ControlFlow : IBlocksDeobfuscator {

                private InstructionEmulator _emulator;
                private Blocks _blocks;
                private MethodDef _method;
                private IList<Local> _locals;

                private static readonly Code[] LDC_OPCODES = new Code[] { Code.Ldc_I4, Code.Ldc_I4_M1, Code.Ldc_I4_0, Code.Ldc_I4_1, Code.Ldc_I4_2, Code.Ldc_I4_3, Code.Ldc_I4_4, Code.Ldc_I4_5, Code.Ldc_I4_6, Code.Ldc_I4_7, Code.Ldc_I4_8, Code.Ldc_I4_S };
                private static readonly Code[] LDLOC_OPCODES = new Code[] { Code.Ldloc, Code.Ldloc_0, Code.Ldloc_1, Code.Ldloc_2, Code.Ldloc_3, Code.Ldloc_S };
                private static readonly Code[] STLOC_OPCODES = new Code[] { Code.Stloc, Code.Stloc_0, Code.Stloc_1, Code.Stloc_2, Code.Stloc_3, Code.Stloc_S };

                private Dictionary<Block, List<Block>> _origSwitchTargets;

                public bool ExecuteIfNotModified { get; } = false;

                public void DeobfuscateBegin(Blocks blocks) {
                        _blocks = blocks;
                        _method = blocks.Method;
                        _locals = blocks.Locals;
                        _origSwitchTargets = new Dictionary<Block, List<Block>>();

                        _emulator = new InstructionEmulator();
                        _emulator.Initialize(blocks, false);
                }

                public bool Deobfuscate(List<Block> allBlocks) {
                        _method.Body.KeepOldMaxStack = true;
                        if (allBlocks.Count <= 0) {
                                return false;
                        }

                        var switchBlocks = new List<Block>();
                        foreach (var block in allBlocks) {
                                if (IsSwitchBlockStart(block)) {
                                        switchBlocks.Add(block);
                                }
                        }
                        if (switchBlocks.Count <= 0) {
                                return false;
                        }

                        foreach (var switchBlock in switchBlocks) {
                                _origSwitchTargets.Add(switchBlock, new List<Block>(switchBlock.Targets));
                        }
                        DeFlattening(allBlocks, switchBlocks);

                        _method.Body.OptimizeBranches();
                        _method.Body.SimplifyBranches();
                        return true;
                }

                private void DeFlattening(List<Block> allBlocks, List<Block> switchBlocks) {
                        var toProcess = new List<Block>();
                        var savedLocals = new Dictionary<Block, List<Value>>();

                        // Find the first switch
                        var firstFreshSwitchTuple = FallThroughAndFindFirstSwitch(null, allBlocks, 0);
                        // Find the first switch case (assume the default case is unused)
                        var firstCase = FallThroughNextCase(firstFreshSwitchTuple.Item2);

                        // Redirect to the first case
                        DisconnectFromSwitch(firstCase);
                        firstFreshSwitchTuple.Item1.ReplaceLastNonBranchWithBranch(0, firstCase);

                        var handlers = new List<Block>();
                        foreach (var handler in _method.Body.ExceptionHandlers) {
                                foreach (var block in allBlocks) {
                                        if (block.FirstInstr.Instruction.Equals(handler.HandlerStart)) {
                                                handlers.Add(block);
                                                break;
                                        }
                                }
                        }
                        var locals = SaveEmulatorLocals();
                        foreach (var handlerBlock in handlers) {
                                var handlerFirstFreshSwitchTuple = FallThroughAndFindFirstSwitch(null, handlerBlock, 0);
                                // Find the first switch case of the handler (assume the default case is unused)
                                var nextCase = FallThroughNextCase(handlerFirstFreshSwitchTuple.Item2);

                                DisconnectFromSwitch(nextCase);
                                handlerFirstFreshSwitchTuple.Item1.ReplaceLastNonBranchWithBranch(0, nextCase);
                                toProcess.Add(nextCase);
                                savedLocals.Add(nextCase, locals);
                        }

                        toProcess.Add(firstCase);
                        while (toProcess.Count > 0) {
                                var curBlock = toProcess;
                                toProcess.Remove(curBlock);

                                if (savedLocals.ContainsKey(curBlock)) {
                                        RestoreEmulatorLocals(savedLocals);
                                        savedLocals.Remove(curBlock);
                                }

                                // Redirect to the next case
                                var nextCase = FallThroughNextCase(curBlock);
                                Cleanup(curBlock);
                                DisconnectFromSwitch(nextCase);
                                if (curBlock.IsFallThrough()) {
                                        curBlock.ReplaceLastNonBranchWithBranch(0, nextCase);
                                }
                                else if (IsLeave(curBlock.LastInstr)) {
                                        curBlock.Targets = nextCase;
                                }
                                else {
                                        throw new Exception("DeFlattening: Unexpected (0x1)");
                                }

                                if (nextCase.LastInstr.OpCode.Code != Code.Ret && !handleBranch(toProcess, savedLocals, nextCase)) {
                                        toProcess.Add(nextCase);
                                }
                        }
                }

                private bool handleBranch(List<Block> toProcess, Dictionary<Block, List<Value>> savedLocals, Block block) {
                        if (block.IsConditionalBranch()) {
                                var falseBr = block.FallThrough;
                                var trueBr = block.Targets;
                                if (!handleBranch(toProcess, savedLocals, trueBr)) {
                                        toProcess.Add(trueBr);
                                        savedLocals.Add(trueBr, SaveEmulatorLocals());
                                }
                                if (!handleBranch(toProcess, savedLocals, falseBr)) {
                                        toProcess.Add(falseBr);
                                        savedLocals.Add(falseBr, SaveEmulatorLocals());
                                }
                                return true;
                        }
                        else if (!IsSwitchBlockStart(block) && block.LastInstr.OpCode.Code == Code.Switch) {
                                foreach (var target in block.Targets) {
                                        if (!handleBranch(toProcess, savedLocals, target)) {
                                                toProcess.Add(target);
                                                savedLocals.Add(target, SaveEmulatorLocals());
                                        }
                                }
                                // Switch default
                                var defaultCase = block.FallThrough;
                                toProcess.Add(defaultCase);
                                savedLocals.Add(defaultCase, SaveEmulatorLocals());
                                return true;
                        }
                        return false;
                }

                private void DisconnectFromSwitch(Block caseBlock) {
                        if (caseBlock.Sources != null) {
                                var toRemove = new List<Block>();
                                foreach (var source in caseBlock.Sources) {
                                        if (IsSwitchBlockFreshStart(source)) {
                                                toRemove.Add(source);
                                        }
                                        else if (IsSwitchBlockStart(source)) {
                                                toRemove.Add(source);
                                                source.Targets.Remove(caseBlock);
                                        }
                                }
                                foreach (var block in toRemove) {
                                        caseBlock.Sources.Remove(block);
                                }
                        }
                }

                // Remove useless instrs
                private void Cleanup(Block caseBlock) {
                        if (caseBlock.IsFallThrough() && IsSwitchBlockStart(caseBlock.FallThrough)) {
                                if (IsCalculateSwitchValue(caseBlock)) {
                                        caseBlock.Instructions.RemoveRange(caseBlock.Instructions.Count - 5, 5);
                                }
                                else if (IsConstantSwitchValue(caseBlock)) {
                                        caseBlock.Instructions.Remove(caseBlock.LastInstr);
                                }
                        }
                }

                // Return next switch case
                private Block FallThroughNextCase(Block curBlock) {
                        if (IsSwitchBlockFreshStart(curBlock)) {
                                var nextCase = GetCase(curBlock, GetCaseValueFromFreshSwitch(curBlock).Value);
                                if (IsSwitchBlockStart(nextCase)) {
                                        throw new Exception("FallThroughNextCase: Unexpected (0x1)");
                                }
                                else if (IsSwitchBlockFreshStart(nextCase)) {
                                        nextCase = FallThroughNextCase(nextCase);
                                }
                                return nextCase;
                        }
                        // If the next branch is a switch block
                        else if (curBlock.IsFallThrough() && (IsSwitchBlockFreshStart(curBlock.FallThrough) || IsSwitchBlockStart(curBlock.FallThrough))) {
                                if (IsSwitchBlockFreshStart(curBlock.FallThrough)) {
                                        return FallThroughNextCase(curBlock.FallThrough);
                                }
                                else {
                                        // Calculate the stack value
                                        _emulator.Emulate(curBlock.Instructions);
                                        var nextCase = GetCase(curBlock.FallThrough, GetCaseValueFromSwitch(curBlock.FallThrough, (Int32Value)_emulator.Pop()).Value);
                                        if (IsSwitchBlockStart(nextCase)) {
                                                throw new Exception("FallThroughNextCase: Unexpected (0x2)");
                                        }
                                        else if (IsSwitchBlockFreshStart(nextCase)) {
                                                nextCase = FallThroughNextCase(nextCase);
                                        }
                                        return nextCase;
                                }
                        }
                        else if (curBlock.IsFallThrough()) {
                                return curBlock.FallThrough;
                        }
                        else if (IsLeave(curBlock.LastInstr)) {
                                return curBlock.Targets;
                        }
                        else {
                                throw new Exception("FallThroughNextCase: Unexpected (0x3)");
                        }
                }

                private bool IsLeave(Instr instr) {
                        return instr.OpCode.Code == Code.Leave || instr.OpCode.Code == Code.Leave_S;
                }

                //            prev   switch
                private Tuple<Block, Block> FallThroughAndFindFirstSwitch(Block prev, Block block, int depth) {
                        if (depth >= 30) {
                                throw new Exception("Overflow");
                        }
                        else if (block.IsConditionalBranch() || !block.IsFallThrough()) {
                                throw new Exception("Conditional branch not supported yet");
                        }
                        else if (IsSwitchBlockStart(block) || block.LastInstr.OpCode.Code == Code.Ret) {
                                throw new Exception("Unexpected state");
                        }

                        if (IsSwitchBlockFreshStart(block)) {
                                return new Tuple<Block, Block> {
                                        Item1 = prev,
                                        Item2 = block,
                                };
                        }
                        else {
                                return FallThroughAndFindFirstSwitch(block, block.FallThrough, depth++);
                        }
                }

                private Int32Value GetCaseValueFromFreshSwitch(Block switchBlock) {
                        if (!switchBlock.IsFallThrough()) {
                                throw new Exception("GetCaseValueFromFreshSwitch: Invalid switch (0x1)");
                        }
                        else if (!IsSwitchBlockFreshStart(switchBlock)) {
                                throw new Exception("GetCaseValueFromFreshSwitch: Invalid switch (0x2)");
                        }

                        var instrs = new List<Instr>();
                        // Copy switch block's instrs but skip switch instruction
                        instrs.AddRange(switchBlock.Instructions);
                        instrs.AddRange(switchBlock.FallThrough.Instructions.GetRange(0, switchBlock.FallThrough.Instructions.Count - 1));

                        _emulator.Emulate(instrs);
                        return (Int32Value)_emulator.Pop();
                }

                private Int32Value GetCaseValueFromSwitch(Block switchBlock, Int32Value stackValue) {
                        if (!IsSwitchBlockStart(switchBlock)) {
                                throw new Exception("GetCaseValueFromFreshSwitch: Invalid switch (0x1)");
                        }

                        _emulator.Push(stackValue);
                        // Copy switch block's instrs but skip switch instruction
                        _emulator.Emulate(switchBlock.Instructions.GetRange(0, switchBlock.Instructions.Count - 1));
                        return (Int32Value)_emulator.Pop();
                }

                private Block GetCase(Block switchBlock, int key) {
                        if (IsSwitchBlockFreshStart(switchBlock)) {
                                return _origSwitchTargets;
                        }
                        else if (IsSwitchBlockStart(switchBlock)) {
                                return _origSwitchTargets;
                        }
                        else {
                                throw new Exception("GetCase: Invalid switch");
                        }
                }

                private bool IsSwitchBlockFreshStart(Block block) {
                        if (!block.IsFallThrough()) {
                                return false;
                        }

                        var nextBlock = block.FallThrough;
                        return block.Instructions.Count == 1 && block.Instructions.OpCode.Code == Code.Ldc_I4 && IsSwitchBlockStart(nextBlock);
                }

                private bool IsSwitchBlockStart(Block block) {
                        var pattern = new List<object>
                        {
                                Code.Ldc_I4,
                                Code.Xor,
                                Code.Dup,
                                Code.Stloc,
                                Code.Ldc_I4,
                                Code.Rem_Un,
                                Code.Switch
                        };

                        return OpcodeMatch(block, pattern);
                }

                private bool IsCalculateSwitchValue(Block block) {
                        var pattern = new List<object>
                        {
                                Code.Ldloc,
                                Code.Ldc_I4,
                                Code.Mul,
                                Code.Ldc_I4,
                                Code.Xor,
                        };

                        return OpcodeMatch(block, pattern);
                }

                /*
               * ldc.i4 ...
               * br switch
               */
                private bool IsConstantSwitchValue(Block block) {
                        return block.Instructions.Count > 0 && block.LastInstr.IsLdcI4() && block.IsFallThrough() && IsSwitchBlockStart(block.FallThrough);
                }

                private bool OpcodeMatch(Block block, List<object> opcodes) {
                        if (block.Instructions.Count < opcodes.Count) {
                                return false;
                        }

                        for (var i = 0; i < opcodes.Count; i++) {
                                object opcode = opcodes;
                                if (!opcode.GetType().IsArray) {
                                        if ((Code)opcode == Code.Ldc_I4) {
                                                opcodes = LDC_OPCODES;
                                        }
                                        else if ((Code)opcode == Code.Stloc) {
                                                opcodes = STLOC_OPCODES;
                                        }
                                        else if ((Code)opcode == Code.Ldloc) {
                                                opcodes = LDLOC_OPCODES;
                                        }
                                }
                        }

                        var idx = block.Instructions.IndexOf(block.LastInstr);
                        for (var i = opcodes.Count - 1; i >= 0; i--, idx--) {
                                var instr = block.Instructions;
                                if (opcodes.GetType().IsArray) {
                                        bool found = false;
                                        foreach (var opcode in (Code[])opcodes) {
                                                if (instr.OpCode.Code == opcode) {
                                                        found = true;
                                                        break;
                                                }
                                        }
                                        if (!found) {
                                                return false;
                                        }
                                }
                                else if (instr.OpCode.Code != (Code)opcodes) {
                                        return false;
                                }
                        }

                        return true;
                }

                private List<Value> SaveEmulatorLocals() {
                        var locals = new List<Value>();
                        for (var i = 0; i < _locals.Count; i++) {
                                locals.Add(_emulator.GetLocal(i));
                        }

                        return locals;
                }

                private void RestoreEmulatorLocals(List<Value> locals) {
                        for (var i = 0; i < locals.Count; i++) {
                                _emulator.SetLocal(_locals, locals);
                        }
                }
        }
}

刹那间灬掠过 发表于 2018-11-11 13:47

不懂膜拜………

ugvnui 发表于 2018-11-11 17:12

牛掰的手法,为毛我拖出来序号是乱的。。。。。

壹万叁 发表于 2018-11-11 22:53

支持谢谢分享~

jadis 发表于 2018-11-11 23:02

thanks a lot ~

我是你波哥啊 发表于 2018-11-11 23:12

不错不错!!!!

bentom 发表于 2018-11-11 23:22

下载下来学习一下,谢谢了!

cjchome 发表于 2018-11-11 23:40

不太懂,先学习一下

坐和放宽 发表于 2018-11-12 08:37

学习一下.NET的混淆

ericchang999 发表于 2018-11-12 09:14

学习一下,看看能不能去掉.
页: [1] 2
查看完整版本: [.NET] 超难控制流混淆UnpackMe