.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
吾爱盘:
不知道是国外哪个壳,用自己之前写的控制流分析库把控制流混淆清掉了(不是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;
}
}
} 第一步的查壳工具十分关键。 wwh1004 发表于 2019-1-20 10:28
不知道是国外哪个壳,用自己之前写的控制流分析库把控制流混淆清掉了(不是de4dot.blocks!!!!!!!是自己写的 ...
不错,大神有心了 这是干嘛的嗯嗯嗯嗯 javazhangwei 发表于 2019-1-21 12:15
这是干嘛的嗯嗯嗯嗯
这是尝试破解的样本,用来检验破解人员的技术实力。{:1_935:} 没人了吗,欢迎攻克 确实没办法,混淆的太过了,楼上的大佬贴出的代码我没有VS编译不了。用x64dbg调试,一停在断点程序就瘫了。dnSpy切换成IL指令集并且关掉局部变量可以调试,但是看不到变量值也没办法继续调下去了 我自己试了一下 其中有几个类把dnspy搞死了卡死在decompiling了 请这种情况下怎么搞? 我只用了de4dot去去掉混淆的名字 别的不知道怎么继续。 用了些笨方法,破解了不到一半吧,另外一部分可能需要一组key才能解了
页:
[1]