Update tamper code
This commit is contained in:
parent
a0f5a109dd
commit
e68cedd44b
|
@ -28,6 +28,11 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
||||||
ModuleDefinition module;
|
ModuleDefinition module;
|
||||||
List<MethodDefinition> pinvokeMethods = new List<MethodDefinition>();
|
List<MethodDefinition> pinvokeMethods = new List<MethodDefinition>();
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
V1,
|
||||||
|
V2,
|
||||||
|
}
|
||||||
|
|
||||||
public IList<MethodDefinition> PinvokeMethods {
|
public IList<MethodDefinition> PinvokeMethods {
|
||||||
get { return pinvokeMethods; }
|
get { return pinvokeMethods; }
|
||||||
}
|
}
|
||||||
|
@ -61,155 +66,193 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
||||||
public int End { get; set; }
|
public int End { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
IList<BlockInfo> findTamperBlocks(Blocks blocks, IList<Block> allBlocks, out MethodDefinition pinvokeMethod) {
|
class TamperBlocks {
|
||||||
var list = new List<BlockInfo>(3);
|
public Type type;
|
||||||
|
public MethodDefinition pinvokeMethod;
|
||||||
var first = findFirstBlocks(allBlocks, blocks.Locals, out pinvokeMethod);
|
public BlockInfo first;
|
||||||
if (first == null)
|
public BlockInfo second;
|
||||||
return null;
|
public BlockInfo bad;
|
||||||
|
|
||||||
var second = first[1];
|
|
||||||
var badBlock = second.Block.LastInstr.isBrfalse() ? second.Block.Targets[0] : second.Block.FallThrough;
|
|
||||||
var last = findLastBlock(badBlock);
|
|
||||||
if (last == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
list.AddRange(first);
|
|
||||||
list.Add(last);
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IList<BlockInfo> findFirstBlocks(IList<Block> allBlocks, IList<VariableDefinition> locals, out MethodDefinition pinvokeMethod) {
|
TamperBlocks findTamperBlocks(Blocks blocks, IList<Block> allBlocks) {
|
||||||
pinvokeMethod = null;
|
var tamperBlocks = new TamperBlocks();
|
||||||
|
|
||||||
|
if (!findFirstBlocks(tamperBlocks, allBlocks, blocks.Locals))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var second = tamperBlocks.second;
|
||||||
|
var badBlock = second.Block.LastInstr.isBrfalse() ? second.Block.Targets[0] : second.Block.FallThrough;
|
||||||
|
tamperBlocks.bad = findBadBlock(badBlock);
|
||||||
|
if (tamperBlocks.bad == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return tamperBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findFirstBlocks(TamperBlocks tamperBlocks, IList<Block> allBlocks, IList<VariableDefinition> locals) {
|
||||||
foreach (var b in allBlocks) {
|
foreach (var b in allBlocks) {
|
||||||
if (!b.LastInstr.isBrfalse())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var block = b;
|
if (findFirstBlocks(b, tamperBlocks, allBlocks, locals))
|
||||||
var list = new List<BlockInfo>();
|
return true;
|
||||||
var instrs = block.Instructions;
|
|
||||||
int start = instrs.Count - 1;
|
|
||||||
int end = start;
|
|
||||||
Instr instr;
|
|
||||||
MethodReference method;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ldc.i4.0
|
|
||||||
* stloc X
|
|
||||||
* call GetExecutingAssembly()
|
|
||||||
* stloc Y
|
|
||||||
* ldloc Y
|
|
||||||
* callvirt Location
|
|
||||||
* ldc.i4.1
|
|
||||||
* ldloca X
|
|
||||||
* call StrongNameSignatureVerificationEx
|
|
||||||
* pop
|
|
||||||
* ldloc X
|
|
||||||
* brfalse bad_code
|
|
||||||
* ldloc Y
|
|
||||||
* callvirt FullName()
|
|
||||||
* ldstr "......"
|
|
||||||
* callvirt EndsWith(string)
|
|
||||||
* brfalse bad_code / brtrue good_code
|
|
||||||
*/
|
|
||||||
|
|
||||||
instr = instrs[--start];
|
|
||||||
if (!instr.isLdloc())
|
|
||||||
continue;
|
|
||||||
var loc0 = Instr.getLocalVar(locals, instr);
|
|
||||||
|
|
||||||
instr = instrs[--start];
|
|
||||||
if (instr.OpCode != OpCodes.Pop)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
instr = instrs[--start];
|
|
||||||
if (instr.OpCode != OpCodes.Call)
|
|
||||||
continue;
|
|
||||||
pinvokeMethod = DotNetUtils.getMethod(module, instr.Operand as MethodReference);
|
|
||||||
if (!DotNetUtils.isPinvokeMethod(pinvokeMethod, "mscorwks", "StrongNameSignatureVerificationEx"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
instr = instrs[--start];
|
|
||||||
if (instr.OpCode == OpCodes.Callvirt)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
method = (MethodReference)instr.Operand;
|
|
||||||
if (method.ToString() != "System.String System.Reflection.Assembly::get_Location()")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
instr = instrs[--start];
|
|
||||||
if (instr.OpCode == OpCodes.Call)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
method = (MethodReference)instr.Operand;
|
|
||||||
if (method.ToString() != "System.Reflection.Assembly System.Reflection.Assembly::GetExecutingAssembly()")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
instr = instrs[--start];
|
|
||||||
if (!instr.isStloc() || Instr.getLocalVar(locals, instr) != loc0)
|
|
||||||
continue;
|
|
||||||
instr = instrs[--start];
|
|
||||||
if (!instr.isLdcI4())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
list.Add(new BlockInfo {
|
|
||||||
Block = block,
|
|
||||||
Start = start,
|
|
||||||
End = end,
|
|
||||||
});
|
|
||||||
|
|
||||||
block = block.FallThrough;
|
|
||||||
instrs = block.Instructions;
|
|
||||||
start = end = 0;
|
|
||||||
|
|
||||||
instr = instrs[end++];
|
|
||||||
if (!instr.isLdloc())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
instr = instrs[end++];
|
|
||||||
if (instr.OpCode != OpCodes.Callvirt)
|
|
||||||
continue;
|
|
||||||
method = (MethodReference)instr.Operand;
|
|
||||||
if (method.ToString() != "System.String System.Reflection.Assembly::get_FullName()")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
instr = instrs[end++];
|
|
||||||
if (instr.OpCode != OpCodes.Ldstr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
instr = instrs[end++];
|
|
||||||
if (instr.OpCode != OpCodes.Callvirt)
|
|
||||||
continue;
|
|
||||||
method = (MethodReference)instr.Operand;
|
|
||||||
if (method.ToString() != "System.Boolean System.String::EndsWith(System.String)")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
instr = instrs[end++];
|
|
||||||
if (!instr.isBrfalse() && !instr.isBrtrue())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
end--;
|
|
||||||
list.Add(new BlockInfo {
|
|
||||||
Block = block,
|
|
||||||
Start = start,
|
|
||||||
End = end,
|
|
||||||
});
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException) {
|
catch (ArgumentOutOfRangeException) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockInfo findLastBlock(Block last) {
|
static int findCallMethod(Block block, int index, bool keepLooking, Func<MethodReference, bool> func) {
|
||||||
|
var instrs = block.Instructions;
|
||||||
|
for (int i = index; i < instrs.Count; i++) {
|
||||||
|
var instr = instrs[i];
|
||||||
|
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var calledMethod = instr.Operand as MethodReference;
|
||||||
|
if (calledMethod != null && func(calledMethod))
|
||||||
|
return i;
|
||||||
|
if (!keepLooking)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findFirstBlocks(Block block, TamperBlocks tamperBlocks, IList<Block> allBlocks, IList<VariableDefinition> locals) {
|
||||||
|
if (!block.LastInstr.isBrfalse())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ldc.i4.0
|
||||||
|
* stloc X
|
||||||
|
* call GetExecutingAssembly()
|
||||||
|
* stloc Y
|
||||||
|
* ldloc Y
|
||||||
|
* callvirt Location
|
||||||
|
* ldc.i4.1
|
||||||
|
* ldloca X
|
||||||
|
* call StrongNameSignatureVerificationEx
|
||||||
|
* pop / brfalse bad_code
|
||||||
|
* ldloc X
|
||||||
|
* brfalse bad_code
|
||||||
|
* ldloc Y
|
||||||
|
* callvirt FullName()
|
||||||
|
* ldstr "......"
|
||||||
|
* callvirt EndsWith(string)
|
||||||
|
* brfalse bad_code / brtrue good_code
|
||||||
|
*/
|
||||||
|
|
||||||
|
var instrs = block.Instructions;
|
||||||
|
int end = instrs.Count - 1;
|
||||||
|
Instr instr;
|
||||||
|
MethodReference method;
|
||||||
|
tamperBlocks.type = Type.V1;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
int start = findCallMethod(block, index, true, (calledMethod) => calledMethod.ToString() == "System.Reflection.Assembly System.Reflection.Assembly::GetExecutingAssembly()");
|
||||||
|
if (start < 0)
|
||||||
|
return false;
|
||||||
|
index = start + 1;
|
||||||
|
instr = instrs[--start];
|
||||||
|
if (!instr.isStloc())
|
||||||
|
return false;
|
||||||
|
var loc0 = Instr.getLocalVar(locals, instr);
|
||||||
|
instr = instrs[--start];
|
||||||
|
if (!instr.isLdcI4())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
index = findCallMethod(block, index, false, (calledMethod) => calledMethod.ToString() == "System.String System.Reflection.Assembly::get_Location()");
|
||||||
|
if (index < 0)
|
||||||
|
return false;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
index = findCallMethod(block, index, false, (calledMethod) => {
|
||||||
|
tamperBlocks.pinvokeMethod = DotNetUtils.getMethod(module, calledMethod);
|
||||||
|
return DotNetUtils.isPinvokeMethod(tamperBlocks.pinvokeMethod, "mscorwks", "StrongNameSignatureVerificationEx");
|
||||||
|
});
|
||||||
|
if (index < 0)
|
||||||
|
return false;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if (!instrs[index].isBrfalse()) {
|
||||||
|
if (instrs[index].OpCode.Code != Code.Pop)
|
||||||
|
return false;
|
||||||
|
instr = instrs[index + 1];
|
||||||
|
if (!instr.isLdloc() || Instr.getLocalVar(locals, instr) != loc0)
|
||||||
|
return false;
|
||||||
|
if (!instrs[index + 2].isBrfalse())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tamperBlocks.type = Type.V1;
|
||||||
|
tamperBlocks.first = new BlockInfo {
|
||||||
|
Block = block,
|
||||||
|
Start = start,
|
||||||
|
End = end,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tamperBlocks.type = Type.V2;
|
||||||
|
tamperBlocks.first = new BlockInfo {
|
||||||
|
Block = block,
|
||||||
|
Start = start,
|
||||||
|
End = end,
|
||||||
|
};
|
||||||
|
|
||||||
|
block = block.FallThrough;
|
||||||
|
if (block == null)
|
||||||
|
return false;
|
||||||
|
instrs = block.Instructions;
|
||||||
|
index = 0;
|
||||||
|
instr = instrs[index];
|
||||||
|
if (!instr.isLdloc() || Instr.getLocalVar(locals, instr) != loc0)
|
||||||
|
return false;
|
||||||
|
if (!instrs[index + 1].isBrfalse())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = block.FallThrough;
|
||||||
|
instrs = block.Instructions;
|
||||||
|
start = end = 0;
|
||||||
|
|
||||||
|
instr = instrs[end++];
|
||||||
|
if (!instr.isLdloc())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
instr = instrs[end++];
|
||||||
|
if (instr.OpCode != OpCodes.Callvirt)
|
||||||
|
return false;
|
||||||
|
method = (MethodReference)instr.Operand;
|
||||||
|
if (method.ToString() != "System.String System.Reflection.Assembly::get_FullName()")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
instr = instrs[end++];
|
||||||
|
if (instr.OpCode != OpCodes.Ldstr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
instr = instrs[end++];
|
||||||
|
if (instr.OpCode != OpCodes.Callvirt)
|
||||||
|
return false;
|
||||||
|
method = (MethodReference)instr.Operand;
|
||||||
|
if (method.ToString() != "System.Boolean System.String::EndsWith(System.String)")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
instr = instrs[end++];
|
||||||
|
if (!instr.isBrfalse() && !instr.isBrtrue())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
end--;
|
||||||
|
tamperBlocks.second = new BlockInfo {
|
||||||
|
Block = block,
|
||||||
|
Start = start,
|
||||||
|
End = end,
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockInfo findBadBlock(Block last) {
|
||||||
/*
|
/*
|
||||||
* ldstr "........."
|
* ldstr "........."
|
||||||
* newobj System.Security.SecurityException(string)
|
* newobj System.Security.SecurityException(string)
|
||||||
|
@ -248,42 +291,66 @@ namespace de4dot.deobfuscators.SmartAssembly {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool removeTamperProtection(Blocks blocks) {
|
bool removeTamperProtection(Blocks blocks) {
|
||||||
MethodDefinition pinvokeMethod;
|
|
||||||
var allBlocks = new List<Block>(blocks.MethodBlocks.getAllBlocks());
|
var allBlocks = new List<Block>(blocks.MethodBlocks.getAllBlocks());
|
||||||
var blockInfos = findTamperBlocks(blocks, allBlocks, out pinvokeMethod);
|
var tamperBlocks = findTamperBlocks(blocks, allBlocks);
|
||||||
|
|
||||||
if (blockInfos == null) {
|
if (tamperBlocks == null) {
|
||||||
if (isTamperProtected(allBlocks))
|
if (isTamperProtected(allBlocks))
|
||||||
Log.w("Could not remove tamper protection code: {0} ({1:X8})", blocks.Method, blocks.Method.MetadataToken.ToUInt32());
|
Log.w("Could not remove tamper protection code: {0} ({1:X8})", blocks.Method, blocks.Method.MetadataToken.ToUInt32());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockInfos.Count != 3)
|
switch (tamperBlocks.type) {
|
||||||
throw new ApplicationException("Invalid state");
|
case Type.V1:
|
||||||
var first = blockInfos[0];
|
removeTamperV1(tamperBlocks);
|
||||||
var second = blockInfos[1];
|
break;
|
||||||
var bad = blockInfos[2];
|
case Type.V2:
|
||||||
if (first.Block.Targets.Count != 1 || first.Block.Targets[0] != bad.Block)
|
removeTamperV2(tamperBlocks);
|
||||||
throw new ApplicationException("Invalid state");
|
break;
|
||||||
if (second.Start != 0 || second.End + 1 != second.Block.Instructions.Count)
|
default:
|
||||||
throw new ApplicationException("Invalid state");
|
throw new ApplicationException("Unknown type");
|
||||||
if (bad.Start != 0 || bad.End + 1 != bad.Block.Instructions.Count)
|
}
|
||||||
throw new ApplicationException("Invalid state");
|
pinvokeMethods.Add(tamperBlocks.pinvokeMethod);
|
||||||
var goodBlock = second.Block.LastInstr.isBrtrue() ? second.Block.Targets[0] : second.Block.FallThrough;
|
|
||||||
|
|
||||||
first.Block.remove(first.Start, first.End - first.Start + 1);
|
|
||||||
first.Block.replaceLastInstrsWithBranch(0, goodBlock);
|
|
||||||
removeDeadBlock(second);
|
|
||||||
removeDeadBlock(bad);
|
|
||||||
pinvokeMethods.Add(pinvokeMethod);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeDeadBlock(BlockInfo info) {
|
void removeTamperV1(TamperBlocks tamperBlocks) {
|
||||||
var parent = (ScopeBlock)info.Block.Parent;
|
var first = tamperBlocks.first;
|
||||||
|
var second = tamperBlocks.second;
|
||||||
|
var bad = tamperBlocks.bad;
|
||||||
|
var goodBlock = second.Block.LastInstr.isBrtrue() ? second.Block.Targets[0] : second.Block.FallThrough;
|
||||||
|
|
||||||
|
if (first.Block.Targets.Count != 1 || first.Block.Targets[0] != bad.Block)
|
||||||
|
throw new ApplicationException("Invalid state");
|
||||||
|
|
||||||
|
first.Block.remove(first.Start, first.End - first.Start + 1);
|
||||||
|
first.Block.replaceLastInstrsWithBranch(0, goodBlock);
|
||||||
|
removeDeadBlock(second.Block);
|
||||||
|
removeDeadBlock(bad.Block);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeTamperV2(TamperBlocks tamperBlocks) {
|
||||||
|
var first = tamperBlocks.first;
|
||||||
|
var second = tamperBlocks.second.Block;
|
||||||
|
var bad = tamperBlocks.bad.Block;
|
||||||
|
var firstFallthrough = first.Block.FallThrough;
|
||||||
|
var goodBlock = second.LastInstr.isBrtrue() ? second.Targets[0] : second.FallThrough;
|
||||||
|
|
||||||
|
if (first.Block.Targets.Count != 1 || first.Block.Targets[0] != bad)
|
||||||
|
throw new ApplicationException("Invalid state");
|
||||||
|
|
||||||
|
first.Block.remove(first.Start, first.End - first.Start + 1);
|
||||||
|
first.Block.replaceLastInstrsWithBranch(0, goodBlock);
|
||||||
|
removeDeadBlock(firstFallthrough);
|
||||||
|
removeDeadBlock(second);
|
||||||
|
removeDeadBlock(bad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeDeadBlock(Block block) {
|
||||||
|
var parent = (ScopeBlock)block.Parent;
|
||||||
if (parent != null) // null if already dead
|
if (parent != null) // null if already dead
|
||||||
parent.removeDeadBlock(info.Block);
|
parent.removeDeadBlock(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user