Merge branch 'master' into confuser

This commit is contained in:
de4dot 2013-11-15 21:18:11 +01:00
commit 33a00e644c
156 changed files with 8044 additions and 1308 deletions

View File

@ -41,8 +41,14 @@
<Compile Include="AssemblyService.cs" />
<Compile Include="DelegateStringDecrypter.cs" />
<Compile Include="EmuStringDecrypter.cs" />
<Compile Include="GenericService.cs" />
<Compile Include="IAssemblyService.cs" />
<Compile Include="IGenericService.cs" />
<Compile Include="IMethodDecrypterService.cs" />
<Compile Include="IStringDecrypter.cs" />
<Compile Include="IStringDecrypterService.cs" />
<Compile Include="IUserGenericService.cs" />
<Compile Include="MethodDecrypterService.cs" />
<Compile Include="methodsrewriter\AssemblyResolver.cs" />
<Compile Include="methodsrewriter\CodeGenerator.cs" />
<Compile Include="methodsrewriter\IMethodsRewriter.cs" />
@ -58,6 +64,7 @@
<Compile Include="methodsrewriter\TypeResolver.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SimpleData.cs" />
<Compile Include="StringDecrypterService.cs" />
<Compile Include="Utils.cs" />
</ItemGroup>
<ItemGroup>
@ -66,9 +73,9 @@
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\blocks\blocks.csproj">
<ProjectReference Include="..\de4dot.blocks\de4dot.blocks.csproj">
<Project>{045B96F2-AF80-4C4C-8D27-E38635AC705E}</Project>
<Name>blocks</Name>
<Name>de4dot.blocks</Name>
</ProjectReference>
<ProjectReference Include="..\de4dot.mdecrypt\de4dot.mdecrypt.csproj">
<Project>{5C93C5E2-196F-4877-BF65-96FEBFCEFCA1}</Project>

View File

@ -27,12 +27,13 @@ using AssemblyData;
namespace AssemblyServer {
public static class Start {
public static int Main2(string[] args) {
if (args.Length != 2)
if (args.Length != 3)
Environment.Exit(1);
var channelName = args[0];
var uri = args[1];
var serviceType = (AssemblyServiceType)int.Parse(args[0]);
var channelName = args[1];
var uri = args[2];
var service = new AssemblyService();
var service = (AssemblyService)AssemblyService.Create(serviceType);
StartServer(service, channelName, uri);
service.WaitExit();
return 0;

View File

@ -18,25 +18,51 @@
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using dnlib.DotNet;
using de4dot.blocks;
using de4dot.mdecrypt;
namespace AssemblyData {
public class AssemblyService : MarshalByRefObject, IAssemblyService {
IStringDecrypter stringDecrypter = null;
public abstract class AssemblyService : MarshalByRefObject, IAssemblyService {
ManualResetEvent exitEvent = new ManualResetEvent(false);
Assembly assembly = null;
protected Assembly assembly = null;
AssemblyResolver assemblyResolver = new AssemblyResolver();
bool installCompileMethodCalled = false;
public static AssemblyService Create(AssemblyServiceType serviceType) {
switch (serviceType) {
case AssemblyServiceType.StringDecrypter:
return new StringDecrypterService();
case AssemblyServiceType.MethodDecrypter:
return new MethodDecrypterService();
case AssemblyServiceType.Generic:
return new GenericService();
default:
throw new ArgumentException("Invalid assembly service type");
}
}
public static Type GetType(AssemblyServiceType serviceType) {
switch (serviceType) {
case AssemblyServiceType.StringDecrypter:
return typeof(StringDecrypterService);
case AssemblyServiceType.MethodDecrypter:
return typeof(MethodDecrypterService);
case AssemblyServiceType.Generic:
return typeof(GenericService);
default:
throw new ArgumentException("Invalid assembly service type");
}
}
public void DoNothing() {
}
public void Exit() {
public virtual void Exit() {
exitEvent.Set();
}
@ -48,17 +74,12 @@ namespace AssemblyData {
return null;
}
void CheckStringDecrypter() {
if (stringDecrypter == null)
throw new ApplicationException("setStringDecrypterType() hasn't been called yet.");
}
void CheckAssembly() {
protected void CheckAssembly() {
if (assembly == null)
throw new ApplicationException("loadAssembly() hasn't been called yet.");
throw new ApplicationException("LoadAssembly() hasn't been called yet.");
}
public void LoadAssembly(string filename) {
protected void LoadAssemblyInternal(string filename) {
if (assembly != null)
throw new ApplicationException("Only one assembly can be explicitly loaded");
try {
@ -68,86 +89,5 @@ namespace AssemblyData {
throw new ApplicationException(string.Format("Could not load assembly {0}. Maybe it's 32-bit or 64-bit only?", filename));
}
}
public void SetStringDecrypterType(StringDecrypterType type) {
if (stringDecrypter != null)
throw new ApplicationException("StringDecrypterType already set");
switch (type) {
case StringDecrypterType.Delegate:
stringDecrypter = new DelegateStringDecrypter();
break;
case StringDecrypterType.Emulate:
stringDecrypter = new EmuStringDecrypter();
break;
default:
throw new ApplicationException(string.Format("Unknown StringDecrypterType {0}", type));
}
}
public int DefineStringDecrypter(int methodToken) {
CheckStringDecrypter();
var methodInfo = FindMethod(methodToken);
if (methodInfo == null)
throw new ApplicationException(string.Format("Could not find method {0:X8}", methodToken));
if (methodInfo.ReturnType != typeof(string) && methodInfo.ReturnType != typeof(object))
throw new ApplicationException(string.Format("Method return type must be string or object: {0}", methodInfo));
return stringDecrypter.DefineStringDecrypter(methodInfo);
}
public object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken) {
CheckStringDecrypter();
var caller = GetCaller(callerToken);
foreach (var arg in args)
SimpleData.Unpack((object[])arg);
return SimpleData.Pack(stringDecrypter.DecryptStrings(stringDecrypterMethod, args, caller));
}
MethodBase GetCaller(int callerToken) {
try {
return assembly.GetModules()[0].ResolveMethod(callerToken);
}
catch {
return null;
}
}
MethodInfo FindMethod(int methodToken) {
CheckAssembly();
foreach (var module in assembly.GetModules()) {
var method = module.ResolveMethod(methodToken) as MethodInfo;
if (method != null)
return method;
}
return null;
}
public void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo) {
if (installCompileMethodCalled)
throw new ApplicationException("installCompileMethod() has already been called");
installCompileMethodCalled = true;
DynamicMethodsDecrypter.Instance.DecryptMethodsInfo = decryptMethodsInfo;
DynamicMethodsDecrypter.Instance.InstallCompileMethod();
}
public void LoadObfuscator(string filename) {
LoadAssembly(filename);
DynamicMethodsDecrypter.Instance.Module = assembly.ManifestModule;
DynamicMethodsDecrypter.Instance.LoadObfuscator();
}
public bool CanDecryptMethods() {
CheckAssembly();
return DynamicMethodsDecrypter.Instance.CanDecryptMethods();
}
public DumpedMethods DecryptMethods() {
CheckAssembly();
return DynamicMethodsDecrypter.Instance.DecryptMethods();
}
}
}

View File

@ -0,0 +1,67 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Reflection;
namespace AssemblyData {
class GenericService : AssemblyService, IGenericService {
IUserGenericService userGenericService;
public override void Exit() {
if (userGenericService != null)
userGenericService.Dispose();
userGenericService = null;
base.Exit();
}
public void LoadUserService(Type createServiceType, object createMethodArgs) {
var createServiceMethod = GetCreateUserServiceMethod(createServiceType);
userGenericService = createServiceMethod.Invoke(null, null) as IUserGenericService;
if (userGenericService == null)
throw new ApplicationException("create-service-method failed to create user service");
}
MethodInfo GetCreateUserServiceMethod(Type createServiceType) {
if (createServiceType == null)
throw new ApplicationException(string.Format("Create-service-type is null"));
foreach (var method in createServiceType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) {
if (method.GetCustomAttributes(typeof(CreateUserGenericServiceAttribute), false).Length > 0)
return method;
}
throw new ApplicationException(string.Format("Failed to find create-service-method. Type token: Type: {0}", createServiceType));
}
void CheckUserService() {
if (userGenericService == null)
throw new ApplicationException("LoadUserService() hasn't been called yet.");
}
public void LoadAssembly(string filename) {
CheckUserService();
LoadAssemblyInternal(filename);
userGenericService.AssemblyLoaded(assembly);
}
public object SendMessage(int msg, object[] args) {
CheckUserService();
return userGenericService.HandleMessage(msg, args);
}
}
}

View File

@ -17,29 +17,15 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using dnlib.DotNet;
using de4dot.blocks;
using de4dot.mdecrypt;
namespace AssemblyData {
public enum StringDecrypterType {
Delegate,
Emulate,
public enum AssemblyServiceType {
StringDecrypter,
MethodDecrypter,
Generic,
}
public interface IAssemblyService {
void DoNothing();
void Exit();
void LoadAssembly(string filename);
void SetStringDecrypterType(StringDecrypterType type);
int DefineStringDecrypter(int methodToken);
object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken);
void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo);
void LoadObfuscator(string filename);
bool CanDecryptMethods();
DumpedMethods DecryptMethods();
}
}

View File

@ -0,0 +1,31 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
namespace AssemblyData {
public class CreateUserGenericServiceAttribute : Attribute {
}
public interface IGenericService : IAssemblyService {
void LoadUserService(Type createServiceType, object createMethodArgs);
void LoadAssembly(string filename);
object SendMessage(int msg, object[] args);
}
}

View File

@ -0,0 +1,30 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using de4dot.blocks;
using de4dot.mdecrypt;
namespace AssemblyData {
public interface IMethodDecrypterService : IAssemblyService {
void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo);
void LoadObfuscator(string filename);
bool CanDecryptMethods();
DumpedMethods DecryptMethods();
}
}

View File

@ -0,0 +1,32 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
namespace AssemblyData {
public enum StringDecrypterType {
Delegate,
Emulate,
}
public interface IStringDecrypterService : IAssemblyService {
void LoadAssembly(string filename);
void SetStringDecrypterType(StringDecrypterType type);
int DefineStringDecrypter(int methodToken);
object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken);
}
}

View File

@ -0,0 +1,28 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Reflection;
namespace AssemblyData {
public interface IUserGenericService : IDisposable {
void AssemblyLoaded(Assembly assembly);
object HandleMessage(int msg, object[] args);
}
}

View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using de4dot.blocks;
using de4dot.mdecrypt;
namespace AssemblyData {
class MethodDecrypterService : AssemblyService, IMethodDecrypterService {
bool installCompileMethodCalled = false;
public void InstallCompileMethod(DecryptMethodsInfo decryptMethodsInfo) {
if (installCompileMethodCalled)
throw new ApplicationException("installCompileMethod() has already been called");
installCompileMethodCalled = true;
DynamicMethodsDecrypter.Instance.DecryptMethodsInfo = decryptMethodsInfo;
DynamicMethodsDecrypter.Instance.InstallCompileMethod();
}
public void LoadObfuscator(string filename) {
LoadAssemblyInternal(filename);
DynamicMethodsDecrypter.Instance.Module = assembly.ManifestModule;
DynamicMethodsDecrypter.Instance.LoadObfuscator();
}
public bool CanDecryptMethods() {
CheckAssembly();
return DynamicMethodsDecrypter.Instance.CanDecryptMethods();
}
public DumpedMethods DecryptMethods() {
CheckAssembly();
return DynamicMethodsDecrypter.Instance.DecryptMethods();
}
}
}

View File

@ -0,0 +1,93 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Reflection;
namespace AssemblyData {
class StringDecrypterService : AssemblyService, IStringDecrypterService {
IStringDecrypter stringDecrypter = null;
void CheckStringDecrypter() {
if (stringDecrypter == null)
throw new ApplicationException("SetStringDecrypterType() hasn't been called yet.");
}
public void LoadAssembly(string filename) {
LoadAssemblyInternal(filename);
}
public void SetStringDecrypterType(StringDecrypterType type) {
if (stringDecrypter != null)
throw new ApplicationException("StringDecrypterType already set");
switch (type) {
case StringDecrypterType.Delegate:
stringDecrypter = new DelegateStringDecrypter();
break;
case StringDecrypterType.Emulate:
stringDecrypter = new EmuStringDecrypter();
break;
default:
throw new ApplicationException(string.Format("Unknown StringDecrypterType {0}", type));
}
}
public int DefineStringDecrypter(int methodToken) {
CheckStringDecrypter();
var methodInfo = FindMethod(methodToken);
if (methodInfo == null)
throw new ApplicationException(string.Format("Could not find method {0:X8}", methodToken));
if (methodInfo.ReturnType != typeof(string) && methodInfo.ReturnType != typeof(object))
throw new ApplicationException(string.Format("Method return type must be string or object: {0}", methodInfo));
return stringDecrypter.DefineStringDecrypter(methodInfo);
}
public object[] DecryptStrings(int stringDecrypterMethod, object[] args, int callerToken) {
CheckStringDecrypter();
var caller = GetCaller(callerToken);
foreach (var arg in args)
SimpleData.Unpack((object[])arg);
return SimpleData.Pack(stringDecrypter.DecryptStrings(stringDecrypterMethod, args, caller));
}
MethodBase GetCaller(int callerToken) {
try {
return assembly.GetModules()[0].ResolveMethod(callerToken);
}
catch {
return null;
}
}
MethodInfo FindMethod(int methodToken) {
CheckAssembly();
foreach (var module in assembly.GetModules()) {
var method = module.ResolveMethod(methodToken) as MethodInfo;
if (method != null)
return method;
}
return null;
}
}
}

View File

@ -338,7 +338,7 @@ namespace AssemblyData.methodsrewriter {
return list;
}
static FieldInfo GgetStackTraceStackFramesField() {
static FieldInfo GetStackTraceStackFramesField() {
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
return ResolverUtils.GetFieldThrow(typeof(StackTrace), typeof(StackFrame[]), flags, "Could not find StackTrace's frames (StackFrame[]) field");
}
@ -367,7 +367,7 @@ namespace AssemblyData.methodsrewriter {
}
StackTrace RtFixStackTrace(StackTrace stackTrace) {
var framesField = GgetStackTraceStackFramesField();
var framesField = GetStackTraceStackFramesField();
var frames = (StackFrame[])framesField.GetValue(stackTrace);
var newFrames = new List<StackFrame>(frames.Length);

View File

@ -1,53 +0,0 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
namespace de4dot.blocks.cflow {
public class Real8Value : Value {
public readonly double value;
public Real8Value(double value)
: base(ValueType.Real8) {
this.value = value;
}
public static Real8Value Add(Real8Value a, Real8Value b) {
return new Real8Value(a.value + b.value);
}
public static Real8Value Sub(Real8Value a, Real8Value b) {
return new Real8Value(a.value - b.value);
}
public static Real8Value Mul(Real8Value a, Real8Value b) {
return new Real8Value(a.value * b.value);
}
public static Real8Value Div(Real8Value a, Real8Value b) {
return new Real8Value(a.value / b.value);
}
public static Real8Value Rem(Real8Value a, Real8Value b) {
return new Real8Value(a.value % b.value);
}
public static Real8Value Neg(Real8Value a) {
return new Real8Value(-a.value);
}
}
}

View File

@ -170,38 +170,60 @@ namespace de4dot.blocks {
dest.Add(block);
}
struct VisitState {
public BlockInfo Info;
public List<BaseBlock> Targets;
public int TargetIndex;
public BlockInfo TargetInfo;
public VisitState(BlockInfo info) {
this.Info = info;
this.Targets = null;
this.TargetIndex = 0;
this.TargetInfo = null;
}
}
Stack<VisitState> visitStateStack = new Stack<VisitState>();
void Visit(BlockInfo info) {
if (info.baseBlock == firstBlock)
// This method used to be recursive but to prevent stack overflows,
// it's not recursive anymore.
VisitState state = new VisitState(info);
recursive_call:
if (state.Info.baseBlock == firstBlock)
throw new ApplicationException("Can't visit firstBlock");
stack.Push(info);
info.onStack = true;
info.dfsNumber = dfsNumber;
info.low = dfsNumber;
stack.Push(state.Info);
state.Info.onStack = true;
state.Info.dfsNumber = dfsNumber;
state.Info.low = dfsNumber;
dfsNumber++;
foreach (var tmp in GetTargets(info.baseBlock)) {
var targetInfo = GetInfo(tmp);
if (targetInfo == null)
state.Targets = GetTargets(state.Info.baseBlock);
state.TargetIndex = 0;
return_to_caller:
for (; state.TargetIndex < state.Targets.Count; state.TargetIndex++) {
state.TargetInfo = GetInfo(state.Targets[state.TargetIndex]);
if (state.TargetInfo == null)
continue;
if (targetInfo.baseBlock == firstBlock)
if (state.TargetInfo.baseBlock == firstBlock)
continue;
if (!targetInfo.Visited()) {
Visit(targetInfo);
info.low = Math.Min(info.low, targetInfo.low);
if (!state.TargetInfo.Visited()) {
visitStateStack.Push(state);
state = new VisitState(state.TargetInfo);
goto recursive_call;
}
else if (targetInfo.onStack)
info.low = Math.Min(info.low, targetInfo.dfsNumber);
else if (state.TargetInfo.onStack)
state.Info.low = Math.Min(state.Info.low, state.TargetInfo.dfsNumber);
}
if (info.low != info.dfsNumber)
return;
if (state.Info.low != state.Info.dfsNumber)
goto return_from_method;
var sccBlocks = new List<BaseBlock>();
while (true) {
var poppedInfo = stack.Pop();
poppedInfo.onStack = false;
sccBlocks.Add(poppedInfo.baseBlock);
if (ReferenceEquals(info, poppedInfo))
if (ReferenceEquals(state.Info, poppedInfo))
break;
}
if (sccBlocks.Count > 1) {
@ -213,6 +235,14 @@ namespace de4dot.blocks {
else {
sorted.Insert(0, sccBlocks[0]);
}
return_from_method:
if (visitStateStack.Count == 0)
return;
state = visitStateStack.Pop();
state.Info.low = Math.Min(state.Info.low, state.TargetInfo.low);
state.TargetIndex++;
goto return_to_caller;
}
void SortLoopBlock(List<BaseBlock> list) {

View File

@ -100,25 +100,38 @@ namespace de4dot.blocks {
return false;
}
void ScanBaseBlock(BaseBlock bb, int stackStart) {
if (blockInfos.ContainsKey(bb) || !scopeBlock.IsOurBaseBlock(bb))
return;
var blockInfo = new BlockInfo(bb, stackStart);
blockInfos[bb] = blockInfo;
var block = bb as Block;
if (block == null) { // i.e., if try, filter, or handler block
// It's not important to know the exact values, so we set them both to 0.
// Compilers must make sure the stack is empty when entering a try block.
blockInfo.stackStart = blockInfo.stackEnd = 0;
return;
struct ScanBaseBlockState {
public BaseBlock bb;
public int stackStart;
public ScanBaseBlockState(BaseBlock bb, int stackStart) {
this.bb = bb;
this.stackStart = stackStart;
}
}
Stack<ScanBaseBlockState> scanBaseBlockStack = new Stack<ScanBaseBlockState>();
void ScanBaseBlock(BaseBlock bb, int stackStart) {
scanBaseBlockStack.Push(new ScanBaseBlockState(bb, stackStart));
while (scanBaseBlockStack.Count > 0) {
var state = scanBaseBlockStack.Pop();
if (blockInfos.ContainsKey(state.bb) || !scopeBlock.IsOurBaseBlock(state.bb))
continue;
blockInfo.CalculateStackUsage();
var blockInfo = new BlockInfo(state.bb, state.stackStart);
blockInfos[state.bb] = blockInfo;
foreach (var target in block.GetTargets())
ScanBaseBlock(target, blockInfo.stackEnd);
var block = state.bb as Block;
if (block == null) { // i.e., if try, filter, or handler block
// It's not important to know the exact values, so we set them both to 0.
// Compilers must make sure the stack is empty when entering a try block.
blockInfo.stackStart = blockInfo.stackEnd = 0;
continue;
}
blockInfo.CalculateStackUsage();
foreach (var target in block.GetTargets())
scanBaseBlockStack.Push(new ScanBaseBlockState(target, blockInfo.stackEnd));
}
}
void CreateNewList() {

View File

@ -20,11 +20,11 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("blocks")]
[assembly: AssemblyTitle("de4dot.blocks")]
[assembly: AssemblyDescription("Modifies dnlib MethodDef bodies")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("blocks")]
[assembly: AssemblyProduct("de4dot.blocks")]
[assembly: AssemblyCopyright("Copyright (C) 2011-2013 de4dot@gmail.com")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

View File

@ -0,0 +1,94 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Reflection;
using System.Diagnostics;
namespace de4dot.blocks {
public class StackTracePatcher {
static readonly FieldInfo methodField;
static readonly FieldInfo framesField;
static readonly FieldInfo methodsToSkipField;
static StackTracePatcher() {
methodField = GetStackFrameMethodField();
framesField = GetStackTraceStackFramesField();
methodsToSkipField = GetMethodsToSkipField();
}
static FieldInfo GetStackFrameMethodField() {
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
return GetFieldThrow(typeof(StackFrame), typeof(MethodBase), flags, "Could not find StackFrame's method (MethodBase) field");
}
static FieldInfo GetStackTraceStackFramesField() {
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
return GetFieldThrow(typeof(StackTrace), typeof(StackFrame[]), flags, "Could not find StackTrace's frames (StackFrame[]) field");
}
static FieldInfo GetMethodsToSkipField() {
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
return GetFieldThrow(typeof(StackTrace), "m_iMethodsToSkip", flags, "Could not find StackTrace's iMethodsToSkip field");
}
static FieldInfo GetFieldThrow(Type type, Type fieldType, BindingFlags flags, string msg) {
var info = GetField(type, fieldType, flags);
if (info != null)
return info;
throw new ApplicationException(msg);
}
static FieldInfo GetField(Type type, Type fieldType, BindingFlags flags) {
foreach (var field in type.GetFields(flags)) {
if (field.FieldType == fieldType)
return field;
}
return null;
}
static FieldInfo GetFieldThrow(Type type, string fieldName, BindingFlags flags, string msg) {
var info = GetField(type, fieldName, flags);
if (info != null)
return info;
throw new ApplicationException(msg);
}
static FieldInfo GetField(Type type, string fieldName, BindingFlags flags) {
foreach (var field in type.GetFields(flags)) {
if (field.Name == fieldName)
return field;
}
return null;
}
public static StackTrace WriteStackFrame(StackTrace stackTrace, int frameNo, MethodBase newMethod) {
var frames = (StackFrame[])framesField.GetValue(stackTrace);
int numFramesToSkip = (int)methodsToSkipField.GetValue(stackTrace);
WriteMethodBase(frames[numFramesToSkip + frameNo], newMethod);
return stackTrace;
}
static void WriteMethodBase(StackFrame frame, MethodBase method) {
methodField.SetValue(frame, method);
if (frame.GetMethod() != method)
throw new ApplicationException(string.Format("Could not set new method: {0}", method));
}
}
}

View File

@ -35,7 +35,7 @@ namespace de4dot.blocks.cflow {
this.block = block;
if (!block.LastInstr.IsConditionalBranch() && block.LastInstr.OpCode.Code != Code.Switch)
return false;
instructionEmulator.Initialize(blocks);
instructionEmulator.Initialize(blocks, allBlocks[0] == block);
var instructions = block.Instructions;
if (instructions.Count == 0)

View File

@ -25,7 +25,7 @@ namespace de4dot.blocks.cflow {
if (!intValue.AllBitsValid())
return null;
int index = intValue.value;
int index = intValue.Value;
if (targets == null || index < 0 || index >= targets.Count)
return fallThrough;
else

View File

@ -37,7 +37,7 @@ namespace de4dot.blocks.cflow {
protected override bool Deobfuscate(Block block) {
bool modified = false;
instructionEmulator.Initialize(blocks);
instructionEmulator.Initialize(blocks, allBlocks[0] == block);
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
@ -89,14 +89,14 @@ namespace de4dot.blocks.cflow {
var intValue = (Int32Value)value;
if (!intValue.AllBitsValid())
return false;
block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.value));
block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.Value));
return true;
}
else if (value.IsInt64()) {
var intValue = (Int64Value)value;
if (!intValue.AllBitsValid())
return false;
block.Instructions[index] = new Instr(OpCodes.Ldc_I8.ToInstruction(intValue.value));
block.Instructions[index] = new Instr(OpCodes.Ldc_I8.ToInstruction(intValue.Value));
return true;
}
return false;

View File

@ -34,19 +34,24 @@ namespace de4dot.blocks.cflow {
MethodDef prev_method;
List<Value> cached_args = new List<Value>();
List<Value> cached_locals = new List<Value>();
List<Value> cached_zeroed_locals = new List<Value>();
public InstructionEmulator() {
}
public InstructionEmulator(MethodDef method) {
Initialize(method);
Initialize(method, false);
}
public void Initialize(Blocks blocks) {
Initialize(blocks.Method);
public void Initialize(Blocks blocks, bool emulateFromFirstInstruction) {
Initialize(blocks.Method, emulateFromFirstInstruction);
}
public void Initialize(MethodDef method) {
Initialize(method, false);
}
public void Initialize(MethodDef method, bool emulateFromFirstInstruction) {
this.parameterDefs = method.Parameters;
this.localDefs = method.Body.Variables;
valueStack.Initialize();
@ -60,14 +65,17 @@ namespace de4dot.blocks.cflow {
cached_args.Add(GetUnknownValue(parameterDefs[i].Type));
cached_locals.Clear();
for (int i = 0; i < localDefs.Count; i++)
cached_zeroed_locals.Clear();
for (int i = 0; i < localDefs.Count; i++) {
cached_locals.Add(GetUnknownValue(localDefs[i].Type));
cached_zeroed_locals.Add(GetDefaultValue(localDefs[i].Type));
}
}
args.Clear();
args.AddRange(cached_args);
locals.Clear();
locals.AddRange(cached_locals);
locals.AddRange(method.Body.InitLocals && emulateFromFirstInstruction ? cached_zeroed_locals : cached_locals);
}
public void SetProtected(Value value) {
@ -95,6 +103,25 @@ namespace de4dot.blocks.cflow {
return new UnknownValue();
}
static Value GetDefaultValue(TypeSig type) {
if (type == null)
return new UnknownValue();
switch (type.ElementType) {
case ElementType.Boolean:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
return Int32Value.Zero;
case ElementType.I8:
case ElementType.U8:
return Int64Value.Zero;
}
return new UnknownValue();
}
Value TruncateValue(Value value, TypeSig type) {
if (type == null)
return value;
@ -141,7 +168,7 @@ namespace de4dot.blocks.cflow {
case ElementType.R4:
if (value.IsReal8())
return new Real8Value((float)((Real8Value)value).value);
return ((Real8Value)value).ToSingle();
return new UnknownValue();
case ElementType.R8:
@ -297,8 +324,8 @@ namespace de4dot.blocks.cflow {
case Code.Ldc_I8: valueStack.Push(new Int64Value((long)instr.Operand)); break;
case Code.Ldc_R4: valueStack.Push(new Real8Value((float)instr.Operand)); break;
case Code.Ldc_R8: valueStack.Push(new Real8Value((double)instr.Operand)); break;
case Code.Ldc_I4_0: valueStack.Push(Int32Value.zero); break;
case Code.Ldc_I4_1: valueStack.Push(Int32Value.one); break;
case Code.Ldc_I4_0: valueStack.Push(Int32Value.Zero); break;
case Code.Ldc_I4_1: valueStack.Push(Int32Value.One); break;
case Code.Ldc_I4_2: valueStack.Push(new Int32Value(2)); break;
case Code.Ldc_I4_3: valueStack.Push(new Int32Value(3)); break;
case Code.Ldc_I4_4: valueStack.Push(new Int32Value(4)); break;
@ -347,29 +374,29 @@ namespace de4dot.blocks.cflow {
case Code.Castclass: Emulate_Castclass(instr); break;
case Code.Isinst: Emulate_Isinst(instr); break;
case Code.Add_Ovf: EmulateIntOps2(); break;
case Code.Add_Ovf_Un: EmulateIntOps2(); break;
case Code.Sub_Ovf: EmulateIntOps2(); break;
case Code.Sub_Ovf_Un: EmulateIntOps2(); break;
case Code.Mul_Ovf: EmulateIntOps2(); break;
case Code.Mul_Ovf_Un: EmulateIntOps2(); break;
case Code.Add_Ovf: Emulate_Add_Ovf(instr); break;
case Code.Add_Ovf_Un: Emulate_Add_Ovf_Un(instr); break;
case Code.Sub_Ovf: Emulate_Sub_Ovf(instr); break;
case Code.Sub_Ovf_Un: Emulate_Sub_Ovf_Un(instr); break;
case Code.Mul_Ovf: Emulate_Mul_Ovf(instr); break;
case Code.Mul_Ovf_Un: Emulate_Mul_Ovf_Un(instr); break;
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I1_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknown()); break;
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I2_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknown()); break;
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I4_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknown()); break;
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_I8_Un: valueStack.Pop(); valueStack.Push(Int64Value.CreateUnknown()); break;
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U1_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknownUInt8()); break;
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U2_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknownUInt16()); break;
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U4_Un: valueStack.Pop(); valueStack.Push(Int32Value.CreateUnknown()); break;
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_U8_Un: valueStack.Pop(); valueStack.Push(Int64Value.CreateUnknown()); break;
case Code.Conv_Ovf_I1: Emulate_Conv_Ovf_I1(instr); break;
case Code.Conv_Ovf_I1_Un: Emulate_Conv_Ovf_I1_Un(instr); break;
case Code.Conv_Ovf_I2: Emulate_Conv_Ovf_I2(instr); break;
case Code.Conv_Ovf_I2_Un: Emulate_Conv_Ovf_I2_Un(instr); break;
case Code.Conv_Ovf_I4: Emulate_Conv_Ovf_I4(instr); break;
case Code.Conv_Ovf_I4_Un: Emulate_Conv_Ovf_I4_Un(instr); break;
case Code.Conv_Ovf_I8: Emulate_Conv_Ovf_I8(instr); break;
case Code.Conv_Ovf_I8_Un: Emulate_Conv_Ovf_I8_Un(instr); break;
case Code.Conv_Ovf_U1: Emulate_Conv_Ovf_U1(instr); break;
case Code.Conv_Ovf_U1_Un: Emulate_Conv_Ovf_U1_Un(instr); break;
case Code.Conv_Ovf_U2: Emulate_Conv_Ovf_U2(instr); break;
case Code.Conv_Ovf_U2_Un: Emulate_Conv_Ovf_U2_Un(instr); break;
case Code.Conv_Ovf_U4: Emulate_Conv_Ovf_U4(instr); break;
case Code.Conv_Ovf_U4_Un: Emulate_Conv_Ovf_U4_Un(instr); break;
case Code.Conv_Ovf_U8: Emulate_Conv_Ovf_U8(instr); break;
case Code.Conv_Ovf_U8_Un: Emulate_Conv_Ovf_U8_Un(instr); break;
case Code.Ldelem_I1: valueStack.Pop(2); valueStack.Push(Int32Value.CreateUnknown()); break;
case Code.Ldelem_I2: valueStack.Pop(2); valueStack.Push(Int32Value.CreateUnknown()); break;
@ -595,6 +622,166 @@ namespace de4dot.blocks.cflow {
}
}
void Emulate_Conv_Ovf_I1(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I1((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I1((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I1((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_I1_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I1_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I1_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I1_Un((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_I2(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I2((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I2((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I2((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_I2_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I2_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I2_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I2_Un((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_I4(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I4((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I4((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I4((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_I4_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I4_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I4_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I4_Un((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_I8(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I8((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I8((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I8((Real8Value)val1)); break;
default: valueStack.Push(Int64Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_I8_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_I8_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_I8_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_I8_Un((Real8Value)val1)); break;
default: valueStack.Push(Int64Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_U1(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U1((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U1((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U1((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknownUInt8()); break;
}
}
void Emulate_Conv_Ovf_U1_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U1_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U1_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U1_Un((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknownUInt8()); break;
}
}
void Emulate_Conv_Ovf_U2(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U2((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U2((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U2((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknownUInt16()); break;
}
}
void Emulate_Conv_Ovf_U2_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U2_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U2_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U2_Un((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknownUInt16()); break;
}
}
void Emulate_Conv_Ovf_U4(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U4((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U4((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U4((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_U4_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U4_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U4_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U4_Un((Real8Value)val1)); break;
default: valueStack.Push(Int32Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_U8(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U8((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U8((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U8((Real8Value)val1)); break;
default: valueStack.Push(Int64Value.CreateUnknown()); break;
}
}
void Emulate_Conv_Ovf_U8_Un(Instruction instr) {
var val1 = valueStack.Pop();
switch (val1.valueType) {
case ValueType.Int32: valueStack.Push(Int32Value.Conv_Ovf_U8_Un((Int32Value)val1)); break;
case ValueType.Int64: valueStack.Push(Int64Value.Conv_Ovf_U8_Un((Int64Value)val1)); break;
case ValueType.Real8: valueStack.Push(Real8Value.Conv_Ovf_U8_Un((Real8Value)val1)); break;
default: valueStack.Push(Int64Value.CreateUnknown()); break;
}
}
void Emulate_Add(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
@ -702,6 +889,90 @@ namespace de4dot.blocks.cflow {
valueStack.PushUnknown();
}
void Emulate_Add_Ovf(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
if (val1.IsInt32() && val2.IsInt32())
valueStack.Push(Int32Value.Add_Ovf((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Add_Ovf((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Add_Ovf((Real8Value)val1, (Real8Value)val2));
else
valueStack.PushUnknown();
}
void Emulate_Add_Ovf_Un(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
if (val1.IsInt32() && val2.IsInt32())
valueStack.Push(Int32Value.Add_Ovf_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Add_Ovf_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Add_Ovf_Un((Real8Value)val1, (Real8Value)val2));
else
valueStack.PushUnknown();
}
void Emulate_Sub_Ovf(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
if (val1.IsInt32() && val2.IsInt32())
valueStack.Push(Int32Value.Sub_Ovf((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Sub_Ovf((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Sub_Ovf((Real8Value)val1, (Real8Value)val2));
else
valueStack.PushUnknown();
}
void Emulate_Sub_Ovf_Un(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
if (val1.IsInt32() && val2.IsInt32())
valueStack.Push(Int32Value.Sub_Ovf_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Sub_Ovf_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Sub_Ovf_Un((Real8Value)val1, (Real8Value)val2));
else
valueStack.PushUnknown();
}
void Emulate_Mul_Ovf(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
if (val1.IsInt32() && val2.IsInt32())
valueStack.Push(Int32Value.Mul_Ovf((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Mul_Ovf((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Mul_Ovf((Real8Value)val1, (Real8Value)val2));
else
valueStack.PushUnknown();
}
void Emulate_Mul_Ovf_Un(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
if (val1.IsInt32() && val2.IsInt32())
valueStack.Push(Int32Value.Mul_Ovf_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Mul_Ovf_Un((Int64Value)val1, (Int64Value)val2));
else if (val1.IsReal8() && val2.IsReal8())
valueStack.Push(Real8Value.Mul_Ovf_Un((Real8Value)val1, (Real8Value)val2));
else
valueStack.PushUnknown();
}
void Emulate_And(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
@ -794,7 +1065,7 @@ namespace de4dot.blocks.cflow {
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Ceq((Int64Value)val1, (Int64Value)val2));
else if (val1.IsNull() && val2.IsNull())
valueStack.Push(Int32Value.one);
valueStack.Push(Int32Value.One);
else
valueStack.Push(Int32Value.CreateUnknownBool());
}

View File

@ -21,27 +21,27 @@ using System;
namespace de4dot.blocks.cflow {
public class Int32Value : Value {
public static readonly Int32Value zero = new Int32Value(0);
public static readonly Int32Value one = new Int32Value(1);
public static readonly Int32Value Zero = new Int32Value(0);
public static readonly Int32Value One = new Int32Value(1);
const uint NO_UNKNOWN_BITS = uint.MaxValue;
public readonly int value;
public readonly uint validMask;
internal const uint NO_UNKNOWN_BITS = uint.MaxValue;
public readonly int Value;
public readonly uint ValidMask;
public Int32Value(int value)
: base(ValueType.Int32) {
this.value = value;
this.validMask = NO_UNKNOWN_BITS;
this.Value = value;
this.ValidMask = NO_UNKNOWN_BITS;
}
public Int32Value(int value, uint validMask)
: base(ValueType.Int32) {
this.value = value;
this.validMask = validMask;
this.Value = value;
this.ValidMask = validMask;
}
public bool HasUnknownBits() {
return validMask != NO_UNKNOWN_BITS;
return ValidMask != NO_UNKNOWN_BITS;
}
public bool AllBitsValid() {
@ -49,13 +49,17 @@ namespace de4dot.blocks.cflow {
}
bool IsBitValid(int n) {
return IsBitValid(validMask, n);
return IsBitValid(ValidMask, n);
}
static bool IsBitValid(uint validMask, int n) {
return (validMask & (1U << n)) != 0;
}
bool AreBitsValid(uint bitsToTest) {
return (ValidMask & bitsToTest) == bitsToTest;
}
public static Int32Value CreateUnknownBool() {
return new Int32Value(0, NO_UNKNOWN_BITS << 1);
}
@ -77,11 +81,11 @@ namespace de4dot.blocks.cflow {
}
public bool IsNonZero() {
return (value & validMask) != 0;
return ((uint)Value & ValidMask) != 0;
}
public bool HasValue(int value) {
return AllBitsValid() && this.value == value;
return AllBitsValid() && this.Value == value;
}
public bool HasValue(uint value) {
@ -113,11 +117,11 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_U1(Int32Value a) {
return Conv_U1(a.value, a.validMask);
return Conv_U1(a.Value, a.ValidMask);
}
public static Int32Value Conv_U1(Int64Value a) {
return Conv_U1((int)a.value, (uint)a.validMask);
return Conv_U1((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_U1(int value, uint validMask) {
@ -127,15 +131,17 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_U1(Real8Value a) {
return new Int32Value((int)(byte)a.value);
if (!a.IsValid)
return CreateUnknownUInt8();
return new Int32Value((int)(byte)a.Value);
}
public static Int32Value Conv_I1(Int32Value a) {
return Conv_I1(a.value, a.validMask);
return Conv_I1(a.Value, a.ValidMask);
}
public static Int32Value Conv_I1(Int64Value a) {
return Conv_I1((int)a.value, (uint)a.validMask);
return Conv_I1((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_I1(int value, uint validMask) {
@ -148,15 +154,17 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_I1(Real8Value a) {
return new Int32Value((int)(sbyte)a.value);
if (!a.IsValid)
return CreateUnknown();
return new Int32Value((int)(sbyte)a.Value);
}
public static Int32Value Conv_U2(Int32Value a) {
return Conv_U2(a.value, a.validMask);
return Conv_U2(a.Value, a.ValidMask);
}
public static Int32Value Conv_U2(Int64Value a) {
return Conv_U2((int)a.value, (uint)a.validMask);
return Conv_U2((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_U2(int value, uint validMask) {
@ -166,15 +174,17 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_U2(Real8Value a) {
return new Int32Value((int)(ushort)a.value);
if (!a.IsValid)
return CreateUnknownUInt16();
return new Int32Value((int)(ushort)a.Value);
}
public static Int32Value Conv_I2(Int32Value a) {
return Conv_I2(a.value, a.validMask);
return Conv_I2(a.Value, a.ValidMask);
}
public static Int32Value Conv_I2(Int64Value a) {
return Conv_I2((int)a.value, (uint)a.validMask);
return Conv_I2((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_I2(int value, uint validMask) {
@ -187,7 +197,9 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_I2(Real8Value a) {
return new Int32Value((int)(short)a.value);
if (!a.IsValid)
return CreateUnknown();
return new Int32Value((int)(short)a.Value);
}
public static Int32Value Conv_U4(Int32Value a) {
@ -195,11 +207,13 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_U4(Int64Value a) {
return new Int32Value((int)(uint)a.value, (uint)a.validMask);
return new Int32Value((int)(uint)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_U4(Real8Value a) {
return new Int32Value((int)(uint)a.value);
if (!a.IsValid)
return CreateUnknown();
return new Int32Value((int)(uint)a.Value);
}
public static Int32Value Conv_I4(Int32Value a) {
@ -207,34 +221,137 @@ namespace de4dot.blocks.cflow {
}
public static Int32Value Conv_I4(Int64Value a) {
return new Int32Value((int)a.value, (uint)a.validMask);
return new Int32Value((int)a.Value, (uint)a.ValidMask);
}
public static Int32Value Conv_I4(Real8Value a) {
return new Int32Value((int)a.value);
if (!a.IsValid)
return CreateUnknown();
return new Int32Value((int)a.Value);
}
bool CheckSign(uint mask) {
return ((uint)Value & mask) == 0 || ((uint)Value & mask) == mask;
}
public static Int32Value Conv_Ovf_I1(Int32Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
!a.CheckSign(NO_UNKNOWN_BITS << 7))
return CreateUnknown();
return Conv_I1(a);
}
public static Int32Value Conv_Ovf_I1_Un(Int32Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
(uint)a.Value > sbyte.MaxValue)
return CreateUnknown();
return Conv_I1(a);
}
public static Int32Value Conv_Ovf_I2(Int32Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
!a.CheckSign(NO_UNKNOWN_BITS << 15))
return CreateUnknown();
return Conv_I2(a);
}
public static Int32Value Conv_Ovf_I2_Un(Int32Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
(uint)a.Value > short.MaxValue)
return CreateUnknown();
return Conv_I2(a);
}
public static Int32Value Conv_Ovf_I4(Int32Value a) {
return a;
}
public static Int32Value Conv_Ovf_I4_Un(Int32Value a) {
if (!IsBitValid(a.ValidMask, 31) || a.Value < 0)
return CreateUnknown();
return a;
}
public static Int64Value Conv_Ovf_I8(Int32Value a) {
ulong validMask = a.ValidMask;
if (IsBitValid(a.ValidMask, 31))
validMask |= Int64Value.NO_UNKNOWN_BITS << 32;
return new Int64Value(a.Value, validMask);
}
public static Int64Value Conv_Ovf_I8_Un(Int32Value a) {
return new Int64Value((long)(uint)a.Value, a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32));
}
public static Int32Value Conv_Ovf_U1(Int32Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
a.Value < 0 || a.Value > byte.MaxValue)
return CreateUnknownUInt8();
return Conv_U1(a);
}
public static Int32Value Conv_Ovf_U1_Un(Int32Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 8) ||
(uint)a.Value > byte.MaxValue)
return CreateUnknownUInt8();
return Conv_U1(a);
}
public static Int32Value Conv_Ovf_U2(Int32Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
a.Value < 0 || a.Value > ushort.MaxValue)
return CreateUnknownUInt16();
return Conv_U2(a);
}
public static Int32Value Conv_Ovf_U2_Un(Int32Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 16) ||
(uint)a.Value > ushort.MaxValue)
return CreateUnknownUInt16();
return Conv_U2(a);
}
public static Int32Value Conv_Ovf_U4(Int32Value a) {
if (!IsBitValid(a.ValidMask, 31) || a.Value < 0)
return CreateUnknown();
return a;
}
public static Int32Value Conv_Ovf_U4_Un(Int32Value a) {
return a;
}
public static Int64Value Conv_Ovf_U8(Int32Value a) {
if (!IsBitValid(a.ValidMask, 31) || a.Value < 0)
return Int64Value.CreateUnknown();
return new Int64Value(a.Value, (ulong)a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32));
}
public static Int64Value Conv_Ovf_U8_Un(Int32Value a) {
return new Int64Value((long)(uint)a.Value, a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32));
}
public static Int32Value Add(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int32Value(a.value + b.value);
return new Int32Value(a.Value + b.Value);
if (ReferenceEquals(a, b))
return new Int32Value(a.value << 1, (a.validMask << 1) | 1);
return new Int32Value(a.Value << 1, (a.ValidMask << 1) | 1);
return CreateUnknown();
}
public static Int32Value Sub(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int32Value(a.value - b.value);
return new Int32Value(a.Value - b.Value);
if (ReferenceEquals(a, b))
return zero;
return Zero;
return CreateUnknown();
}
public static Int32Value Mul(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int32Value(a.value * b.value);
return new Int32Value(a.Value * b.Value);
if (a.IsZero() || b.IsZero())
return zero;
return Zero;
if (a.HasValue(1))
return b;
if (b.HasValue(1))
@ -245,14 +362,14 @@ namespace de4dot.blocks.cflow {
public static Int32Value Div(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int32Value(a.value / b.value);
return new Int32Value(a.Value / b.Value);
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if (ReferenceEquals(a, b) && a.IsNonZero())
return one;
return One;
if (b.HasValue(1))
return a;
return CreateUnknown();
@ -261,14 +378,14 @@ namespace de4dot.blocks.cflow {
public static Int32Value Div_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int32Value((int)((uint)a.value / (uint)b.value));
return new Int32Value((int)((uint)a.Value / (uint)b.Value));
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if (ReferenceEquals(a, b) && a.IsNonZero())
return one;
return One;
if (b.HasValue(1))
return a;
return CreateUnknown();
@ -277,150 +394,219 @@ namespace de4dot.blocks.cflow {
public static Int32Value Rem(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int32Value(a.value % b.value);
return new Int32Value(a.Value % b.Value);
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
return zero;
return Zero;
return CreateUnknown();
}
public static Int32Value Rem_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int32Value((int)((uint)a.value % (uint)b.value));
return new Int32Value((int)((uint)a.Value % (uint)b.Value));
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
return zero;
return Zero;
return CreateUnknown();
}
public static Int32Value Neg(Int32Value a) {
if (a.AllBitsValid())
return new Int32Value(-a.value);
return new Int32Value(-a.Value);
return CreateUnknown();
}
public static Int32Value Add_Ovf(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int32Value(checked(a.Value + b.Value));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int32Value Add_Ovf_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
uint aa = (uint)a.Value, bb = (uint)b.Value;
try {
return new Int32Value((int)checked(aa + bb));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int32Value Sub_Ovf(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int32Value(checked(a.Value - b.Value));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int32Value Sub_Ovf_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
uint aa = (uint)a.Value, bb = (uint)b.Value;
try {
return new Int32Value((int)checked(aa - bb));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int32Value Mul_Ovf(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int32Value(checked(a.Value * b.Value));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int32Value Mul_Ovf_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
uint aa = (uint)a.Value, bb = (uint)b.Value;
try {
return new Int32Value((int)checked(aa * bb));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int32Value And(Int32Value a, Int32Value b) {
int av = a.value, bv = b.value;
uint am = a.validMask, bm = b.validMask;
return new Int32Value(av & bv, (uint)((am & bm) | ((av & am) ^ am) | ((bv & bm) ^ bm)));
int av = a.Value, bv = b.Value;
uint am = a.ValidMask, bm = b.ValidMask;
return new Int32Value(av & bv, (am & bm) | (((uint)av & am) ^ am) | (((uint)bv & bm) ^ bm));
}
public static Int32Value Or(Int32Value a, Int32Value b) {
int av = a.value, bv = b.value;
uint am = a.validMask, bm = b.validMask;
return new Int32Value(av | bv, (uint)((am & bm) | (av & am) | (bv & bm)));
int av = a.Value, bv = b.Value;
uint am = a.ValidMask, bm = b.ValidMask;
return new Int32Value(av | bv, (am & bm) | ((uint)av & am) | ((uint)bv & bm));
}
public static Int32Value Xor(Int32Value a, Int32Value b) {
if (ReferenceEquals(a, b))
return zero;
int av = a.value, bv = b.value;
uint am = a.validMask, bm = b.validMask;
return new Int32Value(av ^ bv, (uint)(am & bm));
return Zero;
int av = a.Value, bv = b.Value;
uint am = a.ValidMask, bm = b.ValidMask;
return new Int32Value(av ^ bv, am & bm);
}
public static Int32Value Not(Int32Value a) {
return new Int32Value(~a.value, a.validMask);
return new Int32Value(~a.Value, a.ValidMask);
}
public static Int32Value Shl(Int32Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
if (b.value == 0)
if (b.Value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(int) * 8)
if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
int shift = b.value;
uint validMask = (a.validMask << shift) | (uint.MaxValue >> (sizeof(int) * 8 - shift));
return new Int32Value(a.value << shift, validMask);
int shift = b.Value;
uint validMask = (a.ValidMask << shift) | (uint.MaxValue >> (sizeof(int) * 8 - shift));
return new Int32Value(a.Value << shift, validMask);
}
public static Int32Value Shr(Int32Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
if (b.value == 0)
if (b.Value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(int) * 8)
if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
int shift = b.value;
uint validMask = a.validMask >> shift;
int shift = b.Value;
uint validMask = a.ValidMask >> shift;
if (a.IsBitValid(sizeof(int) * 8 - 1))
validMask |= (uint.MaxValue << (sizeof(int) * 8 - shift));
return new Int32Value(a.value >> shift, validMask);
return new Int32Value(a.Value >> shift, validMask);
}
public static Int32Value Shr_Un(Int32Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
if (b.value == 0)
if (b.Value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(int) * 8)
if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
int shift = b.value;
uint validMask = (a.validMask >> shift) | (uint.MaxValue << (sizeof(int) * 8 - shift));
return new Int32Value((int)((uint)a.value >> shift), validMask);
int shift = b.Value;
uint validMask = (a.ValidMask >> shift) | (uint.MaxValue << (sizeof(int) * 8 - shift));
return new Int32Value((int)((uint)a.Value >> shift), validMask);
}
static Int32Value create(Bool3 b) {
static Int32Value Create(Bool3 b) {
switch (b) {
case Bool3.False: return zero;
case Bool3.True: return one;
case Bool3.False: return Zero;
case Bool3.True: return One;
default: return CreateUnknownBool();
}
}
public static Int32Value Ceq(Int32Value a, Int32Value b) {
return create(CompareEq(a, b));
return Create(CompareEq(a, b));
}
public static Int32Value Cgt(Int32Value a, Int32Value b) {
return create(CompareGt(a, b));
return Create(CompareGt(a, b));
}
public static Int32Value Cgt_Un(Int32Value a, Int32Value b) {
return create(CompareGt_Un(a, b));
return Create(CompareGt_Un(a, b));
}
public static Int32Value Clt(Int32Value a, Int32Value b) {
return create(CompareLt(a, b));
return Create(CompareLt(a, b));
}
public static Int32Value Clt_Un(Int32Value a, Int32Value b) {
return create(CompareLt_Un(a, b));
return Create(CompareLt_Un(a, b));
}
public static Bool3 CompareEq(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value == b.value ? Bool3.True : Bool3.False;
return a.Value == b.Value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.True;
if ((a.value & a.validMask & b.validMask) != (b.value & a.validMask & b.validMask))
if (((uint)a.Value & a.ValidMask & b.ValidMask) != ((uint)b.Value & a.ValidMask & b.ValidMask))
return Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareNeq(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value != b.value ? Bool3.True : Bool3.False;
return a.Value != b.Value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.False;
if ((a.value & a.validMask & b.validMask) != (b.value & a.validMask & b.validMask))
if (((uint)a.Value & a.ValidMask & b.ValidMask) != ((uint)b.Value & a.ValidMask & b.ValidMask))
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 CompareGt(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value > b.value ? Bool3.True : Bool3.False;
return a.Value > b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(int.MinValue))
return Bool3.False; // min > x => false
if (b.HasValue(int.MaxValue))
@ -430,7 +616,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGt_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return (uint)a.value > (uint)b.value ? Bool3.True : Bool3.False;
return (uint)a.Value > (uint)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(uint.MinValue))
return Bool3.False; // min > x => false
if (b.HasValue(uint.MaxValue))
@ -440,7 +626,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGe(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value >= b.value ? Bool3.True : Bool3.False;
return a.Value >= b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(int.MaxValue))
return Bool3.True; // max >= x => true
if (b.HasValue(int.MinValue))
@ -450,7 +636,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGe_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return (uint)a.value >= (uint)b.value ? Bool3.True : Bool3.False;
return (uint)a.Value >= (uint)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(uint.MaxValue))
return Bool3.True; // max >= x => true
if (b.HasValue(uint.MinValue))
@ -460,7 +646,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLe(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value <= b.value ? Bool3.True : Bool3.False;
return a.Value <= b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(int.MinValue))
return Bool3.True; // min <= x => true
if (b.HasValue(int.MaxValue))
@ -470,7 +656,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLe_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return (uint)a.value <= (uint)b.value ? Bool3.True : Bool3.False;
return (uint)a.Value <= (uint)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(uint.MinValue))
return Bool3.True; // min <= x => true
if (b.HasValue(uint.MaxValue))
@ -480,7 +666,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLt(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value < b.value ? Bool3.True : Bool3.False;
return a.Value < b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(int.MaxValue))
return Bool3.False; // max < x => false
if (b.HasValue(int.MinValue))
@ -490,7 +676,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLt_Un(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return (uint)a.value < (uint)b.value ? Bool3.True : Bool3.False;
return (uint)a.Value < (uint)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(uint.MaxValue))
return Bool3.False; // max < x => false
if (b.HasValue(uint.MinValue))
@ -500,24 +686,24 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareTrue(Int32Value a) {
if (a.AllBitsValid())
return a.value != 0 ? Bool3.True : Bool3.False;
if ((a.value & a.validMask) != 0)
return a.Value != 0 ? Bool3.True : Bool3.False;
if (((uint)a.Value & a.ValidMask) != 0)
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 CompareFalse(Int32Value a) {
if (a.AllBitsValid())
return a.value == 0 ? Bool3.True : Bool3.False;
if ((a.value & a.validMask) != 0)
return a.Value == 0 ? Bool3.True : Bool3.False;
if (((uint)a.Value & a.ValidMask) != 0)
return Bool3.False;
return Bool3.Unknown;
}
public override string ToString() {
if (AllBitsValid())
return value.ToString();
return string.Format("0x{0:X8}({1:X8})", value, validMask);
return Value.ToString();
return string.Format("0x{0:X8}({1:X8})", Value, ValidMask);
}
}
}

View File

@ -21,27 +21,27 @@ using System;
namespace de4dot.blocks.cflow {
public class Int64Value : Value {
public static readonly Int64Value zero = new Int64Value(0);
public static readonly Int64Value one = new Int64Value(1);
public static readonly Int64Value Zero = new Int64Value(0);
public static readonly Int64Value One = new Int64Value(1);
const ulong NO_UNKNOWN_BITS = ulong.MaxValue;
public readonly long value;
public readonly ulong validMask;
internal const ulong NO_UNKNOWN_BITS = ulong.MaxValue;
public readonly long Value;
public readonly ulong ValidMask;
public Int64Value(long value)
: base(ValueType.Int64) {
this.value = value;
this.validMask = NO_UNKNOWN_BITS;
this.Value = value;
this.ValidMask = NO_UNKNOWN_BITS;
}
public Int64Value(long value, ulong validMask)
: base(ValueType.Int64) {
this.value = value;
this.validMask = validMask;
this.Value = value;
this.ValidMask = validMask;
}
bool HasUnknownBits() {
return validMask != NO_UNKNOWN_BITS;
return ValidMask != NO_UNKNOWN_BITS;
}
public bool AllBitsValid() {
@ -49,13 +49,17 @@ namespace de4dot.blocks.cflow {
}
bool IsBitValid(int n) {
return IsBitValid(validMask, n);
return IsBitValid(ValidMask, n);
}
static bool IsBitValid(ulong validMask, int n) {
return (validMask & (1UL << n)) != 0;
}
bool AreBitsValid(ulong bitsToTest) {
return (ValidMask & bitsToTest) == bitsToTest;
}
public static Int64Value CreateUnknown() {
return new Int64Value(0, 0UL);
}
@ -65,11 +69,11 @@ namespace de4dot.blocks.cflow {
}
public bool IsNonZero() {
return ((ulong)value & validMask) != 0;
return ((ulong)Value & ValidMask) != 0;
}
public bool HasValue(long value) {
return AllBitsValid() && this.value == value;
return AllBitsValid() && this.Value == value;
}
public bool HasValue(ulong value) {
@ -77,8 +81,8 @@ namespace de4dot.blocks.cflow {
}
public static Int64Value Conv_U8(Int32Value a) {
long value = (long)(ulong)(uint)a.value;
ulong validMask = a.validMask | (NO_UNKNOWN_BITS << 32);
long value = (long)(ulong)(uint)a.Value;
ulong validMask = a.ValidMask | (NO_UNKNOWN_BITS << 32);
return new Int64Value(value, validMask);
}
@ -87,12 +91,14 @@ namespace de4dot.blocks.cflow {
}
public static Int64Value Conv_U8(Real8Value a) {
return new Int64Value((long)(ulong)a.value);
if (!a.IsValid)
return CreateUnknown();
return new Int64Value((long)(ulong)a.Value);
}
public static Int64Value Conv_I8(Int32Value a) {
long value = a.value;
ulong validMask = a.validMask;
long value = a.Value;
ulong validMask = a.ValidMask;
if (IsBitValid(validMask, 31))
validMask |= NO_UNKNOWN_BITS << 32;
else
@ -105,30 +111,140 @@ namespace de4dot.blocks.cflow {
}
public static Int64Value Conv_I8(Real8Value a) {
return new Int64Value((long)a.value);
if (!a.IsValid)
return CreateUnknown();
return new Int64Value((long)a.Value);
}
bool CheckSign(ulong mask) {
return ((ulong)Value & mask) == 0 || ((ulong)Value & mask) == mask;
}
public static Int32Value Conv_Ovf_I1(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
!a.CheckSign(NO_UNKNOWN_BITS << 7))
return Int32Value.CreateUnknown();
return Int32Value.Conv_I1(a);
}
public static Int32Value Conv_Ovf_I1_Un(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
(ulong)a.Value > (ulong)sbyte.MaxValue)
return Int32Value.CreateUnknown();
return Int32Value.Conv_I1(a);
}
public static Int32Value Conv_Ovf_I2(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
!a.CheckSign(NO_UNKNOWN_BITS << 15))
return Int32Value.CreateUnknown();
return Int32Value.Conv_I2(a);
}
public static Int32Value Conv_Ovf_I2_Un(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
(ulong)a.Value > (ulong)short.MaxValue)
return Int32Value.CreateUnknown();
return Int32Value.Conv_I2(a);
}
public static Int32Value Conv_Ovf_I4(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) ||
!a.CheckSign(NO_UNKNOWN_BITS << 31))
return Int32Value.CreateUnknown();
return Int32Value.Conv_I4(a);
}
public static Int32Value Conv_Ovf_I4_Un(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) ||
(ulong)a.Value > (ulong)int.MaxValue)
return Int32Value.CreateUnknown();
return Int32Value.Conv_I4(a);
}
public static Int64Value Conv_Ovf_I8(Int64Value a) {
return a;
}
public static Int64Value Conv_Ovf_I8_Un(Int64Value a) {
if (!IsBitValid(a.ValidMask, 63) || a.Value < 0)
return CreateUnknown();
return a;
}
public static Int32Value Conv_Ovf_U1(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 7) ||
a.Value < 0 || a.Value > byte.MaxValue)
return Int32Value.CreateUnknownUInt8();
return Int32Value.Conv_U1(a);
}
public static Int32Value Conv_Ovf_U1_Un(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 8) ||
(ulong)a.Value > byte.MaxValue)
return Int32Value.CreateUnknownUInt8();
return Int32Value.Conv_U1(a);
}
public static Int32Value Conv_Ovf_U2(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 15) ||
a.Value < 0 || a.Value > ushort.MaxValue)
return Int32Value.CreateUnknownUInt16();
return Int32Value.Conv_U2(a);
}
public static Int32Value Conv_Ovf_U2_Un(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 16) ||
(ulong)a.Value > ushort.MaxValue)
return Int32Value.CreateUnknownUInt16();
return Int32Value.Conv_U2(a);
}
public static Int32Value Conv_Ovf_U4(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 31) ||
a.Value < 0 || a.Value > uint.MaxValue)
return Int32Value.CreateUnknown();
return Int32Value.Conv_U4(a);
}
public static Int32Value Conv_Ovf_U4_Un(Int64Value a) {
if (!a.AreBitsValid(NO_UNKNOWN_BITS << 32) ||
(ulong)a.Value > uint.MaxValue)
return Int32Value.CreateUnknown();
return Int32Value.Conv_U4(a);
}
public static Int64Value Conv_Ovf_U8(Int64Value a) {
if (!IsBitValid(a.ValidMask, 63) || a.Value < 0)
return CreateUnknown();
return a;
}
public static Int64Value Conv_Ovf_U8_Un(Int64Value a) {
return a;
}
public static Int64Value Add(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int64Value(a.value + b.value);
return new Int64Value(a.Value + b.Value);
if (ReferenceEquals(a, b))
return new Int64Value(a.value << 1, (a.validMask << 1) | 1);
return new Int64Value(a.Value << 1, (a.ValidMask << 1) | 1);
return CreateUnknown();
}
public static Int64Value Sub(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int64Value(a.value - b.value);
return new Int64Value(a.Value - b.Value);
if (ReferenceEquals(a, b))
return zero;
return Zero;
return CreateUnknown();
}
public static Int64Value Mul(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int64Value(a.value * b.value);
return new Int64Value(a.Value * b.Value);
if (a.IsZero() || b.IsZero())
return zero;
return Zero;
if (a.HasValue(1))
return b;
if (b.HasValue(1))
@ -139,14 +255,14 @@ namespace de4dot.blocks.cflow {
public static Int64Value Div(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int64Value(a.value / b.value);
return new Int64Value(a.Value / b.Value);
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if (ReferenceEquals(a, b) && a.IsNonZero())
return one;
return One;
if (b.HasValue(1))
return a;
return CreateUnknown();
@ -155,14 +271,14 @@ namespace de4dot.blocks.cflow {
public static Int64Value Div_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int64Value((long)((ulong)a.value / (ulong)b.value));
return new Int64Value((long)((ulong)a.Value / (ulong)b.Value));
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if (ReferenceEquals(a, b) && a.IsNonZero())
return one;
return One;
if (b.HasValue(1))
return a;
return CreateUnknown();
@ -171,103 +287,172 @@ namespace de4dot.blocks.cflow {
public static Int64Value Rem(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int64Value(a.value % b.value);
return new Int64Value(a.Value % b.Value);
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
return zero;
return Zero;
return CreateUnknown();
}
public static Int64Value Rem_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int64Value((long)((ulong)a.value % (ulong)b.value));
return new Int64Value((long)((ulong)a.Value % (ulong)b.Value));
}
catch (ArithmeticException) {
return CreateUnknown();
}
}
if ((ReferenceEquals(a, b) && a.IsNonZero()) || b.HasValue(1))
return zero;
return Zero;
return CreateUnknown();
}
public static Int64Value Neg(Int64Value a) {
if (a.AllBitsValid())
return new Int64Value(-a.value);
return new Int64Value(-a.Value);
return CreateUnknown();
}
public static Int64Value Add_Ovf(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int64Value(checked(a.Value + b.Value));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int64Value Add_Ovf_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
ulong aa = (ulong)a.Value, bb = (ulong)b.Value;
try {
return new Int64Value((long)checked(aa + bb));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int64Value Sub_Ovf(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int64Value(checked(a.Value - b.Value));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int64Value Sub_Ovf_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
ulong aa = (ulong)a.Value, bb = (ulong)b.Value;
try {
return new Int64Value((long)checked(aa - bb));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int64Value Mul_Ovf(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
try {
return new Int64Value(checked(a.Value * b.Value));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int64Value Mul_Ovf_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid()) {
ulong aa = (ulong)a.Value, bb = (ulong)b.Value;
try {
return new Int64Value((long)checked(aa * bb));
}
catch (OverflowException) {
}
}
return CreateUnknown();
}
public static Int64Value And(Int64Value a, Int64Value b) {
long av = a.value, bv = b.value;
ulong am = a.validMask, bm = b.validMask;
long av = a.Value, bv = b.Value;
ulong am = a.ValidMask, bm = b.ValidMask;
return new Int64Value(av & bv, (am & bm) | (((ulong)av & am) ^ am) | (((ulong)bv & bm) ^ bm));
}
public static Int64Value Or(Int64Value a, Int64Value b) {
long av = a.value, bv = b.value;
ulong am = a.validMask, bm = b.validMask;
long av = a.Value, bv = b.Value;
ulong am = a.ValidMask, bm = b.ValidMask;
return new Int64Value(av | bv, (am & bm) | ((ulong)av & am) | ((ulong)bv & bm));
}
public static Int64Value Xor(Int64Value a, Int64Value b) {
if (ReferenceEquals(a, b))
return zero;
long av = a.value, bv = b.value;
ulong am = a.validMask, bm = b.validMask;
return Zero;
long av = a.Value, bv = b.Value;
ulong am = a.ValidMask, bm = b.ValidMask;
return new Int64Value(av ^ bv, am & bm);
}
public static Int64Value Not(Int64Value a) {
return new Int64Value(~a.value, a.validMask);
return new Int64Value(~a.Value, a.ValidMask);
}
public static Int64Value Shl(Int64Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
if (b.value == 0)
if (b.Value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(long) * 8)
if (b.Value < 0 || b.Value >= sizeof(long) * 8)
return CreateUnknown();
int shift = b.value;
ulong validMask = (a.validMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift));
return new Int64Value(a.value << shift, validMask);
int shift = b.Value;
ulong validMask = (a.ValidMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift));
return new Int64Value(a.Value << shift, validMask);
}
public static Int64Value Shr(Int64Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
if (b.value == 0)
if (b.Value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(long) * 8)
if (b.Value < 0 || b.Value >= sizeof(long) * 8)
return CreateUnknown();
int shift = b.value;
ulong validMask = a.validMask >> shift;
int shift = b.Value;
ulong validMask = a.ValidMask >> shift;
if (a.IsBitValid(sizeof(long) * 8 - 1))
validMask |= (ulong.MaxValue << (sizeof(long) * 8 - shift));
return new Int64Value(a.value >> shift, validMask);
return new Int64Value(a.Value >> shift, validMask);
}
public static Int64Value Shr_Un(Int64Value a, Int32Value b) {
if (b.HasUnknownBits())
return CreateUnknown();
if (b.value == 0)
if (b.Value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(long) * 8)
if (b.Value < 0 || b.Value >= sizeof(long) * 8)
return CreateUnknown();
int shift = b.value;
ulong validMask = (a.validMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift));
return new Int64Value((long)((ulong)a.value >> shift), validMask);
int shift = b.Value;
ulong validMask = (a.ValidMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift));
return new Int64Value((long)((ulong)a.Value >> shift), validMask);
}
static Int32Value Create(Bool3 b) {
switch (b) {
case Bool3.False: return Int32Value.zero;
case Bool3.True: return Int32Value.one;
case Bool3.False: return Int32Value.Zero;
case Bool3.True: return Int32Value.One;
default: return Int32Value.CreateUnknownBool();
}
}
@ -294,27 +479,27 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareEq(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value == b.value ? Bool3.True : Bool3.False;
return a.Value == b.Value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.True;
if (((ulong)a.value & a.validMask & b.validMask) != ((ulong)b.value & a.validMask & b.validMask))
if (((ulong)a.Value & a.ValidMask & b.ValidMask) != ((ulong)b.Value & a.ValidMask & b.ValidMask))
return Bool3.False;
return Bool3.Unknown;
}
public static Bool3 CompareNeq(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value != b.value ? Bool3.True : Bool3.False;
return a.Value != b.Value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.False;
if (((ulong)a.value & a.validMask & b.validMask) != ((ulong)b.value & a.validMask & b.validMask))
if (((ulong)a.Value & a.ValidMask & b.ValidMask) != ((ulong)b.Value & a.ValidMask & b.ValidMask))
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 CompareGt(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value > b.value ? Bool3.True : Bool3.False;
return a.Value > b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(long.MinValue))
return Bool3.False; // min > x => false
if (b.HasValue(long.MaxValue))
@ -324,7 +509,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGt_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return (ulong)a.value > (ulong)b.value ? Bool3.True : Bool3.False;
return (ulong)a.Value > (ulong)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(ulong.MinValue))
return Bool3.False; // min > x => false
if (b.HasValue(ulong.MaxValue))
@ -334,7 +519,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGe(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value >= b.value ? Bool3.True : Bool3.False;
return a.Value >= b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(long.MaxValue))
return Bool3.True; // max >= x => true
if (b.HasValue(long.MinValue))
@ -344,7 +529,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareGe_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return (ulong)a.value >= (ulong)b.value ? Bool3.True : Bool3.False;
return (ulong)a.Value >= (ulong)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(ulong.MaxValue))
return Bool3.True; // max >= x => true
if (b.HasValue(ulong.MinValue))
@ -354,7 +539,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLe(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value <= b.value ? Bool3.True : Bool3.False;
return a.Value <= b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(long.MinValue))
return Bool3.True; // min <= x => true
if (b.HasValue(long.MaxValue))
@ -364,7 +549,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLe_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return (ulong)a.value <= (ulong)b.value ? Bool3.True : Bool3.False;
return (ulong)a.Value <= (ulong)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(ulong.MinValue))
return Bool3.True; // min <= x => true
if (b.HasValue(ulong.MaxValue))
@ -374,7 +559,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLt(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return a.value < b.value ? Bool3.True : Bool3.False;
return a.Value < b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(long.MaxValue))
return Bool3.False; // max < x => false
if (b.HasValue(long.MinValue))
@ -384,7 +569,7 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareLt_Un(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return (ulong)a.value < (ulong)b.value ? Bool3.True : Bool3.False;
return (ulong)a.Value < (ulong)b.Value ? Bool3.True : Bool3.False;
if (a.HasValue(ulong.MaxValue))
return Bool3.False; // max < x => false
if (b.HasValue(ulong.MinValue))
@ -394,24 +579,24 @@ namespace de4dot.blocks.cflow {
public static Bool3 CompareTrue(Int64Value a) {
if (a.AllBitsValid())
return a.value != 0 ? Bool3.True : Bool3.False;
if (((ulong)a.value & a.validMask) != 0)
return a.Value != 0 ? Bool3.True : Bool3.False;
if (((ulong)a.Value & a.ValidMask) != 0)
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 CompareFalse(Int64Value a) {
if (a.AllBitsValid())
return a.value == 0 ? Bool3.True : Bool3.False;
if (((ulong)a.value & a.validMask) != 0)
return a.Value == 0 ? Bool3.True : Bool3.False;
if (((ulong)a.Value & a.ValidMask) != 0)
return Bool3.False;
return Bool3.Unknown;
}
public override string ToString() {
if (AllBitsValid())
return value.ToString();
return string.Format("0x{0:X8}L({1:X8})", value, validMask);
return Value.ToString();
return string.Format("0x{0:X8}L({1:X8})", Value, ValidMask);
}
}
}

View File

@ -55,6 +55,10 @@ namespace de4dot.blocks.cflow {
return inlineInstanceMethods;
}
protected virtual Instruction GetFirstInstruction(IList<Instruction> instrs, ref int index) {
return DotNetUtils.GetInstruction(instrs, ref index);
}
bool InlineMethod(Instruction callInstr, int instrIndex) {
var methodToInline = callInstr.Operand as MethodDef;
if (methodToInline == null)
@ -67,10 +71,11 @@ namespace de4dot.blocks.cflow {
return false;
int index = 0;
var instr = DotNetUtils.GetInstruction(body.Instructions, ref index);
var instr = GetFirstInstruction(body.Instructions, ref index);
if (instr == null)
return false;
bool inlinedMethod;
switch (instr.OpCode.Code) {
case Code.Ldarg:
case Code.Ldarg_S:
@ -83,7 +88,8 @@ namespace de4dot.blocks.cflow {
case Code.Call:
case Code.Callvirt:
case Code.Newobj:
return InlineOtherMethod(instrIndex, methodToInline, instr, index);
inlinedMethod = InlineOtherMethod(instrIndex, methodToInline, instr, index);
break;
case Code.Ldc_I4:
case Code.Ldc_I4_0:
@ -106,11 +112,18 @@ namespace de4dot.blocks.cflow {
case Code.Ldtoken:
case Code.Ldsfld:
case Code.Ldsflda:
return InlineLoadMethod(instrIndex, methodToInline, instr, index);
inlinedMethod = InlineLoadMethod(instrIndex, methodToInline, instr, index);
break;
default:
return false;
inlinedMethod = false;
break;
}
OnInlinedMethod(methodToInline, inlinedMethod);
return inlinedMethod;
}
protected virtual void OnInlinedMethod(MethodDef methodToInline, bool inlinedMethod) {
}
protected override bool IsCompatibleType(int paramIndex, IType origType, IType newType) {

View File

@ -142,7 +142,9 @@ namespace de4dot.blocks.cflow {
if (instr == null || loadIndex != methodArgsCount - popLastArgs)
return null;
if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt) {
switch (instr.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
if (foundLdarga)
return null;
var callInstr = instr;
@ -160,8 +162,8 @@ namespace de4dot.blocks.cflow {
return null;
return new InstructionPatcher(patchIndex, instrIndex, callInstr);
}
else if (instr.OpCode.Code == Code.Newobj) {
case Code.Newobj:
if (foundLdarga)
return null;
var newobjInstr = instr;
@ -185,20 +187,30 @@ namespace de4dot.blocks.cflow {
return null;
return new InstructionPatcher(patchIndex, instrIndex, newobjInstr);
}
else if (instr.OpCode.Code == Code.Ldfld || instr.OpCode.Code == Code.Ldflda ||
instr.OpCode.Code == Code.Ldftn || instr.OpCode.Code == Code.Ldvirtftn) {
case Code.Ldfld:
case Code.Ldflda:
case Code.Ldftn:
case Code.Ldvirtftn:
case Code.Ldlen:
case Code.Initobj:
case Code.Isinst:
case Code.Castclass:
case Code.Newarr:
case Code.Ldtoken:
case Code.Unbox_Any:
var ldInstr = instr;
if (methodArgsCount != 1)
return null;
if (!HasAccessTo(instr.Operand))
if (instr.OpCode.OperandType != OperandType.InlineNone && !HasAccessTo(instr.Operand))
return null;
return new InstructionPatcher(patchIndex, instrIndex, ldInstr);
}
return null;
default:
return null;
}
}
bool HasAccessTo(object operand) {

View File

@ -0,0 +1,177 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
namespace de4dot.blocks.cflow {
public class Real8Value : Value {
public readonly double Value;
public readonly bool IsValid;
public Real8Value(double value)
: base(ValueType.Real8) {
this.Value = value;
this.IsValid = true;
}
public Real8Value(double value, bool isValid)
: base(ValueType.Real8) {
this.Value = value;
this.IsValid = isValid;
}
public static Real8Value CreateUnknown() {
return new Real8Value(0, false);
}
public Real8Value ToSingle() {
if (!IsValid)
return CreateUnknown();
return new Real8Value((float)Value);
}
public static Real8Value Add(Real8Value a, Real8Value b) {
if (!a.IsValid || !b.IsValid)
return CreateUnknown();
return new Real8Value(a.Value + b.Value);
}
public static Real8Value Sub(Real8Value a, Real8Value b) {
if (!a.IsValid || !b.IsValid)
return CreateUnknown();
return new Real8Value(a.Value - b.Value);
}
public static Real8Value Mul(Real8Value a, Real8Value b) {
if (!a.IsValid || !b.IsValid)
return CreateUnknown();
return new Real8Value(a.Value * b.Value);
}
public static Real8Value Div(Real8Value a, Real8Value b) {
if (!a.IsValid || !b.IsValid)
return CreateUnknown();
return new Real8Value(a.Value / b.Value);
}
public static Real8Value Rem(Real8Value a, Real8Value b) {
if (!a.IsValid || !b.IsValid)
return CreateUnknown();
return new Real8Value(a.Value % b.Value);
}
public static Real8Value Neg(Real8Value a) {
if (!a.IsValid)
return CreateUnknown();
return new Real8Value(-a.Value);
}
public static Real8Value Add_Ovf(Real8Value a, Real8Value b) {
return CreateUnknown();
}
public static Real8Value Add_Ovf_Un(Real8Value a, Real8Value b) {
return CreateUnknown();
}
public static Real8Value Sub_Ovf(Real8Value a, Real8Value b) {
return CreateUnknown();
}
public static Real8Value Sub_Ovf_Un(Real8Value a, Real8Value b) {
return CreateUnknown();
}
public static Real8Value Mul_Ovf(Real8Value a, Real8Value b) {
return CreateUnknown();
}
public static Real8Value Mul_Ovf_Un(Real8Value a, Real8Value b) {
return CreateUnknown();
}
public static Int32Value Conv_Ovf_I1(Real8Value a) {
return Int32Value.CreateUnknown();
}
public static Int32Value Conv_Ovf_I1_Un(Real8Value a) {
return Int32Value.CreateUnknown();
}
public static Int32Value Conv_Ovf_I2(Real8Value a) {
return Int32Value.CreateUnknown();
}
public static Int32Value Conv_Ovf_I2_Un(Real8Value a) {
return Int32Value.CreateUnknown();
}
public static Int32Value Conv_Ovf_I4(Real8Value a) {
return Int32Value.CreateUnknown();
}
public static Int32Value Conv_Ovf_I4_Un(Real8Value a) {
return Int32Value.CreateUnknown();
}
public static Int64Value Conv_Ovf_I8(Real8Value a) {
return Int64Value.CreateUnknown();
}
public static Int64Value Conv_Ovf_I8_Un(Real8Value a) {
return Int64Value.CreateUnknown();
}
public static Int32Value Conv_Ovf_U1(Real8Value a) {
return Int32Value.CreateUnknownUInt8();
}
public static Int32Value Conv_Ovf_U1_Un(Real8Value a) {
return Int32Value.CreateUnknownUInt8();
}
public static Int32Value Conv_Ovf_U2(Real8Value a) {
return Int32Value.CreateUnknownUInt16();
}
public static Int32Value Conv_Ovf_U2_Un(Real8Value a) {
return Int32Value.CreateUnknownUInt16();
}
public static Int32Value Conv_Ovf_U4(Real8Value a) {
return Int32Value.CreateUnknown();
}
public static Int32Value Conv_Ovf_U4_Un(Real8Value a) {
return Int32Value.CreateUnknown();
}
public static Int64Value Conv_Ovf_U8(Real8Value a) {
return Int64Value.CreateUnknown();
}
public static Int64Value Conv_Ovf_U8_Un(Real8Value a) {
return Int64Value.CreateUnknown();
}
public override string ToString() {
if (!IsValid)
return "<INVALID_REAL8>";
return Value.ToString();
}
}
}

View File

@ -158,7 +158,7 @@ namespace de4dot.blocks.cflow {
foreach (var source in new List<Block>(block.Sources)) {
if (!isBranchBlock(source))
continue;
instructionEmulator.Initialize(blocks);
instructionEmulator.Initialize(blocks, allBlocks[0] == source);
instructionEmulator.Emulate(source.Instructions);
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.Pop());
@ -183,7 +183,7 @@ namespace de4dot.blocks.cflow {
bool modified = false;
foreach (var source in new List<Block>(block.Sources)) {
if (isBranchBlock(source)) {
instructionEmulator.Initialize(blocks);
instructionEmulator.Initialize(blocks, allBlocks[0] == source);
instructionEmulator.Emulate(source.Instructions);
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.GetLocal(switchVariable));
@ -193,7 +193,7 @@ namespace de4dot.blocks.cflow {
modified = true;
}
else if (IsBccBlock(source)) {
instructionEmulator.Initialize(blocks);
instructionEmulator.Initialize(blocks, allBlocks[0] == source);
instructionEmulator.Emulate(source.Instructions);
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.GetLocal(switchVariable));
@ -223,7 +223,7 @@ namespace de4dot.blocks.cflow {
foreach (var source in new List<Block>(block.Sources)) {
if (!isBranchBlock(source))
continue;
instructionEmulator.Initialize(blocks);
instructionEmulator.Initialize(blocks, allBlocks[0] == source);
instructionEmulator.Emulate(source.Instructions);
var target = GetSwitchTarget(switchTargets, switchFallThrough, instructionEmulator.Pop());
@ -407,7 +407,7 @@ namespace de4dot.blocks.cflow {
}
bool EmulateGetTarget(Block switchBlock, out Block target) {
instructionEmulator.Initialize(blocks);
instructionEmulator.Initialize(blocks, allBlocks[0] == switchBlock);
try {
instructionEmulator.Emulate(switchBlock.Instructions, 0, switchBlock.Instructions.Count - 1);
}
@ -421,7 +421,7 @@ namespace de4dot.blocks.cflow {
}
bool WillHaveKnownTarget(Block switchBlock, Block source) {
instructionEmulator.Initialize(blocks);
instructionEmulator.Initialize(blocks, allBlocks[0] == source);
try {
instructionEmulator.Emulate(source.Instructions);
instructionEmulator.Emulate(switchBlock.Instructions, 0, switchBlock.Instructions.Count - 1);

View File

@ -9,7 +9,7 @@
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>de4dot.blocks</RootNamespace>
<AssemblyName>blocks</AssemblyName>
<AssemblyName>de4dot.blocks</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
@ -76,6 +76,7 @@
<Compile Include="MethodBlocks.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScopeBlock.cs" />
<Compile Include="StackTracePatcher.cs" />
<Compile Include="TryBlock.cs" />
<Compile Include="TryHandlerBlock.cs" />
<Compile Include="Utils.cs" />

View File

@ -35,8 +35,16 @@ namespace de4dot.code.AssemblyClient {
get { return service; }
}
public AssemblyClient()
: this(new NewProcessAssemblyServerLoader()) {
public IStringDecrypterService StringDecrypterService {
get { return (IStringDecrypterService)service; }
}
public IMethodDecrypterService MethodDecrypterService {
get { return (IMethodDecrypterService)service; }
}
public IGenericService GenericService {
get { return (IGenericService)service; }
}
public AssemblyClient(IAssemblyServerLoader loader) {

View File

@ -18,21 +18,22 @@
*/
using dnlib.DotNet;
using AssemblyData;
namespace de4dot.code.AssemblyClient {
public interface IAssemblyClientFactory {
IAssemblyClient Create();
IAssemblyClient Create(AssemblyServiceType serviceType);
}
public class SameAppDomainAssemblyClientFactory : IAssemblyClientFactory {
public IAssemblyClient Create() {
return new AssemblyClient(new SameAppDomainAssemblyServerLoader());
public IAssemblyClient Create(AssemblyServiceType serviceType) {
return new AssemblyClient(new SameAppDomainAssemblyServerLoader(serviceType));
}
}
public class NewAppDomainAssemblyClientFactory : IAssemblyClientFactory {
public IAssemblyClient Create() {
return new AssemblyClient(new NewAppDomainAssemblyServerLoader());
public IAssemblyClient Create(AssemblyServiceType serviceType) {
return new AssemblyClient(new NewAppDomainAssemblyServerLoader(serviceType));
}
}
@ -47,12 +48,12 @@ namespace de4dot.code.AssemblyClient {
this.serverVersion = serverVersion;
}
public IAssemblyClient Create(ModuleDef module) {
return new AssemblyClient(new NewProcessAssemblyServerLoader(GetServerClrVersion(module)));
public IAssemblyClient Create(AssemblyServiceType serviceType, ModuleDef module) {
return new AssemblyClient(new NewProcessAssemblyServerLoader(serviceType, GetServerClrVersion(module)));
}
public IAssemblyClient Create() {
return new AssemblyClient(new NewProcessAssemblyServerLoader(serverVersion));
public IAssemblyClient Create(AssemblyServiceType serviceType) {
return new AssemblyClient(new NewProcessAssemblyServerLoader(serviceType, serverVersion));
}
internal static ServerClrVersion GetServerClrVersion(ModuleDef module) {

View File

@ -23,6 +23,9 @@ using AssemblyData;
namespace de4dot.code.AssemblyClient {
public interface IAssemblyClient : IDisposable {
IAssemblyService Service { get; }
IStringDecrypterService StringDecrypterService { get; }
IMethodDecrypterService MethodDecrypterService { get; }
IGenericService GenericService { get; }
void Connect();
void WaitConnected();
}

View File

@ -35,13 +35,15 @@ namespace de4dot.code.AssemblyClient {
readonly string assemblyServerFilename;
protected string ipcName;
protected string ipcUri;
protected AssemblyServiceType serviceType;
string url;
protected IpcAssemblyServerLoader()
: this(ServerClrVersion.CLR_ANY_ANYCPU) {
protected IpcAssemblyServerLoader(AssemblyServiceType serviceType)
: this(serviceType, ServerClrVersion.CLR_ANY_ANYCPU) {
}
protected IpcAssemblyServerLoader(ServerClrVersion serverVersion) {
protected IpcAssemblyServerLoader(AssemblyServiceType serviceType, ServerClrVersion serverVersion) {
this.serviceType = serviceType;
assemblyServerFilename = GetServerName(serverVersion);
ipcName = Utils.RandomName(15, 20);
ipcUri = Utils.RandomName(15, 20);
@ -69,7 +71,7 @@ namespace de4dot.code.AssemblyClient {
public abstract void LoadServer(string filename);
public IAssemblyService CreateService() {
return (IAssemblyService)Activator.GetObject(typeof(AssemblyService), url);
return (IAssemblyService)Activator.GetObject(AssemblyService.GetType(serviceType), url);
}
public abstract void Dispose();

View File

@ -19,6 +19,7 @@
using System;
using System.Threading;
using AssemblyData;
namespace de4dot.code.AssemblyClient {
// Starts the server in a new app domain.
@ -26,6 +27,10 @@ namespace de4dot.code.AssemblyClient {
AppDomain appDomain;
Thread thread;
public NewAppDomainAssemblyServerLoader(AssemblyServiceType serviceType)
: base(serviceType) {
}
public override void LoadServer(string filename) {
if (appDomain != null)
throw new ApplicationException("Server is already loaded");
@ -33,7 +38,9 @@ namespace de4dot.code.AssemblyClient {
appDomain = AppDomain.CreateDomain(Utils.RandomName(15, 20));
thread = new Thread(new ThreadStart(() => {
try {
appDomain.ExecuteAssembly(filename, null, new string[] { ipcName, ipcUri });
appDomain.ExecuteAssembly(filename, null, new string[] {
((int)serviceType).ToString(), ipcName, ipcUri
});
}
catch (NullReferenceException) {
// Here if appDomain was set to null by Dispose() before this thread started

View File

@ -19,17 +19,19 @@
using System;
using System.Diagnostics;
using AssemblyData;
namespace de4dot.code.AssemblyClient {
// Starts the server in a new process
class NewProcessAssemblyServerLoader : IpcAssemblyServerLoader {
Process process;
public NewProcessAssemblyServerLoader() {
public NewProcessAssemblyServerLoader(AssemblyServiceType serviceType)
: base(serviceType) {
}
public NewProcessAssemblyServerLoader(ServerClrVersion version)
: base(version) {
public NewProcessAssemblyServerLoader(AssemblyServiceType serviceType, ServerClrVersion version)
: base(serviceType, version) {
}
public override void LoadServer(string filename) {
@ -37,7 +39,8 @@ namespace de4dot.code.AssemblyClient {
throw new ApplicationException("Server is already loaded");
var psi = new ProcessStartInfo {
Arguments = string.Format("{0} {1}", Utils.ShellEscape(ipcName), Utils.ShellEscape(ipcUri)),
Arguments = string.Format("{0} {1} {2}", (int)serviceType,
Utils.ShellEscape(ipcName), Utils.ShellEscape(ipcUri)),
CreateNoWindow = true,
ErrorDialog = false,
FileName = filename,

View File

@ -24,11 +24,16 @@ namespace de4dot.code.AssemblyClient {
// Starts the server in the current app domain.
class SameAppDomainAssemblyServerLoader : IAssemblyServerLoader {
IAssemblyService service;
AssemblyServiceType serviceType;
public SameAppDomainAssemblyServerLoader(AssemblyServiceType serviceType) {
this.serviceType = serviceType;
}
public void LoadServer() {
if (service != null)
throw new ApplicationException("Server already loaded");
service = new AssemblyService();
service = AssemblyService.Create(serviceType);
}
public IAssemblyService CreateService() {

View File

@ -0,0 +1,24 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
namespace System.Runtime.ExceptionServices {
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
class HandleProcessCorruptedStateExceptionsAttribute : Attribute {
}
}

View File

@ -26,6 +26,7 @@ using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.Writer;
using dnlib.PE;
using AssemblyData;
using de4dot.code.deobfuscators;
using de4dot.blocks;
using de4dot.blocks.cflow;
@ -375,9 +376,9 @@ namespace de4dot.code {
CheckSupportedStringDecrypter(StringFeatures.AllowDynamicDecryption);
var newProcFactory = assemblyClientFactory as NewProcessAssemblyClientFactory;
if (newProcFactory != null)
assemblyClient = newProcFactory.Create(module);
assemblyClient = newProcFactory.Create(AssemblyServiceType.StringDecrypter, module);
else
assemblyClient = assemblyClientFactory.Create();
assemblyClient = assemblyClientFactory.Create(AssemblyServiceType.StringDecrypter);
assemblyClient.Connect();
break;
@ -432,12 +433,12 @@ namespace de4dot.code {
return;
assemblyClient.WaitConnected();
assemblyClient.Service.LoadAssembly(options.Filename);
assemblyClient.StringDecrypterService.LoadAssembly(options.Filename);
if (options.StringDecrypterType == DecrypterType.Delegate)
assemblyClient.Service.SetStringDecrypterType(AssemblyData.StringDecrypterType.Delegate);
assemblyClient.StringDecrypterService.SetStringDecrypterType(AssemblyData.StringDecrypterType.Delegate);
else if (options.StringDecrypterType == DecrypterType.Emulate)
assemblyClient.Service.SetStringDecrypterType(AssemblyData.StringDecrypterType.Emulate);
assemblyClient.StringDecrypterService.SetStringDecrypterType(AssemblyData.StringDecrypterType.Emulate);
else
throw new ApplicationException(string.Format("Invalid string decrypter type '{0}'", options.StringDecrypterType));
@ -752,11 +753,22 @@ namespace de4dot.code {
}
Dictionary<MethodDef, SimpleDeobFlags> simpleDeobfuscatorFlags = new Dictionary<MethodDef, SimpleDeobFlags>();
bool Check(MethodDef method, SimpleDeobFlags flag) {
if (method == null)
return false;
SimpleDeobFlags oldFlags;
simpleDeobfuscatorFlags.TryGetValue(method, out oldFlags);
simpleDeobfuscatorFlags[method] = oldFlags | flag;
return (oldFlags & flag) == flag;
}
bool Clear(MethodDef method, SimpleDeobFlags flag) {
if (method == null)
return false;
SimpleDeobFlags oldFlags;
if (!simpleDeobfuscatorFlags.TryGetValue(method, out oldFlags))
return false;
simpleDeobfuscatorFlags[method] = oldFlags & ~flag;
return true;
}
void Deobfuscate(MethodDef method, string msg, Action<Blocks> handler) {
if (savedMethodBodies != null)
@ -784,12 +796,16 @@ namespace de4dot.code {
Logger.Instance.DeIndent();
}
void ISimpleDeobfuscator.MethodModified(MethodDef method) {
Clear(method, SimpleDeobFlags.HasDeobfuscated);
}
void ISimpleDeobfuscator.Deobfuscate(MethodDef method) {
((ISimpleDeobfuscator)this).Deobfuscate(method, false);
}
void ISimpleDeobfuscator.Deobfuscate(MethodDef method, bool force) {
if (!force && Check(method, SimpleDeobFlags.HasDeobfuscated))
if (method == null || (!force && Check(method, SimpleDeobFlags.HasDeobfuscated)))
return;
Deobfuscate(method, "Deobfuscating control flow", (blocks) => {

View File

@ -89,7 +89,7 @@ namespace de4dot.code {
foreach (var methodToken in methodTokens) {
if (methodTokenToId.ContainsKey(methodToken))
continue;
methodTokenToId[methodToken] = assemblyClient.Service.DefineStringDecrypter(methodToken);
methodTokenToId[methodToken] = assemblyClient.StringDecrypterService.DefineStringDecrypter(methodToken);
}
}
@ -117,7 +117,7 @@ namespace de4dot.code {
AssemblyData.SimpleData.Pack(list[i].args);
args[i] = list[i].args;
}
var decryptedStrings = assemblyClient.Service.DecryptStrings(methodId, args, Method.MDToken.ToInt32());
var decryptedStrings = assemblyClient.StringDecrypterService.DecryptStrings(methodId, args, Method.MDToken.ToInt32());
if (decryptedStrings.Length != args.Length)
throw new ApplicationException("Invalid decrypted strings array length");
AssemblyData.SimpleData.Unpack(decryptedStrings);

View File

@ -24,6 +24,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -34,6 +35,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
@ -72,16 +74,36 @@
<Compile Include="deobfuscators\Agile_NET\StackFrameHelper.cs" />
<Compile Include="deobfuscators\Agile_NET\StringDecrypter.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\CilOperandInstructionRestorer.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\Csvm.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\CsvmDataReader.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\CsvmMethodData.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\CsvmToCilMethodConverter.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\FieldsInfo.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\OpCodeHandler.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\OpCodeHandlers.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\UnknownHandlerInfo.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\VmOpCodeHandlerDetector.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\VmOperands.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\CsvmToCilMethodConverterBase.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v1\Csvm.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v1\CsvmToCilMethodConverter.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v1\FieldsInfo.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v1\OpCodeHandler.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v1\OpCodeHandlers.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v1\UnknownHandlerInfo.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v1\VmOpCodeHandlerDetector.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\CompositeHandlerDetector.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\CompositeOpCodeHandler.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\Csvm.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\CsvmInfo.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\CsvmResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>CsvmResources.resx</DependentUpon>
</Compile>
<Compile Include="deobfuscators\Agile_NET\vm\v2\CsvmToCilMethodConverter.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\HandlerTypeCode.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\MethodFinder.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\MethodSigInfoCreator.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandler.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandlerInfo.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandlerInfoReader.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandlerInfos.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\VmOpCode.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\VmOpCodeHandlerDetector.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\VmOperand.cs" />
<Compile Include="deobfuscators\ArrayFinder.cs" />
<Compile Include="deobfuscators\Babel_NET\AssemblyResolver.cs" />
<Compile Include="deobfuscators\Babel_NET\BabelInflater.cs" />
@ -155,9 +177,12 @@
<Compile Include="deobfuscators\CRC32.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\AntiDebugger.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\AssemblyResolver.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\CoMethodCallInliner.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\ConstantsDecrypter.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\CoUtils.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\Deobfuscator.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\InlinedMethodTypes.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\LdnullFixer.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\MethodBodyReader.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\MethodsDecrypter.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\ProxyCallFixer.cs" />
@ -183,7 +208,14 @@
<Compile Include="deobfuscators\DeobUtils.cs" />
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.cs" />
<Compile Include="deobfuscators\Dotfuscator\StringDecrypter.cs" />
<Compile Include="deobfuscators\Eazfuscator_NET\Dynocode.cs" />
<Compile Include="deobfuscators\Eazfuscator_NET\DynamicDynocodeIterator.cs" />
<Compile Include="deobfuscators\Eazfuscator_NET\DynocodeService.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\v4\DnrMethodCallInliner.cs" />
<Compile Include="deobfuscators\ILProtector\DecryptedMethodInfo.cs" />
<Compile Include="deobfuscators\ILProtector\DynamicMethodsDecrypter.cs" />
<Compile Include="deobfuscators\ILProtector\DynamicMethodsDecrypterService.cs" />
<Compile Include="deobfuscators\ILProtector\DynamicMethodsRestorer.cs" />
<Compile Include="deobfuscators\ILProtector\MethodsDecrypterBase.cs" />
<Compile Include="deobfuscators\MyPEImage.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\v3\AntiStrongName.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeDecrypter.cs" />
@ -235,7 +267,7 @@
<Compile Include="deobfuscators\ILProtector\Deobfuscator.cs" />
<Compile Include="deobfuscators\ILProtector\MainType.cs" />
<Compile Include="deobfuscators\ILProtector\MethodReader.cs" />
<Compile Include="deobfuscators\ILProtector\MethodsDecrypter.cs" />
<Compile Include="deobfuscators\ILProtector\StaticMethodsDecrypter.cs" />
<Compile Include="deobfuscators\InitializedDataCreator.cs" />
<Compile Include="deobfuscators\InlinedMethodsFinder.cs" />
<Compile Include="deobfuscators\ISimpleDeobfuscator.cs" />
@ -257,6 +289,7 @@
<Compile Include="deobfuscators\MethodStack.cs" />
<Compile Include="deobfuscators\MPRESS\Deobfuscator.cs" />
<Compile Include="deobfuscators\MPRESS\Lzmat.cs" />
<Compile Include="deobfuscators\NullStream.cs" />
<Compile Include="deobfuscators\Operations.cs" />
<Compile Include="deobfuscators\ProxyCallFixerBase.cs" />
<Compile Include="deobfuscators\QuickLZ.cs" />
@ -297,6 +330,7 @@
<Compile Include="deobfuscators\Xenocode\Deobfuscator.cs" />
<Compile Include="deobfuscators\Xenocode\StringDecrypter.cs" />
<Compile Include="DumpedMethodsRestorer.cs" />
<Compile Include="HandleProcessCorruptedStateExceptionsAttribute.cs" />
<Compile Include="IDeobfuscatorContext.cs" />
<Compile Include="IObfuscatedFile.cs" />
<Compile Include="Logger.cs" />
@ -361,9 +395,9 @@
<Project>{FBD84077-9D35-41FE-89DF-8D79EFE0B595}</Project>
<Name>AssemblyData</Name>
</ProjectReference>
<ProjectReference Include="..\blocks\blocks.csproj">
<ProjectReference Include="..\de4dot.blocks\de4dot.blocks.csproj">
<Project>{045B96F2-AF80-4C4C-8D27-E38635AC705E}</Project>
<Name>blocks</Name>
<Name>de4dot.blocks</Name>
</ProjectReference>
<ProjectReference Include="..\de4dot.mdecrypt\de4dot.mdecrypt.csproj">
<Project>{5C93C5E2-196F-4877-BF65-96FEBFCEFCA1}</Project>
@ -374,6 +408,12 @@
<Name>dnlib</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="deobfuscators\Agile_NET\vm\v2\CsvmResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>CsvmResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>mkdir "..\$(OutDir)..\LICENSES"

View File

@ -88,19 +88,6 @@ namespace de4dot.code.deobfuscators.Agile_NET {
static readonly string[] requiredFields1 = new string[] {
"System.Boolean",
};
static readonly string[] requiredFields2 = new string[] {
"System.Boolean",
"System.Reflection.Assembly",
};
static readonly string[] requiredFields3 = new string[] {
"System.Boolean",
"System.Byte[]",
};
static readonly string[] requiredFields4 = new string[] {
"System.Boolean",
"System.Reflection.Assembly",
"System.Byte[]",
};
bool Find2() {
foreach (var cctor in DeobUtils.GetInitCctors(module, 3)) {
foreach (var calledMethod in DotNetUtils.GetCalledMethods(module, cctor)) {
@ -108,8 +95,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (type.IsPublic)
continue;
var fieldTypes = new FieldTypes(type);
if (!fieldTypes.Exactly(requiredFields1) && !fieldTypes.Exactly(requiredFields2) &&
!fieldTypes.Exactly(requiredFields3) && !fieldTypes.Exactly(requiredFields4))
if (!fieldTypes.All(requiredFields1))
continue;
if (!HasInitializeMethod(type, "_Initialize") && !HasInitializeMethod(type, "_Initialize64"))
continue;
@ -126,11 +112,19 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return false;
}
static string[] requiredFields6 = new string[] {
"System.Byte[]",
};
static string[] requiredFields7 = new string[] {
"System.Byte[]",
"System.Collections.Hashtable",
};
bool Find3() {
foreach (var type in module.Types) {
if (type.Fields.Count != 1)
if (type.Fields.Count < 1 || type.Fields.Count > 2)
continue;
if (type.Fields[0].FieldSig.GetFieldType().GetFullName() != "System.Byte[]")
var fieldTypes = new FieldTypes(type);
if (!fieldTypes.Exactly(requiredFields6) && !fieldTypes.Exactly(requiredFields7))
continue;
if (type.Methods.Count != 2)
continue;

View File

@ -85,7 +85,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
ResourceDecrypter resourceDecrypter;
StackFrameHelper stackFrameHelper;
vm.Csvm csvm;
vm.v1.Csvm csvmV1;
vm.v2.Csvm csvmV2;
internal class Options : OptionsBase {
public bool DecryptMethods { get; set; }
@ -166,7 +167,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
ToInt32(stringDecrypter.Detected) +
ToInt32(proxyCallFixer.Detected) +
ToInt32(resourceDecrypter.Detected) +
ToInt32(csvm.Detected);
ToInt32(csvmV1.Detected || csvmV2.Detected);
if (sum > 0)
val += 100 + 10 * (sum - 1);
if (cliSecureAttributes.Count != 0)
@ -185,8 +186,10 @@ namespace de4dot.code.deobfuscators.Agile_NET {
resourceDecrypter.Find();
proxyCallFixer = new ProxyCallFixer(module);
proxyCallFixer.FindDelegateCreator();
csvm = new vm.Csvm(DeobfuscatedFile.DeobfuscatorContext, module);
csvm.Find();
csvmV1 = new vm.v1.Csvm(DeobfuscatedFile.DeobfuscatorContext, module);
csvmV1.Find();
csvmV2 = new vm.v2.Csvm(DeobfuscatedFile.DeobfuscatorContext, module);
csvmV2.Find();
}
void FindCliSecureAttribute() {
@ -227,7 +230,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter);
newOne.resourceDecrypter = new ResourceDecrypter(module, resourceDecrypter);
newOne.proxyCallFixer = new ProxyCallFixer(module, proxyCallFixer);
newOne.csvm = new vm.Csvm(DeobfuscatedFile.DeobfuscatorContext, module, csvm);
newOne.csvmV1 = new vm.v1.Csvm(DeobfuscatedFile.DeobfuscatorContext, module, csvmV1);
newOne.csvmV2 = new vm.v2.Csvm(DeobfuscatedFile.DeobfuscatorContext, module, csvmV2);
return newOne;
}
@ -270,9 +274,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
FindPossibleNamesToRemove(cliSecureRtType.LoadMethod);
}
if (options.RestoreVmCode) {
if (csvm.Restore())
AddResourceToBeRemoved(csvm.Resource, "CSVM data resource");
if (options.RestoreVmCode && (csvmV1.Detected || csvmV2.Detected)) {
if (csvmV1.Detected && csvmV1.Restore())
AddResourceToBeRemoved(csvmV1.Resource, "CSVM data resource");
else if (csvmV2.Detected && csvmV2.Restore())
AddResourceToBeRemoved(csvmV2.Resource, "CSVM data resource");
else {
Logger.e("Couldn't restore VM methods. Use --dont-rename or it will not run");
PreserveTokensAndTypes();

View File

@ -23,9 +23,7 @@ using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
// Tries to restore the operands of the following CIL instructions:
// ldelema
// ldobj
// stobj
// ldelema, ldelem.*, stelem.*, ldobj, stobj
class CilOperandInstructionRestorer {
MethodDef method;
@ -42,10 +40,66 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (instr.Operand != null)
continue;
TypeSig operandType = null;
TypeSig operandType = null, operandTypeTmp;
OpCode newOpCode = null;
SZArraySig arrayType;
switch (instr.OpCode.Code) {
case Code.Ldelem:
arrayType = MethodStack.GetLoadedType(method, instrs, i, 1) as SZArraySig;
if (arrayType == null)
break;
operandTypeTmp = arrayType.Next;
if (operandTypeTmp == null)
newOpCode = OpCodes.Ldelem_Ref;
else {
switch (operandTypeTmp.ElementType) {
case ElementType.I: newOpCode = OpCodes.Ldelem_I; break;
case ElementType.I1: newOpCode = OpCodes.Ldelem_I1; break;
case ElementType.I2: newOpCode = OpCodes.Ldelem_I2; break;
case ElementType.I4: newOpCode = OpCodes.Ldelem_I4; break;
case ElementType.I8: newOpCode = OpCodes.Ldelem_I8; break;
case ElementType.U: newOpCode = OpCodes.Ldelem_I; break;
case ElementType.U1: newOpCode = OpCodes.Ldelem_U1; break;
case ElementType.U2: newOpCode = OpCodes.Ldelem_U2; break;
case ElementType.U4: newOpCode = OpCodes.Ldelem_U4; break;
case ElementType.U8: newOpCode = OpCodes.Ldelem_I8; break;
case ElementType.R4: newOpCode = OpCodes.Ldelem_R4; break;
case ElementType.R8: newOpCode = OpCodes.Ldelem_R8; break;
default: newOpCode = OpCodes.Ldelem_Ref; break;
//TODO: Ldelem
}
}
break;
case Code.Stelem:
arrayType = MethodStack.GetLoadedType(method, instrs, i, 2) as SZArraySig;
if (arrayType == null)
break;
operandTypeTmp = arrayType.Next;
if (operandTypeTmp == null)
newOpCode = OpCodes.Stelem_Ref;
else {
switch (operandTypeTmp.ElementType) {
case ElementType.U:
case ElementType.I: newOpCode = OpCodes.Stelem_I; break;
case ElementType.U1:
case ElementType.I1: newOpCode = OpCodes.Stelem_I1; break;
case ElementType.U2:
case ElementType.I2: newOpCode = OpCodes.Stelem_I2; break;
case ElementType.U4:
case ElementType.I4: newOpCode = OpCodes.Stelem_I4; break;
case ElementType.U8:
case ElementType.I8: newOpCode = OpCodes.Stelem_I8; break;
case ElementType.R4: newOpCode = OpCodes.Stelem_R4; break;
case ElementType.R8: newOpCode = OpCodes.Stelem_R8; break;
default: newOpCode = OpCodes.Stelem_Ref; break;
//TODO: Stelem
}
}
break;
case Code.Ldelema:
var arrayType = MethodStack.GetLoadedType(method, instrs, i, 1) as SZArraySig;
arrayType = MethodStack.GetLoadedType(method, instrs, i, 1) as SZArraySig;
if (arrayType == null)
break;
operandType = arrayType.Next;
@ -64,12 +118,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
default:
continue;
}
if (!IsValidType(operandType)) {
if (newOpCode == null && !IsValidType(operandType)) {
atLeastOneFailed = true;
continue;
}
instr.Operand = operandType.ToTypeDefOrRef();
if (newOpCode != null)
instr.OpCode = newOpCode;
}
return !atLeastOneFailed;

View File

@ -25,22 +25,33 @@ using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
class CsvmToCilMethodConverter {
IDeobfuscatorContext deobfuscatorContext;
ModuleDefMD module;
VmOpCodeHandlerDetector opCodeDetector;
CilOperandInstructionRestorer operandRestorer = new CilOperandInstructionRestorer();
abstract class CsvmToCilMethodConverterBase {
readonly IDeobfuscatorContext deobfuscatorContext;
readonly protected ModuleDefMD module;
readonly CilOperandInstructionRestorer operandRestorer = new CilOperandInstructionRestorer();
readonly Dictionary<Instruction, int> cilToVmIndex = new Dictionary<Instruction, int>();
readonly Dictionary<int, Instruction> vmIndexToCil = new Dictionary<int, Instruction>();
public CsvmToCilMethodConverter(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module, VmOpCodeHandlerDetector opCodeDetector) {
public CsvmToCilMethodConverterBase(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module) {
this.deobfuscatorContext = deobfuscatorContext;
this.module = module;
this.opCodeDetector = opCodeDetector;
}
protected void SetCilToVmIndex(Instruction instr, int vmIndex) {
cilToVmIndex[instr] = vmIndex;
}
protected void SetVmIndexToCil(Instruction instr, int vmIndex) {
vmIndexToCil[vmIndex] = instr;
}
public void Convert(MethodDef cilMethod, CsvmMethodData csvmMethod) {
cilToVmIndex.Clear();
vmIndexToCil.Clear();
var newInstructions = ReadInstructions(cilMethod, csvmMethod);
var newLocals = ReadLocals(cilMethod, csvmMethod);
var newExceptions = ReadExceptions(cilMethod, csvmMethod, newInstructions);
var newExceptions = ReadExceptions(cilMethod, csvmMethod);
FixInstructionOperands(newInstructions);
FixLocals(newInstructions, cilMethod.Body.Variables);
@ -59,7 +70,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (op == null)
continue;
UpdateLocalInstruction(instr, locals[op.local], op.local);
UpdateLocalInstruction(instr, locals[op.Local], op.Local);
}
}
@ -134,7 +145,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (op == null)
continue;
UpdateArgInstruction(instr, method.Parameters[op.arg], op.arg);
UpdateArgInstruction(instr, method.Parameters[op.Arg], op.Arg);
}
}
@ -197,28 +208,16 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
}
List<Instruction> ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
var instrs = new List<Instruction>();
uint offset = 0;
while (reader.BaseStream.Position < reader.BaseStream.Length) {
int vmOpCode = reader.ReadUInt16();
var instr = opCodeDetector.Handlers[vmOpCode].Read(reader);
instr.Offset = offset;
offset += (uint)GetInstructionSize(instr);
instrs.Add(instr);
}
return instrs;
}
protected abstract List<Instruction> ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod);
static int GetInstructionSize(Instruction instr) {
protected static int GetInstructionSize(Instruction instr) {
var opcode = instr.OpCode;
if (opcode == null)
return 5; // Load store/field
var op = instr.Operand as SwitchTargetDisplOperand;
if (op == null)
return instr.GetSize();
return instr.OpCode.Size + (op.targetDisplacements.Length + 1) * 4;
return instr.OpCode.Size + (op.TargetDisplacements.Length + 1) * 4;
}
List<Local> ReadLocals(MethodDef cilMethod, CsvmMethodData csvmMethod) {
@ -289,7 +288,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
}
List<ExceptionHandler> ReadExceptions(MethodDef cilMethod, CsvmMethodData csvmMethod, List<Instruction> cilInstructions) {
List<ExceptionHandler> ReadExceptions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
var reader = new BinaryReader(new MemoryStream(csvmMethod.Exceptions));
var ehs = new List<ExceptionHandler>();
@ -302,14 +301,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
for (int i = 0; i < numExceptions; i++) {
var eh = new ExceptionHandler((ExceptionHandlerType)reader.ReadInt32());
eh.TryStart = GetInstruction(cilInstructions, reader.ReadInt32());
eh.TryEnd = GetInstructionEnd(cilInstructions, reader.ReadInt32());
eh.HandlerStart = GetInstruction(cilInstructions, reader.ReadInt32());
eh.HandlerEnd = GetInstructionEnd(cilInstructions, reader.ReadInt32());
eh.TryStart = GetInstruction(reader.ReadInt32());
eh.TryEnd = GetInstructionEnd(reader.ReadInt32());
eh.HandlerStart = GetInstruction(reader.ReadInt32());
eh.HandlerEnd = GetInstructionEnd(reader.ReadInt32());
if (eh.HandlerType == ExceptionHandlerType.Catch)
eh.CatchType = module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
else if (eh.HandlerType == ExceptionHandlerType.Filter)
eh.FilterStart = GetInstruction(cilInstructions, reader.ReadInt32());
eh.FilterStart = GetInstruction(reader.ReadInt32());
ehs.Add(eh);
}
@ -317,22 +316,20 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return ehs;
}
static Instruction GetInstruction(IList<Instruction> instrs, int index) {
return instrs[index];
Instruction GetInstruction(int vmIndex) {
return vmIndexToCil[vmIndex];
}
static Instruction GetInstructionEnd(IList<Instruction> instrs, int index) {
index++;
if (index == instrs.Count)
return null;
return instrs[index];
Instruction GetInstructionEnd(int vmIndex) {
vmIndex++;
Instruction instr;
vmIndexToCil.TryGetValue(vmIndex, out instr);
return instr;
}
static Instruction GetInstruction(IList<Instruction> instrs, Instruction source, int displ) {
int sourceIndex = instrs.IndexOf(source);
if (sourceIndex < 0)
throw new ApplicationException("Could not find source instruction");
return instrs[sourceIndex + displ];
Instruction GetInstruction(Instruction source, int displ) {
int vmIndex = cilToVmIndex[source];
return vmIndexToCil[vmIndex + displ];
}
void FixInstructionOperands(IList<Instruction> instrs) {
@ -344,41 +341,33 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
object FixOperand(IList<Instruction> instrs, Instruction instr, IVmOperand vmOperand) {
if (vmOperand is TokenOperand)
return GetMemberRef(((TokenOperand)vmOperand).token);
if (vmOperand is TargetDisplOperand)
return GetInstruction(instrs, instr, ((TargetDisplOperand)vmOperand).displacement);
return GetInstruction(instr, ((TargetDisplOperand)vmOperand).Displacement);
if (vmOperand is SwitchTargetDisplOperand) {
var targetDispls = ((SwitchTargetDisplOperand)vmOperand).targetDisplacements;
var targetDispls = ((SwitchTargetDisplOperand)vmOperand).TargetDisplacements;
Instruction[] targets = new Instruction[targetDispls.Length];
for (int i = 0; i < targets.Length; i++)
targets[i] = GetInstruction(instrs, instr, targetDispls[i]);
targets[i] = GetInstruction(instr, targetDispls[i]);
return targets;
}
if (vmOperand is ArgOperand || vmOperand is LocalOperand)
return vmOperand;
if (vmOperand is LoadFieldOperand)
return FixLoadStoreFieldInstruction(instr, ((LoadFieldOperand)vmOperand).token, OpCodes.Ldsfld, OpCodes.Ldfld);
if (vmOperand is LoadFieldAddressOperand)
return FixLoadStoreFieldInstruction(instr, ((LoadFieldAddressOperand)vmOperand).token, OpCodes.Ldsflda, OpCodes.Ldflda);
if (vmOperand is StoreFieldOperand)
return FixLoadStoreFieldInstruction(instr, ((StoreFieldOperand)vmOperand).token, OpCodes.Stsfld, OpCodes.Stfld);
if (vmOperand is FieldInstructionOperand) {
var fieldInfo = (FieldInstructionOperand)vmOperand;
return FixLoadStoreFieldInstruction(instr, fieldInfo.Field, fieldInfo.StaticOpCode, fieldInfo.InstanceOpCode);
}
throw new ApplicationException(string.Format("Unknown operand type: {0}", vmOperand.GetType()));
}
IField FixLoadStoreFieldInstruction(Instruction instr, int token, OpCode staticInstr, OpCode instanceInstr) {
var fieldRef = module.ResolveToken(token) as IField;
IField FixLoadStoreFieldInstruction(Instruction instr, IField fieldRef, OpCode staticInstr, OpCode instanceInstr) {
var field = deobfuscatorContext.ResolveField(fieldRef);
bool isStatic;
if (field == null) {
Logger.w("Could not resolve field {0:X8}. Assuming it's not static.", token);
Logger.w("Could not resolve field {0:X8}. Assuming it's not static.", fieldRef == null ? 0 : fieldRef.MDToken.Raw);
isStatic = false;
}
else
@ -387,13 +376,6 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return fieldRef;
}
ITokenOperand GetMemberRef(int token) {
var memberRef = module.ResolveToken(token) as ITokenOperand;
if (memberRef == null)
throw new ApplicationException(string.Format("Could not find member ref: {0:X8}", token));
return memberRef;
}
static void RestoreConstrainedPrefix(MethodDef method) {
if (method == null || method.Body == null)
return;

View File

@ -17,66 +17,50 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using dnlib.DotNet;
using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
interface IVmOperand {
}
class TokenOperand : IVmOperand {
public int token; // any type of token
public TokenOperand(int token) {
this.token = token;
}
}
class TargetDisplOperand : IVmOperand {
public int displacement; // number of instructions from current instr
public readonly int Displacement; // number of VM instructions from current VM instr
public TargetDisplOperand(int displacement) {
this.displacement = displacement;
this.Displacement = displacement;
}
}
class SwitchTargetDisplOperand : IVmOperand {
public int[] targetDisplacements; // number of instructions from current instr
public readonly int[] TargetDisplacements; // number of VM instructions from current VM instr
public SwitchTargetDisplOperand(int[] targetDisplacements) {
this.targetDisplacements = targetDisplacements;
this.TargetDisplacements = targetDisplacements;
}
}
class ArgOperand : IVmOperand {
public ushort arg;
public readonly ushort Arg;
public ArgOperand(ushort arg) {
this.arg = arg;
this.Arg = arg;
}
}
class LocalOperand : IVmOperand {
public ushort local;
public readonly ushort Local;
public LocalOperand(ushort local) {
this.local = local;
this.Local = local;
}
}
// OpCode must be changed to ldfld / ldsfld
class LoadFieldOperand : IVmOperand {
public int token;
public LoadFieldOperand(int token) {
this.token = token;
}
}
class FieldInstructionOperand : IVmOperand {
public readonly OpCode StaticOpCode;
public readonly OpCode InstanceOpCode;
public readonly IField Field;
// OpCode must be changed to ldflda / ldsflda
class LoadFieldAddressOperand : IVmOperand {
public int token;
public LoadFieldAddressOperand(int token) {
this.token = token;
}
}
// OpCode must be changed to stfld / stsfld
class StoreFieldOperand : IVmOperand {
public int token;
public StoreFieldOperand(int token) {
this.token = token;
public FieldInstructionOperand(OpCode staticOpCode, OpCode instanceOpCode, IField field) {
this.StaticOpCode = staticOpCode;
this.InstanceOpCode = instanceOpCode;
this.Field = field;
}
}
}

View File

@ -23,7 +23,7 @@ using System.IO;
using dnlib.DotNet;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class Csvm {
IDeobfuscatorContext deobfuscatorContext;
ModuleDefMD module;
@ -140,7 +140,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
var vmModulePath = Path.Combine(Path.GetDirectoryName(module.Location), vmFilename);
Logger.v("CSVM filename: {0}", vmFilename);
var dataKey = "cs cached VmOpCodeHandlerDetector";
var dataKey = "cs cached VmOpCodeHandlerDetector v1";
var dict = (Dictionary<string, VmOpCodeHandlerDetector>)deobfuscatorContext.GetData(dataKey);
if (dict == null)
deobfuscatorContext.SetData(dataKey, dict = new Dictionary<string, VmOpCodeHandlerDetector>(StringComparer.OrdinalIgnoreCase));

View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class CsvmToCilMethodConverter : CsvmToCilMethodConverterBase {
VmOpCodeHandlerDetector opCodeDetector;
public CsvmToCilMethodConverter(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module, VmOpCodeHandlerDetector opCodeDetector)
: base(deobfuscatorContext, module) {
this.opCodeDetector = opCodeDetector;
}
protected override List<Instruction> ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
var instrs = new List<Instruction>();
uint offset = 0;
while (reader.BaseStream.Position < reader.BaseStream.Length) {
int vmOpCode = reader.ReadUInt16();
var instr = opCodeDetector.Handlers[vmOpCode].Read(reader, module);
instr.Offset = offset;
offset += (uint)GetInstructionSize(instr);
SetCilToVmIndex(instr, instrs.Count);
SetVmIndexToCil(instr, instrs.Count);
instrs.Add(instr);
}
return instrs;
}
}
}

View File

@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using dnlib.DotNet;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class FieldsInfo {
public static readonly object EnumType = new object();
Dictionary<string, int> fieldTypes = new Dictionary<string, int>(StringComparer.Ordinal);

View File

@ -24,12 +24,12 @@ using de4dot.blocks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
partial class OpCodeHandler {
public string Name { get; set; }
public OpCodeHandlerSigInfo OpCodeHandlerSigInfo { get; set; }
public Predicate<UnknownHandlerInfo> Check { get; set; }
public Func<BinaryReader, Instruction> Read { get; set; }
public Func<BinaryReader, IInstructionOperandResolver, Instruction> Read { get; set; }
public bool Detect(UnknownHandlerInfo info) {
var sigInfo = OpCodeHandlerSigInfo;
@ -68,7 +68,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
static partial class OpCodeHandlers {
static Instruction arithmetic_read(BinaryReader reader) {
static Instruction arithmetic_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Add.ToInstruction();
case 1: return OpCodes.Add_Ovf.ToInstruction();
@ -91,25 +91,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Type System.Reflection.Module::ResolveType(System.Int32)");
}
static Instruction newarr_read(BinaryReader reader) {
return new Instruction {
OpCode = OpCodes.Newarr,
Operand = new TokenOperand(reader.ReadInt32()),
};
static Instruction newarr_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Newarr, resolver.ResolveToken(reader.ReadUInt32()));
}
static Instruction box_read(BinaryReader reader) {
static Instruction box_read(BinaryReader reader, IInstructionOperandResolver resolver) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Box; break;
case 1: instr.OpCode = OpCodes.Unbox_Any; break;
default: throw new ApplicationException("Invalid opcode");
}
instr.Operand = new TokenOperand(reader.ReadInt32());
instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
return instr;
}
static Instruction call_read(BinaryReader reader) {
static Instruction call_read(BinaryReader reader, IInstructionOperandResolver resolver) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Newobj; break;
@ -117,22 +114,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
case 2: instr.OpCode = OpCodes.Callvirt; break;
default: throw new ApplicationException("Invalid opcode");
}
instr.Operand = new TokenOperand(reader.ReadInt32());
instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
return instr;
}
static Instruction cast_read(BinaryReader reader) {
static Instruction cast_read(BinaryReader reader, IInstructionOperandResolver resolver) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Castclass; break;
case 1: instr.OpCode = OpCodes.Isinst; break;
default: throw new ApplicationException("Invalid opcode");
}
instr.Operand = new TokenOperand(reader.ReadInt32());
instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
return instr;
}
static Instruction compare_read(BinaryReader reader) {
static Instruction compare_read(BinaryReader reader, IInstructionOperandResolver resolver) {
int type = reader.ReadByte();
Instruction instr = new Instruction();
switch (type) {
@ -205,7 +202,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
new InstructionInfo1 { Type = 11, Second = true, Third = true, OpCode = OpCodes.Conv_Ovf_U_Un },
new InstructionInfo1 { Type = 12, Second = true, Third = true, OpCode = OpCodes.Conv_R_Un },
};
static Instruction convert_read(BinaryReader reader) {
static Instruction convert_read(BinaryReader reader, IInstructionOperandResolver resolver) {
byte type = reader.ReadByte();
bool second = reader.ReadBoolean();
bool third = reader.ReadBoolean();
@ -215,7 +212,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (type != info.Type || info.Second != second || info.Third != third)
continue;
instr = new Instruction { OpCode = info.OpCode };
instr = new Instruction(info.OpCode);
break;
}
if (instr == null)
@ -224,7 +221,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return instr;
}
static Instruction dup_read(BinaryReader reader) {
static Instruction dup_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Dup.ToInstruction();
case 1: return OpCodes.Pop.ToInstruction();
@ -262,7 +259,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
new InstructionInfo2 { First = true, Second = true, Value = 28, OpCode = OpCodes.Ldelem_Ref },
new InstructionInfo2 { First = true, Second = false, Value = 0, OpCode = OpCodes.Ldelem },
};
static Instruction ldelem_read(BinaryReader reader) {
static Instruction ldelem_read(BinaryReader reader, IInstructionOperandResolver resolver) {
Instruction instr = null;
bool first = reader.ReadBoolean();
bool second = reader.ReadBoolean();
@ -274,9 +271,9 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
continue;
if (second)
instr = new Instruction { OpCode = info.OpCode };
instr = new Instruction(info.OpCode);
else
instr = new Instruction { OpCode = info.OpCode, Operand = new TokenOperand(value) };
instr = new Instruction(info.OpCode, resolver.ResolveToken((uint)value));
break;
}
if (instr == null)
@ -289,29 +286,26 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags)");
}
static Instruction endfinally_read(BinaryReader reader) {
static Instruction endfinally_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Endfinally.ToInstruction();
}
static Instruction ldfld_read(BinaryReader reader) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.Operand = new LoadFieldOperand(reader.ReadInt32()); break;
case 1: instr.Operand = new LoadFieldAddressOperand(reader.ReadInt32()); break;
case 2: instr.Operand = new StoreFieldOperand(reader.ReadInt32()); break;
static Instruction ldfld_read(BinaryReader reader, IInstructionOperandResolver resolver) {
byte b = reader.ReadByte();
var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
switch (b) {
case 0: return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsfld, OpCodes.Ldfld, field));
case 1: return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsflda, OpCodes.Ldflda, field));
case 2: return new Instruction(null, new FieldInstructionOperand(OpCodes.Stsfld, OpCodes.Stfld, field));
default: throw new ApplicationException("Invalid opcode");
}
return instr;
}
static Instruction initobj_read(BinaryReader reader) {
return new Instruction {
OpCode = OpCodes.Initobj,
Operand = new TokenOperand(reader.ReadInt32()),
};
static Instruction initobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Initobj, resolver.ResolveToken(reader.ReadUInt32()));
}
static Instruction ldloc_read(BinaryReader reader) {
static Instruction ldloc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
bool isLdarg = reader.ReadBoolean();
ushort index = reader.ReadUInt16();
@ -328,7 +322,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return instr;
}
static Instruction ldloca_read(BinaryReader reader) {
static Instruction ldloca_read(BinaryReader reader, IInstructionOperandResolver resolver) {
Instruction instr = new Instruction();
if (reader.ReadBoolean()) {
instr.OpCode = OpCodes.Ldarga;
@ -342,25 +336,19 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return instr;
}
static Instruction ldelema_read(BinaryReader reader) {
return new Instruction {
OpCode = OpCodes.Ldelema,
Operand = null,
};
static Instruction ldelema_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Ldelema, null);
}
static Instruction ldlen_read(BinaryReader reader) {
static Instruction ldlen_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Ldlen.ToInstruction();
}
static Instruction ldobj_read(BinaryReader reader) {
return new Instruction {
OpCode = OpCodes.Ldobj,
Operand = null,
};
static Instruction ldobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Ldobj, null);
}
static Instruction ldstr_read(BinaryReader reader) {
static Instruction ldstr_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Ldstr.ToInstruction(reader.ReadString());
}
@ -368,11 +356,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MemberInfo System.Reflection.Module::ResolveMember(System.Int32)");
}
static Instruction ldtoken_read(BinaryReader reader) {
return new Instruction {
OpCode = OpCodes.Ldtoken,
Operand = new TokenOperand(reader.ReadInt32()),
};
static Instruction ldtoken_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Ldtoken, resolver.ResolveToken(reader.ReadUInt32()));
}
static bool leave_check(UnknownHandlerInfo info) {
@ -381,15 +366,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
!DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MemberInfo System.Reflection.Module::ResolveMember(System.Int32)");
}
static Instruction leave_read(BinaryReader reader) {
static Instruction leave_read(BinaryReader reader, IInstructionOperandResolver resolver) {
int displacement = reader.ReadInt32();
return new Instruction {
OpCode = OpCodes.Leave,
Operand = new TargetDisplOperand(displacement),
};
return new Instruction(OpCodes.Leave, new TargetDisplOperand(displacement));
}
static Instruction ldc_read(BinaryReader reader) {
static Instruction ldc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch ((ElementType)reader.ReadByte()) {
case ElementType.I4: return Instruction.CreateLdcI4(reader.ReadInt32());
case ElementType.I8: return OpCodes.Ldc_I8.ToInstruction(reader.ReadInt64());
@ -400,29 +382,24 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
}
}
static Instruction ldftn_read(BinaryReader reader) {
static Instruction ldftn_read(BinaryReader reader, IInstructionOperandResolver resolver) {
byte code = reader.ReadByte();
int token = reader.ReadInt32();
uint token = reader.ReadUInt32();
Instruction instr;
switch (code) {
case 0:
instr = new Instruction { OpCode = OpCodes.Ldftn, Operand = new TokenOperand(token) };
break;
return new Instruction(OpCodes.Ldftn, resolver.ResolveToken(token));
case 1:
reader.ReadInt32(); // token of newobj .ctor
instr = new Instruction { OpCode = OpCodes.Ldvirtftn, Operand = new TokenOperand(token) };
break;
return new Instruction(OpCodes.Ldvirtftn, resolver.ResolveToken(token));
default:
throw new ApplicationException("Invalid opcode");
}
return instr;
}
static Instruction logical_read(BinaryReader reader) {
static Instruction logical_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch (reader.ReadByte()) {
case 0: return OpCodes.And.ToInstruction();
case 1: return OpCodes.Or.ToInstruction();
@ -448,7 +425,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return false;
}
static Instruction nop_read(BinaryReader reader) {
static Instruction nop_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Nop.ToInstruction();
}
@ -456,7 +433,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodBase System.Reflection.Module::ResolveMethod(System.Int32)");
}
static Instruction ret_read(BinaryReader reader) {
static Instruction ret_read(BinaryReader reader, IInstructionOperandResolver resolver) {
reader.ReadInt32(); // token of current method
return OpCodes.Ret.ToInstruction();
}
@ -465,11 +442,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return info.ExecuteMethod.Body.Variables.Count == 0;
}
static Instruction rethrow_read(BinaryReader reader) {
static Instruction rethrow_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Rethrow.ToInstruction();
}
static Instruction stloc_read(BinaryReader reader) {
static Instruction stloc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
bool isStarg = reader.ReadBoolean();
ushort index = reader.ReadUInt16();
@ -487,33 +464,27 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
return instr;
}
static Instruction stobj_read(BinaryReader reader) {
return new Instruction {
OpCode = OpCodes.Stobj,
Operand = null,
};
static Instruction stobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return new Instruction(OpCodes.Stobj, null);
}
static Instruction switch_read(BinaryReader reader) {
static Instruction switch_read(BinaryReader reader, IInstructionOperandResolver resolver) {
int numTargets = reader.ReadInt32();
int[] targetDispls = new int[numTargets];
for (int i = 0; i < targetDispls.Length; i++)
targetDispls[i] = reader.ReadInt32();
return new Instruction {
OpCode = OpCodes.Switch,
Operand = new SwitchTargetDisplOperand(targetDispls),
};
return new Instruction(OpCodes.Switch, new SwitchTargetDisplOperand(targetDispls));
}
static bool throw_check(UnknownHandlerInfo info) {
return !DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags)");
}
static Instruction throw_read(BinaryReader reader) {
static Instruction throw_read(BinaryReader reader, IInstructionOperandResolver resolver) {
return OpCodes.Throw.ToInstruction();
}
static Instruction neg_read(BinaryReader reader) {
static Instruction neg_read(BinaryReader reader, IInstructionOperandResolver resolver) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Neg.ToInstruction();
case 1: return OpCodes.Not.ToInstruction();

View File

@ -17,9 +17,9 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
namespace de4dot.code.deobfuscators.Agile_NET.vm {
namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
static partial class OpCodeHandlers {
public static readonly OpCodeHandler[][] opcodeHandlers = new OpCodeHandler[][] {
public static readonly OpCodeHandler[][] Handlers = new OpCodeHandler[][] {
new OpCodeHandler[] {
new OpCodeHandler {
Name = "arithmetic",

View File

@ -23,7 +23,7 @@ using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class UnknownHandlerInfo {
TypeDef type;
CsvmInfo csvmInfo;

View File

@ -24,7 +24,7 @@ using dnlib.DotNet.Emit;
using de4dot.blocks;
using de4dot.blocks.cflow;
namespace de4dot.code.deobfuscators.Agile_NET.vm {
namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
class OpCodeHandlerSigInfo {
public object[] RequiredFieldTypes { get; set; }
public string[] ExecuteMethodLocals { get; set; }
@ -214,7 +214,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
opCodeHandlers = new List<OpCodeHandler>();
var detected = new List<OpCodeHandler>();
foreach (var handlersList in OpCodeHandlers.opcodeHandlers) {
foreach (var handlersList in OpCodeHandlers.Handlers) {
opCodeHandlers.Clear();
foreach (var handlerType in handlerTypes) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,335 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class CompositeHandlerDetector {
readonly List<OpCodeHandler> handlers;
public CompositeHandlerDetector(IList<OpCodeHandler> handlers) {
this.handlers = new List<OpCodeHandler>(handlers.Count);
OpCodeHandler nop = null;
foreach (var handler in handlers) {
if (nop == null && handler.OpCodeHandlerInfo.TypeCode == HandlerTypeCode.Nop)
nop = handler;
else
this.handlers.Add(handler);
}
if (nop != null)
this.handlers.Add(nop);
}
struct MatchState {
public HandlerState OtherState;
public HandlerState CompositeState;
public MatchState(HandlerState OtherState, HandlerState CompositeState) {
this.OtherState = OtherState;
this.CompositeState = CompositeState;
}
}
struct HandlerState {
public readonly HandlerMethod HandlerMethod;
public readonly IList<Block> Blocks;
public readonly int BlockIndex;
public int InstructionIndex;
public HandlerState(HandlerMethod handlerMethod, int blockIndex, int instructionIndex) {
this.HandlerMethod = handlerMethod;
this.Blocks = handlerMethod.Blocks.MethodBlocks.GetAllBlocks();
this.BlockIndex = blockIndex;
this.InstructionIndex = instructionIndex;
}
public HandlerState(HandlerMethod handlerMethod, IList<Block> blocks, int blockIndex, int instructionIndex) {
this.HandlerMethod = handlerMethod;
this.Blocks = blocks;
this.BlockIndex = blockIndex;
this.InstructionIndex = instructionIndex;
}
public HandlerState Clone() {
return new HandlerState(HandlerMethod, Blocks, BlockIndex, InstructionIndex);
}
}
struct FindHandlerState {
public HandlerState CompositeState;
public readonly Dictionary<int, bool> VisitedCompositeBlocks;
public bool Done;
public FindHandlerState(HandlerState compositeState) {
this.CompositeState = compositeState;
this.VisitedCompositeBlocks = new Dictionary<int, bool>();
this.Done = false;
}
public FindHandlerState(HandlerState compositeState, Dictionary<int, bool> visitedCompositeBlocks, bool done) {
this.CompositeState = compositeState;
this.VisitedCompositeBlocks = new Dictionary<int, bool>(visitedCompositeBlocks);
this.Done = done;
}
public FindHandlerState Clone() {
return new FindHandlerState(CompositeState.Clone(), VisitedCompositeBlocks, Done);
}
}
public bool FindHandlers(CompositeOpCodeHandler composite) {
composite.OpCodeHandlerInfos.Clear();
var compositeExecState = new FindHandlerState(new HandlerState(composite.ExecMethod, 0, 0));
while (!compositeExecState.Done) {
var handler = FindHandlerMethod(ref compositeExecState);
if (handler == null)
return false;
composite.OpCodeHandlerInfos.Add(handler.OpCodeHandlerInfo);
}
return composite.OpCodeHandlerInfos.Count != 0;
}
OpCodeHandler FindHandlerMethod(ref FindHandlerState findExecState) {
foreach (var handler in handlers) {
FindHandlerState findExecStateNew = findExecState.Clone();
if (!Matches(handler.ExecMethod, ref findExecStateNew))
continue;
findExecState = findExecStateNew;
return handler;
}
return null;
}
Stack<MatchState> stack = new Stack<MatchState>();
bool Matches(HandlerMethod handler, ref FindHandlerState findState) {
HandlerState? nextState = null;
stack.Clear();
stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
while (stack.Count > 0) {
var matchState = stack.Pop();
if (matchState.CompositeState.InstructionIndex == 0) {
if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
continue;
findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
}
else {
if (!findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
throw new ApplicationException("Block hasn't been visited");
}
if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
return false;
var hblock = matchState.OtherState.Blocks[matchState.OtherState.BlockIndex];
var hinstrs = hblock.Instructions;
int hi = matchState.OtherState.InstructionIndex;
var cblock = matchState.CompositeState.Blocks[matchState.CompositeState.BlockIndex];
var cinstrs = cblock.Instructions;
int ci = matchState.CompositeState.InstructionIndex;
if (hi < hinstrs.Count)
return false;
if (ci < cinstrs.Count) {
if (hblock.CountTargets() != 0)
return false;
if (hblock.LastInstr.OpCode.Code == Code.Ret) {
if (nextState != null)
return false;
nextState = matchState.CompositeState;
}
}
else {
if (cblock.CountTargets() != hblock.CountTargets())
return false;
if (cblock.FallThrough != null || hblock.FallThrough != null) {
if (cblock.FallThrough == null || hblock.FallThrough == null)
return false;
var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.FallThrough);
var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.FallThrough);
stack.Push(new MatchState(hs, cs));
}
if (cblock.Targets != null || hblock.Targets != null) {
if (cblock.Targets == null || hblock.Targets == null ||
cblock.Targets.Count != hblock.Targets.Count)
return false;
for (int i = 0; i < cblock.Targets.Count; i++) {
var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.Targets[i]);
var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.Targets[i]);
stack.Push(new MatchState(hs, cs));
}
}
}
}
if (nextState == null) {
findState.Done = true;
return true;
}
else {
if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
findState.CompositeState.InstructionIndex == nextState.Value.InstructionIndex)
return false;
findState.CompositeState = nextState.Value;
return true;
}
}
static HandlerState CreateHandlerState(HandlerMethod handler, IList<Block> blocks, Block target) {
return new HandlerState(handler, blocks.IndexOf(target), 0);
}
static bool Compare(ref HandlerState handler, ref HandlerState composite) {
var hinstrs = handler.Blocks[handler.BlockIndex].Instructions;
int hi = handler.InstructionIndex;
var cinstrs = composite.Blocks[composite.BlockIndex].Instructions;
int ci = composite.InstructionIndex;
while (true) {
if (hi >= hinstrs.Count && ci >= cinstrs.Count)
break;
if (hi >= hinstrs.Count || ci >= cinstrs.Count)
return false;
var hinstr = hinstrs[hi++];
var cinstr = cinstrs[ci++];
if (hinstr.OpCode.Code == Code.Nop ||
cinstr.OpCode.Code == Code.Nop) {
if (hinstr.OpCode.Code != Code.Nop)
hi--;
if (cinstr.OpCode.Code != Code.Nop)
ci--;
continue;
}
if (hi == hinstrs.Count && hinstr.OpCode.Code == Code.Ret) {
if (cinstr.OpCode.Code != Code.Br && cinstr.OpCode.Code != Code.Ret)
ci--;
break;
}
if (hinstr.OpCode.Code != cinstr.OpCode.Code)
return false;
if (hinstr.OpCode.Code == Code.Ldfld &&
hi + 1 < hinstrs.Count && ci + 1 < cinstrs.Count) {
var hfield = hinstr.Operand as FieldDef;
var cfield = cinstr.Operand as FieldDef;
if (hfield != null && cfield != null &&
!hfield.IsStatic && !cfield.IsStatic &&
hfield.DeclaringType == handler.HandlerMethod.Method.DeclaringType &&
cfield.DeclaringType == composite.HandlerMethod.Method.DeclaringType &&
SignatureEqualityComparer.Instance.Equals(hfield.Signature, cfield.Signature)) {
cinstr = cinstrs[ci++];
hinstr = hinstrs[hi++];
if (cinstr.OpCode.Code != Code.Ldc_I4 ||
hinstr.OpCode.Code != Code.Ldc_I4)
return false;
continue;
}
}
if (!CompareOperand(hinstr.OpCode.OperandType, cinstr.Operand, hinstr.Operand))
return false;
}
handler.InstructionIndex = hi;
composite.InstructionIndex = ci;
return true;
}
static bool CompareOperand(OperandType opType, object a, object b) {
switch (opType) {
case OperandType.ShortInlineI:
return (a is byte && b is byte && (byte)a == (byte)b) ||
(a is sbyte && b is sbyte && (sbyte)a == (sbyte)b);
case OperandType.InlineI:
return a is int && b is int && (int)a == (int)b;
case OperandType.InlineI8:
return a is long && b is long && (long)a == (long)b;
case OperandType.ShortInlineR:
return a is float && b is float && (float)a == (float)b;
case OperandType.InlineR:
return a is double && b is double && (double)a == (double)b;
case OperandType.InlineField:
return FieldEqualityComparer.CompareDeclaringTypes.Equals(a as IField, b as IField);
case OperandType.InlineMethod:
return MethodEqualityComparer.CompareDeclaringTypes.Equals(a as IMethod, b as IMethod);
case OperandType.InlineSig:
return SignatureEqualityComparer.Instance.Equals(a as MethodSig, b as MethodSig);
case OperandType.InlineString:
return string.Equals(a as string, b as string);
case OperandType.InlineSwitch:
var al = a as IList<Instruction>;
var bl = b as IList<Instruction>;
return al != null && bl != null && al.Count == bl.Count;
case OperandType.InlineTok:
var fa = a as IField;
var fb = b as IField;
if (fa != null && fb != null)
return FieldEqualityComparer.CompareDeclaringTypes.Equals(fa, fb);
var ma = a as IMethod;
var mb = b as IMethod;
if (ma != null && mb != null)
return MethodEqualityComparer.CompareDeclaringTypes.Equals(ma, mb);
return TypeEqualityComparer.Instance.Equals(a as ITypeDefOrRef, b as ITypeDefOrRef);
case OperandType.InlineType:
return TypeEqualityComparer.Instance.Equals(a as ITypeDefOrRef, b as ITypeDefOrRef);
case OperandType.InlineVar:
case OperandType.ShortInlineVar:
var la = a as Local;
var lb = b as Local;
if (la != null && lb != null)
return true;
var pa = a as Parameter;
var pb = b as Parameter;
return pa != null && pb != null && pa.Index == pb.Index;
case OperandType.InlineBrTarget:
case OperandType.ShortInlineBrTarget:
case OperandType.InlineNone:
case OperandType.InlinePhi:
return true;
default:
return false;
}
}
}
}

View File

@ -0,0 +1,67 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using System.Text;
using dnlib.DotNet;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class HandlerMethod {
public MethodDef Method { get; private set; }
public Blocks Blocks { get; private set; }
public HandlerMethod(MethodDef method) {
this.Method = method;
this.Blocks = new Blocks(method);
}
}
class PrimitiveHandlerMethod : HandlerMethod {
public MethodSigInfo Sig { get; set; }
public PrimitiveHandlerMethod(MethodDef method)
: base(method) {
}
}
class CompositeOpCodeHandler {
public TypeDef HandlerType { get; private set; }
public HandlerMethod ExecMethod { get; private set; }
public List<OpCodeHandlerInfo> OpCodeHandlerInfos { get; private set; }
public CompositeOpCodeHandler(TypeDef handlerType, HandlerMethod execMethod) {
this.HandlerType = handlerType;
this.ExecMethod = execMethod;
this.OpCodeHandlerInfos = new List<OpCodeHandlerInfo>();
}
public override string ToString() {
if (OpCodeHandlerInfos.Count == 0)
return "<nothing>";
var sb = new StringBuilder();
foreach (var handler in OpCodeHandlerInfos) {
if (sb.Length != 0)
sb.Append(", ");
sb.Append(handler.Name);
}
return sb.ToString();
}
}
}

View File

@ -0,0 +1,164 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using dnlib.DotNet;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class Csvm {
IDeobfuscatorContext deobfuscatorContext;
ModuleDefMD module;
EmbeddedResource resource;
AssemblyRef vmAssemblyRef;
public bool Detected {
get { return resource != null && vmAssemblyRef != null; }
}
public EmbeddedResource Resource {
get { return Detected ? resource : null; }
}
public Csvm(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module) {
this.deobfuscatorContext = deobfuscatorContext;
this.module = module;
}
public Csvm(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module, Csvm oldOne) {
this.deobfuscatorContext = deobfuscatorContext;
this.module = module;
if (oldOne.resource != null)
this.resource = (EmbeddedResource)module.Resources[oldOne.module.Resources.IndexOf(oldOne.resource)];
if (oldOne.vmAssemblyRef != null)
this.vmAssemblyRef = module.ResolveAssemblyRef(oldOne.vmAssemblyRef.Rid);
}
public void Find() {
resource = FindCsvmResource();
vmAssemblyRef = FindVmAssemblyRef();
}
AssemblyRef FindVmAssemblyRef() {
foreach (var memberRef in module.GetMemberRefs()) {
var sig = memberRef.MethodSig;
if (sig == null)
continue;
if (sig.RetType.GetElementType() != ElementType.Object)
continue;
if (sig.Params.Count != 2)
continue;
if (memberRef.Name != "RunMethod")
continue;
if (memberRef.FullName == "System.Object VMRuntime.Libraries.CSVMRuntime::RunMethod(System.String,System.Object[])")
return memberRef.DeclaringType.Scope as AssemblyRef;
}
return null;
}
EmbeddedResource FindCsvmResource() {
return DotNetUtils.GetResource(module, "_CSVM") as EmbeddedResource;
}
public bool Restore() {
if (!Detected)
return true;
int oldIndent = Logger.Instance.IndentLevel;
try {
Restore2();
return true;
}
catch {
return false;
}
finally {
Logger.Instance.IndentLevel = oldIndent;
}
}
void Restore2() {
Logger.n("Restoring CSVM methods");
Logger.Instance.Indent();
var opcodeDetector = GetVmOpCodeHandlerDetector();
var csvmMethods = new CsvmDataReader(resource.Data).Read();
var converter = new CsvmToCilMethodConverter(deobfuscatorContext, module, opcodeDetector);
var methodPrinter = new MethodPrinter();
foreach (var csvmMethod in csvmMethods) {
var cilMethod = module.ResolveToken(csvmMethod.Token) as MethodDef;
if (cilMethod == null)
throw new ApplicationException(string.Format("Could not find method {0:X8}", csvmMethod.Token));
converter.Convert(cilMethod, csvmMethod);
Logger.v("Restored method {0:X8}", cilMethod.MDToken.ToInt32());
PrintMethod(methodPrinter, cilMethod);
}
Logger.Instance.DeIndent();
Logger.n("Restored {0} CSVM methods", csvmMethods.Count);
}
static void PrintMethod(MethodPrinter methodPrinter, MethodDef method) {
const LoggerEvent dumpLogLevel = LoggerEvent.Verbose;
if (Logger.Instance.IgnoresEvent(dumpLogLevel))
return;
Logger.Instance.Indent();
Logger.v("Locals:");
Logger.Instance.Indent();
for (int i = 0; i < method.Body.Variables.Count; i++)
Logger.v("#{0}: {1}", i, method.Body.Variables[i].Type);
Logger.Instance.DeIndent();
Logger.v("Code:");
Logger.Instance.Indent();
methodPrinter.Print(dumpLogLevel, method.Body.Instructions, method.Body.ExceptionHandlers);
Logger.Instance.DeIndent();
Logger.Instance.DeIndent();
}
VmOpCodeHandlerDetector GetVmOpCodeHandlerDetector() {
var vmFilename = vmAssemblyRef.Name + ".dll";
var vmModulePath = Path.Combine(Path.GetDirectoryName(module.Location), vmFilename);
Logger.v("CSVM filename: {0}", vmFilename);
var dataKey = "cs cached VmOpCodeHandlerDetector v2";
var dict = (Dictionary<string, VmOpCodeHandlerDetector>)deobfuscatorContext.GetData(dataKey);
if (dict == null)
deobfuscatorContext.SetData(dataKey, dict = new Dictionary<string, VmOpCodeHandlerDetector>(StringComparer.OrdinalIgnoreCase));
VmOpCodeHandlerDetector detector;
if (dict.TryGetValue(vmModulePath, out detector))
return detector;
dict[vmModulePath] = detector = new VmOpCodeHandlerDetector(ModuleDefMD.Load(vmModulePath));
detector.FindHandlers();
Logger.v("CSVM opcodes: {0}", detector.Handlers.Count);
Logger.Instance.Indent();
for (int i = 0; i < detector.Handlers.Count; i++)
Logger.v("{0:X4}: {1}", i, detector.Handlers[i]);
Logger.Instance.DeIndent();
return detector;
}
}
}

View File

@ -0,0 +1,779 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class CsvmInfo {
ModuleDef module;
public TypeDef VmHandlerBaseType;
public MethodDef LogicalOpShrUn;
public MethodDef LogicalOpShl;
public MethodDef LogicalOpShr;
public MethodDef LogicalOpAnd;
public MethodDef LogicalOpXor;
public MethodDef LogicalOpOr;
public MethodDef CompareLt;
public MethodDef CompareLte;
public MethodDef CompareGt;
public MethodDef CompareGte;
public MethodDef CompareEq;
public MethodDef CompareEqz;
public MethodDef ArithmeticSubOvfUn;
public MethodDef ArithmeticMulOvfUn;
public MethodDef ArithmeticRemUn;
public MethodDef ArithmeticRem;
public MethodDef ArithmeticDivUn;
public MethodDef ArithmeticDiv;
public MethodDef ArithmeticMul;
public MethodDef ArithmeticMulOvf;
public MethodDef ArithmeticSub;
public MethodDef ArithmeticSubOvf;
public MethodDef ArithmeticAddOvfUn;
public MethodDef ArithmeticAddOvf;
public MethodDef ArithmeticAdd;
public MethodDef UnaryNot;
public MethodDef UnaryNeg;
public MethodDef ArgsGet;
public MethodDef ArgsSet;
public MethodDef LocalsGet;
public MethodDef LocalsSet;
public CsvmInfo(ModuleDef module) {
this.module = module;
}
public bool Initialize() {
return FindVmHandlerBase() &&
FindLocalOpsMethods() &&
FindComparerMethods() &&
FindArithmeticMethods() &&
FindUnaryOpsMethods() &&
FindArgsLocals();
}
public bool FindVmHandlerBase() {
foreach (var type in module.Types) {
if (!type.IsPublic || !type.IsAbstract)
continue;
if (type.HasFields || type.HasProperties || type.HasEvents)
continue;
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
continue;
if (CountVirtual(type) != 2)
continue;
VmHandlerBaseType = type;
return true;
}
return false;
}
public bool FindLocalOpsMethods() {
foreach (var type in module.Types) {
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
continue;
if (type.Methods.Count != 6 && type.Methods.Count != 7)
continue;
LogicalOpShrUn = FindLogicalOpMethodShrUn(type);
if (LogicalOpShrUn == null)
continue;
LogicalOpShl = FindLogicalOpMethodShl(type);
LogicalOpShr = FindLogicalOpMethodShr(type);
LogicalOpAnd = FindLogicalOpMethodAnd(type);
LogicalOpXor = FindLogicalOpMethodXor(type);
LogicalOpOr = FindLogicalOpMethodOr(type);
if (LogicalOpShrUn != null && LogicalOpShl != null &&
LogicalOpShr != null && LogicalOpAnd != null &&
LogicalOpXor != null && LogicalOpOr != null)
return true;
}
return false;
}
MethodDef FindLogicalOpMethodShrUn(TypeDef type) {
return FindLogicalOpMethod(type, ElementType.U4, ElementType.I4, ElementType.U4, Code.Shr_Un);
}
MethodDef FindLogicalOpMethodShl(TypeDef type) {
return FindLogicalOpMethod(type, ElementType.I4, ElementType.I4, ElementType.I4, Code.Shl);
}
MethodDef FindLogicalOpMethodShr(TypeDef type) {
return FindLogicalOpMethod(type, ElementType.I4, ElementType.I4, ElementType.I4, Code.Shr);
}
MethodDef FindLogicalOpMethod(TypeDef type, ElementType e1, ElementType e2, ElementType e3, Code code) {
foreach (var method in type.Methods) {
if (!CheckLogicalMethodSig(method))
continue;
if (method.Body == null)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 7; i++) {
var ldarg0 = instrs[i];
if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[i + 1], e1))
continue;
var ldarg1 = instrs[i + 2];
if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
continue;
if (!CheckUnboxAny(instrs[i + 3], e2))
continue;
var ldci4 = instrs[i + 4];
if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 0x1F)
continue;
if (instrs[i + 5].OpCode.Code != Code.And)
continue;
if (instrs[i + 6].OpCode.Code != code)
continue;
if (!CheckBox(instrs[i + 7], e3))
continue;
return method;
}
}
return null;
}
MethodDef FindLogicalOpMethodAnd(TypeDef type) {
return FindLogicalOpMethod(type, Code.And);
}
MethodDef FindLogicalOpMethodXor(TypeDef type) {
return FindLogicalOpMethod(type, Code.Xor);
}
MethodDef FindLogicalOpMethodOr(TypeDef type) {
return FindLogicalOpMethod(type, Code.Or);
}
MethodDef FindLogicalOpMethod(TypeDef type, Code code) {
foreach (var method in type.Methods) {
if (!CheckLogicalMethodSig(method))
continue;
if (method.Body == null)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 5; i++) {
var ldarg0 = instrs[i];
if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
continue;
var ldarg1 = instrs[i + 2];
if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
continue;
if (!CheckUnboxAny(instrs[i + 3], ElementType.I4))
continue;
if (instrs[i + 4].OpCode.Code != code)
continue;
if (!CheckBox(instrs[i + 5], ElementType.I4))
continue;
return method;
}
}
return null;
}
static bool CheckLogicalMethodSig(MethodDef method) {
return method != null &&
method.IsStatic &&
method.MethodSig.GetParamCount() == 2 &&
method.MethodSig.RetType.GetElementType() == ElementType.Object &&
method.MethodSig.Params[0].GetElementType() == ElementType.Object &&
method.MethodSig.Params[1].GetElementType() == ElementType.Object;
}
public bool FindComparerMethods() {
foreach (var type in module.Types) {
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
continue;
if (type.Methods.Count != 9)
continue;
CompareLt = FindCompareLt(type);
if (CompareLt == null)
continue;
CompareLte = FindCompareLte(type);
CompareGt = FindCompareGt(type);
CompareGte = FindCompareGte(type);
CompareEq = FindCompareEq(type);
CompareEqz = FindCompareEqz(type);
if (CompareLt != null && CompareLte != null &&
CompareGt != null && CompareGte != null &&
CompareEq != null && CompareEqz != null)
return true;
}
return false;
}
MethodDef FindCompareLt(TypeDef type) {
return FindCompareMethod(type, Code.Clt, false);
}
MethodDef FindCompareLte(TypeDef type) {
return FindCompareMethod(type, Code.Cgt, true);
}
MethodDef FindCompareGt(TypeDef type) {
return FindCompareMethod(type, Code.Cgt, false);
}
MethodDef FindCompareGte(TypeDef type) {
return FindCompareMethod(type, Code.Clt, true);
}
MethodDef FindCompareMethod(TypeDef type, Code code, bool invert) {
foreach (var method in type.Methods) {
if (!CheckCompareMethodSig(method))
continue;
if (method.Body == null)
continue;
var instrs = method.Body.Instructions;
int end = instrs.Count - 6;
if (invert)
end -= 2;
for (int i = 0; i < end; i++) {
int index = i;
var ldarg0 = instrs[index++];
if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[index++], ElementType.I4))
continue;
var ldarg1 = instrs[index++];
if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
continue;
if (!CheckUnboxAny(instrs[index++], ElementType.I4))
continue;
if (instrs[index++].OpCode.Code != code)
continue;
if (invert) {
var ldci4 = instrs[index++];
if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 0)
continue;
if (instrs[index++].OpCode.Code != Code.Ceq)
continue;
}
if (!instrs[index++].IsStloc())
continue;
return method;
}
}
return null;
}
static bool CheckCompareMethodSig(MethodDef method) {
if (method == null || !method.IsStatic)
return false;
var sig = method.MethodSig;
if (sig == null || sig.GetParamCount() != 3)
return false;
if (sig.RetType.GetElementType() != ElementType.Boolean)
return false;
if (sig.Params[0].GetElementType() != ElementType.Object)
return false;
if (sig.Params[1].GetElementType() != ElementType.Object)
return false;
var arg2 = sig.Params[2] as ValueTypeSig;
if (arg2 == null || arg2.TypeDef == null || !arg2.TypeDef.IsEnum)
return false;
return true;
}
MethodDef FindCompareEq(TypeDef type) {
foreach (var method in type.Methods) {
if (!CheckCompareEqMethodSig(method))
continue;
if (method.Body == null)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 5; i++) {
var ldarg0 = instrs[i];
if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
continue;
var ldarg1 = instrs[i + 2];
if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
continue;
if (!CheckUnboxAny(instrs[i + 3], ElementType.I4))
continue;
if (instrs[i + 4].OpCode.Code != Code.Ceq)
continue;
if (!instrs[i + 5].IsStloc())
continue;
return method;
}
}
return null;
}
static bool CheckCompareEqMethodSig(MethodDef method) {
return method != null &&
method.IsStatic &&
method.MethodSig.GetParamCount() == 2 &&
method.MethodSig.RetType.GetElementType() == ElementType.Boolean &&
method.MethodSig.Params[0].GetElementType() == ElementType.Object &&
method.MethodSig.Params[1].GetElementType() == ElementType.Object;
}
MethodDef FindCompareEqz(TypeDef type) {
foreach (var method in type.Methods) {
if (!CheckCompareEqzMethodSig(method))
continue;
if (method.Body == null)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 4; i++) {
var ldarg0 = instrs[i];
if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
continue;
var ldci4 = instrs[i + 2];
if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 0)
continue;
if (instrs[i + 3].OpCode.Code != Code.Ceq)
continue;
if (!instrs[i + 4].IsStloc())
continue;
return method;
}
}
return null;
}
static bool CheckCompareEqzMethodSig(MethodDef method) {
return method != null &&
method.IsStatic &&
method.MethodSig.GetParamCount() == 1 &&
method.MethodSig.RetType.GetElementType() == ElementType.Boolean &&
method.MethodSig.Params[0].GetElementType() == ElementType.Object;
}
public bool FindArithmeticMethods() {
foreach (var type in module.Types) {
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
continue;
if (type.Methods.Count != 15)
continue;
ArithmeticSubOvfUn = FindArithmeticSubOvfUn(type);
if (ArithmeticSubOvfUn == null)
continue;
ArithmeticMulOvfUn = FindArithmeticMulOvfUn(type);
ArithmeticRemUn = FindArithmeticRemUn(type);
ArithmeticRem = FindArithmeticRem(type);
ArithmeticDivUn = FindArithmeticDivUn(type);
ArithmeticDiv = FindArithmeticDiv(type);
ArithmeticMul = FindArithmeticMul(type);
ArithmeticMulOvf = FindArithmeticMulOvf(type);
ArithmeticSub = FindArithmeticSub(type);
ArithmeticSubOvf = FindArithmeticSubOvf(type);
ArithmeticAddOvfUn = FindArithmeticAddOvfUn(type);
ArithmeticAddOvf = FindArithmeticAddOvf(type);
ArithmeticAdd = FindArithmeticAdd(type);
if (ArithmeticSubOvfUn != null && ArithmeticMulOvfUn != null &&
ArithmeticRemUn != null && ArithmeticRem != null &&
ArithmeticDivUn != null && ArithmeticDiv != null &&
ArithmeticMul != null && ArithmeticMulOvf != null &&
ArithmeticSub != null && ArithmeticSubOvf != null &&
ArithmeticAddOvfUn != null && ArithmeticAddOvf != null &&
ArithmeticAdd != null)
return true;
}
return false;
}
MethodDef FindArithmeticSubOvfUn(TypeDef type) {
return FindArithmeticOpUn(type, Code.Sub_Ovf_Un);
}
MethodDef FindArithmeticMulOvfUn(TypeDef type) {
return FindArithmeticOpUn(type, Code.Mul_Ovf_Un);
}
MethodDef FindArithmeticAddOvfUn(TypeDef type) {
return FindArithmeticOpUn(type, Code.Add_Ovf_Un);
}
MethodDef FindArithmeticOpUn(TypeDef type, Code code) {
foreach (var method in type.Methods) {
if (!CheckArithmeticUnMethodSig(method))
continue;
if (method.Body == null)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 8; i++) {
var ldarg0 = instrs[i];
if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
continue;
if (!CheckCallvirt(instrs[i + 1], "System.Int32", "()"))
continue;
if (instrs[i + 2].OpCode.Code != Code.Conv_Ovf_U4)
continue;
var ldarg1 = instrs[i + 3];
if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
continue;
if (!CheckCallvirt(instrs[i + 4], "System.Int32", "()"))
continue;
if (instrs[i + 5].OpCode.Code != Code.Conv_Ovf_U4)
continue;
if (instrs[i + 6].OpCode.Code != code)
continue;
if (!CheckBox(instrs[i + 7], ElementType.U4))
continue;
if (!instrs[i + 8].IsStloc())
continue;
return method;
}
}
return null;
}
static bool CheckArithmeticUnMethodSig(MethodDef method) {
return method != null &&
method.IsStatic &&
method.MethodSig.GetParamCount() == 2 &&
method.MethodSig.RetType.GetElementType() == ElementType.Object &&
method.MethodSig.Params[0].GetElementType() == ElementType.Class &&
method.MethodSig.Params[1].GetElementType() == ElementType.Class;
}
MethodDef FindArithmeticRemUn(TypeDef type) {
return FindArithmeticDivOrRemUn(type, Code.Rem_Un);
}
MethodDef FindArithmeticDivUn(TypeDef type) {
return FindArithmeticDivOrRemUn(type, Code.Div_Un);
}
MethodDef FindArithmeticDivOrRemUn(TypeDef type, Code code) {
foreach (var method in type.Methods) {
if (!CheckArithmeticUnMethodSig(method))
continue;
if (method.Body == null)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 7; i++) {
var ldarg0 = instrs[i];
if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
continue;
if (!CheckCallvirt(instrs[i + 1], "System.Int32", "()"))
continue;
var ldarg1 = instrs[i + 2];
if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
continue;
if (!CheckCallvirt(instrs[i + 3], "System.Int32", "()"))
continue;
if (instrs[i + 4].OpCode.Code != code)
continue;
if (!CheckBox(instrs[i + 5], ElementType.U4))
continue;
if (!instrs[i + 6].IsStloc())
continue;
return method;
}
}
return null;
}
MethodDef FindArithmeticRem(TypeDef type) {
return FindArithmeticOther(type, Code.Rem);
}
MethodDef FindArithmeticDiv(TypeDef type) {
return FindArithmeticOther(type, Code.Div);
}
MethodDef FindArithmeticMul(TypeDef type) {
return FindArithmeticOther(type, Code.Mul);
}
MethodDef FindArithmeticMulOvf(TypeDef type) {
return FindArithmeticOther(type, Code.Mul_Ovf);
}
MethodDef FindArithmeticSub(TypeDef type) {
return FindArithmeticOther(type, Code.Sub);
}
MethodDef FindArithmeticSubOvf(TypeDef type) {
return FindArithmeticOther(type, Code.Sub_Ovf);
}
MethodDef FindArithmeticAdd(TypeDef type) {
return FindArithmeticOther(type, Code.Add);
}
MethodDef FindArithmeticAddOvf(TypeDef type) {
return FindArithmeticOther(type, Code.Add_Ovf);
}
MethodDef FindArithmeticOther(TypeDef type, Code code) {
foreach (var method in type.Methods) {
if (!CheckArithmeticOtherMethodSig(method))
continue;
if (method.Body == null)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 6; i++) {
var ldarg0 = instrs[i];
if (!ldarg0.IsLdarg() || ldarg0.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
continue;
var ldarg1 = instrs[i + 2];
if (!ldarg1.IsLdarg() || ldarg1.GetParameterIndex() != 1)
continue;
if (!CheckUnboxAny(instrs[i + 3], ElementType.I4))
continue;
if (instrs[i + 4].OpCode.Code != code)
continue;
if (!CheckBox(instrs[i + 5], ElementType.I4))
continue;
return method;
}
}
return null;
}
static bool CheckArithmeticOtherMethodSig(MethodDef method) {
return method != null &&
method.IsStatic &&
method.MethodSig.GetParamCount() == 2 &&
method.MethodSig.RetType.GetElementType() == ElementType.Object &&
method.MethodSig.Params[0].GetElementType() == ElementType.Object &&
method.MethodSig.Params[1].GetElementType() == ElementType.Object;
}
public bool FindUnaryOpsMethods() {
UnaryNot = FindUnaryOpMethod(Code.Not);
UnaryNeg = FindUnaryOpMethod(Code.Neg);
return UnaryNot != null && UnaryNeg != null;
}
MethodDef FindUnaryOpMethod(Code code) {
foreach (var type in module.Types) {
if (type.BaseType != VmHandlerBaseType)
continue;
if (type.Methods.Count != 4)
continue;
foreach (var method in type.Methods) {
if (!method.HasBody || !method.IsStatic)
continue;
if (!DotNetUtils.IsMethod(method, "System.Object", "(System.Object)"))
continue;
if (CountThrows(method) != 1)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 4; i++) {
var ldarg = instrs[i];
if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
continue;
if (instrs[i + 2].OpCode.Code != code)
continue;
if (!CheckBox(instrs[i + 3], ElementType.I4))
continue;
if (!instrs[i + 4].IsStloc())
continue;
return method;
}
}
}
return null;
}
static int CountThrows(MethodDef method) {
if (method == null || method.Body == null)
return 0;
int count = 0;
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code == Code.Throw)
count++;
}
return count;
}
public bool FindArgsLocals() {
var vmState = FindVmState();
if (vmState == null)
return false;
var ctor = vmState.FindMethod(".ctor");
return FindArgsLocals(ctor, 1, out ArgsGet, out ArgsSet) &&
FindArgsLocals(ctor, 2, out LocalsGet, out LocalsSet);
}
TypeDef FindVmState() {
if (VmHandlerBaseType == null)
return null;
foreach (var method in VmHandlerBaseType.Methods) {
if (method.IsStatic || !method.IsAbstract)
continue;
if (method.Parameters.Count != 2)
continue;
var arg1 = method.Parameters[1].Type.TryGetTypeDef();
if (arg1 == null)
continue;
return arg1;
}
return null;
}
static bool FindArgsLocals(MethodDef ctor, int arg, out MethodDef getter, out MethodDef setter) {
getter = null;
setter = null;
if (ctor == null || !ctor.HasBody)
return false;
setter = FindSetter(ctor, arg);
if (setter == null)
return false;
var propField = GetPropField(setter);
if (propField == null)
return false;
getter = FindGetter(ctor.DeclaringType, propField);
return getter != null;
}
static MethodDef FindSetter(MethodDef ctor, int arg) {
if (ctor == null || !ctor.HasBody)
return null;
var instrs = ctor.Body.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
var ldarg = instrs[i];
if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != arg)
continue;
var call = instrs[i + 1];
if (call.OpCode.Code != Code.Call)
continue;
var method = call.Operand as MethodDef;
if (method == null)
continue;
if (method.DeclaringType != ctor.DeclaringType)
continue;
return method;
}
return null;
}
static FieldDef GetPropField(MethodDef method) {
if (method == null || !method.HasBody)
return null;
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code != Code.Stfld)
continue;
var field = instr.Operand as FieldDef;
if (field == null || field.DeclaringType != method.DeclaringType)
continue;
return field;
}
return null;
}
static MethodDef FindGetter(TypeDef type, FieldDef propField) {
foreach (var method in type.Methods) {
if (method.IsStatic || !method.HasBody)
continue;
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code != Code.Ldfld)
continue;
if (instr.Operand != propField)
continue;
return method;
}
}
return null;
}
static bool CheckCallvirt(Instruction instr, string returnType, string parameters) {
if (instr.OpCode.Code != Code.Callvirt)
return false;
return DotNetUtils.IsMethod(instr.Operand as IMethod, returnType, parameters);
}
bool CheckUnboxAny(Instruction instr, ElementType expectedType) {
if (instr == null || instr.OpCode.Code != Code.Unbox_Any)
return false;
var typeSig = module.CorLibTypes.GetCorLibTypeSig(instr.Operand as ITypeDefOrRef);
return typeSig.GetElementType() == expectedType;
}
bool CheckBox(Instruction instr, ElementType expectedType) {
if (instr == null || instr.OpCode.Code != Code.Box)
return false;
var typeSig = module.CorLibTypes.GetCorLibTypeSig(instr.Operand as ITypeDefOrRef);
return typeSig.GetElementType() == expectedType;
}
static int CountVirtual(TypeDef type) {
int count = 0;
foreach (var method in type.Methods) {
if (method.IsVirtual)
count++;
}
return count;
}
}
}

View File

@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18052
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CsvmResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal CsvmResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("de4dot.code.deobfuscators.Agile_NET.vm.v2.CsvmResources", typeof(CsvmResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM1_v2 {
get {
object obj = ResourceManager.GetObject("CSVM1_v2", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM2_v2 {
get {
object obj = ResourceManager.GetObject("CSVM2_v2", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM3_v2 {
get {
object obj = ResourceManager.GetObject("CSVM3_v2", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="CSVM1_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM1_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CSVM2_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM2_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CSVM3_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM3_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

View File

@ -0,0 +1,64 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class CsvmToCilMethodConverter : CsvmToCilMethodConverterBase {
VmOpCodeHandlerDetector opCodeDetector;
public CsvmToCilMethodConverter(IDeobfuscatorContext deobfuscatorContext, ModuleDefMD module, VmOpCodeHandlerDetector opCodeDetector)
: base(deobfuscatorContext, module) {
this.opCodeDetector = opCodeDetector;
}
protected override List<Instruction> ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
var instrs = new List<Instruction>();
var handlerInfoReader = new OpCodeHandlerInfoReader(module);
int numVmInstrs = reader.ReadInt32();
var vmInstrs = new ushort[numVmInstrs];
for (int i = 0; i < numVmInstrs; i++)
vmInstrs[i] = reader.ReadUInt16();
uint offset = 0;
for (int vmInstrIndex = 0; vmInstrIndex < numVmInstrs; vmInstrIndex++) {
var composite = opCodeDetector.Handlers[vmInstrs[vmInstrIndex]];
var handlerInfos = composite.OpCodeHandlerInfos;
if (handlerInfos.Count == 0)
handlerInfos = new List<OpCodeHandlerInfo>() { new OpCodeHandlerInfo(HandlerTypeCode.Nop, null) };
for (int hi = 0; hi < handlerInfos.Count; hi++) {
var instr = handlerInfoReader.Read(handlerInfos[hi].TypeCode, reader);
instr.Offset = offset;
offset += (uint)GetInstructionSize(instr);
SetCilToVmIndex(instr, vmInstrIndex);
if (hi == 0)
SetVmIndexToCil(instr, vmInstrIndex);
instrs.Add(instr);
}
}
return instrs;
}
}
}

View File

@ -0,0 +1,102 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
// These constants are hard coded. Don't change the values (i.e., only append if more are needed)
enum HandlerTypeCode {
Add,
Add_Ovf,
Add_Ovf_Un,
And,
Beq,
Bge,
Bge_Un,
Bgt,
Bgt_Un,
Ble,
Ble_Un,
Blt,
Blt_Un,
Bne_Un,
Box,
Br,
Brfalse,
Brtrue,
Call,
Callvirt,
Castclass,
Ceq,
Cgt,
Cgt_Un,
Clt,
Clt_Un,
Conv,
Div,
Div_Un,
Dup,
Endfinally,
Initobj,
Isinst,
Ldarg,
Ldarga,
Ldc,
Ldelem,
Ldelema,
Ldfld_Ldsfld,
Ldflda_Ldsflda,
Ldftn,
Ldlen,
Ldloc,
Ldloca,
Ldobj,
Ldstr,
Ldtoken,
Ldvirtftn,
Leave,
Mul,
Mul_Ovf,
Mul_Ovf_Un,
Neg,
Newarr,
Newobj,
Nop,
Not,
Or,
Pop,
Rem,
Rem_Un,
Ret,
Rethrow,
Shl,
Shr,
Shr_Un,
Starg,
Stelem,
Stfld_Stsfld,
Stloc,
Stobj,
Sub,
Sub_Ovf,
Sub_Ovf_Un,
Switch,
Throw,
Unbox_Any,
Xor,
}
}

View File

@ -0,0 +1,109 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class MethodFinder {
readonly IList<OpCodeHandlerInfo> handlerInfos;
readonly PrimitiveHandlerMethod handlerMethod;
class SigState {
public readonly MethodSigInfo SigInfo;
public SigState(PrimitiveHandlerMethod handlerMethod) {
this.SigInfo = handlerMethod.Sig;
}
}
public MethodFinder(IList<OpCodeHandlerInfo> handlerInfos, PrimitiveHandlerMethod handlerMethod) {
this.handlerInfos = handlerInfos;
this.handlerMethod = handlerMethod;
}
public OpCodeHandler FindHandler() {
var handler = FindHandler(new SigState(handlerMethod));
if (handler == null)
return null;
return new OpCodeHandler(handler, handlerMethod.Method.DeclaringType, handlerMethod);
}
OpCodeHandlerInfo FindHandler(SigState execSigState) {
foreach (var handler in handlerInfos) {
if (Matches(handler.ExecSig, execSigState))
return handler;
}
return null;
}
struct MatchInfo {
public int HandlerIndex;
public int SigIndex;
public MatchInfo(int handlerIndex, int sigIndex) {
this.HandlerIndex = handlerIndex;
this.SigIndex = sigIndex;
}
}
Dictionary<int, int> sigIndexToHandlerIndex = new Dictionary<int, int>();
Dictionary<int, int> handlerIndexToSigIndex = new Dictionary<int, int>();
Stack<MatchInfo> stack = new Stack<MatchInfo>();
bool Matches(MethodSigInfo handlerSig, SigState sigState) {
stack.Clear();
sigIndexToHandlerIndex.Clear();
handlerIndexToSigIndex.Clear();
var handlerInfos = handlerSig.BlockInfos;
var sigInfos = sigState.SigInfo.BlockInfos;
stack.Push(new MatchInfo(0, 0));
while (stack.Count > 0) {
var info = stack.Pop();
int handlerIndex, sigIndex;
bool hasVisitedHandler = handlerIndexToSigIndex.TryGetValue(info.HandlerIndex, out sigIndex);
bool hasVisitedSig = sigIndexToHandlerIndex.TryGetValue(info.SigIndex, out handlerIndex);
if (hasVisitedHandler != hasVisitedSig)
return false;
if (hasVisitedHandler) {
if (handlerIndex != info.HandlerIndex || sigIndex != info.SigIndex)
return false;
continue;
}
handlerIndexToSigIndex[info.HandlerIndex] = info.SigIndex;
sigIndexToHandlerIndex[info.SigIndex] = info.HandlerIndex;
var handlerBlock = handlerInfos[info.HandlerIndex];
var sigBlock = sigInfos[info.SigIndex];
if (!handlerBlock.Equals(sigBlock))
return false;
for (int i = 0; i < handlerBlock.Targets.Count; i++) {
int handlerTargetIndex = handlerBlock.Targets[i];
int sigTargetIndex = sigBlock.Targets[i];
stack.Push(new MatchInfo(handlerTargetIndex, sigTargetIndex));
}
}
return true;
}
}
}

View File

@ -0,0 +1,737 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.MD;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class MethodSigInfo {
readonly List<BlockInfo> blockInfos;
public List<BlockInfo> BlockInfos {
get { return blockInfos; }
}
public MethodSigInfo() {
this.blockInfos = new List<BlockInfo>();
}
public MethodSigInfo(IEnumerable<BlockInfo> blockInfos) {
this.blockInfos = new List<BlockInfo>(blockInfos);
}
}
class BlockInfo : IEquatable<BlockInfo> {
readonly List<int> targets;
public byte[] Hash { get; set; }
public List<int> Targets {
get { return targets; }
}
public BlockInfo() {
this.targets = new List<int>();
}
public BlockInfo(byte[] hash, IEnumerable<int> targets) {
this.Hash = hash;
this.targets = new List<int>(targets);
}
public override string ToString() {
if (Hash == null)
return "<null>";
return BitConverter.ToString(Hash).Replace("-", string.Empty);
}
public bool Equals(BlockInfo other) {
return Equals(Hash, other.Hash) &&
Targets.Count == other.Targets.Count;
}
bool Equals(byte[] a, byte[] b) {
if (a == b)
return true;
if (a == null || b == null)
return false;
if (a.Length != b.Length)
return false;
for (int i = 0; i < a.Length; i++) {
if (a[i] != b[i])
return false;
}
return true;
}
}
class MethodSigInfoCreator {
MethodSigInfo methodSigInfo;
Blocks blocks;
IList<Block> allBlocks;
Dictionary<Block, BlockInfo> blockToInfo;
Dictionary<object, int> methodToId = new Dictionary<object, int>();
public void AddId(object key, int id) {
if (key != null)
methodToId[key] = id;
}
int GetId(object key) {
if (key == null)
return int.MinValue;
int id;
if (methodToId.TryGetValue(key, out id))
return id;
return int.MinValue + 1;
}
public MethodSigInfo Create(Blocks blocks) {
methodSigInfo = new MethodSigInfo();
this.blocks = blocks;
allBlocks = blocks.MethodBlocks.GetAllBlocks();
blockToInfo = new Dictionary<Block, BlockInfo>();
foreach (var block in allBlocks) {
var blockInfo = new BlockInfo();
blockToInfo[block] = blockInfo;
methodSigInfo.BlockInfos.Add(blockInfo);
}
foreach (var block in allBlocks) {
var blockInfo = blockToInfo[block];
Update(blockInfo, block);
if (block.FallThrough != null)
blockInfo.Targets.Add(allBlocks.IndexOf(block.FallThrough));
if (block.Targets != null) {
foreach (var target in block.Targets)
blockInfo.Targets.Add(allBlocks.IndexOf(target));
}
}
return methodSigInfo;
}
void Update(BlockInfo blockInfo, Block block) {
using (var hasher = MD5.Create()) {
bool emptyHash;
using (var outStream = new NullStream()) {
using (var csStream = new CryptoStream(outStream, hasher, CryptoStreamMode.Write)) {
var writer = new BinaryWriter(csStream);
Update(writer, blockInfo, block);
}
emptyHash = outStream.Length == 0;
}
if (!emptyHash)
blockInfo.Hash = hasher.Hash;
}
}
void Update(BinaryWriter writer, BlockInfo blockInfo, Block block) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
switch (instr.OpCode.Code) {
case Code.Beq_S:
case Code.Bge_S:
case Code.Bgt_S:
case Code.Ble_S:
case Code.Blt_S:
case Code.Bne_Un_S:
case Code.Bge_Un_S:
case Code.Bgt_Un_S:
case Code.Ble_Un_S:
case Code.Blt_Un_S:
case Code.Brfalse_S:
case Code.Brtrue_S:
case Code.Leave_S:
case Code.Beq:
case Code.Bge:
case Code.Bgt:
case Code.Ble:
case Code.Blt:
case Code.Bne_Un:
case Code.Bge_Un:
case Code.Bgt_Un:
case Code.Ble_Un:
case Code.Blt_Un:
case Code.Brfalse:
case Code.Brtrue:
case Code.Leave:
writer.Write((ushort)SimplifyBranch(instr.OpCode.Code));
break;
case Code.Switch:
writer.Write((ushort)instr.OpCode.Code);
writer.Write(blockInfo.Targets.Count);
break;
case Code.Br_S:
case Code.Br:
break;
case Code.Ret:
break;
case Code.Ldc_I4_M1:
case Code.Ldc_I4_0:
case Code.Ldc_I4_1:
case Code.Ldc_I4_2:
case Code.Ldc_I4_3:
case Code.Ldc_I4_4:
case Code.Ldc_I4_5:
case Code.Ldc_I4_6:
case Code.Ldc_I4_7:
case Code.Ldc_I4_8:
case Code.Ldc_I4:
case Code.Ldc_I4_S:
writer.Write((ushort)Code.Ldc_I4);
writer.Write(instr.GetLdcI4Value());
break;
case Code.Ldc_I8:
writer.Write((ushort)instr.OpCode.Code);
writer.Write((long)instr.Operand);
break;
case Code.Ldc_R4:
writer.Write((ushort)instr.OpCode.Code);
writer.Write((float)instr.Operand);
break;
case Code.Ldc_R8:
writer.Write((ushort)instr.OpCode.Code);
writer.Write((double)instr.Operand);
break;
case Code.Ldfld:
var typeField = instr.Operand as FieldDef;
bool isField = IsTypeField(typeField);
writer.Write((ushort)instr.OpCode.Code);
writer.Write(isField);
if (isField) {
if (i + 1 < instrs.Count && instrs[i + 1].IsLdcI4())
i++;
writer.Write(GetFieldId(typeField));
}
else
Write(writer, instr.Operand);
break;
case Code.Call:
case Code.Callvirt:
case Code.Newobj:
case Code.Jmp:
case Code.Ldftn:
case Code.Ldvirtftn:
case Code.Ldtoken:
case Code.Stfld:
case Code.Ldsfld:
case Code.Stsfld:
case Code.Ldflda:
case Code.Ldsflda:
case Code.Cpobj:
case Code.Ldobj:
case Code.Castclass:
case Code.Isinst:
case Code.Unbox:
case Code.Stobj:
case Code.Box:
case Code.Newarr:
case Code.Ldelema:
case Code.Ldelem:
case Code.Stelem:
case Code.Unbox_Any:
case Code.Refanyval:
case Code.Mkrefany:
case Code.Initobj:
case Code.Constrained:
case Code.Sizeof:
writer.Write((ushort)instr.OpCode.Code);
Write(writer, instr.Operand);
break;
case Code.Ldstr:
writer.Write((ushort)instr.OpCode.Code);
break;
case Code.Ldarg:
case Code.Ldarg_S:
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
writer.Write((ushort)Code.Ldarg);
writer.Write(instr.Instruction.GetParameterIndex());
break;
case Code.Ldarga:
case Code.Ldarga_S:
writer.Write((ushort)Code.Ldarga);
writer.Write(instr.Instruction.GetParameterIndex());
break;
case Code.Starg:
case Code.Starg_S:
writer.Write((ushort)Code.Starg);
writer.Write(instr.Instruction.GetParameterIndex());
break;
case Code.Ldloc:
case Code.Ldloc_S:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
writer.Write((ushort)Code.Ldloc);
break;
case Code.Ldloca:
case Code.Ldloca_S:
writer.Write((ushort)Code.Ldloca);
break;
case Code.Stloc:
case Code.Stloc_S:
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
writer.Write((ushort)Code.Stloc);
break;
case Code.Ldnull:
case Code.Throw:
case Code.Rethrow:
case Code.Ldlen:
case Code.Ckfinite:
case Code.Arglist:
case Code.Localloc:
case Code.Volatile:
case Code.Tailcall:
case Code.Cpblk:
case Code.Initblk:
case Code.Refanytype:
case Code.Readonly:
case Code.Break:
case Code.Endfinally:
case Code.Endfilter:
writer.Write((ushort)instr.OpCode.Code);
break;
case Code.Calli:
writer.Write((ushort)instr.OpCode.Code);
Write(writer, instr.Operand);
break;
case Code.Unaligned:
writer.Write((ushort)instr.OpCode.Code);
writer.Write((byte)instr.Operand);
break;
default:
break;
}
}
}
void Write(BinaryWriter writer, object op) {
var fd = op as FieldDef;
if (fd != null) {
Write(writer, fd);
return;
}
var mr = op as MemberRef;
if (mr != null) {
Write(writer, mr);
return;
}
var md = op as MethodDef;
if (md != null) {
Write(writer, md);
return;
}
var ms = op as MethodSpec;
if (ms != null) {
Write(writer, ms);
return;
}
var td = op as TypeDef;
if (td != null) {
Write(writer, td);
return;
}
var tr = op as TypeRef;
if (tr != null) {
Write(writer, tr);
return;
}
var ts = op as TypeSpec;
if (ts != null) {
Write(writer, ts);
return;
}
var fsig = op as FieldSig;
if (fsig != null) {
Write(writer, fsig);
return;
}
var msig = op as MethodSig;
if (msig != null) {
Write(writer, msig);
return;
}
var gsig = op as GenericInstMethodSig;
if (gsig != null) {
Write(writer, gsig);
return;
}
var asmRef = op as AssemblyRef;
if (asmRef != null) {
Write(writer, asmRef);
return;
}
writer.Write((byte)ObjectType.Unknown);
}
enum ObjectType : byte {
// 00..3F = Table.XXX values.
Unknown = 0x40,
TypeSig = 0x41,
FieldSig = 0x42,
MethodSig = 0x43,
GenericInstMethodSig = 0x44,
}
void Write(BinaryWriter writer, TypeSig sig) {
Write(writer, sig, 0);
}
void Write(BinaryWriter writer, TypeSig sig, int level) {
if (level++ > 20)
return;
writer.Write((byte)ObjectType.TypeSig);
var etype = sig.GetElementType();
writer.Write((byte)etype);
switch (etype) {
case ElementType.Ptr:
case ElementType.ByRef:
case ElementType.SZArray:
case ElementType.Pinned:
Write(writer, sig.Next, level);
break;
case ElementType.Array:
var arySig = (ArraySig)sig;
writer.Write(arySig.Rank);
writer.Write(arySig.Sizes.Count);
writer.Write(arySig.LowerBounds.Count);
Write(writer, sig.Next, level);
break;
case ElementType.CModReqd:
case ElementType.CModOpt:
Write(writer, ((ModifierSig)sig).Modifier);
Write(writer, sig.Next, level);
break;
case ElementType.ValueArray:
writer.Write(((ValueArraySig)sig).Size);
Write(writer, sig.Next, level);
break;
case ElementType.Module:
writer.Write(((ModuleSig)sig).Index);
Write(writer, sig.Next, level);
break;
case ElementType.GenericInst:
var gis = (GenericInstSig)sig;
Write(writer, gis.GenericType, level);
foreach (var ga in gis.GenericArguments)
Write(writer, ga, level);
Write(writer, sig.Next, level);
break;
case ElementType.FnPtr:
Write(writer, ((FnPtrSig)sig).Signature);
break;
case ElementType.Var:
case ElementType.MVar:
writer.Write(((GenericSig)sig).Number);
break;
case ElementType.ValueType:
case ElementType.Class:
Write(writer, ((TypeDefOrRefSig)sig).TypeDefOrRef);
break;
case ElementType.End:
case ElementType.Void:
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
case ElementType.I8:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.String:
case ElementType.TypedByRef:
case ElementType.I:
case ElementType.U:
case ElementType.R:
case ElementType.Object:
case ElementType.Internal:
case ElementType.Sentinel:
default:
break;
}
}
void Write(BinaryWriter writer, FieldSig sig) {
writer.Write((byte)ObjectType.FieldSig);
writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention()));
Write(writer, sig.GetFieldType());
}
void Write(BinaryWriter writer, MethodSig sig) {
writer.Write((byte)ObjectType.MethodSig);
writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention()));
Write(writer, sig.GetRetType());
foreach (var p in sig.GetParams())
Write(writer, p);
writer.Write(sig.GetParamCount());
bool hasParamsAfterSentinel = sig.GetParamsAfterSentinel() != null;
writer.Write(hasParamsAfterSentinel);
if (hasParamsAfterSentinel) {
foreach (var p in sig.GetParamsAfterSentinel())
Write(writer, p);
}
}
void Write(BinaryWriter writer, GenericInstMethodSig sig) {
writer.Write((byte)ObjectType.GenericInstMethodSig);
writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention()));
foreach (var ga in sig.GetGenericArguments())
Write(writer, ga);
}
void Write(BinaryWriter writer, FieldDef fd) {
writer.Write((byte)Table.Field);
Write(writer, fd.DeclaringType);
var attrMask = FieldAttributes.Static | FieldAttributes.InitOnly |
FieldAttributes.Literal | FieldAttributes.SpecialName |
FieldAttributes.PinvokeImpl | FieldAttributes.RTSpecialName;
writer.Write((ushort)(fd == null ? 0 : fd.Attributes & attrMask));
Write(writer, fd == null ? null : fd.Signature);
}
void Write(BinaryWriter writer, MemberRef mr) {
writer.Write((byte)Table.MemberRef);
var parent = mr == null ? null : mr.Class;
Write(writer, parent);
bool canWriteName = IsFromNonObfuscatedAssembly(parent);
writer.Write(canWriteName);
if (canWriteName)
writer.Write(mr.Name);
Write(writer, mr == null ? null : mr.Signature);
}
void Write(BinaryWriter writer, MethodDef md) {
writer.Write((byte)Table.Method);
Write(writer, md.DeclaringType);
var attrMask1 = MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask |
MethodImplAttributes.ForwardRef | MethodImplAttributes.PreserveSig |
MethodImplAttributes.InternalCall;
writer.Write((ushort)(md == null ? 0 : md.ImplAttributes & attrMask1));
var attrMask2 = MethodAttributes.Static | MethodAttributes.Virtual |
MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask |
MethodAttributes.CheckAccessOnOverride | MethodAttributes.Abstract |
MethodAttributes.SpecialName | MethodAttributes.PinvokeImpl |
MethodAttributes.UnmanagedExport | MethodAttributes.RTSpecialName;
writer.Write((ushort)(md == null ? 0 : md.Attributes & attrMask2));
Write(writer, md == null ? null : md.Signature);
writer.Write(md == null ? 0 : md.ParamDefs.Count);
writer.Write(md == null ? 0 : md.GenericParameters.Count);
writer.Write(md == null ? false : md.HasImplMap);
writer.Write(GetId(md));
}
void Write(BinaryWriter writer, MethodSpec ms) {
writer.Write((byte)Table.MethodSpec);
Write(writer, ms == null ? null : ms.Method);
Write(writer, ms == null ? null : ms.Instantiation);
}
void Write(BinaryWriter writer, TypeDef td) {
writer.Write((byte)Table.TypeDef);
Write(writer, td == null ? null : td.BaseType);
var attrMask = TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask |
TypeAttributes.Abstract | TypeAttributes.SpecialName |
TypeAttributes.Import | TypeAttributes.WindowsRuntime |
TypeAttributes.StringFormatMask | TypeAttributes.RTSpecialName;
writer.Write((uint)(td == null ? 0 : td.Attributes & attrMask));
Write(writer, td == null ? null : td.BaseType);
writer.Write(td == null ? 0 : td.GenericParameters.Count);
writer.Write(td == null ? 0 : td.Interfaces.Count);
if (td != null) {
foreach (var iface in td.Interfaces)
Write(writer, iface);
}
writer.Write(GetId(td));
}
void Write(BinaryWriter writer, TypeRef tr) {
writer.Write((byte)Table.TypeRef);
Write(writer, tr == null ? null : tr.ResolutionScope);
bool canWriteName = IsFromNonObfuscatedAssembly(tr);
writer.Write(canWriteName);
if (canWriteName) {
writer.Write(tr.Namespace);
writer.Write(tr.Name);
}
}
void Write(BinaryWriter writer, TypeSpec ts) {
writer.Write((byte)Table.TypeSpec);
Write(writer, ts == null ? null : ts.TypeSig);
}
void Write(BinaryWriter writer, AssemblyRef asmRef) {
writer.Write((byte)Table.AssemblyRef);
bool canWriteAsm = IsNonObfuscatedAssembly(asmRef);
writer.Write(canWriteAsm);
if (canWriteAsm) {
bool hasPk = !PublicKeyBase.IsNullOrEmpty2(asmRef.PublicKeyOrToken);
writer.Write(hasPk);
if (hasPk)
writer.Write(PublicKeyBase.ToPublicKeyToken(asmRef.PublicKeyOrToken).Data);
writer.Write(asmRef.Name);
writer.Write(asmRef.Culture);
}
}
static bool IsFromNonObfuscatedAssembly(IMemberRefParent mrp) {
return IsFromNonObfuscatedAssembly(mrp as TypeRef);
}
static bool IsFromNonObfuscatedAssembly(TypeRef tr) {
if (tr == null)
return false;
for (int i = 0; i < 100; i++) {
var asmRef = tr.ResolutionScope as AssemblyRef;
if (asmRef != null)
return IsNonObfuscatedAssembly(asmRef);
var tr2 = tr.ResolutionScope as TypeRef;
if (tr2 != null) {
tr = tr2;
continue;
}
break;
}
return false;
}
static bool IsNonObfuscatedAssembly(AssemblyRef asmRef) {
if (asmRef == null)
return false;
// The only external asm refs it uses...
if (asmRef.Name != "mscorlib" && asmRef.Name != "System")
return false;
return true;
}
bool IsTypeField(FieldDef fd) {
return fd != null && fd.DeclaringType == blocks.Method.DeclaringType;
}
int GetFieldId(FieldDef fd) {
if (fd == null)
return int.MinValue;
var fieldType = fd.FieldSig.GetFieldType();
if (fieldType == null)
return int.MinValue + 1;
int result = 0;
for (int i = 0; i < 100; i++) {
result += (int)fieldType.ElementType;
if (fieldType.Next == null)
break;
result += 0x100;
fieldType = fieldType.Next;
}
var td = fieldType.TryGetTypeDef();
if (td != null && td.IsEnum)
return result + 0x10000000;
return result;
}
static Code SimplifyBranch(Code code) {
switch (code) {
case Code.Beq_S: return Code.Beq;
case Code.Bge_S: return Code.Bge;
case Code.Bgt_S: return Code.Bgt;
case Code.Ble_S: return Code.Ble;
case Code.Blt_S: return Code.Blt;
case Code.Bne_Un_S: return Code.Bne_Un;
case Code.Bge_Un_S: return Code.Bge_Un;
case Code.Bgt_Un_S: return Code.Bgt_Un;
case Code.Ble_Un_S: return Code.Ble_Un;
case Code.Blt_Un_S: return Code.Blt_Un;
case Code.Br_S: return Code.Br;
case Code.Brfalse_S: return Code.Brfalse;
case Code.Brtrue_S: return Code.Brtrue;
case Code.Leave_S: return Code.Leave;
default: return code;
}
}
}
}

View File

@ -0,0 +1,38 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using dnlib.DotNet;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class OpCodeHandler {
public OpCodeHandlerInfo OpCodeHandlerInfo { get; private set; }
public TypeDef HandlerType { get; private set; }
public HandlerMethod ExecMethod { get; private set; }
public OpCodeHandler(OpCodeHandlerInfo opCodeHandlerInfo, TypeDef handlerType, HandlerMethod execMethod) {
this.OpCodeHandlerInfo = opCodeHandlerInfo;
this.HandlerType = handlerType;
this.ExecMethod = execMethod;
}
public override string ToString() {
return OpCodeHandlerInfo.Name;
}
}
}

View File

@ -0,0 +1,123 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class OpCodeHandlerInfo {
public HandlerTypeCode TypeCode { get; private set; }
public string Name { get; private set; }
public MethodSigInfo ExecSig { get; private set; }
public OpCodeHandlerInfo(HandlerTypeCode typeCode, MethodSigInfo execSig) {
this.TypeCode = typeCode;
this.Name = GetHandlerName(typeCode);
this.ExecSig = execSig;
}
public override string ToString() {
return Name;
}
static string GetHandlerName(HandlerTypeCode code) {
switch (code) {
case HandlerTypeCode.Add: return "add";
case HandlerTypeCode.Add_Ovf: return "add.ovf";
case HandlerTypeCode.Add_Ovf_Un: return "add.ovf.un";
case HandlerTypeCode.And: return "and";
case HandlerTypeCode.Beq: return "beq";
case HandlerTypeCode.Bge: return "bge";
case HandlerTypeCode.Bge_Un: return "bge.un";
case HandlerTypeCode.Bgt: return "bgt";
case HandlerTypeCode.Bgt_Un: return "bgt.un";
case HandlerTypeCode.Ble: return "ble";
case HandlerTypeCode.Ble_Un: return "ble.un";
case HandlerTypeCode.Blt: return "blt";
case HandlerTypeCode.Blt_Un: return "blt.un";
case HandlerTypeCode.Bne_Un: return "bne.un";
case HandlerTypeCode.Box: return "box";
case HandlerTypeCode.Br: return "br";
case HandlerTypeCode.Brfalse: return "brfalse";
case HandlerTypeCode.Brtrue: return "brtrue";
case HandlerTypeCode.Call: return "call";
case HandlerTypeCode.Callvirt: return "callvirt";
case HandlerTypeCode.Castclass: return "castclass";
case HandlerTypeCode.Ceq: return "ceq";
case HandlerTypeCode.Cgt: return "cgt";
case HandlerTypeCode.Cgt_Un: return "cgt.un";
case HandlerTypeCode.Clt: return "clt";
case HandlerTypeCode.Clt_Un: return "clt.un";
case HandlerTypeCode.Conv: return "conv";
case HandlerTypeCode.Div: return "div";
case HandlerTypeCode.Div_Un: return "div.un";
case HandlerTypeCode.Dup: return "dup";
case HandlerTypeCode.Endfinally: return "endfinally";
case HandlerTypeCode.Initobj: return "initobj";
case HandlerTypeCode.Isinst: return "isinst";
case HandlerTypeCode.Ldarg: return "ldarg";
case HandlerTypeCode.Ldarga: return "ldarga";
case HandlerTypeCode.Ldc: return "ldc";
case HandlerTypeCode.Ldelem: return "ldelem";
case HandlerTypeCode.Ldelema: return "ldelema";
case HandlerTypeCode.Ldfld_Ldsfld: return "ldfld/ldsfld";
case HandlerTypeCode.Ldflda_Ldsflda:return "ldflda/ldsflda";
case HandlerTypeCode.Ldftn: return "ldftn";
case HandlerTypeCode.Ldlen: return "ldlen";
case HandlerTypeCode.Ldloc: return "ldloc";
case HandlerTypeCode.Ldloca: return "ldloca";
case HandlerTypeCode.Ldobj: return "ldobj";
case HandlerTypeCode.Ldstr: return "ldstr";
case HandlerTypeCode.Ldtoken: return "ldtoken";
case HandlerTypeCode.Ldvirtftn: return "ldvirtftn";
case HandlerTypeCode.Leave: return "leave";
case HandlerTypeCode.Mul: return "mul";
case HandlerTypeCode.Mul_Ovf: return "mul.ovf";
case HandlerTypeCode.Mul_Ovf_Un: return "mul.ovf.un";
case HandlerTypeCode.Neg: return "neg";
case HandlerTypeCode.Newarr: return "newarr";
case HandlerTypeCode.Newobj: return "newobj";
case HandlerTypeCode.Nop: return "nop";
case HandlerTypeCode.Not: return "not";
case HandlerTypeCode.Or: return "or";
case HandlerTypeCode.Pop: return "pop";
case HandlerTypeCode.Rem: return "rem";
case HandlerTypeCode.Rem_Un: return "rem.un";
case HandlerTypeCode.Ret: return "ret";
case HandlerTypeCode.Rethrow: return "rethrow";
case HandlerTypeCode.Shl: return "shl";
case HandlerTypeCode.Shr: return "shr";
case HandlerTypeCode.Shr_Un: return "shr.un";
case HandlerTypeCode.Starg: return "starg";
case HandlerTypeCode.Stelem: return "stelem";
case HandlerTypeCode.Stfld_Stsfld: return "stfld/stsfld";
case HandlerTypeCode.Stloc: return "stloc";
case HandlerTypeCode.Stobj: return "stobj";
case HandlerTypeCode.Sub: return "sub";
case HandlerTypeCode.Sub_Ovf: return "sub.ovf";
case HandlerTypeCode.Sub_Ovf_Un: return "sub.ovf.un";
case HandlerTypeCode.Switch: return "switch";
case HandlerTypeCode.Throw: return "throw";
case HandlerTypeCode.Unbox_Any: return "unbox.any";
case HandlerTypeCode.Xor: return "xor";
default: throw new ApplicationException("Invalid handler type code");
}
}
}
}

View File

@ -0,0 +1,528 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using dnlib.DotNet.Emit;
using dnlib.DotNet;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class OpCodeHandlerInfoReader {
IInstructionOperandResolver resolver;
Dictionary<HandlerTypeCode, Func<BinaryReader, Instruction>> readHandlers;
public OpCodeHandlerInfoReader(IInstructionOperandResolver resolver) {
this.resolver = resolver;
this.readHandlers = new Dictionary<HandlerTypeCode, Func<BinaryReader, Instruction>> {
{ HandlerTypeCode.Add, Handler_Add },
{ HandlerTypeCode.Add_Ovf, Handler_Add_Ovf },
{ HandlerTypeCode.Add_Ovf_Un, Handler_Add_Ovf_Un },
{ HandlerTypeCode.And, Handler_And },
{ HandlerTypeCode.Beq, Handler_Beq },
{ HandlerTypeCode.Bge, Handler_Bge },
{ HandlerTypeCode.Bge_Un, Handler_Bge_Un },
{ HandlerTypeCode.Bgt, Handler_Bgt },
{ HandlerTypeCode.Bgt_Un, Handler_Bgt_Un },
{ HandlerTypeCode.Ble, Handler_Ble },
{ HandlerTypeCode.Ble_Un, Handler_Ble_Un },
{ HandlerTypeCode.Blt, Handler_Blt },
{ HandlerTypeCode.Blt_Un, Handler_Blt_Un },
{ HandlerTypeCode.Bne_Un, Handler_Bne_Un },
{ HandlerTypeCode.Box, Handler_Box },
{ HandlerTypeCode.Br, Handler_Br },
{ HandlerTypeCode.Brfalse, Handler_Brfalse },
{ HandlerTypeCode.Brtrue, Handler_Brtrue },
{ HandlerTypeCode.Call, Handler_Call },
{ HandlerTypeCode.Callvirt, Handler_Callvirt },
{ HandlerTypeCode.Castclass, Handler_Castclass },
{ HandlerTypeCode.Ceq, Handler_Ceq },
{ HandlerTypeCode.Cgt, Handler_Cgt },
{ HandlerTypeCode.Cgt_Un, Handler_Cgt_Un },
{ HandlerTypeCode.Clt, Handler_Clt },
{ HandlerTypeCode.Clt_Un, Handler_Clt_Un },
{ HandlerTypeCode.Conv, Handler_Conv },
{ HandlerTypeCode.Div, Handler_Div },
{ HandlerTypeCode.Div_Un, Handler_Div_Un },
{ HandlerTypeCode.Dup, Handler_Dup },
{ HandlerTypeCode.Endfinally, Handler_Endfinally },
{ HandlerTypeCode.Initobj, Handler_Initobj },
{ HandlerTypeCode.Isinst, Handler_Isinst },
{ HandlerTypeCode.Ldarg, Handler_Ldarg },
{ HandlerTypeCode.Ldarga, Handler_Ldarga },
{ HandlerTypeCode.Ldc, Handler_Ldc },
{ HandlerTypeCode.Ldelem, Handler_Ldelem },
{ HandlerTypeCode.Ldelema, Handler_Ldelema },
{ HandlerTypeCode.Ldfld_Ldsfld, Handler_Ldfld_Ldsfld },
{ HandlerTypeCode.Ldflda_Ldsflda, Handler_Ldflda_Ldsflda },
{ HandlerTypeCode.Ldftn, Handler_Ldftn },
{ HandlerTypeCode.Ldlen, Handler_Ldlen },
{ HandlerTypeCode.Ldloc, Handler_Ldloc },
{ HandlerTypeCode.Ldloca, Handler_Ldloca },
{ HandlerTypeCode.Ldobj, Handler_Ldobj },
{ HandlerTypeCode.Ldstr, Handler_Ldstr },
{ HandlerTypeCode.Ldtoken, Handler_Ldtoken },
{ HandlerTypeCode.Ldvirtftn, Handler_Ldvirtftn },
{ HandlerTypeCode.Leave, Handler_Leave },
{ HandlerTypeCode.Mul, Handler_Mul },
{ HandlerTypeCode.Mul_Ovf, Handler_Mul_Ovf },
{ HandlerTypeCode.Mul_Ovf_Un, Handler_Mul_Ovf_Un },
{ HandlerTypeCode.Neg, Handler_Neg },
{ HandlerTypeCode.Newarr, Handler_Newarr },
{ HandlerTypeCode.Newobj, Handler_Newobj },
{ HandlerTypeCode.Nop, Handler_Nop },
{ HandlerTypeCode.Not, Handler_Not },
{ HandlerTypeCode.Or, Handler_Or },
{ HandlerTypeCode.Pop, Handler_Pop },
{ HandlerTypeCode.Rem, Handler_Rem },
{ HandlerTypeCode.Rem_Un, Handler_Rem_Un },
{ HandlerTypeCode.Ret, Handler_Ret },
{ HandlerTypeCode.Rethrow, Handler_Rethrow },
{ HandlerTypeCode.Shl, Handler_Shl },
{ HandlerTypeCode.Shr, Handler_Shr },
{ HandlerTypeCode.Shr_Un, Handler_Shr_Un },
{ HandlerTypeCode.Starg, Handler_Starg },
{ HandlerTypeCode.Stelem, Handler_Stelem },
{ HandlerTypeCode.Stfld_Stsfld, Handler_Stfld_Stsfld },
{ HandlerTypeCode.Stloc, Handler_Stloc },
{ HandlerTypeCode.Stobj, Handler_Stobj },
{ HandlerTypeCode.Sub, Handler_Sub },
{ HandlerTypeCode.Sub_Ovf, Handler_Sub_Ovf },
{ HandlerTypeCode.Sub_Ovf_Un, Handler_Sub_Ovf_Un },
{ HandlerTypeCode.Switch, Handler_Switch },
{ HandlerTypeCode.Throw, Handler_Throw },
{ HandlerTypeCode.Unbox_Any, Handler_Unbox_Any },
{ HandlerTypeCode.Xor, Handler_Xor },
};
}
public Instruction Read(HandlerTypeCode typeCode, BinaryReader reader) {
Func<BinaryReader, Instruction> readHandler;
if (!readHandlers.TryGetValue(typeCode, out readHandler))
throw new ApplicationException("Invalid handler type");
return readHandler(reader);
}
Instruction Handler_Add(BinaryReader reader) {
return OpCodes.Add.ToInstruction();
}
Instruction Handler_Add_Ovf(BinaryReader reader) {
return OpCodes.Add_Ovf.ToInstruction();
}
Instruction Handler_Add_Ovf_Un(BinaryReader reader) {
return OpCodes.Add_Ovf_Un.ToInstruction();
}
Instruction Handler_And(BinaryReader reader) {
return OpCodes.And.ToInstruction();
}
Instruction Handler_Beq(BinaryReader reader) {
return new Instruction(OpCodes.Beq, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Bge(BinaryReader reader) {
return new Instruction(OpCodes.Bge, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Bge_Un(BinaryReader reader) {
return new Instruction(OpCodes.Bge_Un, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Bgt(BinaryReader reader) {
return new Instruction(OpCodes.Bgt, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Bgt_Un(BinaryReader reader) {
return new Instruction(OpCodes.Bgt_Un, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Ble(BinaryReader reader) {
return new Instruction(OpCodes.Ble, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Ble_Un(BinaryReader reader) {
return new Instruction(OpCodes.Ble_Un, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Blt(BinaryReader reader) {
return new Instruction(OpCodes.Blt, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Blt_Un(BinaryReader reader) {
return new Instruction(OpCodes.Blt_Un, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Bne_Un(BinaryReader reader) {
return new Instruction(OpCodes.Bne_Un, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Box(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
return OpCodes.Box.ToInstruction(type);
}
Instruction Handler_Br(BinaryReader reader) {
return new Instruction(OpCodes.Br, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Brfalse(BinaryReader reader) {
return new Instruction(OpCodes.Brfalse, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Brtrue(BinaryReader reader) {
return new Instruction(OpCodes.Brtrue, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Call(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
return OpCodes.Call.ToInstruction(method);
}
Instruction Handler_Callvirt(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
return OpCodes.Callvirt.ToInstruction(method);
}
Instruction Handler_Castclass(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
return OpCodes.Castclass.ToInstruction(type);
}
Instruction Handler_Ceq(BinaryReader reader) {
return OpCodes.Ceq.ToInstruction();
}
Instruction Handler_Cgt(BinaryReader reader) {
return OpCodes.Cgt.ToInstruction();
}
Instruction Handler_Cgt_Un(BinaryReader reader) {
return OpCodes.Cgt_Un.ToInstruction();
}
Instruction Handler_Clt(BinaryReader reader) {
return OpCodes.Clt.ToInstruction();
}
Instruction Handler_Clt_Un(BinaryReader reader) {
return OpCodes.Clt_Un.ToInstruction();
}
class ConvInfo {
public byte Type { get; private set; }
public bool Second { get; private set; }
public bool Third { get; private set; }
public OpCode OpCode { get; private set; }
public ConvInfo(byte type, bool second, bool third, OpCode opCode) {
this.Type = type;
this.Second = second;
this.Third = third;
this.OpCode = opCode;
}
}
readonly static List<ConvInfo> instructionInfos1 = new List<ConvInfo> {
new ConvInfo(0, false, false, OpCodes.Conv_I1),
new ConvInfo(1, false, false, OpCodes.Conv_I2),
new ConvInfo(2, false, false, OpCodes.Conv_I4),
new ConvInfo(3, false, false, OpCodes.Conv_I8),
new ConvInfo(4, false, false, OpCodes.Conv_R4),
new ConvInfo(5, false, false, OpCodes.Conv_R8),
new ConvInfo(6, false, false, OpCodes.Conv_U1),
new ConvInfo(7, false, false, OpCodes.Conv_U2),
new ConvInfo(8, false, false, OpCodes.Conv_U4),
new ConvInfo(9, false, false, OpCodes.Conv_U8),
new ConvInfo(10, false, false, OpCodes.Conv_I),
new ConvInfo(11, false, false, OpCodes.Conv_U),
new ConvInfo(0, true, false, OpCodes.Conv_Ovf_I1),
new ConvInfo(1, true, false, OpCodes.Conv_Ovf_I2),
new ConvInfo(2, true, false, OpCodes.Conv_Ovf_I4),
new ConvInfo(3, true, false, OpCodes.Conv_Ovf_I8),
new ConvInfo(6, true, false, OpCodes.Conv_Ovf_U1),
new ConvInfo(7, true, false, OpCodes.Conv_Ovf_U2),
new ConvInfo(8, true, false, OpCodes.Conv_Ovf_U4),
new ConvInfo(9, true, false, OpCodes.Conv_Ovf_U8),
new ConvInfo(10, true, false, OpCodes.Conv_Ovf_I),
new ConvInfo(11, true, false, OpCodes.Conv_Ovf_U),
new ConvInfo(0, true, true, OpCodes.Conv_Ovf_I1_Un),
new ConvInfo(1, true, true, OpCodes.Conv_Ovf_I2_Un),
new ConvInfo(2, true, true, OpCodes.Conv_Ovf_I4_Un),
new ConvInfo(3, true, true, OpCodes.Conv_Ovf_I8_Un),
new ConvInfo(6, true, true, OpCodes.Conv_Ovf_U1_Un),
new ConvInfo(7, true, true, OpCodes.Conv_Ovf_U2_Un),
new ConvInfo(8, true, true, OpCodes.Conv_Ovf_U4_Un),
new ConvInfo(9, true, true, OpCodes.Conv_Ovf_U8_Un),
new ConvInfo(10, true, true, OpCodes.Conv_Ovf_I_Un),
new ConvInfo(11, true, true, OpCodes.Conv_Ovf_U_Un),
new ConvInfo(12, true, true, OpCodes.Conv_R_Un),
};
Instruction Handler_Conv(BinaryReader reader) {
byte type = reader.ReadByte();
bool second = reader.ReadBoolean();
bool third = reader.ReadBoolean();
Instruction instr = null;
foreach (var info in instructionInfos1) {
if (type != info.Type || info.Second != second || info.Third != third)
continue;
instr = new Instruction { OpCode = info.OpCode };
break;
}
if (instr == null)
throw new ApplicationException("Invalid opcode");
return instr;
}
Instruction Handler_Div(BinaryReader reader) {
return OpCodes.Div.ToInstruction();
}
Instruction Handler_Div_Un(BinaryReader reader) {
return OpCodes.Div_Un.ToInstruction();
}
Instruction Handler_Dup(BinaryReader reader) {
return OpCodes.Dup.ToInstruction();
}
Instruction Handler_Endfinally(BinaryReader reader) {
return OpCodes.Endfinally.ToInstruction();
}
Instruction Handler_Initobj(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
return OpCodes.Initobj.ToInstruction(type);
}
Instruction Handler_Isinst(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
return OpCodes.Isinst.ToInstruction(type);
}
Instruction Handler_Ldarg(BinaryReader reader) {
return new Instruction(OpCodes.Ldarg, new ArgOperand(reader.ReadUInt16()));
}
Instruction Handler_Ldarga(BinaryReader reader) {
return new Instruction(OpCodes.Ldarga, new ArgOperand(reader.ReadUInt16()));
}
Instruction Handler_Ldc(BinaryReader reader) {
switch ((ElementType)reader.ReadByte()) {
case ElementType.I4: return Instruction.CreateLdcI4(reader.ReadInt32());
case ElementType.I8: return OpCodes.Ldc_I8.ToInstruction(reader.ReadInt64());
case ElementType.R4: return OpCodes.Ldc_R4.ToInstruction(reader.ReadSingle());
case ElementType.R8: return OpCodes.Ldc_R8.ToInstruction(reader.ReadDouble());
case ElementType.Object: return OpCodes.Ldnull.ToInstruction();
default: throw new ApplicationException("Invalid instruction");
}
}
Instruction Handler_Ldelem(BinaryReader reader) {
return new Instruction(OpCodes.Ldelem, null);
}
Instruction Handler_Ldelema(BinaryReader reader) {
return new Instruction(OpCodes.Ldelema, null);
}
Instruction Handler_Ldfld_Ldsfld(BinaryReader reader) {
var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsfld, OpCodes.Ldfld, field));
}
Instruction Handler_Ldflda_Ldsflda(BinaryReader reader) {
var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsflda, OpCodes.Ldflda, field));
}
Instruction Handler_Ldftn(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
return OpCodes.Ldftn.ToInstruction(method);
}
Instruction Handler_Ldlen(BinaryReader reader) {
return OpCodes.Ldlen.ToInstruction();
}
Instruction Handler_Ldloc(BinaryReader reader) {
return new Instruction(OpCodes.Ldloc, new LocalOperand(reader.ReadUInt16()));
}
Instruction Handler_Ldloca(BinaryReader reader) {
return new Instruction(OpCodes.Ldloca, new LocalOperand(reader.ReadUInt16()));
}
Instruction Handler_Ldobj(BinaryReader reader) {
return new Instruction(OpCodes.Ldobj, null);
}
Instruction Handler_Ldstr(BinaryReader reader) {
return OpCodes.Ldstr.ToInstruction(reader.ReadString());
}
Instruction Handler_Ldtoken(BinaryReader reader) {
var member = resolver.ResolveToken(reader.ReadUInt32()) as ITokenOperand;
return OpCodes.Ldtoken.ToInstruction(member);
}
Instruction Handler_Ldvirtftn(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
reader.ReadUInt32();
return OpCodes.Ldvirtftn.ToInstruction(method);
}
Instruction Handler_Leave(BinaryReader reader) {
return new Instruction(OpCodes.Leave, new TargetDisplOperand(reader.ReadInt32()));
}
Instruction Handler_Mul(BinaryReader reader) {
return OpCodes.Mul.ToInstruction();
}
Instruction Handler_Mul_Ovf(BinaryReader reader) {
return OpCodes.Mul_Ovf.ToInstruction();
}
Instruction Handler_Mul_Ovf_Un(BinaryReader reader) {
return OpCodes.Mul_Ovf_Un.ToInstruction();
}
Instruction Handler_Neg(BinaryReader reader) {
return OpCodes.Neg.ToInstruction();
}
Instruction Handler_Newarr(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
return OpCodes.Newarr.ToInstruction(type);
}
Instruction Handler_Newobj(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
return OpCodes.Newobj.ToInstruction(method);
}
Instruction Handler_Nop(BinaryReader reader) {
return OpCodes.Nop.ToInstruction();
}
Instruction Handler_Not(BinaryReader reader) {
return OpCodes.Not.ToInstruction();
}
Instruction Handler_Or(BinaryReader reader) {
return OpCodes.Or.ToInstruction();
}
Instruction Handler_Pop(BinaryReader reader) {
return OpCodes.Pop.ToInstruction();
}
Instruction Handler_Rem(BinaryReader reader) {
return OpCodes.Rem.ToInstruction();
}
Instruction Handler_Rem_Un(BinaryReader reader) {
return OpCodes.Rem_Un.ToInstruction();
}
Instruction Handler_Ret(BinaryReader reader) {
var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
return OpCodes.Ret.ToInstruction();
}
Instruction Handler_Rethrow(BinaryReader reader) {
return OpCodes.Rethrow.ToInstruction();
}
Instruction Handler_Shl(BinaryReader reader) {
return OpCodes.Shl.ToInstruction();
}
Instruction Handler_Shr(BinaryReader reader) {
return OpCodes.Shr.ToInstruction();
}
Instruction Handler_Shr_Un(BinaryReader reader) {
return OpCodes.Shr_Un.ToInstruction();
}
Instruction Handler_Starg(BinaryReader reader) {
return new Instruction(OpCodes.Starg, new ArgOperand(reader.ReadUInt16()));
}
Instruction Handler_Stelem(BinaryReader reader) {
return new Instruction(OpCodes.Stelem, null);
}
Instruction Handler_Stfld_Stsfld(BinaryReader reader) {
var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Stsfld, OpCodes.Stfld, field));
}
Instruction Handler_Stloc(BinaryReader reader) {
ushort loc = reader.ReadUInt16();
var etype = (ElementType)reader.ReadInt32();
return new Instruction(OpCodes.Stloc, new LocalOperand(loc));
}
Instruction Handler_Stobj(BinaryReader reader) {
return new Instruction(OpCodes.Stobj, null);
}
Instruction Handler_Sub(BinaryReader reader) {
return OpCodes.Sub.ToInstruction();
}
Instruction Handler_Sub_Ovf(BinaryReader reader) {
return OpCodes.Sub_Ovf.ToInstruction();
}
Instruction Handler_Sub_Ovf_Un(BinaryReader reader) {
return OpCodes.Sub_Ovf_Un.ToInstruction();
}
Instruction Handler_Switch(BinaryReader reader) {
int size = reader.ReadInt32();
var offsets = new int[size];
for (int i = 0; i < size; i++)
offsets[i] = reader.ReadInt32();
return new Instruction(OpCodes.Switch, new SwitchTargetDisplOperand(offsets));
}
Instruction Handler_Throw(BinaryReader reader) {
return OpCodes.Throw.ToInstruction();
}
Instruction Handler_Unbox_Any(BinaryReader reader) {
var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
return OpCodes.Unbox_Any.ToInstruction(type);
}
Instruction Handler_Xor(BinaryReader reader) {
return OpCodes.Xor.ToInstruction();
}
}
}

View File

@ -0,0 +1,98 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
static class OpCodeHandlerInfos {
enum OpCodeHandlersFileVersion : int {
V1 = 1,
}
public static void Write(BinaryWriter writer, IList<OpCodeHandlerInfo> handlerInfos) {
WriteV1(writer, handlerInfos);
}
public static void WriteV1(BinaryWriter writer, IList<OpCodeHandlerInfo> handlerInfos) {
writer.Write((int)OpCodeHandlersFileVersion.V1);
writer.Write(handlerInfos.Count);
foreach (var handler in handlerInfos) {
writer.Write((int)handler.TypeCode);
var infos = handler.ExecSig.BlockInfos;
writer.Write(infos.Count);
foreach (var info in infos) {
if (info.Hash == null)
writer.Write(0);
else {
writer.Write(info.Hash.Length);
writer.Write(info.Hash);
}
writer.Write(info.Targets.Count);
foreach (var target in info.Targets)
writer.Write(target);
}
}
}
public static List<OpCodeHandlerInfo> Read(BinaryReader reader) {
switch ((OpCodeHandlersFileVersion)reader.ReadInt32()) {
case OpCodeHandlersFileVersion.V1: return ReadV1(reader);
default: throw new ApplicationException("Invalid file version");
}
}
static List<OpCodeHandlerInfo> ReadV1(BinaryReader reader) {
int numHandlers = reader.ReadInt32();
var list = new List<OpCodeHandlerInfo>(numHandlers);
for (int i = 0; i < numHandlers; i++) {
var typeCode = (HandlerTypeCode)reader.ReadInt32();
int numInfos = reader.ReadInt32();
var sigInfo = new MethodSigInfo();
for (int j = 0; j < numInfos; j++) {
var info = new BlockInfo();
info.Hash = reader.ReadBytes(reader.ReadInt32());
if (info.Hash.Length == 0)
info.Hash = null;
int numTargets = reader.ReadInt32();
for (int k = 0; k < numTargets; k++)
info.Targets.Add(reader.ReadInt32());
sigInfo.BlockInfos.Add(info);
}
list.Add(new OpCodeHandlerInfo(typeCode, sigInfo));
}
return list;
}
public static readonly IList<OpCodeHandlerInfo>[] HandlerInfos = new IList<OpCodeHandlerInfo>[] {
ReadOpCodeHandlerInfos(CsvmResources.CSVM1_v2),
ReadOpCodeHandlerInfos(CsvmResources.CSVM2_v2),
ReadOpCodeHandlerInfos(CsvmResources.CSVM3_v2),
};
static IList<OpCodeHandlerInfo> ReadOpCodeHandlerInfos(byte[] data) {
return OpCodeHandlerInfos.Read(new BinaryReader(new MemoryStream(data)));
}
}
}

Some files were not shown because too many files have changed in this diff Show More