吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4569|回复: 12
收起左侧

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

  [复制链接]
wwh1004 发表于 2018-11-11 10:24
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

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

加壳前:

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

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

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

附上代码吧,见笑了,我是看到这个帖子才刚开始学 dnlib ,C#也不是太熟
[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], 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.Count - 1];
				toProcess.Remove(curBlock);

				if (savedLocals.ContainsKey(curBlock)) {
					RestoreEmulatorLocals(savedLocals[curBlock]);
					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[0] = 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[0];
				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[0];
			}
			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[switchBlock.FallThrough][key];
			}
			else if (IsSwitchBlockStart(switchBlock)) {
				return _origSwitchTargets[switchBlock][key];
			}
			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[0].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[i];
				if (!opcode.GetType().IsArray) {
					if ((Code)opcode == Code.Ldc_I4) {
						opcodes[i] = LDC_OPCODES;
					}
					else if ((Code)opcode == Code.Stloc) {
						opcodes[i] = STLOC_OPCODES;
					}
					else if ((Code)opcode == Code.Ldloc) {
						opcodes[i] = LDLOC_OPCODES;
					}
				}
			}

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

免费评分

参与人数 1吾爱币 +2 热心值 +1 收起 理由
wwh1004 + 2 + 1 只有这么多了

查看全部评分

刹那间灬掠过 发表于 2018-11-11 13:47
不懂膜拜………

免费评分

参与人数 1违规 +1 收起 理由
CrazyNut + 1 严禁CM区灌水,无关回复,请仔细阅读版规!

查看全部评分

ugvnui 发表于 2018-11-11 17:12
牛掰的手法,为毛我拖出来序号是乱的。。。。。

免费评分

参与人数 1吾爱币 +1 收起 理由
wwh1004 + 1 ConfuserEx还是很厉害的

查看全部评分

壹万叁 发表于 2018-11-11 22:53
支持谢谢分享~

免费评分

参与人数 1吾爱币 -1 收起 理由
CrazyNut -1 新人注意CM区灌水直接给违规噢

查看全部评分

jadis 发表于 2018-11-11 23:02
thanks a lot ~

免费评分

参与人数 1吾爱币 -1 收起 理由
CrazyNut -1 新人注意CM区灌水直接给违规噢

查看全部评分

我是你波哥啊 发表于 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
学习一下,看看能不能去掉.
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 15:36

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表