Implemented ConfuserEx deobfuscator

x86 cflow and x86 constant decryption
Backport of LINQ (LinqBridge)
Shift left/right emulation fixes in de4dot core
Block class extended to hold additional information
This commit is contained in:
ViR Dash 2017-02-13 11:14:22 +02:00
parent 126758fa6f
commit 23477ccb5f
32 changed files with 4550 additions and 750 deletions

BIN
BeaEngine.dll Normal file

Binary file not shown.

BIN
LinqBridge.dll Normal file

Binary file not shown.

View File

@ -1,320 +1,348 @@
/*
Copyright (C) 2011-2015 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.Emit;
namespace de4dot.blocks {
public class Block : BaseBlock {
List<Instr> instructions = new List<Instr>();
// List of all explicit (non-fall-through) targets. It's just one if it's a normal
// branch, but if it's a switch, it could be many targets.
List<Block> targets;
// This is the fall through Block (non branch instructions)
Block fallThrough;
// All blocks that fall through or branches to this block
List<Block> sources = new List<Block>();
public Block FallThrough {
get { return fallThrough; }
set { fallThrough = value; }
}
public List<Block> Targets {
get { return targets; }
set { targets = value; }
}
public List<Block> Sources {
get { return sources; }
}
public Instr FirstInstr {
get {
if (instructions.Count == 0)
Add(new Instr(OpCodes.Nop.ToInstruction()));
return instructions[0];
}
}
public Instr LastInstr {
get {
if (instructions.Count == 0)
Add(new Instr(OpCodes.Nop.ToInstruction()));
return instructions[instructions.Count - 1];
}
}
public void Add(Instr instr) {
instructions.Add(instr);
}
public void Insert(int index, Instruction instr) {
instructions.Insert(index, new Instr(instr));
}
public List<Instr> Instructions {
get { return instructions; }
}
// If last instr is a br/br.s, removes it and replaces it with a fall through
public void RemoveLastBr() {
if (!LastInstr.IsBr())
return;
if (fallThrough != null || (LastInstr.Operand != null && (targets == null || targets.Count != 1)))
throw new ApplicationException("Invalid block state when last instr is a br/br.s");
fallThrough = LastInstr.Operand != null ? targets[0] : null;
targets = null;
instructions.RemoveAt(instructions.Count - 1);
}
public void Replace(int index, int num, Instruction instruction) {
if (num <= 0)
throw new ArgumentOutOfRangeException("num");
Remove(index, num);
instructions.Insert(index, new Instr(instruction));
}
public void Remove(int index, int num) {
if (index + num > instructions.Count)
throw new ApplicationException("Overflow");
if (num > 0 && index + num == instructions.Count && LastInstr.IsConditionalBranch())
DisconnectFromFallThroughAndTargets();
instructions.RemoveRange(index, num);
}
public void Remove(IEnumerable<int> indexes) {
var instrsToDelete = new List<int>(Utils.Unique(indexes));
instrsToDelete.Sort();
instrsToDelete.Reverse();
foreach (var index in instrsToDelete)
Remove(index, 1);
}
// Replace the last instructions with a branch to target
public void ReplaceLastInstrsWithBranch(int numInstrs, Block target) {
if (numInstrs < 0 || numInstrs > instructions.Count)
throw new ApplicationException("Invalid numInstrs to replace with branch");
if (target == null)
throw new ApplicationException("Invalid new target, it's null");
DisconnectFromFallThroughAndTargets();
if (numInstrs > 0)
instructions.RemoveRange(instructions.Count - numInstrs, numInstrs);
fallThrough = target;
target.sources.Add(this);
}
public void ReplaceLastNonBranchWithBranch(int numInstrs, Block target) {
if (LastInstr.IsBr())
numInstrs++;
ReplaceLastInstrsWithBranch(numInstrs, target);
}
public void ReplaceBccWithBranch(bool isTaken) {
Block target = isTaken ? targets[0] : fallThrough;
ReplaceLastInstrsWithBranch(1, target);
}
public void ReplaceSwitchWithBranch(Block target) {
if (LastInstr.OpCode.Code != Code.Switch)
throw new ApplicationException("Last instruction is not a switch");
ReplaceLastInstrsWithBranch(1, target);
}
public void SetNewFallThrough(Block newFallThrough) {
DisconnectFromFallThrough();
fallThrough = newFallThrough;
newFallThrough.sources.Add(this);
}
public void SetNewTarget(int index, Block newTarget) {
DisconnectFromBlock(targets[index]);
targets[index] = newTarget;
newTarget.sources.Add(this);
}
public void RemoveDeadBlock() {
if (sources.Count != 0)
throw new ApplicationException("Trying to remove a non-dead block");
RemoveGuaranteedDeadBlock();
}
// Removes a block that has been guaranteed to be dead. This method won't verify
// that it really is dead.
public void RemoveGuaranteedDeadBlock() {
DisconnectFromFallThroughAndTargets();
Parent = null;
}
void DisconnectFromFallThroughAndTargets() {
DisconnectFromFallThrough();
DisconnectFromTargets();
}
void DisconnectFromFallThrough() {
if (fallThrough != null) {
DisconnectFromBlock(fallThrough);
fallThrough = null;
}
}
void DisconnectFromTargets() {
if (targets != null) {
foreach (var target in targets)
DisconnectFromBlock(target);
targets = null;
}
}
void DisconnectFromBlock(Block target) {
if (!target.sources.Remove(this))
throw new ApplicationException("Could not remove the block from its target block");
}
public int CountTargets() {
int count = fallThrough != null ? 1 : 0;
if (targets != null)
count += targets.Count;
return count;
}
// Returns the target iff it has only ONE target. Else it returns null.
public Block GetOnlyTarget() {
if (CountTargets() != 1)
return null;
if (fallThrough != null)
return fallThrough;
return targets[0];
}
// Returns all targets. FallThrough (if not null) is always returned first!
public IEnumerable<Block> GetTargets() {
if (fallThrough != null)
yield return fallThrough;
if (targets != null) {
foreach (var block in targets)
yield return block;
}
}
// Returns true iff other is the only block in Sources
public bool IsOnlySource(Block other) {
return sources.Count == 1 && sources[0] == other;
}
// Returns true if we can merge other with this
public bool CanMerge(Block other) {
return CanAppend(other) && other.IsOnlySource(this);
}
// Merge two blocks into one
public void Merge(Block other) {
if (!CanMerge(other))
throw new ApplicationException("Can't merge the two blocks!");
Append(other);
other.DisconnectFromFallThroughAndTargets();
other.Parent = null;
}
public bool CanAppend(Block other) {
if (other == null || other == this || GetOnlyTarget() != other)
return false;
// If it's eg. a leave, then don't merge them since it clears the stack.
return LastInstr.IsBr() || Instr.IsFallThrough(LastInstr.OpCode);
}
public void Append(Block other) {
if (!CanAppend(other))
throw new ApplicationException("Can't append the block!");
RemoveLastBr(); // Get rid of last br/br.s if present
var newInstructions = new List<Instr>(instructions.Count + other.instructions.Count);
AddInstructions(newInstructions, instructions, false);
AddInstructions(newInstructions, other.instructions, true);
instructions = newInstructions;
DisconnectFromFallThroughAndTargets();
if (other.targets != null)
targets = new List<Block>(other.targets);
else
targets = null;
fallThrough = other.fallThrough;
UpdateSources();
}
void AddInstructions(IList<Instr> dest, IList<Instr> instrs, bool clone) {
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
if (instr.OpCode != OpCodes.Nop)
dest.Add(clone ? new Instr(instr.Instruction.Clone()) : instr);
}
}
// Update each target's Sources property. Must only be called if this isn't in the
// Sources list!
public void UpdateSources() {
if (fallThrough != null)
fallThrough.sources.Add(this);
if (targets != null) {
foreach (var target in targets)
target.sources.Add(this);
}
}
// Returns true if it falls through
public bool IsFallThrough() {
return targets == null && fallThrough != null;
}
public bool CanFlipConditionalBranch() {
return LastInstr.CanFlipConditionalBranch();
}
public void FlipConditionalBranch() {
if (fallThrough == null || targets == null || targets.Count != 1)
throw new ApplicationException("Invalid bcc block state");
LastInstr.FlipConditonalBranch();
var oldFallThrough = fallThrough;
fallThrough = targets[0];
targets[0] = oldFallThrough;
}
// Returns true if it's a conditional branch
public bool IsConditionalBranch() {
return LastInstr.IsConditionalBranch();
}
public bool IsNopBlock() {
if (!IsFallThrough())
return false;
foreach (var instr in instructions) {
if (instr.OpCode.Code != Code.Nop)
return false;
}
return true;
}
}
}
/*
Copyright (C) 2011-2015 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.Emit;
namespace de4dot.blocks {
public enum BlockType
{
Normal,
Switch,
SwitchCase
}
public class SwitchData
{
public readonly Block Block;
public SwitchData(Block switchBlock)
{
Block = switchBlock;
}
public int? Key = null;
public bool IsKeyHardCoded = false;
}
public class Block : BaseBlock
{
public Block()
{
SwitchData = new SwitchData(this);
}
public BlockType BlockType = BlockType.Normal;
public SwitchData SwitchData;
public bool Processed = false;
List<Instr> instructions = new List<Instr>();
// List of all explicit (non-fall-through) targets. It's just one if it's a normal
// branch, but if it's a switch, it could be many targets.
List<Block> targets;
// This is the fall through Block (non branch instructions)
Block fallThrough;
// All blocks that fall through or branches to this block
List<Block> sources = new List<Block>();
public Block FallThrough {
get { return fallThrough; }
set { fallThrough = value; }
}
public List<Block> Targets {
get { return targets; }
set { targets = value; }
}
public List<Block> Sources {
get { return sources; }
}
public Instr FirstInstr {
get {
if (instructions.Count == 0)
Add(new Instr(OpCodes.Nop.ToInstruction()));
return instructions[0];
}
}
public Instr LastInstr {
get {
if (instructions.Count == 0)
Add(new Instr(OpCodes.Nop.ToInstruction()));
return instructions[instructions.Count - 1];
}
}
public void Add(Instr instr) {
instructions.Add(instr);
}
public void Insert(int index, Instruction instr) {
instructions.Insert(index, new Instr(instr));
}
public List<Instr> Instructions {
get { return instructions; }
}
// If last instr is a br/br.s, removes it and replaces it with a fall through
public void RemoveLastBr() {
if (!LastInstr.IsBr())
return;
if (fallThrough != null || (LastInstr.Operand != null && (targets == null || targets.Count != 1)))
throw new ApplicationException("Invalid block state when last instr is a br/br.s");
fallThrough = LastInstr.Operand != null ? targets[0] : null;
targets = null;
instructions.RemoveAt(instructions.Count - 1);
}
public void Replace(int index, int num, Instruction instruction) {
if (num <= 0)
throw new ArgumentOutOfRangeException("num");
Remove(index, num);
instructions.Insert(index, new Instr(instruction));
}
public void Remove(int index, int num) {
if (index + num > instructions.Count)
throw new ApplicationException("Overflow");
if (num > 0 && index + num == instructions.Count && LastInstr.IsConditionalBranch())
DisconnectFromFallThroughAndTargets();
instructions.RemoveRange(index, num);
}
public void Remove(IEnumerable<int> indexes) {
var instrsToDelete = new List<int>(Utils.Unique(indexes));
instrsToDelete.Sort();
instrsToDelete.Reverse();
foreach (var index in instrsToDelete)
Remove(index, 1);
}
// Replace the last instructions with a branch to target
public void ReplaceLastInstrsWithBranch(int numInstrs, Block target) {
if (numInstrs < 0 || numInstrs > instructions.Count)
throw new ApplicationException("Invalid numInstrs to replace with branch");
if (target == null)
throw new ApplicationException("Invalid new target, it's null");
DisconnectFromFallThroughAndTargets();
if (numInstrs > 0)
instructions.RemoveRange(instructions.Count - numInstrs, numInstrs);
fallThrough = target;
target.sources.Add(this);
}
public void ReplaceLastNonBranchWithBranch(int numInstrs, Block target) {
if (LastInstr.IsBr())
numInstrs++;
ReplaceLastInstrsWithBranch(numInstrs, target);
}
public void ReplaceBccWithBranch(bool isTaken) {
Block target = isTaken ? targets[0] : fallThrough;
ReplaceLastInstrsWithBranch(1, target);
}
public void ReplaceSwitchWithBranch(Block target) {
if (LastInstr.OpCode.Code != Code.Switch)
throw new ApplicationException("Last instruction is not a switch");
ReplaceLastInstrsWithBranch(1, target);
}
public void SetNewFallThrough(Block newFallThrough) {
DisconnectFromFallThrough();
fallThrough = newFallThrough;
newFallThrough.sources.Add(this);
}
public void SetNewTarget(int index, Block newTarget) {
DisconnectFromBlock(targets[index]);
targets[index] = newTarget;
newTarget.sources.Add(this);
}
public void RemoveDeadBlock() {
if (sources.Count != 0)
throw new ApplicationException("Trying to remove a non-dead block");
RemoveGuaranteedDeadBlock();
}
// Removes a block that has been guaranteed to be dead. This method won't verify
// that it really is dead.
public void RemoveGuaranteedDeadBlock() {
DisconnectFromFallThroughAndTargets();
Parent = null;
}
void DisconnectFromFallThroughAndTargets() {
DisconnectFromFallThrough();
DisconnectFromTargets();
}
void DisconnectFromFallThrough() {
if (fallThrough != null) {
DisconnectFromBlock(fallThrough);
fallThrough = null;
}
}
void DisconnectFromTargets() {
if (targets != null) {
foreach (var target in targets)
DisconnectFromBlock(target);
targets = null;
}
}
void DisconnectFromBlock(Block target) {
if (!target.sources.Remove(this))
throw new ApplicationException("Could not remove the block from its target block");
}
public int CountTargets() {
int count = fallThrough != null ? 1 : 0;
if (targets != null)
count += targets.Count;
return count;
}
// Returns the target iff it has only ONE target. Else it returns null.
public Block GetOnlyTarget() {
if (CountTargets() != 1)
return null;
if (fallThrough != null)
return fallThrough;
return targets[0];
}
// Returns all targets. FallThrough (if not null) is always returned first!
public IEnumerable<Block> GetTargets() {
if (fallThrough != null)
yield return fallThrough;
if (targets != null) {
foreach (var block in targets)
yield return block;
}
}
// Returns true iff other is the only block in Sources
public bool IsOnlySource(Block other) {
return sources.Count == 1 && sources[0] == other;
}
// Returns true if we can merge other with this
public bool CanMerge(Block other) {
return CanAppend(other) && other.IsOnlySource(this);
}
// Merge two blocks into one
public void Merge(Block other) {
if (!CanMerge(other))
throw new ApplicationException("Can't merge the two blocks!");
Append(other);
other.DisconnectFromFallThroughAndTargets();
other.Parent = null;
}
public bool CanAppend(Block other) {
if (other == null || other == this || GetOnlyTarget() != other)
return false;
// If it's eg. a leave, then don't merge them since it clears the stack.
return LastInstr.IsBr() || Instr.IsFallThrough(LastInstr.OpCode);
}
public void Append(Block other) {
if (!CanAppend(other))
throw new ApplicationException("Can't append the block!");
RemoveLastBr(); // Get rid of last br/br.s if present
var newInstructions = new List<Instr>(instructions.Count + other.instructions.Count);
AddInstructions(newInstructions, instructions, false);
AddInstructions(newInstructions, other.instructions, true);
instructions = newInstructions;
DisconnectFromFallThroughAndTargets();
if (other.targets != null)
targets = new List<Block>(other.targets);
else
targets = null;
fallThrough = other.fallThrough;
UpdateSources();
}
void AddInstructions(IList<Instr> dest, IList<Instr> instrs, bool clone) {
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
if (instr.OpCode != OpCodes.Nop)
dest.Add(clone ? new Instr(instr.Instruction.Clone()) : instr);
}
}
// Update each target's Sources property. Must only be called if this isn't in the
// Sources list!
public void UpdateSources() {
if (fallThrough != null)
fallThrough.sources.Add(this);
if (targets != null) {
foreach (var target in targets)
target.sources.Add(this);
}
}
// Returns true if it falls through
public bool IsFallThrough() {
return targets == null && fallThrough != null;
}
public bool CanFlipConditionalBranch() {
return LastInstr.CanFlipConditionalBranch();
}
public void FlipConditionalBranch() {
if (fallThrough == null || targets == null || targets.Count != 1)
throw new ApplicationException("Invalid bcc block state");
LastInstr.FlipConditonalBranch();
var oldFallThrough = fallThrough;
fallThrough = targets[0];
targets[0] = oldFallThrough;
}
// Returns true if it's a conditional branch
public bool IsConditionalBranch() {
return LastInstr.IsConditionalBranch();
}
public bool IsNopBlock() {
if (!IsFallThrough())
return false;
foreach (var instr in instructions) {
if (instr.OpCode.Code != Code.Nop)
return false;
}
return true;
}
}
}

View File

@ -541,8 +541,8 @@ namespace de4dot.blocks.cflow {
return CreateUnknown();
if (b.Value == 0)
return a;
if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
//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);
@ -553,8 +553,8 @@ namespace de4dot.blocks.cflow {
return CreateUnknown();
if (b.Value == 0)
return a;
if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
//if (b.Value < 0 || b.Value >= sizeof(int) * 8)
// return CreateUnknown();
int shift = b.Value;
uint validMask = a.ValidMask >> shift;
if (a.IsBitValid(sizeof(int) * 8 - 1))
@ -567,8 +567,8 @@ namespace de4dot.blocks.cflow {
return CreateUnknown();
if (b.Value == 0)
return a;
if (b.Value < 0 || b.Value >= sizeof(int) * 8)
return CreateUnknown();
//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);

View File

@ -1,102 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{045B96F2-AF80-4C4C-8D27-E38635AC705E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>de4dot.blocks</RootNamespace>
<AssemblyName>de4dot.blocks</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\de4dot.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Debug\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Release\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Compile Include="BaseBlock.cs" />
<Compile Include="Block.cs" />
<Compile Include="Blocks.cs" />
<Compile Include="BlocksSorter.cs" />
<Compile Include="cflow\AccessChecker.cs" />
<Compile Include="cflow\BlockCflowDeobfuscator.cs" />
<Compile Include="cflow\BlockDeobfuscator.cs" />
<Compile Include="cflow\BlocksCflowDeobfuscator.cs" />
<Compile Include="cflow\BranchEmulator.cs" />
<Compile Include="cflow\CachedCflowDeobfuscator.cs" />
<Compile Include="cflow\CflowDeobfuscator.cs" />
<Compile Include="cflow\CflowUtils.cs" />
<Compile Include="cflow\ConstantsFolder.cs" />
<Compile Include="cflow\DeadCodeRemover.cs" />
<Compile Include="cflow\DeadStoreRemover.cs" />
<Compile Include="cflow\DupBlockDeobfuscator.cs" />
<Compile Include="cflow\IBlocksDeobfuscator.cs" />
<Compile Include="cflow\ICflowDeobfuscator.cs" />
<Compile Include="cflow\InstructionEmulator.cs" />
<Compile Include="cflow\Int32Value.cs" />
<Compile Include="cflow\Int64Value.cs" />
<Compile Include="cflow\MethodCallInliner.cs" />
<Compile Include="cflow\MethodCallInlinerBase.cs" />
<Compile Include="cflow\Real8Value.cs" />
<Compile Include="cflow\StLdlocFixer.cs" />
<Compile Include="cflow\SwitchCflowDeobfuscator.cs" />
<Compile Include="cflow\Value.cs" />
<Compile Include="cflow\ValueStack.cs" />
<Compile Include="CodeGenerator.cs" />
<Compile Include="DeadBlocksRemover.cs" />
<Compile Include="DotNetUtils.cs" />
<Compile Include="DumpedMethod.cs" />
<Compile Include="DumpedMethods.cs" />
<Compile Include="FilterHandlerBlock.cs" />
<Compile Include="ForwardScanOrder.cs" />
<Compile Include="GenericArgsSubstitutor.cs" />
<Compile Include="HandlerBlock.cs" />
<Compile Include="Instr.cs" />
<Compile Include="InstructionListParser.cs" />
<Compile Include="MemberDefDict.cs" />
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\dnlib\src\dnlib.csproj">
<Project>{FDFC1237-143F-4919-8318-4926901F4639}</Project>
<Name>dnlib</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{045B96F2-AF80-4C4C-8D27-E38635AC705E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>de4dot.blocks</RootNamespace>
<AssemblyName>de4dot.blocks</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\de4dot.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Debug\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Release\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Compile Include="BaseBlock.cs" />
<Compile Include="Block.cs" />
<Compile Include="Blocks.cs" />
<Compile Include="BlocksSorter.cs" />
<Compile Include="cflow\AccessChecker.cs" />
<Compile Include="cflow\BlockCflowDeobfuscator.cs" />
<Compile Include="cflow\BlockDeobfuscator.cs" />
<Compile Include="cflow\BlocksCflowDeobfuscator.cs" />
<Compile Include="cflow\BranchEmulator.cs" />
<Compile Include="cflow\CachedCflowDeobfuscator.cs" />
<Compile Include="cflow\CflowDeobfuscator.cs" />
<Compile Include="cflow\CflowUtils.cs" />
<Compile Include="cflow\ConstantsFolder.cs" />
<Compile Include="cflow\DeadCodeRemover.cs" />
<Compile Include="cflow\DeadStoreRemover.cs" />
<Compile Include="cflow\DupBlockDeobfuscator.cs" />
<Compile Include="cflow\IBlocksDeobfuscator.cs" />
<Compile Include="cflow\ICflowDeobfuscator.cs" />
<Compile Include="cflow\InstructionEmulator.cs" />
<Compile Include="cflow\Int32Value.cs" />
<Compile Include="cflow\Int64Value.cs" />
<Compile Include="cflow\MethodCallInliner.cs" />
<Compile Include="cflow\MethodCallInlinerBase.cs" />
<Compile Include="cflow\Real8Value.cs" />
<Compile Include="cflow\StLdlocFixer.cs" />
<Compile Include="cflow\SwitchCflowDeobfuscator.cs" />
<Compile Include="cflow\Value.cs" />
<Compile Include="cflow\ValueStack.cs" />
<Compile Include="CodeGenerator.cs" />
<Compile Include="DeadBlocksRemover.cs" />
<Compile Include="DotNetUtils.cs" />
<Compile Include="DumpedMethod.cs" />
<Compile Include="DumpedMethods.cs" />
<Compile Include="FilterHandlerBlock.cs" />
<Compile Include="ForwardScanOrder.cs" />
<Compile Include="GenericArgsSubstitutor.cs" />
<Compile Include="HandlerBlock.cs" />
<Compile Include="Instr.cs" />
<Compile Include="InstructionListParser.cs" />
<Compile Include="MemberDefDict.cs" />
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\dnlib\src\dnlib.csproj">
<Project>{FDFC1237-143F-4919-8318-4926901F4639}</Project>
<Name>dnlib</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
-->
</Project>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
@ -14,6 +14,7 @@
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\de4dot.snk</AssemblyOriginatorKeyFile>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -25,6 +26,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -36,11 +38,15 @@
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="LinqBridge">
<HintPath>..\LinqBridge.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Remoting" />
@ -150,6 +156,29 @@
<Compile Include="deobfuscators\CodeWall\randomc\CRandomMersenne.cs" />
<Compile Include="deobfuscators\CodeWall\randomc\CRandomMother.cs" />
<Compile Include="deobfuscators\CodeWall\StringDecrypter.cs" />
<Compile Include="deobfuscators\ConfuserEx\ConstantDecrypter.cs" />
<Compile Include="deobfuscators\ConfuserEx\ConstantInliner.cs" />
<Compile Include="deobfuscators\ConfuserEx\Deobfuscator.cs" />
<Compile Include="deobfuscators\ConfuserEx\ControlFlowSolver.cs" />
<Compile Include="deobfuscators\ConfuserEx\LzmaFinder.cs" />
<Compile Include="deobfuscators\ConfuserEx\ResourceDecrypter.cs" />
<Compile Include="deobfuscators\ConfuserEx\Utils.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Bea\Constants.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Bea\Engine.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Bea\Structs.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86ADD.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86DIV.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86IMUL.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86MOV.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86NEG.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86NOT.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86POP.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86PUSH.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86SUB.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Instructions\X86XOR.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\UnmanagedBuff.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\X86Instruction.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\X86Method.cs" />
<Compile Include="deobfuscators\Confuser\AntiDebugger.cs" />
<Compile Include="deobfuscators\Confuser\AntiDumping.cs" />
<Compile Include="deobfuscators\Confuser\Arg64ConstantsReader.cs" />
@ -270,6 +299,7 @@
<Compile Include="deobfuscators\InitializedDataCreator.cs" />
<Compile Include="deobfuscators\InlinedMethodsFinder.cs" />
<Compile Include="deobfuscators\ISimpleDeobfuscator.cs" />
<Compile Include="deobfuscators\Lzma.cs" />
<Compile Include="deobfuscators\MaxtoCode\CryptDecrypter.cs" />
<Compile Include="deobfuscators\MaxtoCode\Decrypter6.cs" />
<Compile Include="deobfuscators\MaxtoCode\DecrypterInfo.cs" />
@ -423,4 +453,4 @@ copy "$(SolutionDir)COPYING" "..\$(OutDir)..\LICENSES"</PostBuildEvent>
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@ -1,113 +1,113 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
//
// 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 {
get {
object obj = ResourceManager.GetObject("CSVM1", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM2 {
get {
object obj = ResourceManager.GetObject("CSVM2", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM3 {
get {
object obj = ResourceManager.GetObject("CSVM3", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM4 {
get {
object obj = ResourceManager.GetObject("CSVM4", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM5 {
get {
object obj = ResourceManager.GetObject("CSVM5", resourceCulture);
return ((byte[])(obj));
}
}
}
}
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// 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 {
get {
object obj = ResourceManager.GetObject("CSVM1", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM2 {
get {
object obj = ResourceManager.GetObject("CSVM2", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM3 {
get {
object obj = ResourceManager.GetObject("CSVM3", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM4 {
get {
object obj = ResourceManager.GetObject("CSVM4", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM5 {
get {
object obj = ResourceManager.GetObject("CSVM5", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@ -0,0 +1,663 @@
using de4dot.blocks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using de4dot.blocks.cflow;
using de4dot.code.deobfuscators.ConfuserEx.x86;
namespace de4dot.code.deobfuscators.ConfuserEx
{
public class ConstantDecrypterBase
{
private X86Method _nativeMethod;
private readonly InstructionEmulator _instructionEmulator = new InstructionEmulator();
private int? CalculateKey()
{
var popValue = _instructionEmulator.Peek();
if (popValue == null || !popValue.IsInt32() || !(popValue as Int32Value).AllBitsValid())
return null;
_instructionEmulator.Pop();
int result = _nativeMethod.Execute(((Int32Value)popValue).Value);
return result;
}
public MethodDef Method { get; set; }
public MethodDef NativeMethod { get; set; }
public byte[] Decrypted { get; set; }
public uint Magic1 { get; set; }
public uint Magic2 { get; set; }
public bool CanRemove { get; set; } = true;
private uint CalculateMagic(uint index)
{
_instructionEmulator.Push(new Int32Value((int)index));
_nativeMethod = new X86Method(NativeMethod, Method.Module as ModuleDefMD); //TODO: Possible null
int? key = CalculateKey();
uint uint_0 = (uint) key.Value;
uint_0 &= 0x3fffffff;
uint_0 <<= 2;
return uint_0;
}
public string DecryptString(uint index)
{
index = CalculateMagic(index);
int count = BitConverter.ToInt32(Decrypted, (int)index);
return string.Intern(Encoding.UTF8.GetString(Decrypted, (int)index + 4, count));
}
public T DecryptConstant<T>(uint index)
{
index = CalculateMagic(index);
T[] array = new T[1];
Buffer.BlockCopy(Decrypted, (int)index, array, 0, Marshal.SizeOf(typeof(T)));
return array[0];
}
public byte[] DecryptArray(uint index)
{
index = CalculateMagic(index);
int count = BitConverter.ToInt32(Decrypted, (int)index);
//int lengt = BitConverter.ToInt32(Decrypted, (int)index+4); we actualy dont need that
byte[] buffer = new byte[count - 4];
Buffer.BlockCopy(Decrypted, (int)index + 8, buffer, 0, count - 4);
return buffer;
}
}
public class ConstantsDecrypter
{
TypeDef arrayType;
MethodDef constantsDecInitMethod;
FieldDef decryptedField, arrayField;
List<ConstantDecrypterBase> constantDecrpers = new List<ConstantDecrypterBase>();
byte[] decryptedBytes;
bool canRemoveLzma = true;
public bool CanRemoveLzma
{
get { return canRemoveLzma; }
}
public TypeDef Type
{
get { return arrayType; }
}
public MethodDef Method
{
get { return constantsDecInitMethod; }
}
public List<FieldDef> Fields
{
get { return new List<FieldDef>() { decryptedField, arrayField }; }
}
public List<ConstantDecrypterBase> Decrypters
{
get { return constantDecrpers; }
}
public bool Detected
{
get { return constantsDecInitMethod != null && decryptedBytes != null && constantDecrpers.Count != 0 && decryptedField != null && arrayField != null; }
}
ModuleDef module;
MethodDef lzmaMethod;
ISimpleDeobfuscator deobfuscator;
public ConstantsDecrypter(ModuleDef module, MethodDef lzmaMethod, ISimpleDeobfuscator deobfsucator)
{
this.module = module;
this.lzmaMethod = lzmaMethod;
this.deobfuscator = deobfsucator;
}
public void Find()
{
var moduleCctor = DotNetUtils.GetModuleTypeCctor(module);
if (moduleCctor == null)
return;
foreach (var inst in moduleCctor.Body.Instructions)
{
if (inst.OpCode != OpCodes.Call)
continue;
if (!(inst.Operand is MethodDef))
continue;
var method = inst.Operand as MethodDef;
if (!method.HasBody || !method.IsStatic)
continue;
if (!DotNetUtils.IsMethod(method, "System.Void", "()"))
continue;
deobfuscator.Deobfuscate(method, SimpleDeobfuscatorFlags.Force);
if (!isStrDecryptInit(method))
continue;
constantsDecInitMethod = method;
FindStringDecrypters(moduleCctor.DeclaringType);
}
}
bool isStrDecryptInit(MethodDef method)
{
var instructions = method.Body.Instructions;
if (instructions.Count < 15)
return false;
if (!instructions[0].IsLdcI4())
return false;
if (!instructions[1].IsStloc()) //uint num = 96u;
return false;
if (!instructions[2].IsLdcI4())
return false;
if (instructions[0].GetLdcI4Value() != instructions[2].GetLdcI4Value())
return false;
if (instructions[3].OpCode != OpCodes.Newarr)
return false;
if (instructions[3].Operand.ToString() != "System.UInt32")
return false;
if (instructions[4].OpCode != OpCodes.Dup)
return false;
if (instructions[5].OpCode != OpCodes.Ldtoken)
return false;
var aField = instructions[5].Operand as FieldDef;
if (aField == null)
return false;
if (aField.InitialValue == null)
return false;
if (aField.Attributes != (FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.HasFieldRVA))
return false;
if (instructions[6].OpCode != OpCodes.Call)
return false;
if (instructions[6].Operand.ToString() != "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)")
return false;
if (!instructions[7].IsStloc()) // uint[] array = new uint[] {.....};
return false;
var l = instructions.Count;
if (!instructions[l - 4].IsLdloc())
return false;
if (instructions[l - 3].OpCode != OpCodes.Call)
return false;
if (instructions[l - 3].Operand != lzmaMethod)
return false;
if (instructions[l - 2].OpCode != OpCodes.Stsfld) //<Module>.byte_0 = <Module>.smethod_0(array4);
return false;
var dField = instructions[l - 2].Operand as FieldDef;
if (dField == null)
return false;
try
{
DecryptArray(ConvertArray<uint, byte>(aField.InitialValue));
}
catch (Exception e) { Console.WriteLine(e.Message); canRemoveLzma = false; return false; }
arrayField = aField;
arrayType = DotNetUtils.GetType(module, aField.FieldSig.Type);
decryptedField = dField;
return true;
}
private T[] ConvertArray<T, T1>(T1[] array)
{
int l = Marshal.SizeOf(typeof(T));
int l1 = Marshal.SizeOf(typeof(T1));
var buffer = new T[(array.Length * l1) / l];
Buffer.BlockCopy(array, 0, buffer, 0, array.Length * l1);
return buffer;
}
private void DecryptArray(uint[] array)
{
uint num = 1680u; // array size?
uint[] array2 = new uint[16];
uint num2 = 3186233426u;
for (int i = 0; i < 16; i++)
{
num2 ^= num2 >> 12;
num2 ^= num2 << 25;
num2 ^= num2 >> 27;
array2[i] = num2;
}
int num3 = 0;
int num4 = 0;
uint[] array3 = new uint[16];
byte[] array4 = new byte[num * 4u];
while ((long)num3 < (long)((ulong)num))
{
for (int j = 0; j < 16; j++)
{
array3[j] = array[num3 + j];
}
uint num5 = array3[9] >> 23;
array3[0] = array3[0] * 865957733u;
array3[9] = array3[9] << 9;
array3[9] = (array3[9] | num5);
array3[3] = (array3[3] ^ 4272581837u);
array3[8] = (array3[8] ^ array2[8]);
num5 = (array3[14] & 3955221806u);
num5 *= 1105615415u;
array3[14] = (array3[14] & 339745489u);
array3[14] = (array3[14] | (array3[0] & 3955221806u));
array3[15] = (array3[15] ^ array3[8]);
array3[0] = (array3[0] & 339745489u);
array3[0] = (array3[0] | num5 * 809663367u);
array3[14] = (array3[14] ^ 1753824488u);
num5 = array3[11] << 18;
array3[11] = array3[11] >> 14;
array3[1] = array3[1] - 301755752u;
array3[11] = (array3[11] | num5);
uint num6 = array3[14] << 3;
num5 = (array3[9] & 2370496838u);
array3[10] = array3[10] - 4147007853u;
uint num7 = array3[14] << 4;
num5 *= 2575732745u;
num6 += array3[14] << 4;
array3[9] = (array3[9] & 1924470457u);
array3[9] = (array3[9] | (array3[2] & 2370496838u));
array3[12] = array3[12] - array3[6];
array3[2] = (array3[2] & 1924470457u);
array3[0] = array3[0] - array3[4];
array3[2] = (array3[2] | num5 * 593100345u);
num5 = array3[6] * 993944645u;
array3[6] = array3[5];
uint num8 = array3[14] * 19u;
array3[5] = num5 * 679153293u;
num5 = (array3[1] & 4141471236u);
num8 += array3[5] * 67u;
num8 += array3[10] * 43u;
array3[13] = (array3[13] ^ array2[13]);
array3[1] = (array3[1] & 153496059u);
num6 += array3[5] * 92u;
num7 += array3[5] * 57u;
num7 += array3[10] * 37u;
num5 *= 831032307u;
array3[1] = (array3[1] | (array3[12] & 4141471236u));
array3[0] = (array3[0] ^ array2[0]);
array3[12] = (array3[12] & 153496059u);
array3[11] = (array3[11] ^ array2[11]);
num6 += array3[10] << 6;
array3[12] = (array3[12] | num5 * 419693883u);
num7 += array3[15] * 107u;
array3[3] = (array3[3] ^ array2[3]);
num5 = (array3[13] & 2032982899u);
array3[13] = (array3[13] & 2261984396u);
num5 *= 3754449215u;
num8 += array3[15] * 125u;
num6 += array3[15] * 179u;
array3[13] = (array3[13] | (array3[7] & 2032982899u));
array3[7] = (array3[7] & 2261984396u);
array3[7] = (array3[7] | num5 * 1302730431u);
num5 = array3[14] * 7u;
num5 += array3[5] * 25u;
array3[12] = (array3[12] ^ ~array3[4]);
num5 += array3[10] << 4;
array3[5] = num6;
array3[10] = num7;
num6 = array3[2] >> 19;
num7 = array3[11] >> 19;
num5 += array3[15] * 46u;
array3[15] = num8;
num8 = array3[0] << 2;
array3[2] = array3[2] << 13;
array3[11] = array3[11] << 13;
array3[14] = num5;
array3[0] = array3[0] >> 30;
array3[2] = (array3[2] | num6);
array3[6] = (array3[6] ^ 825592879u);
array3[2] = (array3[2] ^ array2[2]);
array3[11] = (array3[11] | num7);
num5 = array3[15] << 1;
array3[0] = (array3[0] | num8);
num8 = array3[15] * 23u;
num7 = array3[15] * 7u;
num8 += array3[7] * 45u;
num7 += array3[7] * 11u;
num5 += array3[15];
array3[9] = (array3[9] ^ array2[9]);
num5 += array3[7] * 7u;
num8 += array3[13] << 7;
array3[3] = (array3[3] ^ ~array3[8]);
array3[10] = array3[10] * 2256145475u;
num6 = array3[15] << 2;
num6 += array3[15];
num7 += array3[13] << 5;
num7 += array3[1] << 1;
num6 += array3[7] << 2;
num6 += array3[7] << 3;
num8 += array3[13];
num8 += array3[1] * 143u;
num5 += array3[13] << 2;
num6 += array3[13] << 1;
num7 += array3[1] << 5;
num5 += array3[13] << 4;
array3[15] = num7;
num5 += array3[1] * 23u;
num6 += array3[13] << 5;
array3[7] = num5;
num6 += array3[1] * 39u;
array3[1] = num8;
num8 = array3[1] * 26u;
num7 = array3[1] << 6;
array3[7] = (array3[7] ^ array2[7]);
array3[13] = num6;
num5 = array3[1] << 1;
num5 += array3[1] << 3;
num6 = array3[1] * 13u;
num5 += array3[13] << 1;
num7 += array3[1];
num6 += array3[13] * 45u;
array3[9] = (array3[9] ^ 786150263u);
num8 += array3[13] * 88u;
num6 += array3[2] * 67u;
array3[8] = (array3[8] ^ 110539985u);
num5 += array3[13] << 5;
num6 += array3[11] << 1;
num8 += array3[2] * 133u;
array3[10] = (array3[10] ^ array2[10]);
num8 += array3[11] << 6;
array3[15] = array3[15] - 2992485470u;
array3[0] = array3[0] - array3[6];
num6 += array3[11] << 5;
num5 += array3[2] * 51u;
num5 += array3[11] * 25u;
array3[12] = (array3[12] ^ ~array3[3]);
num7 += array3[13] * 222u;
array3[13] = num5;
array3[1] = num6;
array3[13] = array3[13] * 3578289835u;
num6 = (array3[10] & 381620437u);
array3[10] = (array3[10] & 3913346858u);
num5 = array3[0] * 14u;
num7 += array3[2] * 333u;
array3[2] = num8;
num5 += array3[3] * 11u;
array3[10] = (array3[10] | (array3[14] & 381620437u));
array3[7] = (array3[7] ^ ~array3[4]);
num6 *= 3323466531u;
array3[14] = (array3[14] & 3913346858u);
num8 = array3[0] << 2;
num5 += array3[5] * 54u;
array3[14] = (array3[14] | num6 * 1991488651u);
num7 += array3[11] * 164u;
num6 = (array3[2] & 2341248020u);
array3[11] = num7;
num7 = array3[0] * 11u;
num8 += array3[0] << 4;
array3[2] = (array3[2] & 1953719275u);
num8 += array3[3] << 2;
array3[2] = (array3[2] | (array3[11] & 2341248020u));
num8 += array3[3] << 4;
num6 *= 4030567715u;
array3[14] = (array3[14] ^ array2[14]);
array3[11] = (array3[11] & 1953719275u);
array3[11] = (array3[11] | num6 * 62866059u);
num6 = array3[0] << 2;
num8 += array3[5] * 90u;
num7 += array3[3] << 4;
num7 += array3[5] << 2;
num6 += array3[0];
array3[12] = (array3[12] ^ array2[12]);
num7 += array3[5] << 6;
num8 += array3[13] * 117u;
array3[9] = (array3[9] ^ array3[5]);
num5 += array3[13] * 52u;
num6 += array3[3] << 1;
num6 += array3[3];
num7 += array3[13] * 126u;
num6 += array3[5] << 4;
num6 += array3[5];
array3[5] = num8;
array3[3] = num5;
num6 += array3[13] * 11u;
array3[0] = num6;
array3[13] = num7;
num6 = array3[6] << 1;
num6 += array3[15] << 1;
num5 = array3[12] << 29;
num6 += array3[15] << 2;
num7 = array3[7] << 12;
array3[11] = array3[11] - array3[10];
array3[7] = array3[7] >> 20;
array3[12] = array3[12] >> 3;
array3[12] = (array3[12] | num5);
array3[14] = (array3[14] ^ ~array3[8]);
array3[1] = (array3[1] ^ array2[1]);
array3[1] = (array3[1] ^ 3215842197u);
num8 = array3[6] * 7u;
array3[7] = (array3[7] | num7);
num8 += array3[15] * 26u;
num5 = array3[6] << 2;
num5 += array3[15] << 2;
array3[9] = array3[9] - array3[2];
num7 = array3[6] << 2;
array3[4] = (array3[4] ^ array2[4]);
num6 += array3[4] << 4;
array3[3] = (array3[3] ^ 1425746098u);
num5 += array3[15];
num8 += array3[4] * 69u;
num5 += array3[4] * 15u;
num7 += array3[6];
num6 += array3[1] * 15u;
num8 += array3[1] * 63u;
array3[6] = num6;
num7 += array3[15] * 11u;
num7 += array3[4] * 31u;
num7 += array3[1] * 30u;
num5 += array3[1] << 4;
array3[5] = (array3[5] ^ array2[5]);
array3[4] = num7;
num7 = (array3[5] & 2375297997u);
array3[6] = (array3[6] ^ array2[6]);
num7 *= 3574473459u;
array3[15] = num5;
array3[5] = (array3[5] & 1919669298u);
array3[5] = (array3[5] | (array3[13] & 2375297997u));
array3[1] = num8;
array3[15] = (array3[15] ^ array2[15]);
num8 = array3[0] << 5;
array3[13] = (array3[13] & 1919669298u);
array3[13] = (array3[13] | num7 * 2683487803u);
array3[0] = array3[0] >> 27;
array3[0] = (array3[0] | num8);
for (int k = 0; k < 16; k++)
{
uint num9 = array3[k];
array4[num4++] = (byte)num9;
array4[num4++] = (byte)(num9 >> 8);
array4[num4++] = (byte)(num9 >> 16);
array4[num4++] = (byte)(num9 >> 24);
array2[k] ^= num9;
}
num3 += 16;
}
decryptedBytes = Lzma.Decompress(array4);
}
private void FindStringDecrypters(TypeDef type)
{
foreach (var method in type.Methods)
{
if (!method.HasBody)
continue;
if (!(method.Signature.ContainsGenericParameter))
continue;
var sig = method.MethodSig;
if (sig == null)
continue;
if (sig.Params.Count != 1)
continue;
if (sig.Params[0].GetElementType() != ElementType.U4)
continue;
if (!(sig.RetType.RemovePinnedAndModifiers() is GenericMVar))
continue;
if (sig.GenParamCount != 1)
continue;
deobfuscator.Deobfuscate(method, SimpleDeobfuscatorFlags.Force);
IsStringDecrypter(method);
}
}
string[] strDecryptCalledMethods = {
"System.Text.Encoding System.Text.Encoding::get_UTF8()",
"System.String System.Text.Encoding::GetString(System.Byte[],System.Int32,System.Int32)",
"System.Array System.Array::CreateInstance(System.Type,System.Int32)",
"System.String System.String::Intern(System.String)",
"System.Void System.Buffer::BlockCopy(System.Array,System.Int32,System.Array,System.Int32,System.Int32)",
"System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)",
"System.Type System.Type::GetElementType()"
};
private void IsStringDecrypter(MethodDef method)
{
var instr = method.Body.Instructions;
if (instr.Count < 25)
return;
int i = 0;
if (!instr[i++].IsLdarg())
return;
if (instr[i].OpCode != OpCodes.Call)
return;
var nativeMethod = instr[i++].Operand as MethodDef;
if (nativeMethod == null || !nativeMethod.IsStatic || !nativeMethod.IsNative)
return;
if (!DotNetUtils.IsMethod(nativeMethod, "System.Int32", "(System.Int32)"))
return;
if (!instr[i++].IsStarg()) //uint_0 = (uint_0 * 2857448701u ^ 1196001109u);
return;
if (!instr[i++].IsLdarg())
return;
if (!instr[i].IsLdcI4() || instr[i++].GetLdcI4Value() != 0x1E)
return;
if (instr[i++].OpCode != OpCodes.Shr_Un)
return;
if (!instr[i++].IsStloc()) //uint num = uint_0 >> 30;
return;
i++;
//TODO: Implement
//if (!instr[10].IsLdloca())
// return;
if (instr[i++].OpCode != OpCodes.Initobj)
return;
if (!instr[i++].IsLdarg())
return;
if (!instr[i].IsLdcI4() || instr[i++].GetLdcI4Value() != 0x3FFFFFFF)
return;
if (instr[i++].OpCode != OpCodes.And)
return;
if (!instr[i++].IsStarg()) //uint_0 &= 1073741823u;
return;
if (!instr[i++].IsLdarg())
return;
if (!instr[i].IsLdcI4() || instr[i++].GetLdcI4Value() != 2)
return;
if (instr[i++].OpCode != OpCodes.Shl)
return;
if (!instr[i++].IsStarg()) //uint_0 <<= 2;
return;
foreach (var mtd in strDecryptCalledMethods)
if (!DotNetUtils.CallsMethod(method, mtd))
return;
//TODO: Implement
//if (!DotNetUtils.LoadsField(method, decryptedField))
// return;
constantDecrpers.Add(new ConstantDecrypterBase()
{
Decrypted = decryptedBytes,
Method = method,
NativeMethod = nativeMethod,
});
}
static bool VerifyGenericArg(MethodSpec gim, ElementType etype)
{
if (gim == null)
return false;
var gims = gim.GenericInstMethodSig;
if (gims == null || gims.GenericArguments.Count != 1)
return false;
return gims.GenericArguments[0].GetElementType() == etype;
}
public string DecryptString(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.String))
return null;
return info.DecryptString(magic1);
}
public object DecryptSByte(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.I1))
return null;
return info.DecryptConstant<sbyte>(magic1);
}
public object DecryptByte(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.U1))
return null;
return info.DecryptConstant<byte>(magic1);
}
public object DecryptInt16(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.I2))
return null;
return info.DecryptConstant<short>(magic1);
}
public object DecryptUInt16(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.U2))
return null;
return info.DecryptConstant<ushort>(magic1);
}
public object DecryptInt32(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.I4))
return null;
return info.DecryptConstant<int>(magic1);
}
public object DecryptUInt32(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.U4))
return null;
return info.DecryptConstant<uint>(magic1);
}
public object DecryptInt64(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.I8))
return null;
return info.DecryptConstant<long>(magic1);
}
public object DecryptUInt64(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.U8))
return null;
return info.DecryptConstant<ulong>(magic1);
}
public object DecryptSingle(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.R4))
return null;
return info.DecryptConstant<float>(magic1);
}
public object DecryptDouble(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.R8))
return null;
return info.DecryptConstant<double>(magic1);
}
public object DecryptArray(ConstantDecrypterBase info, MethodSpec gim, uint magic1)
{
if (!VerifyGenericArg(gim, ElementType.SZArray))
return null;
return info.DecryptArray(magic1);
}
}
}

View File

@ -0,0 +1,181 @@
using System.Collections.Generic;
using de4dot.blocks;
using de4dot.blocks.cflow;
using System;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.ConfuserEx
{
class ConstantsInliner : IBlocksDeobfuscator
{
Blocks blocks;
SByteValueInliner sbyteValueInliner;
ByteValueInliner byteValueInliner;
Int16ValueInliner int16ValueInliner;
UInt16ValueInliner uint16ValueInliner;
Int32ValueInliner int32ValueInliner;
UInt32ValueInliner uint32ValueInliner;
Int64ValueInliner int64ValueInliner;
UInt64ValueInliner uint64ValueInliner;
SingleValueInliner singleValueInliner;
DoubleValueInliner doubleValueInliner;
ArrayValueInliner arrayValueInliner;
public bool ExecuteIfNotModified { get; set; }
public ConstantsInliner(SByteValueInliner sbyteValueInliner, ByteValueInliner byteValueInliner,
Int16ValueInliner int16ValueInliner, UInt16ValueInliner uint16ValueInliner, Int32ValueInliner int32ValueInliner,
UInt32ValueInliner uint32ValueInliner, Int64ValueInliner int64ValueInliner, UInt64ValueInliner uint64ValueInliner,
SingleValueInliner singleValueInliner, DoubleValueInliner doubleValueInliner, ArrayValueInliner arrayValueInliner)
{
this.sbyteValueInliner = sbyteValueInliner;
this.byteValueInliner = byteValueInliner;
this.int16ValueInliner = int16ValueInliner;
this.uint16ValueInliner = uint16ValueInliner;
this.int32ValueInliner = int32ValueInliner;
this.uint32ValueInliner = uint32ValueInliner;
this.int64ValueInliner = int64ValueInliner;
this.uint64ValueInliner = uint64ValueInliner;
this.singleValueInliner = singleValueInliner;
this.doubleValueInliner = doubleValueInliner;
this.arrayValueInliner = arrayValueInliner;
}
public void DeobfuscateBegin(Blocks blocks)
{
this.blocks = blocks;
}
public bool Deobfuscate(List<Block> allBlocks)
{
bool modified = false;
foreach (var block in allBlocks)
{
modified |= sbyteValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= byteValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= int16ValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= uint16ValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= int32ValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= uint32ValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= int64ValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= uint64ValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= singleValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= doubleValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
modified |= arrayValueInliner.Decrypt(blocks.Method, allBlocks) != 0;
}
return modified;
}
}
public class SByteValueInliner : ValueInlinerBase<sbyte>
{
protected override void InlineReturnValues(IList<CallResult> callResults)
{
foreach (var callResult in callResults)
{
var block = callResult.block;
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
block.Replace(callResult.callStartIndex, num, Instruction.CreateLdcI4((int)callResult.returnValue));
RemoveUnboxInstruction(block, callResult.callStartIndex + 1, "System.SByte");
Logger.v("Decrypted sbyte: {0}", callResult.returnValue);
}
}
}
public class ByteValueInliner : ValueInlinerBase<byte>
{
protected override void InlineReturnValues(IList<CallResult> callResults)
{
foreach (var callResult in callResults)
{
var block = callResult.block;
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
block.Replace(callResult.callStartIndex, num, Instruction.CreateLdcI4((int)callResult.returnValue));
RemoveUnboxInstruction(block, callResult.callStartIndex + 1, "System.Byte");
Logger.v("Decrypted byte: {0}", callResult.returnValue);
}
}
}
public class Int16ValueInliner : ValueInlinerBase<short>
{
protected override void InlineReturnValues(IList<CallResult> callResults)
{
foreach (var callResult in callResults)
{
var block = callResult.block;
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
block.Replace(callResult.callStartIndex, num, Instruction.CreateLdcI4((int)callResult.returnValue));
RemoveUnboxInstruction(block, callResult.callStartIndex + 1, "System.Int16");
Logger.v("Decrypted int16: {0}", callResult.returnValue);
}
}
}
public class UInt16ValueInliner : ValueInlinerBase<ushort>
{
protected override void InlineReturnValues(IList<CallResult> callResults)
{
foreach (var callResult in callResults)
{
var block = callResult.block;
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
block.Replace(callResult.callStartIndex, num, Instruction.CreateLdcI4((int)callResult.returnValue));
RemoveUnboxInstruction(block, callResult.callStartIndex + 1, "System.UInt16");
Logger.v("Decrypted uint16: {0}", callResult.returnValue);
}
}
}
public class UInt32ValueInliner : ValueInlinerBase<uint>
{
protected override void InlineReturnValues(IList<CallResult> callResults)
{
foreach (var callResult in callResults)
{
var block = callResult.block;
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
block.Replace(callResult.callStartIndex, num, Instruction.CreateLdcI4((int)callResult.returnValue));
RemoveUnboxInstruction(block, callResult.callStartIndex + 1, "System.UInt32");
Logger.v("Decrypted uint32: {0}", callResult.returnValue);
}
}
}
public class UInt64ValueInliner : ValueInlinerBase<ulong>
{
protected override void InlineReturnValues(IList<CallResult> callResults)
{
foreach (var callResult in callResults)
{
var block = callResult.block;
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
block.Replace(callResult.callStartIndex, num, OpCodes.Ldc_I8.ToInstruction((long)callResult.returnValue));
RemoveUnboxInstruction(block, callResult.callStartIndex + 1, "System.UInt64");
Logger.v("Decrypted uint64: {0}", callResult.returnValue);
}
}
}
public class ArrayValueInliner : ValueInlinerBase<Array>
{
InitializedDataCreator initializedDataCreator;
public ArrayValueInliner(InitializedDataCreator initializedDataCreator) { this.initializedDataCreator = initializedDataCreator; }
protected override void InlineReturnValues(IList<CallResult> callResults)
{
foreach (var callResult in callResults)
{
var block = callResult.block;
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
var generic = (callResult.GetMethodRef() as MethodSpec).GenericInstMethodSig.GenericArguments;
ITypeDefOrRef sig = generic[0].Next.ToTypeDefOrRef();
initializedDataCreator.AddInitializeArrayCode(block, callResult.callStartIndex, num, sig, callResult.returnValue as byte[]);
RemoveUnboxInstruction(block, callResult.callStartIndex + 1, sig.ToString()); //TODO: sig.ToString() ??
Logger.v("Decrypted array <{1}>: {0}", callResult.returnValue, sig.ToString());
}
}
}
}

View File

@ -0,0 +1,322 @@
using System;
using System.Collections.Generic;
using System.Linq;
using de4dot.blocks;
using de4dot.blocks.cflow;
using de4dot.code.deobfuscators.ConfuserEx.x86;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.ConfuserEx
{
class ControlFlowSolver : IBlocksDeobfuscator
{
public bool ExecuteIfNotModified { get; }
private readonly InstructionEmulator _instructionEmulator = new InstructionEmulator();
private Blocks _blocks;
private X86Method _nativeMethod;
private Local _switchKey;
private int? CalculateKey()
{
var popValue = _instructionEmulator.Peek();
if (popValue == null || !popValue.IsInt32() || !(popValue as Int32Value).AllBitsValid())
return null;
_instructionEmulator.Pop();
int result = _nativeMethod.Execute(((Int32Value)popValue).Value);
return result;
}
private int CalculateSwitchCaseIndex(Block block, int nativeKey)
{
_instructionEmulator.Push(new Int32Value(nativeKey));
_instructionEmulator.Emulate(block.Instructions, block.SwitchData.IsKeyHardCoded ? 2 : 1, block.Instructions.Count - 1);
var popValue = _instructionEmulator.Peek();
_instructionEmulator.Pop();
return ((Int32Value)popValue).Value;
}
private void ProcessHardcodedSwitch(Block switchBlock) // a single-case switch
{
var targets = switchBlock.Targets;
_instructionEmulator.Push(new Int32Value(switchBlock.SwitchData.Key.Value));
int? key = CalculateKey();
if (!key.HasValue)
throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE");
int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value);
if (targets.Count < switchCaseIndex)
throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE");
var targetBlock = targets[switchCaseIndex];
targetBlock.SwitchData.Key = key;
switchBlock.Instructions.Clear();
switchBlock.ReplaceLastNonBranchWithBranch(0, targetBlock);
}
private void ProcessBlock(List<Block> switchCaseBlocks, Block block, Block switchBlock)
{
var targets = switchBlock.Targets;
_instructionEmulator.Emulate(block.Instructions, 0, block.Instructions.Count);
if (_instructionEmulator.Peek().IsUnknown())
throw new Exception("CRITICAL ERROR: STACK VALUE UNKNOWN");
int? key = CalculateKey();
if (!key.HasValue)
throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE");
int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value);
if (targets.Count < switchCaseIndex)
throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE");
var targetBlock = targets[switchCaseIndex];
targetBlock.SwitchData.Key = key;
block.Add(new Instr(OpCodes.Pop.ToInstruction())); // neutralize the arithmetics and leave de4dot to remove them
block.ReplaceLastNonBranchWithBranch(0, targetBlock);
ProcessFallThroughs(switchCaseBlocks, switchBlock, targetBlock, key.Value);
block.Processed = true;
}
private void ProcessTernaryBlock(List<Block> switchCaseBlocks, Block ternaryBlock, Block switchBlock)
{
var targets = switchBlock.Targets;
for (int i = 0; i < 2; i++) // loop both source blocks
{
var sourceBlock = ternaryBlock.Sources[0];
if(ternaryBlock.SwitchData.Key.HasValue) // single instruction: pop -- no key!
SetLocalSwitchKey(ternaryBlock.SwitchData.Key.Value); // set old key for both iterations!
_instructionEmulator.Emulate(sourceBlock.Instructions, 0, sourceBlock.Instructions.Count);
_instructionEmulator.Emulate(ternaryBlock.Instructions, 0, ternaryBlock.Instructions.Count);
if (_instructionEmulator.Peek().IsUnknown())
throw new Exception("CRITICAL ERROR: STACK VALUE UNKNOWN");
int? key = CalculateKey();
if (!key.HasValue)
throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE");
int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value);
if (targets.Count < switchCaseIndex)
throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE");
var targetBlock = targets[switchCaseIndex];
targetBlock.SwitchData.Key = key;
sourceBlock.Instructions[sourceBlock.Instructions.Count - 1] = new Instr(OpCodes.Pop.ToInstruction());
sourceBlock.ReplaceLastNonBranchWithBranch(0, targets[switchCaseIndex]);
ProcessFallThroughs(switchCaseBlocks, switchBlock, targets[switchCaseIndex], key.Value);
// the second source block now becomes the first one
}
//switchCaseBlock.Instructions.Clear();
ternaryBlock.Add(new Instr(OpCodes.Pop.ToInstruction())); // don't add pop before both iterations have finished
ternaryBlock.Processed = true;
}
public void DeobfuscateBegin(Blocks blocks)
{
_blocks = blocks;
_instructionEmulator.Initialize(_blocks, true);
}
public bool Deobfuscate(List<Block> methodBlocks)
{
List<Block> switchBlocks = GetSwitchBlocks(methodBlocks); // blocks that contain a switch
int modifications = 0;
foreach (Block switchBlock in switchBlocks)
{
if (!switchBlock.SwitchData.IsConfuserExSwitch())
{
Console.WriteLine("Unsupported switch block obfuscation!");
continue;
}
if (switchBlock.SwitchData.IsKeyHardCoded)
{
ProcessHardcodedSwitch(switchBlock);
modifications++;
continue;
}
_switchKey = Instr.GetLocalVar(_blocks.Locals,
switchBlock.Instructions[switchBlock.Instructions.Count - 4]);
if (DeobfuscateSwitchBlock(methodBlocks, switchBlock))
modifications++;
}
return modifications > 0;
}
private bool DeobfuscateSwitchBlock(List<Block> methodBlocks, Block switchBlock)
{
List<Block> switchFallThroughs = methodBlocks.FindAll(b => b.FallThrough == switchBlock); // blocks that fallthrough to the switch block
_instructionEmulator.Initialize(_blocks, true); //TODO: Remove temporary precaution
int blocksLeft = switchFallThroughs.Count; // how many blocks left to proccess
int blockIndex = 0; // block that sets the first switch destination
int failedCount = 0;
while (blocksLeft > 0)
{
if (blockIndex > switchFallThroughs.Count - 1)
{
blockIndex = 0;
}
if (failedCount > switchFallThroughs.Count)
{
Console.WriteLine("Some blocks couldn't be processed!");
break;
}
Block switchCaseBlock = switchFallThroughs[blockIndex];
if (switchCaseBlock.Processed)
{
blockIndex++;
continue;
}
if (NeedSwitchKey(switchCaseBlock))
{
if (!switchCaseBlock.SwitchData.Key.HasValue)
{
failedCount++;
blockIndex++;
continue;
}
SetLocalSwitchKey(switchCaseBlock.SwitchData.Key.Value);
}
if (switchCaseBlock.IsTernary())
{
ProcessTernaryBlock(switchFallThroughs, switchCaseBlock, switchBlock);
}
else
{
ProcessBlock(switchFallThroughs, switchCaseBlock, switchBlock);
}
failedCount = 0;
blocksLeft--;
blockIndex++;
}
if (blocksLeft == switchFallThroughs.Count) // Have we modified anything?
return false;
return true;
}
public bool IsSwitchBlock(Block block)
{
if (block.LastInstr.OpCode.Code != Code.Switch || ((Instruction[])block.LastInstr.Operand)?.Length == 0)
return false;
if (!block.SwitchData.IsNative())
return false;
_nativeMethod = new X86Method(block.SwitchData.GetNativeMethod(), _blocks.Method.Module as ModuleDefMD); //TODO: Possible null
return true;
}
public List<Block> GetSwitchBlocks(List<Block> blocks) // get the blocks which contain the switch statement
{
List<Block> switchBlocks = new List<Block>();
foreach (Block block in blocks)
if (IsSwitchBlock(block))
switchBlocks.Add(block);
return switchBlocks;
}
private readonly List<Block> _processedFallThroughs = new List<Block>();
// add the switch key to all appropriate fallthroughs
private void ProcessFallThroughs(List<Block> switchCaseBlocks, Block switchBlock, Block targetBlock, int switchKey)
{
DoProcessFallThroughs(switchCaseBlocks, switchBlock, targetBlock, switchKey);
_processedFallThroughs.Clear();
}
private void DoProcessFallThroughs(List<Block> switchCaseBlocks, Block switchBlock, Block targetBlock, int switchKey)
{
if (_processedFallThroughs.Contains(targetBlock))
return;
_processedFallThroughs.Add(targetBlock);
if (targetBlock.FallThrough == switchBlock && switchCaseBlocks.Contains(targetBlock) && !targetBlock.SwitchData.Key.HasValue)
targetBlock.SwitchData.Key = switchKey;
var fallThrough = targetBlock.FallThrough;
if (fallThrough == null)
return;
if (fallThrough.LastInstr.OpCode != OpCodes.Ret && fallThrough != switchBlock)
DoProcessFallThroughs(switchCaseBlocks, switchBlock, fallThrough, switchKey);
if (targetBlock.CountTargets() > 1)
foreach (Block targetBlockTarget in targetBlock.Targets)
{
if (targetBlockTarget == switchBlock)
return;
DoProcessFallThroughs(switchCaseBlocks, switchBlock, targetBlockTarget, switchKey);
}
}
private bool NeedSwitchKey(Block block)
{
foreach (var instr in block.Instructions)
if (instr.IsLdloc() && Instr.GetLocalVar(_blocks.Locals, instr) == _switchKey)
return true;
return false;
}
private int? GetSwitchKey()
{
var val = _instructionEmulator.GetLocal(_switchKey);
if (!val.IsInt32())
return null;
var value = val as Int32Value;
if (value == null || !value.AllBitsValid())
return null;
return value.Value;
}
private void SetLocalSwitchKey(int key)
{
_instructionEmulator.SetLocal(_switchKey, new Int32Value(key));
}
}
}

View File

@ -0,0 +1,278 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
using de4dot.blocks;
using de4dot.blocks.cflow;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System.Collections.Generic;
namespace de4dot.code.deobfuscators.ConfuserEx
{
public class DeobfuscatorInfo : DeobfuscatorInfoBase
{
public const string THE_NAME = "ConfuserEx";
public const string THE_TYPE = "cx";
const string DEFAULT_REGEX = DeobfuscatorBase.DEFAULT_ASIAN_VALID_NAME_REGEX;
public DeobfuscatorInfo()
: base(DEFAULT_REGEX)
{
}
public override string Name
{
get { return THE_NAME; }
}
public override string Type
{
get { return THE_TYPE; }
}
public override IDeobfuscator CreateDeobfuscator()
{
return new Deobfuscator(new Deobfuscator.Options
{
RenameResourcesInCode = false,
ValidNameRegex = validNameRegex.Get(),
});
}
class Deobfuscator : DeobfuscatorBase
{
bool detectedConfuserExAttribute = false, deobfuscating = false;
string version = "";
LzmaFinder lzmaFinder;
ConstantsDecrypter constantDecrypter;
ResourceDecrypter resourceDecrypter;
#region ConstantInliners
SByteValueInliner sbyteValueInliner;
ByteValueInliner byteValueInliner;
Int16ValueInliner int16ValueInliner;
UInt16ValueInliner uint16ValueInliner;
Int32ValueInliner int32ValueInliner;
UInt32ValueInliner uint32ValueInliner;
Int64ValueInliner int64ValueInliner;
UInt64ValueInliner uint64ValueInliner;
SingleValueInliner singleValueInliner;
DoubleValueInliner doubleValueInliner;
ArrayValueInliner arrayValueInliner;
#endregion
internal class Options : OptionsBase
{
}
public override string Type
{
get { return DeobfuscatorInfo.THE_TYPE; }
}
public override string TypeLong
{
get { return DeobfuscatorInfo.THE_NAME; }
}
public override string Name
{
get { return $"{TypeLong} {version}"; }
}
public Deobfuscator(Options options)
: base(options)
{
}
protected override int DetectInternal()
{
int 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);
resourceDecrypter = new ResourceDecrypter(module, lzmaFinder.Method, DeobfuscatedFile);
if (lzmaFinder.FoundLzma)
{
constantDecrypter.Find();
resourceDecrypter.Find();
}
DetectConfuserExAttribute();
}
public void DetectConfuserExAttribute()
{
var versions = new List<string>();
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 IEnumerable<IBlocksDeobfuscator> BlocksDeobfuscators
{
get
{
var list = new List<IBlocksDeobfuscator>();
list.Add(new ControlFlowSolver());
if (deobfuscating && int32ValueInliner != null)
list.Add(new ConstantsInliner(sbyteValueInliner, byteValueInliner, int16ValueInliner,
uint16ValueInliner,
int32ValueInliner, uint32ValueInliner, int64ValueInliner, uint64ValueInliner,
singleValueInliner, doubleValueInliner, arrayValueInliner)
{ExecuteIfNotModified = true});
return list;
}
}
bool CanRemoveLzma = true;
public override void DeobfuscateEnd()
{
FindAndRemoveInlinedMethods();
List<MethodDef> toRemoveFromCctor = new List<MethodDef>();
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");
}
var moduleCctor = DotNetUtils.GetModuleTypeCctor(module);
foreach (var instr in moduleCctor.Body.Instructions)
if (instr.OpCode == OpCodes.Call && instr.Operand is MethodDef &&
toRemoveFromCctor.Contains(instr.Operand as MethodDef))
instr.OpCode = OpCodes.Nop;
//No more mixed!
module.IsILOnly = true;
base.DeobfuscateEnd();
}
public override IEnumerable<int> GetStringDecrypterMethods()
{
var list = new List<int>();
return list;
}
}
}
}

View File

@ -0,0 +1,198 @@
using de4dot.blocks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace de4dot.code.deobfuscators.ConfuserEx
{
public class LzmaFinder
{
MethodDef decompressMethod;
List<TypeDef> types = new List<TypeDef>();
public MethodDef Method
{
get { return decompressMethod; }
}
public List<TypeDef> Types
{
get { return types; }
}
public bool FoundLzma
{
get { return decompressMethod != null && types.Count != 0; }
}
ModuleDef module;
ISimpleDeobfuscator deobfuscator;
public LzmaFinder(ModuleDef module, ISimpleDeobfuscator deobfuscator)
{
this.module = module;
this.deobfuscator = deobfuscator;
}
public void Find()
{
var moduleType = DotNetUtils.GetModuleType(module);
if (moduleType == null)
return;
foreach (var method in moduleType.Methods)
{
if (!method.HasBody || !method.IsStatic)
continue;
if (!DotNetUtils.IsMethod(method, "System.Byte[]", "(System.Byte[])"))
continue;
deobfuscator.Deobfuscate(method, SimpleDeobfuscatorFlags.Force);
if (!IsLzmaMethod(method))
continue;
decompressMethod = method;
var type = ((MethodDef)method.Body.Instructions[3].Operand).DeclaringType;
ExtractNestedTypes(type);
}
}
private bool IsLzmaMethod(MethodDef method)
{
var instructions = method.Body.Instructions;
if (instructions.Count < 60)
return false;
var firstInstruction = instructions.FirstOrDefault(
instr =>
instr.OpCode == OpCodes.Newobj &&
instr.Operand.ToString() == "System.Void System.IO.MemoryStream::.ctor(System.Byte[])");
if (firstInstruction == null)
return false;
int i = instructions.IndexOf(firstInstruction) + 1;
if (!instructions[i++].IsStloc())
return false;
if (instructions[i++].OpCode != OpCodes.Newobj)
return false;
if (!instructions[i++].IsStloc()) //<Module>.Class1 @class = new <Module>.Class1();
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 5)
return false;
if (instructions[i++].OpCode != OpCodes.Newarr)
return false;
if (!instructions[i++].IsStloc()) //byte[] buffer = new byte[5];
return false;
if (!instructions[i++].IsLdloc())
return false;
if (!instructions[i++].IsLdloc())
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 0)
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 5)
return false;
if (instructions[i].OpCode != OpCodes.Callvirt || instructions[i++].Operand.ToString() != "System.Int32 System.IO.Stream::Read(System.Byte[],System.Int32,System.Int32)")
return false;
if (instructions[i++].OpCode != OpCodes.Pop) //memoryStream.Read(buffer, 0, 5);
return false;
if (!instructions[i++].IsLdloc())
return false;
if (!instructions[i++].IsLdloc())
return false;
if (instructions[i++].OpCode != OpCodes.Callvirt) //@class.method_5(buffer);
return false;
firstInstruction =
instructions.FirstOrDefault(
instr =>
instr.OpCode == OpCodes.Callvirt &&
instr.Operand.ToString() == "System.Int32 System.IO.Stream::ReadByte()");
if (firstInstruction == null)
return false;
if (i >= instructions.IndexOf(firstInstruction))
return false;
i = instructions.IndexOf(firstInstruction) + 1;
if (!instructions[i++].IsStloc()) //int num2 = memoryStream.ReadByte();
return false;
if (!instructions[i++].IsLdloc())
return false;
if (!instructions[i++].IsLdloc())
return false;
if (instructions[i++].OpCode != OpCodes.Conv_U1)
return false;
if (instructions[i++].OpCode != OpCodes.Conv_U8)
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 8)
return false;
if (!instructions[i++].IsLdloc())
return false;
if (instructions[i++].OpCode != OpCodes.Mul)
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 0x3F)
return false;
if (instructions[i++].OpCode != OpCodes.And)
return false;
if (instructions[i++].OpCode != OpCodes.Shl)
return false;
if (instructions[i++].OpCode != OpCodes.Or)
return false;
if (!instructions[i++].IsStloc()) //num |= (long)((long)((ulong)((byte)num2)) << 8 * i);
return false;
firstInstruction =
instructions.FirstOrDefault(
instr =>
instr.OpCode == OpCodes.Newobj &&
instr.Operand.ToString() == "System.Void System.IO.MemoryStream::.ctor(System.Byte[],System.Boolean)");
if (firstInstruction == null)
return false;
if (i >= instructions.IndexOf(firstInstruction))
return false;
i = instructions.IndexOf(firstInstruction) + 1;
if (!instructions[i++].IsStloc()) //MemoryStream stream_ = new MemoryStream(array, true);
return false;
if (!instructions[i++].IsLdloc())
return false;
if (instructions[i].OpCode != OpCodes.Callvirt || instructions[i++].Operand.ToString() != "System.Int64 System.IO.Stream::get_Length()")
return false;
if (instructions[i].OpCode != OpCodes.Ldc_I8 || (long)instructions[i++].Operand != 13L)
return false;
if (instructions[i++].OpCode != OpCodes.Sub)
return false;
if (!instructions[i++].IsStloc()) //long long_ = memoryStream.Length - 13L;
return false;
return true;
}
private void ExtractNestedTypes(TypeDef type)
{
foreach (var method in type.Methods)
if (method.HasBody)
{
var instr = method.Body.Instructions;
foreach (var inst in instr)
if (inst.Operand is MethodDef)
{
var ntype = (inst.Operand as MethodDef).DeclaringType;
if (!ntype.IsNested)
continue;
if (types.Contains(ntype))
continue;
types.Add(ntype);
ExtractNestedTypes(ntype);
}
}
}
}
}

View File

@ -0,0 +1,293 @@
using de4dot.blocks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace de4dot.code.deobfuscators.ConfuserEx
{
public class ResourceDecrypter
{
TypeDef arrayType;
MethodDef resourceDecInitMethod, assembyResolveMethod;
FieldDef arrayField, asmField;
byte[] decryptedBytes;
bool canRemoveLzma = true;
public bool CanRemoveLzma
{
get { return canRemoveLzma; }
}
public TypeDef Type
{
get { return arrayType; }
}
public MethodDef Method
{
get { return resourceDecInitMethod; }
}
public MethodDef AssembyResolveMethod
{
get { return assembyResolveMethod; }
}
public List<FieldDef> Fields
{
get { return new List<FieldDef>() { arrayField, asmField }; }
}
public bool Detected
{
get
{
return resourceDecInitMethod != null && resourceDecInitMethod != null
&& decryptedBytes != null && arrayField != null && asmField != null;
}
}
ModuleDef module;
MethodDef lzmaMethod;
ISimpleDeobfuscator deobfuscator;
public ResourceDecrypter(ModuleDef module, MethodDef lzmaMethod, ISimpleDeobfuscator deobfsucator)
{
this.module = module;
this.lzmaMethod = lzmaMethod;
this.deobfuscator = deobfsucator;
}
public void Find()
{
var moduleCctor = DotNetUtils.GetModuleTypeCctor(module);
if (moduleCctor == null)
return;
foreach (var inst in moduleCctor.Body.Instructions)
{
if (inst.OpCode != OpCodes.Call)
continue;
if (!(inst.Operand is MethodDef))
continue;
var method = inst.Operand as MethodDef;
if (!method.HasBody || !method.IsStatic)
continue;
if (!DotNetUtils.IsMethod(method, "System.Void", "()"))
continue;
deobfuscator.Deobfuscate(method, SimpleDeobfuscatorFlags.Force);
if (!isResDecryptInit(method))
continue;
resourceDecInitMethod = method;
}
}
bool isResDecryptInit(MethodDef method)
{
var instr = method.Body.Instructions;
if (instr.Count < 15)
return false;
if (!instr[0].IsLdcI4())
return false;
if (!instr[1].IsStloc()) //uint num = 96u;
return false;
if (!instr[2].IsLdcI4())
return false;
if (instr[0].GetLdcI4Value() != instr[2].GetLdcI4Value())
return false;
if (instr[3].OpCode != OpCodes.Newarr)
return false;
if (instr[3].Operand.ToString() != "System.UInt32")
return false;
if (instr[4].OpCode != OpCodes.Dup)
return false;
if (instr[5].OpCode != OpCodes.Ldtoken)
return false;
var aField = instr[5].Operand as FieldDef;
if (aField == null)
return false;
if (aField.InitialValue == null)
return false;
if (aField.Attributes != (FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.HasFieldRVA))
return false;
if (instr[6].OpCode != OpCodes.Call)
return false;
if (instr[6].Operand.ToString() != "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)")
return false;
if (!instr[7].IsStloc()) // uint[] array = new uint[] {.....};
return false;
var l = instr.Count;
if (!instr[l - 10].IsLdloc())
return false;
if (instr[l - 9].OpCode != OpCodes.Call)
return false;
if (instr[l - 9].Operand != lzmaMethod)
return false;
if (instr[l - 8].OpCode != OpCodes.Call)
return false;
if (instr[l - 8].Operand.ToString() != "System.Reflection.Assembly System.Reflection.Assembly::Load(System.Byte[])")
return false;
if (instr[l - 7].OpCode != OpCodes.Stsfld) //<Module>.assembly_0 = Assembly.Load(array4);
return false;
var asField = instr[l - 7].Operand as FieldDef;
if (asField == null)
return false;
if (instr[l - 6].OpCode != OpCodes.Call)
return false;
if (instr[l - 6].Operand.ToString() != "System.AppDomain System.AppDomain::get_CurrentDomain()")
return false;
if (instr[l - 5].OpCode != OpCodes.Ldnull)
return false;
if (instr[l - 4].OpCode != OpCodes.Ldftn)
return false;
var mtd = instr[l - 4].Operand as MethodDef;
if (mtd == null)
return false;
if (!IsAssembyResolveMethod(mtd, asField))
return false;
if (instr[l - 3].OpCode != OpCodes.Newobj)
return false;
if (instr[l - 2].OpCode != OpCodes.Callvirt) //AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(<Module>.smethod_1);
return false;
try
{
DecryptArray(ConvertArray<uint, byte>(aField.InitialValue));
}
catch { canRemoveLzma = false; return false; }
arrayField = aField;
arrayType = DotNetUtils.GetType(module, aField.FieldSig.Type);
asmField = asField;
assembyResolveMethod = mtd;
return true;
}
private T[] ConvertArray<T, T1>(T1[] array)
{
int l = Marshal.SizeOf(typeof(T));
int l1 = Marshal.SizeOf(typeof(T1));
var buffer = new T[(array.Length * l1) / l];
Buffer.BlockCopy(array, 0, buffer, 0, array.Length * l1);
return buffer;
}
private void DecryptArray(uint[] array)
{
int num = array.Length;
uint[] array2 = new uint[16];
uint num2 = 825993394u;
for (int i = 0; i < 16; i++)
{
num2 ^= num2 >> 13;
num2 ^= num2 << 25;
num2 ^= num2 >> 27;
array2[i] = num2;
}
int num3 = 0;
int num4 = 0;
uint[] array3 = new uint[16];
byte[] array4 = new byte[num * 4u];
while ((long)num3 < (long)((ulong)num))
{
for (int j = 0; j < 16; j++)
{
array3[j] = array[num3 + j];
}
array3[0] = (array3[0] ^ array2[0]);
array3[1] = (array3[1] ^ array2[1]);
array3[2] = (array3[2] ^ array2[2]);
array3[3] = (array3[3] ^ array2[3]);
array3[4] = (array3[4] ^ array2[4]);
array3[5] = (array3[5] ^ array2[5]);
array3[6] = (array3[6] ^ array2[6]);
array3[7] = (array3[7] ^ array2[7]);
array3[8] = (array3[8] ^ array2[8]);
array3[9] = (array3[9] ^ array2[9]);
array3[10] = (array3[10] ^ array2[10]);
array3[11] = (array3[11] ^ array2[11]);
array3[12] = (array3[12] ^ array2[12]);
array3[13] = (array3[13] ^ array2[13]);
array3[14] = (array3[14] ^ array2[14]);
array3[15] = (array3[15] ^ array2[15]);
for (int k = 0; k < 16; k++)
{
uint num5 = array3[k];
array4[num4++] = (byte)num5;
array4[num4++] = (byte)(num5 >> 8);
array4[num4++] = (byte)(num5 >> 16);
array4[num4++] = (byte)(num5 >> 24);
array2[k] ^= num5;
}
num3 += 16;
}
decryptedBytes = Lzma.Decompress(array4);
}
private bool IsAssembyResolveMethod(MethodDef method, FieldDef field)
{
if (DotNetUtils.IsMethod(method, "", "()"))
return false;
deobfuscator.Deobfuscate(method, SimpleDeobfuscatorFlags.Force);
var instr = method.Body.Instructions;
if (instr.Count != 10)
return false;
if (instr[0].OpCode != OpCodes.Ldsfld)
return false;
if (instr[0].Operand != field)
return false;
if (instr[1].OpCode != OpCodes.Callvirt)
return false;
if (instr[1].Operand.ToString() != "System.String System.Reflection.Assembly::get_FullName()")
return false;
if (!instr[2].IsLdarg())
return false;
if (instr[3].OpCode != OpCodes.Callvirt)
return false;
if (instr[3].Operand.ToString() != "System.String System.ResolveEventArgs::get_Name()")
return false;
if (instr[4].OpCode != OpCodes.Call)
return false;
if (instr[4].Operand.ToString() != "System.Boolean System.String::op_Equality(System.String,System.String)")
return false;
if (!instr[5].IsBrfalse())
return false;
if (instr[6].OpCode != OpCodes.Ldsfld)
return false;
if (instr[6].Operand != field)
return false;
if (instr[7].OpCode != OpCodes.Ret)
return false;
if (instr[8].OpCode != OpCodes.Ldnull)
return false;
if (instr[9].OpCode != OpCodes.Ret)
return false;
return true;
}
public void Fix()
{
ModuleDef newModule;
try
{
newModule = ModuleDefMD.Load(decryptedBytes);
}
catch { canRemoveLzma = false; return; }
List<Resource> toRemove = new List<Resource>();
List<Resource> toAdd = new List<Resource>();
foreach (var cryptedResource in module.Resources)
foreach (var resource in newModule.Resources)
if (cryptedResource.Name == resource.Name)
{
toRemove.Add(cryptedResource);
toAdd.Add(resource);
}
foreach (var resToRemove in toRemove)
module.Resources.Remove(resToRemove);
foreach (var resToAdd in toAdd)
module.Resources.Add(resToAdd);
}
}
}

View File

@ -0,0 +1,278 @@
using System;
using System.Collections.Generic;
using System.Text;
using de4dot.blocks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.ConfuserEx
{
public static class Utils
{
public static bool IsArithmetical(this Instr instr)
{
switch (instr.OpCode.Code)
{
case Code.Add:
case Code.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.Div:
case Code.Div_Un:
case Code.Mul:
case Code.Mul_Ovf:
case Code.Mul_Ovf_Un:
case Code.Not:
case Code.Shl:
case Code.Shr:
case Code.Shr_Un:
case Code.Sub:
case Code.Sub_Ovf:
case Code.Sub_Ovf_Un:
case Code.Xor:
case Code.And:
case Code.Rem:
case Code.Rem_Un:
case Code.Ceq:
case Code.Cgt:
case Code.Cgt_Un:
case Code.Clt:
case Code.Clt_Un:
case Code.Neg:
case Code.Or:
return true;
}
return false;
}
public static bool IsConv(this Instr instr)
{
switch (instr.OpCode.Code)
{
case Code.Conv_I1:
case Code.Conv_I2:
case Code.Conv_I4:
case Code.Conv_I8:
case Code.Conv_U1:
case Code.Conv_U2:
case Code.Conv_U4:
case Code.Conv_U8:
case Code.Conv_R4:
case Code.Conv_R8:
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I1_Un:
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I2_Un:
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I4_Un:
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_I8_Un:
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U1_Un:
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U2_Un:
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U4_Un:
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_U8_Un:
return true;
}
return false;
}
public static bool IsLdc(this Instr instr)
{
switch (instr.OpCode.Code)
{
case Code.Ldc_I4:
case Code.Ldc_I4_S:
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_M1:
case Code.Ldc_I8:
case Code.Ldc_R4:
case Code.Ldc_R8:
return true;
}
return false;
}
public static bool IsLoc(this Instr instr)
{
switch (instr.OpCode.Code)
{
case Code.Ldloc:
case Code.Ldloc_S:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
case Code.Ldloca:
case Code.Ldloca_S:
case Code.Stloc:
case Code.Stloc_S:
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
return true;
}
return false;
}
public static bool IsValidInstr(this Instr instr)
{
return IsArithmetical(instr) || instr.IsConv() || IsLdc(instr) || IsLoc(instr) || instr.OpCode == OpCodes.Dup;
}
public static bool IsDup(this Block block)
{
if (block.Sources.Count != 1)
return false;
if (block.Instructions.Count != 2)
return false;
if (!block.FirstInstr.IsLdcI4())
return false;
if (block.LastInstr.OpCode != OpCodes.Dup)
if (!block.LastInstr.IsLdcI4() || block.LastInstr.GetLdcI4Value() != block.FirstInstr.GetLdcI4Value())
return false;
return true;
}
}
public static class Extensions
{
public static bool IsConfuserExSwitch(this SwitchData switchData)
{
var instructions = switchData.Block.Instructions;
var lastIndex = instructions.Count - 1;
if (instructions.Count < 4)
return false;
if (!instructions[lastIndex - 3].IsStloc())
return false;
if (!instructions[lastIndex - 2].IsLdcI4())
return false;
if (instructions[lastIndex - 1].OpCode != OpCodes.Rem_Un)
return false;
return true;
}
public static bool IsNative(this SwitchData switchData)
{
var block = switchData.Block;
var instr = block.Instructions;
if (instr.Count <= 4)
return false;
if (instr[0].IsLdcI4() && instr[1].OpCode == OpCodes.Call)
{
switchData.IsKeyHardCoded = true;
block.SwitchData.Key = block.FirstInstr.GetLdcI4Value();
}
if (!switchData.IsKeyHardCoded && instr[0].OpCode != OpCodes.Call)
return false;
var method = block.Instructions[switchData.IsKeyHardCoded ? 1 : 0].Operand as MethodDef;
if (method == null || !method.IsStatic || !method.IsNative)
return false;
if (!DotNetUtils.IsMethod(method, "System.Int32", "(System.Int32)"))
return false;
for (int i = switchData.IsKeyHardCoded ? 2 : 1; i < instr.Count - 1; i++)
if (!instr[i].IsValidInstr())
return false;
return true;
}
public static MethodDef GetNativeMethod(this SwitchData switchData)
{
var block = switchData.Block;
var method = block.Instructions[switchData.IsKeyHardCoded ? 1 : 0].Operand as MethodDef;
return method;
}
public static bool IsTernaryPredicate(this Block ternaryPredicateBlock)
{
if (!ternaryPredicateBlock.LastInstr.IsConditionalBranch())
return false;
if (ternaryPredicateBlock.CountTargets() > 2)
return false;
var source1 = ternaryPredicateBlock.Targets[0];
var source2 = ternaryPredicateBlock.FallThrough;
//if (!IsDup(source1) || !IsDup(source2))
// return false;
if (source1.CountTargets() > 1 || source2.CountTargets() > 1)
return false;
var mainBlock = source1.FallThrough;
if (mainBlock != source2.FallThrough)
return false;
if (mainBlock.Sources.Count != 2)
return false;
if (mainBlock.LastInstr.OpCode == OpCodes.Ret)
return false;
return true;
}
public static bool IsTernary(this Block block)
{
var sources = block.Sources;
if (sources.Count != 2)
return false;
if (!sources[0].IsDup() || !(sources[1]).IsDup()) //TODO: Case without DUP?
return false;
if (sources[0].CountTargets() > 1 || sources[1].CountTargets() > 1)
return false;
if (sources[0].FallThrough != block || sources[1].FallThrough != block)
return false;
if (sources[0].Sources[0] != sources[1].Sources[0])
return false;
if (!sources[0].Sources[0].IsConditionalBranch())
return false;
if (block.LastInstr.OpCode == OpCodes.Ret)
return false;
return true;
}
public static List<Block> GetTernaryPredicates(this List<Block> switchCaseBlocks)
{
List<Block> ternaryPredicates = new List<Block>();
foreach (Block preBlock in switchCaseBlocks)
{
if (IsTernary(preBlock))
{
// switchCaseBlock -> 2x sourceBlock -> ternaryPredicateBlock
ternaryPredicates.Add(preBlock.Sources[0].Sources[0]);
}
}
return ternaryPredicates;
}
public static Block GetTernaryPredicateMainBlock(this Block ternaryPredicateBlock)
{
return ternaryPredicateBlock.FallThrough.FallThrough;
}
}
}

View File

@ -0,0 +1,191 @@

namespace de4dot.Bea
{
public class BeaConstants
{
public static int INSTRUCT_LENGTH = 64;
public enum SegmentRegister : byte
{
ESReg = 1,
DSReg = 2,
FSReg = 3,
GSReg = 4,
CSReg = 5,
SSReg = 6
}
public enum PrefixType : byte
{
NotUsedPrefix = 0,
InUsePrefix = 1,
SuperfluousPrefix = 2,
InvalidPrefix = 4,
MandatoryPrefix = 8
}
public enum InstructionType : uint
{
GENERAL_PURPOSE_INSTRUCTION = 0x10000,
FPU_INSTRUCTION = 0x20000,
MMX_INSTRUCTION = 0x40000,
SSE_INSTRUCTION = 0x80000,
SSE2_INSTRUCTION = 0x100000,
SSE3_INSTRUCTION = 0x200000,
SSSE3_INSTRUCTION = 0x400000,
SSE41_INSTRUCTION = 0x800000,
SSE42_INSTRUCTION = 0x1000000,
SYSTEM_INSTRUCTION = 0x2000000,
VM_INSTRUCTION = 0x4000000,
UNDOCUMENTED_INSTRUCTION = 0x8000000,
AMD_INSTRUCTION = 0x10000000,
ILLEGAL_INSTRUCTION = 0x20000000,
AES_INSTRUCTION = 0x40000000,
CLMUL_INSTRUCTION = 0x80000000,
DATA_TRANSFER = 0x1,
ARITHMETIC_INSTRUCTION,
LOGICAL_INSTRUCTION,
SHIFT_ROTATE,
BIT_UInt8,
CONTROL_TRANSFER,
STRING_INSTRUCTION,
InOutINSTRUCTION,
ENTER_LEAVE_INSTRUCTION,
FLAG_CONTROL_INSTRUCTION,
SEGMENT_REGISTER,
MISCELLANEOUS_INSTRUCTION,
COMPARISON_INSTRUCTION,
LOGARITHMIC_INSTRUCTION,
TRIGONOMETRIC_INSTRUCTION,
UNSUPPORTED_INSTRUCTION,
LOAD_CONSTANTS,
FPUCONTROL,
STATE_MANAGEMENT,
CONVERSION_INSTRUCTION,
SHUFFLE_UNPACK,
PACKED_SINGLE_PRECISION,
SIMD128bits,
SIMD64bits,
CACHEABILITY_CONTROL,
FP_INTEGER_CONVERSION,
SPECIALIZED_128bits,
SIMD_FP_PACKED,
SIMD_FP_HORIZONTAL,
AGENT_SYNCHRONISATION,
PACKED_ALIGN_RIGHT,
PACKED_SIGN,
PACKED_BLENDING_INSTRUCTION,
PACKED_TEST,
PACKED_MINMAX,
HORIZONTAL_SEARCH,
PACKED_EQUALITY,
STREAMING_LOAD,
INSERTION_EXTRACTION,
DOT_PRODUCT,
SAD_INSTRUCTION,
ACCELERATOR_INSTRUCTION,
ROUND_INSTRUCTION
}
public enum EFlagState : byte
{
TE_ = 1,
MO_ = 2,
RE_ = 4,
SE_ = 8,
UN_ = 0x10,
PR_ = 0x20
}
public enum BranchType : short
{
JO = 1,
JC,
JE,
JA,
JS,
JP,
JL,
JG,
JB,
JECXZ,
JmpType,
CallType,
RetType,
JNO = -1,
JNC = -2,
JNE = -3,
JNA = -4,
JNS = -5,
JNP = -6,
JNL = -7,
JNG = -8,
JNB = -9
}
public enum ArgumentType : uint
{
NO_ARGUMENT = 0x10000000,
REGISTER_TYPE = 0x20000000,
MEMORY_TYPE = 0x40000000,
CONSTANT_TYPE = 0x80000000,
MMX_REG = 0x10000,
GENERAL_REG = 0x20000,
FPU_REG = 0x40000,
SSE_REG = 0x80000,
CR_REG = 0x100000,
DR_REG = 0x200000,
SPECIAL_REG = 0x400000,
MEMORY_MANAGEMENT_REG = 0x800000,
SEGMENT_REG = 0x1000000,
RELATIVE_ = 0x4000000,
ABSOLUTE_ = 0x8000000,
READ = 0x1,
WRITE = 0x2,
REG0 = 0x1,
REG1 = 0x2,
REG2 = 0x4,
REG3 = 0x8,
REG4 = 0x10,
REG5 = 0x20,
REG6 = 0x40,
REG7 = 0x80,
REG8 = 0x100,
REG9 = 0x200,
REG10 = 0x400,
REG11 = 0x800,
REG12 = 0x1000,
REG13 = 0x2000,
REG14 = 0x4000,
REG15 = 0x8000
}
public enum SpecialInfo : int
{
UNKNOWN_OPCODE = -1,
OUT_OF_BLOCK = 0,
/* === mask = 0xff */
NoTabulation = 0x00000000,
Tabulation = 0x00000001,
/* === mask = 0xff00 */
MasmSyntax = 0x00000000,
GoAsmSyntax = 0x00000100,
NasmSyntax = 0x00000200,
ATSyntax = 0x00000400,
/* === mask = 0xff0000 */
PrefixedNumeral = 0x00010000,
SuffixedNumeral = 0x00000000,
/* === mask = 0xff000000 */
ShowSegmentRegs = 0x01000000
}
}
}

View File

@ -0,0 +1,32 @@
using System.Runtime.InteropServices;
namespace de4dot.Bea
{
public class BeaEngine
{
[DllImport("BeaEngine.dll")]
public static extern int Disasm([In, Out, MarshalAs(UnmanagedType.LPStruct)] Disasm disasm);
[DllImport("BeaEngine.dll")]
private static extern string BeaEngineVersion();
[DllImport("BeaEngine.dll")]
private static extern string BeaEngineRevision();
public static string Version
{
get
{
return BeaEngineVersion();
}
}
public static string Revision
{
get
{
return BeaEngineRevision();
}
}
}
}

View File

@ -0,0 +1,107 @@
using System;
using System.Runtime.InteropServices;
namespace de4dot.Bea
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class REX_Struct
{
public byte W_;
public byte R_;
public byte X_;
public byte B_;
public byte state;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class PrefixInfo
{
public int Number;
public int NbUndefined;
public byte LockPrefix;
public byte OperandSize;
public byte AddressSize;
public byte RepnePrefix;
public byte RepPrefix;
public byte FSPrefix;
public byte SSPrefix;
public byte GSPrefix;
public byte ESPrefix;
public byte CSPrefix;
public byte DSPrefix;
public byte BranchTaken;
public byte BranchNotTaken;
public REX_Struct REX;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class EFLStruct
{
public byte OF_;
public byte SF_;
public byte ZF_;
public byte AF_;
public byte PF_;
public byte CF_;
public byte TF_;
public byte IF_;
public byte DF_;
public byte NT_;
public byte RF_;
public byte alignment;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class MemoryType
{
public Int32 BaseRegister;
public Int32 IndexRegister;
public Int32 Scale;
public Int64 Displacement;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class InstructionType
{
public Int32 Category;
public Int32 Opcode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string Mnemonic;
public Int32 BranchType;
public EFLStruct Flags;
public UInt64 AddrValue;
public Int64 Immediat;
public UInt32 ImplicitModifiedRegs;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class ArgumentType
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string ArgMnemonic;
public Int32 ArgType;
public Int32 ArgSize;
public UInt32 AccessMode;
public MemoryType Memory;
public UInt32 SegmentReg;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Disasm
{
public IntPtr EIP;
public UInt64 VirtualAddr;
public UInt32 SecurityBlock;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string CompleteInstr;
public UInt32 Archi;
public UInt64 Options;
public InstructionType Instruction;
public ArgumentType Argument1;
public ArgumentType Argument2;
public ArgumentType Argument3;
public PrefixInfo Prefix;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.U4)]
UInt32[] Reserved_;
}
}

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86ADD : X86Instruction
{
public X86ADD(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[2];
Operands[0] = GetOperand(rawInstruction.Argument1);
Operands[1] = GetOperand(rawInstruction.Argument2);
}
public override X86OpCode OpCode { get { return X86OpCode.ADD; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
if (Operands[1] is X86ImmediateOperand)
registers[((X86RegisterOperand) Operands[0]).Register.ToString()] +=
((X86ImmediateOperand) Operands[1]).Immediate;
else
registers[((X86RegisterOperand) Operands[0]).Register.ToString()] +=
registers[((X86RegisterOperand) Operands[1]).Register.ToString()];
}
}
}

View File

@ -0,0 +1,22 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86DIV : X86Instruction
{
public X86DIV(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[2];
Operands[0] = GetOperand(rawInstruction.Argument1);
Operands[1] = GetOperand(rawInstruction.Argument2);
}
public override X86OpCode OpCode { get { return X86OpCode.DIV; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
}
}
}

View File

@ -0,0 +1,29 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86IMUL : X86Instruction
{
public X86IMUL(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[3];
Operands[0] = GetOperand(rawInstruction.Argument1);
Operands[1] =GetOperand( rawInstruction.Argument2);
Operands[2] = GetOperand(rawInstruction.Argument3);
}
public override X86OpCode OpCode { get { return X86OpCode.IMUL; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
var source = ((X86RegisterOperand) Operands[0]).Register.ToString();
var target1 = ((X86RegisterOperand) Operands[1]).Register.ToString();
if (Operands[2] is X86ImmediateOperand)
registers[source] = registers[target1]*((X86ImmediateOperand) Operands[2]).Immediate;
else
registers[source] = registers[target1]*registers[((X86RegisterOperand) Operands[2]).Register.ToString()];
}
}
}

View File

@ -0,0 +1,33 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
internal class X86MOV : X86Instruction
{
public X86MOV(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[2];
Operands[0] = GetOperand(rawInstruction.Argument1);
Operands[1] = GetOperand(rawInstruction.Argument2);
}
public override X86OpCode OpCode
{
get { return X86OpCode.MOV; }
}
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
if (Operands[1] is X86ImmediateOperand)
registers[((X86RegisterOperand) Operands[0]).Register.ToString()] =
(Operands[1] as X86ImmediateOperand).Immediate;
else
{
var regOperand = (X86RegisterOperand) Operands[0];
registers[regOperand.Register.ToString()] =
registers[(Operands[1] as X86RegisterOperand).Register.ToString()];
}
}
}
}

View File

@ -0,0 +1,22 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86NEG : X86Instruction
{
public X86NEG(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[1];
Operands[0] = GetOperand(rawInstruction.Argument1);
}
public override X86OpCode OpCode { get { return X86OpCode.NEG; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
registers[((X86RegisterOperand) Operands[0]).Register.ToString()] =
-registers[((X86RegisterOperand) Operands[0]).Register.ToString()];
}
}
}

View File

@ -0,0 +1,23 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86NOT : X86Instruction
{
public X86NOT(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[1];
Operands[0] = GetOperand(rawInstruction.Argument1);
}
public override X86OpCode OpCode { get { return X86OpCode.NOT; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
registers[((X86RegisterOperand)Operands[0]).Register.ToString()] =
~registers[((X86RegisterOperand) Operands[0]).Register.ToString()];
}
}
}

View File

@ -0,0 +1,26 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86POP : X86Instruction
{
public X86POP(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[1];
Operands[0] = GetOperand(rawInstruction.Argument1);
}
public override X86OpCode OpCode { get { return X86OpCode.POP; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
// Pretend to pop stack
if (localStack.Count < 1)
return;
registers[((X86RegisterOperand) Operands[0]).Register.ToString()] = localStack.Pop();
}
}
}

View File

@ -0,0 +1,26 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86PUSH : X86Instruction
{
public X86PUSH(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[1];
Operands[0] = GetOperand(rawInstruction.Argument1);
}
public override X86OpCode OpCode { get { return X86OpCode.PUSH; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
// Pretend to pop stack
if (localStack.Count < 1)
return;
registers[((X86RegisterOperand) Operands[0]).Register.ToString()] = localStack.Pop();
}
}
}

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86SUB : X86Instruction
{
public X86SUB(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[2];
Operands[0] = GetOperand(rawInstruction.Argument1);
Operands[1] = GetOperand(rawInstruction.Argument2);
}
public override X86OpCode OpCode { get { return X86OpCode.SUB; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
if (Operands[1] is X86ImmediateOperand)
registers[((X86RegisterOperand)Operands[0]).Register.ToString()] -=
((X86ImmediateOperand)Operands[1]).Immediate;
else
registers[((X86RegisterOperand)Operands[0]).Register.ToString()] -=
registers[((X86RegisterOperand)Operands[1]).Register.ToString()];
}
}
}

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using de4dot.Bea;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions
{
class X86XOR : X86Instruction
{
public X86XOR(Disasm rawInstruction) : base()
{
Operands = new IX86Operand[2];
Operands[0] = GetOperand(rawInstruction.Argument1);
Operands[1] = GetOperand(rawInstruction.Argument2);
}
public override X86OpCode OpCode { get { return X86OpCode.XOR; } }
public override void Execute(Dictionary<string, int> registers, Stack<int> localStack)
{
if (Operands[1] is X86ImmediateOperand)
registers[((X86RegisterOperand)Operands[0]).Register.ToString()] ^=
((X86ImmediateOperand)Operands[1]).Immediate;
else
registers[((X86RegisterOperand)Operands[0]).Register.ToString()] ^=
registers[((X86RegisterOperand)Operands[1]).Register.ToString()];
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Runtime.InteropServices;
namespace de4dot.code.x86
{
public class UnmanagedBuffer
{
public readonly IntPtr Ptr = IntPtr.Zero;
public readonly int Length = 0;
public UnmanagedBuffer(byte[] data)
{
Ptr = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, Ptr, data.Length);
Length = data.Length;
}
}
}

View File

@ -0,0 +1,72 @@
using de4dot.Bea;
using System.Collections.Generic;
using System.Globalization;
namespace ConfuserDeobfuscator.Engine.Routines.Ex.x86
{
public enum X86OpCode
{
MOV,
ADD,
SUB,
IMUL,
DIV,
NEG,
NOT,
XOR,
POP,
PUSH
}
public enum X86Register
{
EAX = 537001985,
ECX = 537001986,
EDX = 537001988,
EBX = 537001992,
ESP = 537001989,
EBP = 537001990,
ESI = 537002048,
EDI = 537002112
}
public interface IX86Operand
{
}
public class X86RegisterOperand : IX86Operand
{
public X86Register Register { get; set; }
public X86RegisterOperand(X86Register reg)
{
Register = reg;
}
}
public class X86ImmediateOperand : IX86Operand
{
public int Immediate { get; set; }
public X86ImmediateOperand(int imm)
{
Immediate = imm;
}
}
public abstract class X86Instruction
{
public abstract X86OpCode OpCode { get; }
public IX86Operand[] Operands { get; set; }
public abstract void Execute(Dictionary<string, int> registers, Stack<int> localStack);
public static IX86Operand GetOperand(ArgumentType argument)
{
if (argument.ArgType == -2013265920)
return
new X86ImmediateOperand(int.Parse(argument.ArgMnemonic.TrimEnd('h'),
NumberStyles.HexNumber));
return new X86RegisterOperand((X86Register)argument.ArgType);
}
}
}

View File

@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using ConfuserDeobfuscator.Engine.Routines.Ex.x86;
using ConfuserDeobfuscator.Engine.Routines.Ex.x86.Instructions;
using de4dot.Bea;
using de4dot.code.x86;
using dnlib.DotNet;
namespace de4dot.code.deobfuscators.ConfuserEx.x86
{
public sealed class X86Method
{
public List<X86Instruction> Instructions;
public Stack<int> LocalStack = new Stack<int>();
public Dictionary<string, int> Registers = new Dictionary<string, int>
{
{"EAX", 0},
{"EBX", 0},
{"ECX", 0},
{"EDX", 0},
{"ESP", 0},
{"EBP", 0},
{"ESI", 0},
{"EDI", 0}
};
readonly ModuleDefMD _module;
public X86Method(MethodDef method,ModuleDefMD module)
{
this._module = module;
Instructions = new List<X86Instruction>();
ParseInstructions(method);
}
private void ParseInstructions(MethodDef method)
{
var rawInstructions = new List<Disasm>();
while (true)
{
byte[] bytes = ReadChunk(method, _module);
var disasm = new Disasm();
var buff = new UnmanagedBuffer(bytes);
disasm.EIP = new IntPtr(buff.Ptr.ToInt32());
var instruction = BeaEngine.Disasm(disasm);
_readOffset -= 8 - instruction; // revert offset back for each byte that was not a part of this instruction
var mnemonic = disasm.Instruction.Mnemonic.Trim();
if (mnemonic == "ret") //TODO: Check if this is the only return in function, e.g. check for jumps that go beyond this address
{
Marshal.FreeHGlobal(buff.Ptr);
break;
}
rawInstructions.Add(Clone(disasm));
//disasm.EIP = new IntPtr(disasm.EIP.ToInt32() + instruction);
Marshal.FreeHGlobal(buff.Ptr);
}
//while(rawInstructions.First().Instruction.Mnemonic.Trim() == "pop")
// rawInstructions.Remove(rawInstructions.First());
while (rawInstructions.Last().Instruction.Mnemonic.Trim() == "pop")
rawInstructions.Remove(rawInstructions.Last());
foreach (var instr in rawInstructions)
{
switch (instr.Instruction.Mnemonic.Trim())
{
case "mov":
Instructions.Add(new X86MOV(instr));
break;
case "add":
Instructions.Add(new X86ADD(instr));
break;
case "sub":
Instructions.Add(new X86SUB(instr));
break;
case "imul":
Instructions.Add(new X86IMUL(instr));
break;
case "div":
Instructions.Add(new X86DIV(instr));
break;
case "neg":
Instructions.Add(new X86NEG(instr));
break;
case "not":
Instructions.Add(new X86NOT(instr));
break;
case "xor":
Instructions.Add(new X86XOR(instr));
break;
case "pop":
Instructions.Add(new X86POP(instr));
break;
}
}
}
private int _readOffset;
public byte[] ReadChunk(MethodDef method, ModuleDefMD module)
{
var stream = module.MetaData.PEImage.CreateFullStream();
var offset = module.MetaData.PEImage.ToFileOffset(method.RVA);
byte[] buffer = new byte[8];
if (_readOffset == 0) //TODO: Don't use hardcoded offset
_readOffset = (int) offset + 20; // skip to actual calculation code
stream.Position = _readOffset;
stream.Read(buffer, 0, 8); // read 8 bytes to make sure that's a whole instruction
_readOffset += 8;
return buffer;
}
public int Execute(params int[] @params)
{
foreach (var param in @params)
LocalStack.Push(param);
foreach (var instr in Instructions)
instr.Execute(Registers, LocalStack);
return Registers["EAX"];
}
public static Disasm Clone(Disasm disasm)
{
return new Disasm
{
Archi = disasm.Archi,
Argument1 = disasm.Argument1,
Argument2 = disasm.Argument2,
Argument3 = disasm.Argument3,
CompleteInstr = disasm.CompleteInstr,
EIP = disasm.EIP,
Instruction = disasm.Instruction,
Options = disasm.Options,
Prefix = disasm.Prefix,
SecurityBlock = disasm.SecurityBlock,
VirtualAddr = disasm.VirtualAddr
};
}
}
}

View File

@ -0,0 +1,688 @@
using System;
using System.IO;
namespace de4dot.code.deobfuscators
{
internal static class Lzma
{
const uint kNumStates = 12;
const int kNumPosSlotBits = 6;
const uint kNumLenToPosStates = 4;
const uint kMatchMinLen = 2;
const int kNumAlignBits = 4;
const uint kAlignTableSize = 1 << kNumAlignBits;
const uint kStartPosModelIndex = 4;
const uint kEndPosModelIndex = 14;
const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
const int kNumPosStatesBitsMax = 4;
const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
const int kNumLowLenBits = 3;
const int kNumMidLenBits = 3;
const int kNumHighLenBits = 8;
const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
public static byte[] Decompress(byte[] data)
{
var s = new MemoryStream(data);
var decoder = new LzmaDecoder();
var prop = new byte[5];
s.Read(prop, 0, 5);
decoder.SetDecoderProperties(prop);
long outSize = 0;
for (int i = 0; i < 8; i++)
{
int v = s.ReadByte();
outSize |= ((long)(byte)v) << (8 * i);
}
var b = new byte[(int)outSize];
var z = new MemoryStream(b, true);
long compressedSize = s.Length - 13;
decoder.Code(s, z, compressedSize, outSize);
return b;
}
struct BitDecoder
{
public const int kNumBitModelTotalBits = 11;
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
const int kNumMoveBits = 5;
uint Prob;
public void Init()
{
Prob = kBitModelTotal >> 1;
}
public uint Decode(Decoder rangeDecoder)
{
uint newBound = (rangeDecoder.Range >> kNumBitModelTotalBits) * Prob;
if (rangeDecoder.Code < newBound)
{
rangeDecoder.Range = newBound;
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
if (rangeDecoder.Range < Decoder.kTopValue)
{
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
rangeDecoder.Range <<= 8;
}
return 0;
}
rangeDecoder.Range -= newBound;
rangeDecoder.Code -= newBound;
Prob -= (Prob) >> kNumMoveBits;
if (rangeDecoder.Range < Decoder.kTopValue)
{
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
rangeDecoder.Range <<= 8;
}
return 1;
}
}
struct BitTreeDecoder
{
readonly BitDecoder[] Models;
readonly int NumBitLevels;
public BitTreeDecoder(int numBitLevels)
{
NumBitLevels = numBitLevels;
Models = new BitDecoder[1 << numBitLevels];
}
public void Init()
{
for (uint i = 1; i < (1 << NumBitLevels); i++)
Models[i].Init();
}
public uint Decode(Decoder rangeDecoder)
{
uint m = 1;
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
m = (m << 1) + Models[m].Decode(rangeDecoder);
return m - ((uint)1 << NumBitLevels);
}
public uint ReverseDecode(Decoder rangeDecoder)
{
uint m = 1;
uint symbol = 0;
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
{
uint bit = Models[m].Decode(rangeDecoder);
m <<= 1;
m += bit;
symbol |= (bit << bitIndex);
}
return symbol;
}
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
Decoder rangeDecoder, int NumBitLevels)
{
uint m = 1;
uint symbol = 0;
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
{
uint bit = Models[startIndex + m].Decode(rangeDecoder);
m <<= 1;
m += bit;
symbol |= (bit << bitIndex);
}
return symbol;
}
}
class Decoder
{
public const uint kTopValue = (1 << 24);
public uint Code;
public uint Range;
public Stream Stream;
public void Init(Stream stream)
{
// Stream.Init(stream);
Stream = stream;
Code = 0;
Range = 0xFFFFFFFF;
for (int i = 0; i < 5; i++)
Code = (Code << 8) | (byte)Stream.ReadByte();
}
public void ReleaseStream()
{
Stream = null;
}
public void Normalize()
{
while (Range < kTopValue)
{
Code = (Code << 8) | (byte)Stream.ReadByte();
Range <<= 8;
}
}
public uint DecodeDirectBits(int numTotalBits)
{
uint range = Range;
uint code = Code;
uint result = 0;
for (int i = numTotalBits; i > 0; i--)
{
range >>= 1;
/*
result <<= 1;
if (code >= range)
{
code -= range;
result |= 1;
}
*/
uint t = (code - range) >> 31;
code -= range & (t - 1);
result = (result << 1) | (1 - t);
if (range < kTopValue)
{
code = (code << 8) | (byte)Stream.ReadByte();
range <<= 8;
}
}
Range = range;
Code = code;
return result;
}
}
class LzmaDecoder
{
readonly BitDecoder[] m_IsMatchDecoders = new BitDecoder[kNumStates << kNumPosStatesBitsMax];
readonly BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[kNumStates << kNumPosStatesBitsMax];
readonly BitDecoder[] m_IsRepDecoders = new BitDecoder[kNumStates];
readonly BitDecoder[] m_IsRepG0Decoders = new BitDecoder[kNumStates];
readonly BitDecoder[] m_IsRepG1Decoders = new BitDecoder[kNumStates];
readonly BitDecoder[] m_IsRepG2Decoders = new BitDecoder[kNumStates];
readonly LenDecoder m_LenDecoder = new LenDecoder();
readonly LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
readonly OutWindow m_OutWindow = new OutWindow();
readonly BitDecoder[] m_PosDecoders = new BitDecoder[kNumFullDistances - kEndPosModelIndex];
readonly BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[kNumLenToPosStates];
readonly Decoder m_RangeDecoder = new Decoder();
readonly LenDecoder m_RepLenDecoder = new LenDecoder();
bool _solid = false;
uint m_DictionarySize;
uint m_DictionarySizeCheck;
BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(kNumAlignBits);
uint m_PosStateMask;
public LzmaDecoder()
{
m_DictionarySize = 0xFFFFFFFF;
for (int i = 0; i < kNumLenToPosStates; i++)
m_PosSlotDecoder[i] = new BitTreeDecoder(kNumPosSlotBits);
}
void SetDictionarySize(uint dictionarySize)
{
if (m_DictionarySize != dictionarySize)
{
m_DictionarySize = dictionarySize;
m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));
m_OutWindow.Create(blockSize);
}
}
void SetLiteralProperties(int lp, int lc)
{
m_LiteralDecoder.Create(lp, lc);
}
void SetPosBitsProperties(int pb)
{
uint numPosStates = (uint)1 << pb;
m_LenDecoder.Create(numPosStates);
m_RepLenDecoder.Create(numPosStates);
m_PosStateMask = numPosStates - 1;
}
void Init(Stream inStream, Stream outStream)
{
m_RangeDecoder.Init(inStream);
m_OutWindow.Init(outStream, _solid);
uint i;
for (i = 0; i < kNumStates; i++)
{
for (uint j = 0; j <= m_PosStateMask; j++)
{
uint index = (i << kNumPosStatesBitsMax) + j;
m_IsMatchDecoders[index].Init();
m_IsRep0LongDecoders[index].Init();
}
m_IsRepDecoders[i].Init();
m_IsRepG0Decoders[i].Init();
m_IsRepG1Decoders[i].Init();
m_IsRepG2Decoders[i].Init();
}
m_LiteralDecoder.Init();
for (i = 0; i < kNumLenToPosStates; i++)
m_PosSlotDecoder[i].Init();
// m_PosSpecDecoder.Init();
for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
m_PosDecoders[i].Init();
m_LenDecoder.Init();
m_RepLenDecoder.Init();
m_PosAlignDecoder.Init();
}
public void Code(Stream inStream, Stream outStream,
Int64 inSize, Int64 outSize)
{
Init(inStream, outStream);
var state = new State();
state.Init();
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
UInt64 nowPos64 = 0;
var outSize64 = (UInt64)outSize;
if (nowPos64 < outSize64)
{
m_IsMatchDecoders[state.Index << kNumPosStatesBitsMax].Decode(m_RangeDecoder);
state.UpdateChar();
byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
m_OutWindow.PutByte(b);
nowPos64++;
}
while (nowPos64 < outSize64)
{
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
// while(nowPos64 < next)
{
uint posState = (uint)nowPos64 & m_PosStateMask;
if (m_IsMatchDecoders[(state.Index << kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
{
byte b;
byte prevByte = m_OutWindow.GetByte(0);
if (!state.IsCharState())
b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
(uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0));
else
b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
m_OutWindow.PutByte(b);
state.UpdateChar();
nowPos64++;
}
else
{
uint len;
if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
{
if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
{
if (m_IsRep0LongDecoders[(state.Index << kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
{
state.UpdateShortRep();
m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
nowPos64++;
continue;
}
}
else
{
UInt32 distance;
if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
{
distance = rep1;
}
else
{
if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
distance = rep2;
else
{
distance = rep3;
rep3 = rep2;
}
rep2 = rep1;
}
rep1 = rep0;
rep0 = distance;
}
len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + kMatchMinLen;
state.UpdateRep();
}
else
{
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
len = kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
state.UpdateMatch();
uint posSlot = m_PosSlotDecoder[GetLenToPosState(len)].Decode(m_RangeDecoder);
if (posSlot >= kStartPosModelIndex)
{
var numDirectBits = (int)((posSlot >> 1) - 1);
rep0 = ((2 | (posSlot & 1)) << numDirectBits);
if (posSlot < kEndPosModelIndex)
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
else
{
rep0 += (m_RangeDecoder.DecodeDirectBits(
numDirectBits - kNumAlignBits) << kNumAlignBits);
rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
}
}
else
rep0 = posSlot;
}
if (rep0 >= nowPos64 || rep0 >= m_DictionarySizeCheck)
{
if (rep0 == 0xFFFFFFFF)
break;
}
m_OutWindow.CopyBlock(rep0, len);
nowPos64 += len;
}
}
}
m_OutWindow.Flush();
m_OutWindow.ReleaseStream();
m_RangeDecoder.ReleaseStream();
}
public void SetDecoderProperties(byte[] properties)
{
int lc = properties[0] % 9;
int remainder = properties[0] / 9;
int lp = remainder % 5;
int pb = remainder / 5;
UInt32 dictionarySize = 0;
for (int i = 0; i < 4; i++)
dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
SetDictionarySize(dictionarySize);
SetLiteralProperties(lp, lc);
SetPosBitsProperties(pb);
}
static uint GetLenToPosState(uint len)
{
len -= kMatchMinLen;
if (len < kNumLenToPosStates)
return len;
return unchecked((kNumLenToPosStates - 1));
}
class LenDecoder
{
readonly BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[kNumPosStatesMax];
readonly BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[kNumPosStatesMax];
BitDecoder m_Choice = new BitDecoder();
BitDecoder m_Choice2 = new BitDecoder();
BitTreeDecoder m_HighCoder = new BitTreeDecoder(kNumHighLenBits);
uint m_NumPosStates;
public void Create(uint numPosStates)
{
for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
{
m_LowCoder[posState] = new BitTreeDecoder(kNumLowLenBits);
m_MidCoder[posState] = new BitTreeDecoder(kNumMidLenBits);
}
m_NumPosStates = numPosStates;
}
public void Init()
{
m_Choice.Init();
for (uint posState = 0; posState < m_NumPosStates; posState++)
{
m_LowCoder[posState].Init();
m_MidCoder[posState].Init();
}
m_Choice2.Init();
m_HighCoder.Init();
}
public uint Decode(Decoder rangeDecoder, uint posState)
{
if (m_Choice.Decode(rangeDecoder) == 0)
return m_LowCoder[posState].Decode(rangeDecoder);
uint symbol = kNumLowLenSymbols;
if (m_Choice2.Decode(rangeDecoder) == 0)
symbol += m_MidCoder[posState].Decode(rangeDecoder);
else
{
symbol += kNumMidLenSymbols;
symbol += m_HighCoder.Decode(rangeDecoder);
}
return symbol;
}
}
class LiteralDecoder
{
Decoder2[] m_Coders;
int m_NumPosBits;
int m_NumPrevBits;
uint m_PosMask;
public void Create(int numPosBits, int numPrevBits)
{
if (m_Coders != null && m_NumPrevBits == numPrevBits &&
m_NumPosBits == numPosBits)
return;
m_NumPosBits = numPosBits;
m_PosMask = ((uint)1 << numPosBits) - 1;
m_NumPrevBits = numPrevBits;
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
m_Coders = new Decoder2[numStates];
for (uint i = 0; i < numStates; i++)
m_Coders[i].Create();
}
public void Init()
{
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
for (uint i = 0; i < numStates; i++)
m_Coders[i].Init();
}
uint GetState(uint pos, byte prevByte)
{
return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits));
}
public byte DecodeNormal(Decoder rangeDecoder, uint pos, byte prevByte)
{
return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder);
}
public byte DecodeWithMatchByte(Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
{
return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte);
}
struct Decoder2
{
BitDecoder[] m_Decoders;
public void Create()
{
m_Decoders = new BitDecoder[0x300];
}
public void Init()
{
for (int i = 0; i < 0x300; i++) m_Decoders[i].Init();
}
public byte DecodeNormal(Decoder rangeDecoder)
{
uint symbol = 1;
do
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); while (symbol < 0x100);
return (byte)symbol;
}
public byte DecodeWithMatchByte(Decoder rangeDecoder, byte matchByte)
{
uint symbol = 1;
do
{
uint matchBit = (uint)(matchByte >> 7) & 1;
matchByte <<= 1;
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
symbol = (symbol << 1) | bit;
if (matchBit != bit)
{
while (symbol < 0x100)
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
break;
}
} while (symbol < 0x100);
return (byte)symbol;
}
}
};
}
class OutWindow
{
byte[] _buffer;
uint _pos;
Stream _stream;
uint _streamPos;
uint _windowSize;
public void Create(uint windowSize)
{
if (_windowSize != windowSize)
{
_buffer = new byte[windowSize];
}
_windowSize = windowSize;
_pos = 0;
_streamPos = 0;
}
public void Init(Stream stream, bool solid)
{
ReleaseStream();
_stream = stream;
if (!solid)
{
_streamPos = 0;
_pos = 0;
}
}
public void ReleaseStream()
{
Flush();
_stream = null;
Buffer.BlockCopy(new byte[_buffer.Length], 0, _buffer, 0, _buffer.Length);
}
public void Flush()
{
uint size = _pos - _streamPos;
if (size == 0)
return;
_stream.Write(_buffer, (int)_streamPos, (int)size);
if (_pos >= _windowSize)
_pos = 0;
_streamPos = _pos;
}
public void CopyBlock(uint distance, uint len)
{
uint pos = _pos - distance - 1;
if (pos >= _windowSize)
pos += _windowSize;
for (; len > 0; len--)
{
if (pos >= _windowSize)
pos = 0;
_buffer[_pos++] = _buffer[pos++];
if (_pos >= _windowSize)
Flush();
}
}
public void PutByte(byte b)
{
_buffer[_pos++] = b;
if (_pos >= _windowSize)
Flush();
}
public byte GetByte(uint distance)
{
uint pos = _pos - distance - 1;
if (pos >= _windowSize)
pos += _windowSize;
return _buffer[pos];
}
}
struct State
{
public uint Index;
public void Init()
{
Index = 0;
}
public void UpdateChar()
{
if (Index < 4) Index = 0;
else if (Index < 10) Index -= 3;
else Index -= 6;
}
public void UpdateMatch()
{
Index = (uint)(Index < 7 ? 7 : 10);
}
public void UpdateRep()
{
Index = (uint)(Index < 7 ? 8 : 11);
}
public void UpdateShortRep()
{
Index = (uint)(Index < 7 ? 9 : 11);
}
public bool IsCharState()
{
return Index < 7;
}
}
}
}

View File

@ -1,214 +1,215 @@
/*
Copyright (C) 2011-2015 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.Text;
using dnlib.DotNet;
using de4dot.code;
using de4dot.code.deobfuscators;
using System.IO;
using System.Reflection;
namespace de4dot.cui {
class ExitException : Exception {
public readonly int code;
public ExitException(int code) {
this.code = code;
}
}
class Program {
static IList<IDeobfuscatorInfo> deobfuscatorInfos = CreateDeobfuscatorInfos();
static IList<IDeobfuscatorInfo> LoadPlugin(string assembly) {
var plugins = new List<IDeobfuscatorInfo>();
try {
foreach (Type item in Assembly.LoadFile(assembly).GetTypes()) {
var interfaces = new List<Type>(item.GetInterfaces());
if (item.IsClass && interfaces.Contains(typeof(IDeobfuscatorInfo)))
plugins.Add((IDeobfuscatorInfo)Activator.CreateInstance(item));
}
}
catch {
}
return plugins;
}
public static void GetPlugins(string directory, ref Dictionary<string, IDeobfuscatorInfo> result) {
var plugins = new List<IDeobfuscatorInfo>();
try {
var files = Directory.GetFiles(directory, "deobfuscator.*.dll", SearchOption.TopDirectoryOnly);
foreach (var file in files)
plugins.AddRange(LoadPlugin(Path.GetFullPath(file)));
}
catch {
}
foreach(var p in plugins)
result[p.Type] = p;
}
static IList<IDeobfuscatorInfo> CreateDeobfuscatorInfos() {
var local = new List<IDeobfuscatorInfo> {
new de4dot.code.deobfuscators.Unknown.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Agile_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Babel_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeFort.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeVeil.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeWall.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Confuser.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CryptoObfuscator.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.DeepSea.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Dotfuscator.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.dotNET_Reactor.v3.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.dotNET_Reactor.v4.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Eazfuscator_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.ILProtector.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.MaxtoCode.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.MPRESS.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Rummage.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Xenocode.DeobfuscatorInfo(),
};
var dict = new Dictionary<string, IDeobfuscatorInfo>();
foreach (var d in local)
dict[d.Type] = d;
string pluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin");
GetPlugins(pluginDir, ref dict);
return new List<IDeobfuscatorInfo>(dict.Values);
}
public static int Main(string[] args) {
int exitCode = 0;
const string showAllMessagesEnvName = "SHOWALLMESSAGES";
try {
if (Console.OutputEncoding.IsSingleByte)
Console.OutputEncoding = new UTF8Encoding(false);
Logger.Instance.CanIgnoreMessages = !HasEnv(showAllMessagesEnvName);
Logger.n("");
Logger.n("de4dot v{0} Copyright (C) 2011-2015 de4dot@gmail.com", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
Logger.n("Latest version and source code: https://github.com/0xd4d/de4dot");
Logger.n("");
var options = new FilesDeobfuscator.Options();
ParseCommandLine(args, options);
new FilesDeobfuscator(options).DoIt();
}
catch (ExitException ex) {
exitCode = ex.code;
}
catch (UserException ex) {
Logger.Instance.LogErrorDontIgnore("{0}", ex.Message);
exitCode = 1;
}
catch (Exception ex) {
if (PrintFullStackTrace()) {
PrintStackTrace(ex);
Logger.Instance.LogErrorDontIgnore("\nTry the latest version!");
}
else {
Logger.Instance.LogErrorDontIgnore("\n\n");
Logger.Instance.LogErrorDontIgnore("Hmmmm... something didn't work. Try the latest version.");
}
exitCode = 1;
}
if (Logger.Instance.NumIgnoredMessages > 0) {
if (Logger.Instance.NumIgnoredMessages == 1)
Logger.n("Ignored {0} warning/error", Logger.Instance.NumIgnoredMessages);
else
Logger.n("Ignored {0} warnings/errors", Logger.Instance.NumIgnoredMessages);
Logger.n("Use -v/-vv option or set environment variable {0}=1 to see all messages", showAllMessagesEnvName);
}
if (IsN00bUser()) {
Console.Error.WriteLine("\n\nPress any key to exit...\n");
try {
Console.ReadKey(true);
}
catch (InvalidOperationException) {
}
}
return exitCode;
}
static bool PrintFullStackTrace() {
if (!Logger.Instance.IgnoresEvent(LoggerEvent.Verbose))
return true;
if (HasEnv("STACKTRACE"))
return true;
return false;
}
static bool HasEnv(string name) {
foreach (var tmp in Environment.GetEnvironmentVariables().Keys) {
var env = tmp as string;
if (env == null)
continue;
if (string.Equals(env, name, StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
static bool IsN00bUser() {
if (HasEnv("VisualStudioDir"))
return false;
if (HasEnv("SHELL"))
return false;
return HasEnv("windir") && !HasEnv("PROMPT");
}
public static void PrintStackTrace(Exception ex) {
PrintStackTrace(ex, LoggerEvent.Error);
}
public static void PrintStackTrace(Exception ex, LoggerEvent loggerEvent) {
var line = new string('-', 78);
Logger.Instance.Log(false, null, loggerEvent, "\n\n");
Logger.Instance.Log(false, null, loggerEvent, line);
Logger.Instance.Log(false, null, loggerEvent, "Stack trace:\n{0}", ex.StackTrace);
Logger.Instance.Log(false, null, loggerEvent, "\n\nCaught an exception:\n");
Logger.Instance.Log(false, null, loggerEvent, line);
Logger.Instance.Log(false, null, loggerEvent, "Message:");
Logger.Instance.Log(false, null, loggerEvent, " {0}", ex.Message);
Logger.Instance.Log(false, null, loggerEvent, "Type:");
Logger.Instance.Log(false, null, loggerEvent, " {0}", ex.GetType());
Logger.Instance.Log(false, null, loggerEvent, line);
}
static void ParseCommandLine(string[] args, FilesDeobfuscator.Options options) {
new CommandLineParser(deobfuscatorInfos, options).Parse(args);
Logger.vv("Args:");
Logger.Instance.Indent();
foreach (var arg in args)
Logger.vv("{0}", Utils.ToCsharpString(arg));
Logger.Instance.DeIndent();
}
}
}
/*
Copyright (C) 2011-2015 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.Text;
using dnlib.DotNet;
using de4dot.code;
using de4dot.code.deobfuscators;
using System.IO;
using System.Reflection;
namespace de4dot.cui {
class ExitException : Exception {
public readonly int code;
public ExitException(int code) {
this.code = code;
}
}
class Program {
static IList<IDeobfuscatorInfo> deobfuscatorInfos = CreateDeobfuscatorInfos();
static IList<IDeobfuscatorInfo> LoadPlugin(string assembly) {
var plugins = new List<IDeobfuscatorInfo>();
try {
foreach (Type item in Assembly.LoadFile(assembly).GetTypes()) {
var interfaces = new List<Type>(item.GetInterfaces());
if (item.IsClass && interfaces.Contains(typeof(IDeobfuscatorInfo)))
plugins.Add((IDeobfuscatorInfo)Activator.CreateInstance(item));
}
}
catch {
}
return plugins;
}
public static void GetPlugins(string directory, ref Dictionary<string, IDeobfuscatorInfo> result) {
var plugins = new List<IDeobfuscatorInfo>();
try {
var files = Directory.GetFiles(directory, "deobfuscator.*.dll", SearchOption.TopDirectoryOnly);
foreach (var file in files)
plugins.AddRange(LoadPlugin(Path.GetFullPath(file)));
}
catch {
}
foreach(var p in plugins)
result[p.Type] = p;
}
static IList<IDeobfuscatorInfo> CreateDeobfuscatorInfos() {
var local = new List<IDeobfuscatorInfo> {
new de4dot.code.deobfuscators.Unknown.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Agile_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Babel_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeFort.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeVeil.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeWall.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Confuser.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.ConfuserEx.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CryptoObfuscator.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.DeepSea.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Dotfuscator.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.dotNET_Reactor.v3.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.dotNET_Reactor.v4.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Eazfuscator_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.ILProtector.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.MaxtoCode.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.MPRESS.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Rummage.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Xenocode.DeobfuscatorInfo(),
};
var dict = new Dictionary<string, IDeobfuscatorInfo>();
foreach (var d in local)
dict[d.Type] = d;
string pluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin");
GetPlugins(pluginDir, ref dict);
return new List<IDeobfuscatorInfo>(dict.Values);
}
public static int Main(string[] args) {
int exitCode = 0;
const string showAllMessagesEnvName = "SHOWALLMESSAGES";
try {
if (Console.OutputEncoding.IsSingleByte)
Console.OutputEncoding = new UTF8Encoding(false);
Logger.Instance.CanIgnoreMessages = !HasEnv(showAllMessagesEnvName);
Logger.n("");
Logger.n("de4dot v{0} Copyright (C) 2011-2015 de4dot@gmail.com", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
Logger.n("Latest version and source code: https://github.com/0xd4d/de4dot");
Logger.n("");
var options = new FilesDeobfuscator.Options();
ParseCommandLine(args, options);
new FilesDeobfuscator(options).DoIt();
}
catch (ExitException ex) {
exitCode = ex.code;
}
catch (UserException ex) {
Logger.Instance.LogErrorDontIgnore("{0}", ex.Message);
exitCode = 1;
}
catch (Exception ex) {
if (PrintFullStackTrace()) {
PrintStackTrace(ex);
Logger.Instance.LogErrorDontIgnore("\nTry the latest version!");
}
else {
Logger.Instance.LogErrorDontIgnore("\n\n");
Logger.Instance.LogErrorDontIgnore("Hmmmm... something didn't work. Try the latest version.");
}
exitCode = 1;
}
if (Logger.Instance.NumIgnoredMessages > 0) {
if (Logger.Instance.NumIgnoredMessages == 1)
Logger.n("Ignored {0} warning/error", Logger.Instance.NumIgnoredMessages);
else
Logger.n("Ignored {0} warnings/errors", Logger.Instance.NumIgnoredMessages);
Logger.n("Use -v/-vv option or set environment variable {0}=1 to see all messages", showAllMessagesEnvName);
}
if (IsN00bUser()) {
Console.Error.WriteLine("\n\nPress any key to exit...\n");
try {
Console.ReadKey(true);
}
catch (InvalidOperationException) {
}
}
return exitCode;
}
static bool PrintFullStackTrace() {
if (!Logger.Instance.IgnoresEvent(LoggerEvent.Verbose))
return true;
if (HasEnv("STACKTRACE"))
return true;
return false;
}
static bool HasEnv(string name) {
foreach (var tmp in Environment.GetEnvironmentVariables().Keys) {
var env = tmp as string;
if (env == null)
continue;
if (string.Equals(env, name, StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
static bool IsN00bUser() {
if (HasEnv("VisualStudioDir"))
return false;
if (HasEnv("SHELL"))
return false;
return HasEnv("windir") && !HasEnv("PROMPT");
}
public static void PrintStackTrace(Exception ex) {
PrintStackTrace(ex, LoggerEvent.Error);
}
public static void PrintStackTrace(Exception ex, LoggerEvent loggerEvent) {
var line = new string('-', 78);
Logger.Instance.Log(false, null, loggerEvent, "\n\n");
Logger.Instance.Log(false, null, loggerEvent, line);
Logger.Instance.Log(false, null, loggerEvent, "Stack trace:\n{0}", ex.StackTrace);
Logger.Instance.Log(false, null, loggerEvent, "\n\nCaught an exception:\n");
Logger.Instance.Log(false, null, loggerEvent, line);
Logger.Instance.Log(false, null, loggerEvent, "Message:");
Logger.Instance.Log(false, null, loggerEvent, " {0}", ex.Message);
Logger.Instance.Log(false, null, loggerEvent, "Type:");
Logger.Instance.Log(false, null, loggerEvent, " {0}", ex.GetType());
Logger.Instance.Log(false, null, loggerEvent, line);
}
static void ParseCommandLine(string[] args, FilesDeobfuscator.Options options) {
new CommandLineParser(deobfuscatorInfos, options).Parse(args);
Logger.vv("Args:");
Logger.Instance.Indent();
foreach (var arg in args)
Logger.vv("{0}", Utils.ToCsharpString(arg));
Logger.Instance.DeIndent();
}
}
}