Skip to content

修复控制流保护在#153的错误 #562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions Confuser.Protections/ControlFlow/SwitchMangler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,254 +188,246 @@
throw new NotSupportedException();
}

public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx) {
Trace trace = new Trace(body, ctx.Method.ReturnType.RemoveModifiers().ElementType != ElementType.Void);
var local = new Local(ctx.Method.Module.CorLibTypes.UInt32);
body.Variables.Add(local);
body.InitLocals = true;

body.MaxStack += 2;
IPredicate predicate = null;
if (ctx.Predicate == PredicateType.Normal) {
predicate = new NormalPredicate(ctx);
}
else if (ctx.Predicate == PredicateType.Expression) {
predicate = new ExpressionPredicate(ctx);
}
else if (ctx.Predicate == PredicateType.x86) {
predicate = new x86Predicate(ctx);
}

foreach (InstrBlock block in GetAllBlocks(root)) {
LinkedList<Instruction[]> statements = SpiltStatements(block, trace, ctx);

// Make sure .ctor is executed before switch
if (ctx.Method.IsInstanceConstructor) {
var newStatement = new List<Instruction>();
while (statements.First != null) {
newStatement.AddRange(statements.First.Value);
Instruction lastInstr = statements.First.Value.Last();
statements.RemoveFirst();
if (lastInstr.OpCode == OpCodes.Call && ((IMethod)lastInstr.Operand).Name == ".ctor")
break;
}
statements.AddFirst(newStatement.ToArray());
}

if (statements.Count < 3) continue;

int i;

var keyId = Enumerable.Range(0, statements.Count).ToArray();
ctx.Random.Shuffle(keyId);
var key = new int[keyId.Length];
for (i = 0; i < key.Length; i++) {
var q = ctx.Random.NextInt32() & 0x7fffffff;
key[i] = q - q % statements.Count + keyId[i];
}

var statementKeys = new Dictionary<Instruction, int>();
LinkedListNode<Instruction[]> current = statements.First;
i = 0;
while (current != null) {
if (i != 0)
statementKeys[current.Value[0]] = key[i];
i++;
current = current.Next;
}

var statementLast = new HashSet<Instruction>(statements.Select(st => st.Last()));

Func<IList<Instruction>, bool> hasUnknownSource;
hasUnknownSource = instrs => instrs.Any(instr => {
if (trace.HasMultipleSources(instr.Offset))
return true;
if (trace.BrRefs.TryGetValue(instr.Offset, out var srcs)) {
// Target of switch => assume unknown
if (srcs.Any(src => src.Operand is Instruction[]))
return true;

// Not within current instruction block / targeted in first statement
if (srcs.Any(src => src.Offset <= statements.First.Value.Last().Offset ||
src.Offset >= block.Instructions.Last().Offset))
return true;

// Disable flow obfuscation for blocks reached by jump instructions.
// Bug in #153 caused exactly this behaviour, expect for allowing wrong jump instructions
// There is another issue present here tracked here:
// https://github.com/mkaring/ConfuserEx/issues/162
// Until this issue is resolved, the ctrl flow obfuscation will be severely reduced.
if (srcs.Any())
return true;

// Not targeted by the last of statements
if (srcs.Any(src => !statementLast.Contains(src)))
if (srcs.Any(src => statementLast.Contains(src)))
return true;
}
return false;
});

var switchInstr = new Instruction(OpCodes.Switch);
var switchHdr = new List<Instruction>();

if (predicate != null) {
predicate.Init(body);
switchHdr.Add(Instruction.CreateLdcI4(predicate.GetSwitchKey(key[1])));
predicate.EmitSwitchLoad(switchHdr);
}
else {
switchHdr.Add(Instruction.CreateLdcI4(key[1]));
}

switchHdr.Add(Instruction.Create(OpCodes.Dup));
switchHdr.Add(Instruction.Create(OpCodes.Stloc, local));
switchHdr.Add(Instruction.Create(OpCodes.Ldc_I4, statements.Count));
switchHdr.Add(Instruction.Create(OpCodes.Rem_Un));
switchHdr.Add(switchInstr);

ctx.AddJump(switchHdr, statements.Last.Value[0]);
ctx.AddJunk(switchHdr);

var operands = new Instruction[statements.Count];
current = statements.First;
i = 0;
while (current.Next != null) {
var newStatement = new List<Instruction>(current.Value);

if (i != 0) {
// Convert to switch
bool converted = false;

if (newStatement.Last().IsBr()) {
// Unconditional

var target = (Instruction)newStatement.Last().Operand;
int brKey;
if (!trace.IsBranchTarget(newStatement.Last().Offset) &&
statementKeys.TryGetValue(target, out brKey)) {
var targetKey = predicate != null ? predicate.GetSwitchKey(brKey) : brKey;
var unkSrc = hasUnknownSource(newStatement);

newStatement.RemoveAt(newStatement.Count - 1);

if (unkSrc) {
newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey));
}
else {
var thisKey = key[i];
var r = ctx.Random.NextInt32();
newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
newStatement.Add(Instruction.CreateLdcI4(r));
newStatement.Add(Instruction.Create(OpCodes.Mul));
newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey));
newStatement.Add(Instruction.Create(OpCodes.Xor));
}

ctx.AddJump(newStatement, switchHdr[1]);
ctx.AddJunk(newStatement);
operands[keyId[i]] = newStatement[0];
converted = true;
}
}
else if (newStatement.Last().IsConditionalBranch()) {
// Conditional

var target = (Instruction)newStatement.Last().Operand;
int brKey;
if (!trace.IsBranchTarget(newStatement.Last().Offset) &&
statementKeys.TryGetValue(target, out brKey)) {
bool unkSrc = hasUnknownSource(newStatement);
int nextKey = key[i + 1];
OpCode condBr = newStatement.Last().OpCode;
newStatement.RemoveAt(newStatement.Count - 1);

if (ctx.Random.NextBoolean()) {
condBr = InverseBranch(condBr);
int tmp = brKey;
brKey = nextKey;
nextKey = tmp;
}

var thisKey = key[i];
int r = 0, xorKey = 0;
if (!unkSrc) {
r = ctx.Random.NextInt32();
xorKey = thisKey * r;
}

Instruction brKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(brKey) : brKey));
Instruction nextKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(nextKey) : nextKey));
Instruction pop = Instruction.Create(OpCodes.Pop);

newStatement.Add(Instruction.Create(condBr, brKeyInstr));
newStatement.Add(nextKeyInstr);
newStatement.Add(Instruction.Create(OpCodes.Dup));
newStatement.Add(Instruction.Create(OpCodes.Br, pop));
newStatement.Add(brKeyInstr);
newStatement.Add(Instruction.Create(OpCodes.Dup));
newStatement.Add(pop);

if (!unkSrc) {
newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
newStatement.Add(Instruction.CreateLdcI4(r));
newStatement.Add(Instruction.Create(OpCodes.Mul));
newStatement.Add(Instruction.Create(OpCodes.Xor));
}

ctx.AddJump(newStatement, switchHdr[1]);
ctx.AddJunk(newStatement);
operands[keyId[i]] = newStatement[0];
converted = true;
}
}

if (!converted) {
// Normal

var targetKey = predicate != null ? predicate.GetSwitchKey(key[i + 1]) : key[i + 1];
if (!hasUnknownSource(newStatement)) {
var thisKey = key[i];
var r = ctx.Random.NextInt32();
newStatement.Add(Instruction.Create(OpCodes.Ldloc, local));
newStatement.Add(Instruction.CreateLdcI4(r));
newStatement.Add(Instruction.Create(OpCodes.Mul));
newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey));
newStatement.Add(Instruction.Create(OpCodes.Xor));
}
else {
newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey));
}

ctx.AddJump(newStatement, switchHdr[1]);
ctx.AddJunk(newStatement);
operands[keyId[i]] = newStatement[0];
}
}
else
operands[keyId[i]] = switchHdr[0];

current.Value = newStatement.ToArray();
current = current.Next;
i++;
}
operands[keyId[i]] = current.Value[0];
switchInstr.Operand = operands;

Instruction[] first = statements.First.Value;
statements.RemoveFirst();
Instruction[] last = statements.Last.Value;
statements.RemoveLast();

List<Instruction[]> newStatements = statements.ToList();
ctx.Random.Shuffle(newStatements);

block.Instructions.Clear();
block.Instructions.AddRange(first);
block.Instructions.AddRange(switchHdr);
foreach (var statement in newStatements)
block.Instructions.AddRange(statement);
block.Instructions.AddRange(last);
}
}
}

Check notice on line 432 in Confuser.Protections/ControlFlow/SwitchMangler.cs

View check run for this annotation

codefactor.io / CodeFactor

Confuser.Protections/ControlFlow/SwitchMangler.cs#L191-L432

Complex Method
}