hackjam 发表于 2019-1-19 22:53

.net混淆CrackMe4

本帖最后由 hackjam 于 2019-1-21 01:16 编辑

.net混淆CrackMe4
之前的:
.net混淆CrackMe1 -> https://www.52pojie.cn/thread-853485-1-1.html
.net混淆CrackMe2 -> https://www.52pojie.cn/thread-853763-1-1.html
.net混淆CrackMe3 -> https://www.52pojie.cn/thread-854229-1-1.html

破解前:


破解后:



度盘:
链接: https://pan.baidu.com/s/1G3mBHmdbEsXKdSpzwn8obQ
提取码: 6575

吾爱盘:



wwh1004 发表于 2019-1-20 10:28

不知道是国外哪个壳,用自己之前写的控制流分析库把控制流混淆清掉了(不是de4dot.blocks!!!!!!!是自己写的,最后附上的代码是清理控制流混淆的,可能你不能直接套给de4dot用)

脱完了才发现原来里面还有代码虚拟化,虚拟化前的代码还有许多是无效代码,用来防止分析的

懒得弄了,.NET的CrackMe都快变成了UnpackMe。
这种CM其实真没太大意思的,全是靠壳的强度。
这个虚拟化也不是特别难,2个数组,一个数组储存局部变量,一个数组负责对访问局部变量数组的下标,也就是index,进行解密操作。
虚拟化只是虚拟化了控制流,没把指令也虚拟化掉,说白了就是加强版控制流混淆。可还原性上来说比Agile.NET的虚拟化好还原的多,这个只需要干掉控制流混淆,恢复下局部变量的访问就清掉虚拟化了。而Agile.NET的代码虚拟化是真的把所有指令都虚拟化了,还原起来很麻烦,虽然反编译正常,但是不一定能正常运行,如果研究过Agile.NET虚拟机的应该都清楚,就不多说了。
有时间我再看看把这个虚拟化的还原写出来。
class Program {
        static void Main(string[] args) {
                new Thread(Execute, 4096 * 1000).Start();
        }

        private static void Execute() {
                using (ModuleDefMD moduleDef = ModuleDefMD.Load(@"I:\Downloads\CrackMe-J4\CrackMe-J4-cleaned.exe")) {
                        foreach (MethodDef methodDef in moduleDef.EnumerateAllMethodDefs())
                                if (methodDef.HasBody && !methodDef.Body.HasExceptionHandlers) {
                                        BlockParser parser;
                                        MethodBlock methodBlock;
                                        BlockDeparser deparser;

                                        methodDef.SimplifyMacros();
                                        if (!IsObfuscated(methodDef.Body.Instructions))
                                                continue;
                                        parser = new BlockParser(methodDef.Body.Instructions, methodDef.Body.ExceptionHandlers, methodDef.Body.Variables);
                                        parser.Parse(true);
                                        methodBlock = parser.MethodBlock;
                                        Decflow(methodBlock);
                                        BlockSorter.Sort(methodBlock);
                                        deparser = new BlockDeparser(methodBlock);
                                        deparser.Deparse();
                                        methodDef.Body.Instructions.Clear();
                                        foreach (Instruction instruction in deparser.Instructions)
                                                methodDef.Body.Instructions.Add(instruction);
                                        methodDef.Body.Variables.Clear();
                                        foreach (Local variable in deparser.Variables)
                                                methodDef.Body.Variables.Add(variable);
                                }
                        moduleDef.Write(@"I:\Downloads\CrackMe-J4\CrackMe-J4-cf.exe");
                }
        }

        private static bool IsObfuscated(IList<Instruction> instructions) {
                if (instructions.Count < 3)
                        return false;
                if (instructions.OpCode.Code != Code.Ldc_I4 ||
                        instructions.OpCode.Code != Code.Stloc ||
                        instructions.OpCode.Code != Code.Br)
                        return false;
                return true;
        }

        private static void Decflow(MethodBlock methodBlock) {
                Local ipVariable;
                int maxCaseIp;
                BasicBlock[] jumpTable;

                ipVariable = (Local)ToBasicBlock(methodBlock.FirstBlock).Instructions.Operand;
                foreach (IBlock block in methodBlock.Blocks) {
                        bool isCase;
                        int targetIp;
                        BasicBlock body;

                        isCase = IsCase(ToBasicBlock(block), ipVariable, out targetIp, out body);
                        block.PushExtraData(new BlockInfo() {
                                IsCase = isCase,
                                TargetIp = targetIp,
                                Body = body
                        });
                }
                // set extra-data
                maxCaseIp = methodBlock.Blocks.Max(block => ToBasicBlock(block).PeekExtraData<BlockInfo>().TargetIp);
                jumpTable = new BasicBlock;
                foreach (IBlock block in methodBlock.Blocks) {
                        BasicBlock basicBlock;
                        BlockInfo blockInfo;

                        basicBlock = ToBasicBlock(block);
                        blockInfo = basicBlock.PeekExtraData<BlockInfo>();
                        if (blockInfo.IsCase)
                                jumpTable = blockInfo.Body;
                }
                // build jump-table
                foreach (IBlock block in methodBlock.Blocks) {
                        BasicBlock basicBlock;
                        BlockInfo blockInfo;
                        int targetIp;
                        List<Instruction> instructions;
                        int maxIndex;

                        basicBlock = ToBasicBlock(block);
                        blockInfo = basicBlock.PeekExtraData<BlockInfo>();
                        if (blockInfo.IsCase)
                                continue;
                        if (!HasIpSetter(basicBlock, ipVariable, out targetIp))
                                continue;
                        instructions = basicBlock.Instructions;
                        maxIndex = instructions.Count - 1;
                        SetNop(instructions);
                        SetNop(instructions);
                        basicBlock.LastInstruction.Operand = jumpTable.FirstInstruction;
                        basicBlock.FallThrough = jumpTable;
                }
                // fix jump
                foreach (IBlock block in methodBlock.Blocks)
                        block.PopExtraData();
                // clean extra-data
        }

        private static void SetNop(Instruction instruction) {
                instruction.OpCode = OpCodes.Nop;
                instruction.Operand = null;
        }

        private static bool IsCase(BasicBlock basicBlock, Local ipVariable, out int targetIp, out BasicBlock body) {
                List<Instruction> instructions;

                targetIp = 0;
                body = null;
                instructions = basicBlock.Instructions;
                if (instructions.Count < 4)
                        return false;
                if (instructions.OpCode.Code != Code.Ldloc || instructions.Operand != ipVariable ||
                        instructions.OpCode.Code != Code.Ldc_I4 ||
                        instructions.OpCode.Code != Code.Ceq ||
                        (instructions.OpCode.Code != Code.Brfalse && instructions.OpCode.Code != Code.Brtrue))
                        return false;
                targetIp = (int)instructions.Operand;
                if (instructions.OpCode.Code == Code.Brfalse)
                        body = basicBlock.FallThrough;
                else
                        body = basicBlock.ConditionalTarget;
                return true;
        }

        private static bool HasIpSetter(BasicBlock basicBlock, Local ipVariable, out int targetIp) {
                List<Instruction> instructions;
                int maxIndex;

                targetIp = 0;
                instructions = basicBlock.Instructions;
                if (instructions.Count < 3)
                        return false;
                maxIndex = instructions.Count - 1;
                if (instructions.OpCode.Code != Code.Ldc_I4 ||
                        instructions.OpCode.Code != Code.Stloc || instructions.Operand != ipVariable ||
                        instructions.OpCode.Code != Code.Br)
                        return false;
                targetIp = (int)instructions.Operand;
                return true;
        }

        private static BasicBlock ToBasicBlock(IBlock block) {
                return (BasicBlock)block;
        }

        private sealed class BlockInfo {
                private bool _isCase;
                private int _targetIp;
                private BasicBlock _body;

                public bool IsCase {
                        get => _isCase;
                        set => _isCase = value;
                }

                public int TargetIp {
                        get => _targetIp;
                        set => _targetIp = value;
                }

                public BasicBlock Body {
                        get => _body;
                        set => _body = value;
                }
        }
}

wgh1256 发表于 2019-1-19 23:10

第一步的查壳工具十分关键。

hackjam 发表于 2019-1-20 10:38

wwh1004 发表于 2019-1-20 10:28
不知道是国外哪个壳,用自己之前写的控制流分析库把控制流混淆清掉了(不是de4dot.blocks!!!!!!!是自己写的 ...

不错,大神有心了

javazhangwei 发表于 2019-1-21 12:15

这是干嘛的嗯嗯嗯嗯

wgh1256 发表于 2019-1-21 13:30

javazhangwei 发表于 2019-1-21 12:15
这是干嘛的嗯嗯嗯嗯

这是尝试破解的样本,用来检验破解人员的技术实力。{:1_935:}

hackjam 发表于 2019-1-25 11:26

没人了吗,欢迎攻克

梦游枪手 发表于 2019-1-25 12:24

确实没办法,混淆的太过了,楼上的大佬贴出的代码我没有VS编译不了。用x64dbg调试,一停在断点程序就瘫了。dnSpy切换成IL指令集并且关掉局部变量可以调试,但是看不到变量值也没办法继续调下去了

tfrist 发表于 2019-1-30 02:47

我自己试了一下 其中有几个类把dnspy搞死了卡死在decompiling了 请这种情况下怎么搞? 我只用了de4dot去去掉混淆的名字 别的不知道怎么继续。

梦游枪手 发表于 2019-2-4 14:10

用了些笨方法,破解了不到一半吧,另外一部分可能需要一组key才能解了
页: [1]
查看完整版本: .net混淆CrackMe4