/*
Copyright (C) 2011-2017 TheProxy
This file is part of modified 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 .
*/
using System.Collections.Generic;
using de4dot.blocks;
using de4dot.blocks.cflow;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.ConfuserEx
{
public class DeobfuscatorInfo : DeobfuscatorInfoBase
{
internal const string THE_NAME = "ConfuserEx";
public const string THE_TYPE = "crx";
private const string DEFAULT_REGEX = DeobfuscatorBase.DEFAULT_ASIAN_VALID_NAME_REGEX;
public DeobfuscatorInfo()
: base(DEFAULT_REGEX)
{
}
public override string Name => THE_NAME;
public override string Type => THE_TYPE;
public override IDeobfuscator CreateDeobfuscator()
{
return new Deobfuscator(new Deobfuscator.Options
{
RenameResourcesInCode = false,
ValidNameRegex = validNameRegex.Get()
});
}
private class Deobfuscator : DeobfuscatorBase
{
private readonly ControlFlowFixer _controlFlowFixer = new ControlFlowFixer();
private bool _canRemoveLzma = true;
private ConstantsDecrypter _constantDecrypter;
private bool _detectedConfuserExAttribute, _deobfuscating;
private LzmaFinder _lzmaFinder;
private ProxyCallFixer _proxyCallFixer;
private ResourceDecrypter _resourceDecrypter;
private string _version = "";
public Deobfuscator(Options options)
: base(options)
{
}
public override string Type => THE_TYPE;
public override string TypeLong => THE_NAME;
public override string Name => $"{TypeLong} {_version}";
public override IEnumerable BlocksDeobfuscators
{
get
{
var list = new List();
list.Add(_controlFlowFixer);
if (_deobfuscating && _int32ValueInliner != null)
{
var constantInliner = new ConstantsInliner(_sbyteValueInliner, _byteValueInliner,
_int16ValueInliner,
_uint16ValueInliner, _int32ValueInliner, _uint32ValueInliner, _int64ValueInliner,
_uint64ValueInliner, _singleValueInliner, _doubleValueInliner, _arrayValueInliner)
{
ExecuteIfNotModified = true
};
list.Add(constantInliner);
}
return list;
}
}
protected override int DetectInternal()
{
var val = 0;
if (_detectedConfuserExAttribute) val += 0;
if (_lzmaFinder.FoundLzma) val += 10;
if (_constantDecrypter.Detected) val += 10;
if (_resourceDecrypter.Detected) val += 10;
return val;
}
protected override void ScanForObfuscator()
{
_lzmaFinder = new LzmaFinder(module, DeobfuscatedFile);
_lzmaFinder.Find();
_constantDecrypter = new ConstantsDecrypter(module, _lzmaFinder.Method, DeobfuscatedFile);
Logger.w(
"Constants decryption enabled! Please note that the decryption method has to be set manually!"); //TODO: Remove
_resourceDecrypter = new ResourceDecrypter(module, _lzmaFinder.Method, DeobfuscatedFile);
Logger.w(
"Resource decryption detected! Please note that the decryption method has to be set manually!"); //TODO: Remove
if (_lzmaFinder.FoundLzma)
{
_constantDecrypter.Find();
_resourceDecrypter.Find();
}
_proxyCallFixer = new ProxyCallFixer(module, DeobfuscatedFile);
_proxyCallFixer.FindDelegateCreatorMethod();
_proxyCallFixer.Find();
DetectConfuserExAttribute();
}
private void DetectConfuserExAttribute()
{
foreach (var attribute in module.CustomAttributes)
{
if (attribute.TypeFullName != "ConfusedByAttribute")
continue;
foreach (var argument in attribute.ConstructorArguments)
{
if (argument.Type.ElementType != ElementType.String)
continue;
var value = argument.Value.ToString();
if (!value.Contains("ConfuserEx"))
continue;
_detectedConfuserExAttribute = true;
_version = value.Replace("ConfuserEx", "");
return;
}
}
}
public override void DeobfuscateBegin()
{
if (_constantDecrypter.Detected)
{
_sbyteValueInliner = new SByteValueInliner();
_byteValueInliner = new ByteValueInliner();
_int16ValueInliner = new Int16ValueInliner();
_uint16ValueInliner = new UInt16ValueInliner();
_int32ValueInliner = new Int32ValueInliner();
_uint32ValueInliner = new UInt32ValueInliner();
_int64ValueInliner = new Int64ValueInliner();
_uint64ValueInliner = new UInt64ValueInliner();
_singleValueInliner = new SingleValueInliner();
_doubleValueInliner = new DoubleValueInliner();
_arrayValueInliner = new ArrayValueInliner(initializedDataCreator);
foreach (var info in _constantDecrypter.Decrypters)
{
staticStringInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptString(info, gim, (uint) args[0]));
_sbyteValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptSByte(info, gim, (uint) args[0]));
_byteValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptByte(info, gim, (uint) args[0]));
_int16ValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptInt16(info, gim, (uint) args[0]));
_uint16ValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptUInt16(info, gim, (uint) args[0]));
_int32ValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptInt32(info, gim, (uint) args[0]));
_uint32ValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptUInt32(info, gim, (uint) args[0]));
_int64ValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptInt64(info, gim, (uint) args[0]));
_uint64ValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptUInt64(info, gim, (uint) args[0]));
_singleValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptSingle(info, gim, (uint) args[0]));
_doubleValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptDouble(info, gim, (uint) args[0]));
_arrayValueInliner.Add(info.Method,
(method, gim, args) => _constantDecrypter.DecryptArray(info, gim, (uint) args[0]));
}
_deobfuscating = true;
}
if (_resourceDecrypter.Detected)
{
_resourceDecrypter.Fix();
}
base.DeobfuscateBegin();
}
public override void DeobfuscateEnd()
{
FindAndRemoveInlinedMethods();
var toRemoveFromCctor = new List();
if (_constantDecrypter.Detected)
if (CanRemoveStringDecrypterType)
{
toRemoveFromCctor.Add(_constantDecrypter.Method);
AddMethodToBeRemoved(_constantDecrypter.Method, "Constant Decrypter Initializer");
foreach (var dec in _constantDecrypter.Decrypters)
AddMethodToBeRemoved(dec.Method, "Constant Decrypter Method");
AddFieldsToBeRemoved(_constantDecrypter.Fields, "Constant Decrypter Fields");
AddTypeToBeRemoved(_constantDecrypter.Type, "Array field signature type");
}
else
{
_canRemoveLzma = false;
}
if (_resourceDecrypter.Detected && _resourceDecrypter.CanRemoveLzma)
{
toRemoveFromCctor.Add(_resourceDecrypter.Method);
AddMethodToBeRemoved(_resourceDecrypter.Method, "Resource decrypter Initializer method");
AddMethodToBeRemoved(_resourceDecrypter.AssembyResolveMethod,
"Resource decrypter AssemblyResolve method");
AddFieldsToBeRemoved(_resourceDecrypter.Fields, "Constant Decrypter Fields");
AddTypeToBeRemoved(_resourceDecrypter.Type, "Array field signature type");
}
if (!_constantDecrypter.CanRemoveLzma || !_resourceDecrypter.CanRemoveLzma)
_canRemoveLzma = false;
if (_lzmaFinder.FoundLzma && _canRemoveLzma)
{
AddMethodToBeRemoved(_lzmaFinder.Method, "Lzma Decompress method");
AddTypesToBeRemoved(_lzmaFinder.Types, "Lzma Nested Types");
}
if (_proxyCallFixer.Detected)
{
AddTypesToBeRemoved(_proxyCallFixer.DelegateTypes, "Proxy delegates");
AddMethodsToBeRemoved(_proxyCallFixer.DelegateCreatorMethods, "Proxy creator methods");
AddTypesToBeRemoved(_proxyCallFixer.AttributeTypes, "Proxy creator attributes");
AddMethodsToBeRemoved(_proxyCallFixer.NativeMethods, "Proxy native methods");
}
AddMethodsToBeRemoved(_controlFlowFixer.NativeMethods, "Control flow native methods");
var moduleCctor = DotNetUtils.GetModuleTypeCctor(module);
foreach (var instr in moduleCctor.Body.Instructions)
if (instr.OpCode == OpCodes.Call && instr.Operand is MethodDef
&& toRemoveFromCctor.Contains((MethodDef)instr.Operand))
instr.OpCode = OpCodes.Nop;
//No more mixed!
module.IsILOnly = true;
base.DeobfuscateEnd();
}
public override IEnumerable GetStringDecrypterMethods()
{
return new List();
}
public override void DeobfuscateMethodEnd(Blocks blocks)
{
_proxyCallFixer.Deobfuscate(blocks);
base.DeobfuscateMethodEnd(blocks);
}
internal class Options : OptionsBase
{
}
#region ConstantInliners
private SByteValueInliner _sbyteValueInliner;
private ByteValueInliner _byteValueInliner;
private Int16ValueInliner _int16ValueInliner;
private UInt16ValueInliner _uint16ValueInliner;
private Int32ValueInliner _int32ValueInliner;
private UInt32ValueInliner _uint32ValueInliner;
private Int64ValueInliner _int64ValueInliner;
private UInt64ValueInliner _uint64ValueInliner;
private SingleValueInliner _singleValueInliner;
private DoubleValueInliner _doubleValueInliner;
private ArrayValueInliner _arrayValueInliner;
#endregion
}
}
}