ConfuserEx deobfuscator updates and misc changes

ConfuserEx changes:
* Implement Proxy Call Fixer
* Refactor Control Flow Fixer
Disable main exception handler to let de4dot throw on error
This commit is contained in:
ViR Dash 2017-07-25 17:37:41 +03:00
parent 23477ccb5f
commit e0a2e805d4
8 changed files with 1238 additions and 614 deletions

View File

@ -17,7 +17,7 @@
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
@ -159,8 +159,9 @@
<Compile Include="deobfuscators\ConfuserEx\ConstantDecrypter.cs" /> <Compile Include="deobfuscators\ConfuserEx\ConstantDecrypter.cs" />
<Compile Include="deobfuscators\ConfuserEx\ConstantInliner.cs" /> <Compile Include="deobfuscators\ConfuserEx\ConstantInliner.cs" />
<Compile Include="deobfuscators\ConfuserEx\Deobfuscator.cs" /> <Compile Include="deobfuscators\ConfuserEx\Deobfuscator.cs" />
<Compile Include="deobfuscators\ConfuserEx\ControlFlowSolver.cs" /> <Compile Include="deobfuscators\ConfuserEx\ControlFlowFixer.cs" />
<Compile Include="deobfuscators\ConfuserEx\LzmaFinder.cs" /> <Compile Include="deobfuscators\ConfuserEx\LzmaFinder.cs" />
<Compile Include="deobfuscators\ConfuserEx\ProxyCallFixer.cs" />
<Compile Include="deobfuscators\ConfuserEx\ResourceDecrypter.cs" /> <Compile Include="deobfuscators\ConfuserEx\ResourceDecrypter.cs" />
<Compile Include="deobfuscators\ConfuserEx\Utils.cs" /> <Compile Include="deobfuscators\ConfuserEx\Utils.cs" />
<Compile Include="deobfuscators\ConfuserEx\x86\Bea\Constants.cs" /> <Compile Include="deobfuscators\ConfuserEx\x86\Bea\Constants.cs" />

View File

@ -207,11 +207,11 @@ namespace de4dot.code.deobfuscators.ConfuserEx
return buffer; return buffer;
} }
private void DecryptArray(uint[] array) private void DecryptArray(uint[] array) //TODO: Automatic detection
{ {
uint num = 1680u; // array size? uint num = 960u; // array size?
uint[] array2 = new uint[16]; uint[] array2 = new uint[16];
uint num2 = 3186233426u; uint num2 = 4136251032u;
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
num2 ^= num2 >> 12; num2 ^= num2 >> 12;
@ -229,237 +229,189 @@ namespace de4dot.code.deobfuscators.ConfuserEx
{ {
array3[j] = array[num3 + j]; array3[j] = array[num3 + j];
} }
uint num5 = array3[9] >> 23; uint num5 = array3[3] * 41u;
array3[0] = array3[0] * 865957733u; array3[11] = (array3[11] ^ 3634844963u);
array3[9] = array3[9] << 9; uint num6 = array3[3] * 31u;
array3[9] = (array3[9] | num5); num6 += array3[9] * 47u;
array3[3] = (array3[3] ^ 4272581837u); num5 += array3[9] * 85u;
array3[8] = (array3[8] ^ array2[8]); num5 += array3[10] * 149u;
num5 = (array3[14] & 3955221806u); uint num7 = array3[3] << 1;
num5 *= 1105615415u; num7 += array3[3];
array3[14] = (array3[14] & 339745489u); uint num8 = array3[3] << 1;
array3[14] = (array3[14] | (array3[0] & 3955221806u)); num8 += array3[3] << 3;
array3[15] = (array3[15] ^ array3[8]); num7 += array3[9] << 3;
array3[0] = (array3[0] & 339745489u); num8 += array3[9] * 13u;
array3[0] = (array3[0] | num5 * 809663367u); num7 += array3[9];
array3[14] = (array3[14] ^ 1753824488u); num6 += array3[10] * 71u;
num5 = array3[11] << 18; num7 += array3[10] << 1;
array3[11] = array3[11] >> 14; num6 += array3[1] * 81u;
array3[1] = array3[1] - 301755752u; array3[4] = (array3[4] ^ ~array3[6]);
array3[11] = (array3[11] | num5); num8 += array3[10] << 1;
uint num6 = array3[14] << 3; num7 += array3[10] << 4;
num5 = (array3[9] & 2370496838u); array3[9] = num6;
array3[10] = array3[10] - 4147007853u; num8 += array3[10] << 4;
uint num7 = array3[14] << 4; array3[6] = array3[6] * 395315459u;
num5 *= 2575732745u; num8 += array3[1] * 19u;
num6 += array3[14] << 4; num7 += array3[1] * 23u;
array3[9] = (array3[9] & 1924470457u); num5 += array3[1] * 184u;
array3[9] = (array3[9] | (array3[2] & 2370496838u)); num6 = array3[7] * 19u;
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; array3[10] = num7;
num6 = array3[2] >> 19; num6 += array3[8] * 28u;
num7 = array3[11] >> 19; array3[14] = (array3[14] ^ array3[0]);
num5 += array3[15] * 46u; array3[3] = num8;
array3[15] = num8; num6 += array3[12] << 6;
num8 = array3[0] << 2; array3[1] = num5;
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[2] = (array3[2] ^ array2[2]);
array3[11] = (array3[11] | num7); num5 = array3[7] * 28u;
num5 = array3[15] << 1; num5 += array3[8] << 2;
array3[0] = (array3[0] | num8); num8 = array3[7] << 1;
num8 = array3[15] * 23u; num7 = array3[7] << 5;
num7 = array3[15] * 7u; num8 += array3[7] << 3;
num8 += array3[7] * 45u; num8 += array3[8] * 13u;
num7 += array3[7] * 11u; num7 += array3[7];
num5 += array3[15]; num6 += array3[12];
array3[9] = (array3[9] ^ array2[9]); num7 += array3[8] * 42u;
num5 += array3[7] * 7u; array3[4] = array3[4] - array3[10];
num8 += array3[13] << 7; num8 += array3[12] << 5;
array3[3] = (array3[3] ^ ~array3[8]); num6 += array3[15] * 85u;
array3[10] = array3[10] * 2256145475u; num5 += array3[8] << 5;
num6 = array3[15] << 2; array3[7] = num6;
num6 += array3[15]; array3[11] = array3[11] - 2867139633u;
num7 += array3[13] << 5; num7 += array3[12] * 108u;
num7 += array3[1] << 1; num5 += array3[12] * 93u;
num6 += array3[7] << 2; num8 += array3[12];
num6 += array3[7] << 3; num5 += array3[15] * 141u;
num8 += array3[13]; num8 += array3[15] * 49u;
num8 += array3[1] * 143u; num7 += array3[15] * 163u;
num5 += array3[13] << 2; array3[12] = num5;
num6 += array3[13] << 1;
num7 += array3[1] << 5;
num5 += array3[13] << 4;
array3[15] = num7; array3[15] = num7;
num5 += array3[1] * 23u; array3[8] = num8;
num6 += array3[13] << 5; num5 = array3[7] >> 21;
array3[7] = num5; num6 = array3[15] >> 22;
num6 += array3[1] * 39u; array3[15] = array3[15] << 10;
array3[1] = num8; num8 = array3[1] >> 21;
num8 = array3[1] * 26u; array3[15] = (array3[15] | num6);
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]); array3[12] = (array3[12] ^ array2[12]);
num7 += array3[5] << 6; num6 = (array3[2] & 3262151220u);
num8 += array3[13] * 117u; array3[1] = array3[1] << 11;
array3[9] = (array3[9] ^ array3[5]); array3[1] = (array3[1] | num8);
num5 += array3[13] * 52u; array3[7] = array3[7] << 11;
num6 += array3[3] << 1; array3[0] = array3[0] - array3[14];
num6 += array3[3]; num7 = array3[13] << 4;
num7 += array3[13] * 126u; num8 = array3[3] * 954284655u;
num6 += array3[5] << 4; array3[3] = array3[5];
num6 += array3[5]; array3[5] = num8 * 3102958735u;
array3[5] = num8; array3[7] = (array3[7] | num5);
array3[3] = num5; num5 = array3[10] << 4;
num6 += array3[13] * 11u; num8 = array3[9] * 2468501497u;
array3[0] = num6; array3[2] = (array3[2] & 1032816075u);
array3[13] = num7; array3[13] = array3[13] >> 28;
num6 = array3[6] << 1; array3[13] = (array3[13] | num7);
num6 += array3[15] << 1; array3[7] = array3[7] - 888060325u;
num5 = array3[12] << 29; array3[2] = (array3[2] | (array3[8] & 3262151220u));
num6 += array3[15] << 2; array3[12] = array3[12] * 4056148675u;
num7 = array3[7] << 12; array3[9] = array3[13];
array3[11] = array3[11] - array3[10]; num7 = array3[6] << 5;
array3[7] = array3[7] >> 20; array3[13] = num8 * 1746582089u;
array3[12] = array3[12] >> 3; array3[6] = array3[6] >> 27;
array3[12] = (array3[12] | num5); array3[6] = (array3[6] | num7);
array3[14] = (array3[14] ^ ~array3[8]); array3[8] = (array3[8] & 1032816075u);
array3[1] = (array3[1] ^ array2[1]); array3[7] = (array3[7] ^ array2[7]);
array3[1] = (array3[1] ^ 3215842197u); num5 += array3[11] * 46u;
num8 = array3[6] * 7u; num6 *= 869722291u;
array3[7] = (array3[7] | num7); num8 = array3[10] << 1;
num8 += array3[15] * 26u; num5 += array3[3] * 92u;
num5 = array3[6] << 2; num5 += array3[5] * 149u;
num5 += array3[15] << 2; array3[7] = array3[7] - 3922202313u;
array3[9] = array3[9] - array3[2]; array3[8] = (array3[8] | num6 * 2576221819u);
num7 = array3[6] << 2; num8 += array3[11] * 15u;
array3[4] = (array3[4] ^ array2[4]); num8 += array3[3] * 37u;
num6 += array3[4] << 4; num6 = array3[10] * 7u;
array3[3] = (array3[3] ^ 1425746098u); array3[8] = (array3[8] ^ 1878284212u);
num5 += array3[15]; num8 += array3[5] * 56u;
num8 += array3[4] * 69u; array3[9] = (array3[9] ^ array2[9]);
num5 += array3[4] * 15u; num7 = array3[10] << 3;
num7 += array3[6]; array3[6] = (array3[6] ^ 2841119440u);
num6 += array3[1] * 15u; num6 += array3[11] << 4;
num8 += array3[1] * 63u; array3[2] = (array3[2] ^ 217219923u);
array3[6] = num6; num7 += array3[10];
num7 += array3[15] * 11u; num6 += array3[3] * 29u;
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]); array3[6] = (array3[6] ^ array2[6]);
num7 *= 3574473459u; num7 += array3[11] * 26u;
array3[15] = num5; num7 += array3[3] * 52u;
array3[5] = (array3[5] & 1919669298u); num6 += array3[5] * 49u;
array3[5] = (array3[5] | (array3[13] & 2375297997u)); num7 += array3[5] * 84u;
array3[3] = num5;
array3[10] = num6;
num6 = array3[1] * 15u;
array3[12] = (array3[12] ^ 1080861703u);
array3[5] = num8;
num5 = (array3[4] & 3659960635u);
num6 += array3[12] << 1;
array3[4] = (array3[4] & 635006660u);
array3[4] = (array3[4] | (array3[9] & 3659960635u));
num5 *= 1676034815u;
array3[11] = num7;
num7 = array3[1] * 19u;
num6 += array3[12] << 4;
array3[9] = (array3[9] & 635006660u);
num6 += array3[3] << 6;
num7 += array3[12] * 27u;
array3[5] = array3[5] - array3[8];
array3[9] = (array3[9] | num5 * 1267776767u);
num5 = array3[1] << 2;
num5 += array3[1];
array3[13] = (array3[13] ^ array2[13]);
num8 = array3[1];
num6 += array3[3];
num5 += array3[12] << 3;
num8 += array3[12] << 1;
num8 += array3[12];
num6 += array3[15] * 22u;
num5 += array3[3] * 27u;
num5 += array3[15] << 3;
num7 += array3[3] * 92u;
num8 += array3[3] << 3;
num8 += array3[3];
num5 += array3[15];
num8 += array3[15] << 1;
num8 += array3[15];
array3[3] = num6;
array3[0] = (array3[0] ^ array3[13]);
array3[14] = array3[14] - array3[15];
num7 += array3[15] << 5;
array3[13] = (array3[13] ^ ~array3[1]);
num6 = array3[10] >> 31;
array3[14] = (array3[14] ^ array2[14]);
array3[8] = (array3[8] ^ array2[8]);
array3[12] = num5;
array3[1] = num8; array3[1] = num8;
array3[5] = (array3[5] ^ array2[5]);
array3[11] = (array3[11] ^ array2[11]);
num5 = (array3[11] & 2204625944u);
array3[1] = (array3[1] ^ array2[1]);
array3[4] = (array3[4] ^ array2[4]);
array3[11] = (array3[11] & 2090341351u);
array3[11] = (array3[11] | (array3[4] & 2204625944u));
array3[15] = num7;
num8 = (array3[14] & 2496954112u);
array3[14] = (array3[14] & 1798013183u);
array3[4] = (array3[4] & 2090341351u);
array3[15] = (array3[15] ^ array2[15]); array3[15] = (array3[15] ^ array2[15]);
num8 = array3[0] << 5; array3[10] = array3[10] << 1;
array3[13] = (array3[13] & 1919669298u); num5 *= 338764649u;
array3[13] = (array3[13] | num7 * 2683487803u); array3[14] = (array3[14] | (array3[9] & 2496954112u));
array3[0] = array3[0] >> 27; array3[15] = array3[15] - array3[0];
array3[0] = (array3[0] | num8); array3[10] = (array3[10] | num6);
array3[10] = (array3[10] ^ array2[10]);
array3[3] = (array3[3] ^ array2[3]);
num8 *= 2292397853u;
array3[0] = (array3[0] ^ array2[0]);
array3[0] = (array3[0] ^ 2814140307u);
array3[2] = (array3[2] ^ ~array3[13]);
array3[4] = (array3[4] | num5 * 587046105u);
array3[9] = (array3[9] & 1798013183u);
array3[9] = (array3[9] | num8 * 1520255797u);
for (int k = 0; k < 16; k++) for (int k = 0; k < 16; k++)
{ {
uint num9 = array3[k]; uint num9 = array3[k];
@ -471,7 +423,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
} }
num3 += 16; num3 += 16;
} }
decryptedBytes = Lzma.Decompress(array4); decryptedBytes = Lzma.Decompress(array4);
} }
private void FindStringDecrypters(TypeDef type) private void FindStringDecrypters(TypeDef type)

View File

@ -9,9 +9,11 @@ using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.ConfuserEx namespace de4dot.code.deobfuscators.ConfuserEx
{ {
class ControlFlowSolver : IBlocksDeobfuscator class ControlFlowFixer : IBlocksDeobfuscator
{ {
public bool ExecuteIfNotModified { get; } public bool ExecuteIfNotModified { get; }
public List<MethodDef> NativeMethods = new List<MethodDef>();
private readonly InstructionEmulator _instructionEmulator = new InstructionEmulator(); private readonly InstructionEmulator _instructionEmulator = new InstructionEmulator();
private Blocks _blocks; private Blocks _blocks;
@ -43,15 +45,13 @@ namespace de4dot.code.deobfuscators.ConfuserEx
private void ProcessHardcodedSwitch(Block switchBlock) // a single-case switch private void ProcessHardcodedSwitch(Block switchBlock) // a single-case switch
{ {
var targets = switchBlock.Targets; var targets = switchBlock.Targets;
_instructionEmulator.Push(new Int32Value(switchBlock.SwitchData.Key.Value)); _instructionEmulator.Push(new Int32Value(switchBlock.SwitchData.Key.Value));
int? key = CalculateKey();
int? key = CalculateKey();
if (!key.HasValue) if (!key.HasValue)
throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE"); throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE");
int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value); int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value);
if (targets.Count < switchCaseIndex) if (targets.Count < switchCaseIndex)
throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE"); throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE");
@ -65,19 +65,16 @@ namespace de4dot.code.deobfuscators.ConfuserEx
private void ProcessBlock(List<Block> switchCaseBlocks, Block block, Block switchBlock) private void ProcessBlock(List<Block> switchCaseBlocks, Block block, Block switchBlock)
{ {
var targets = switchBlock.Targets; var targets = switchBlock.Targets;
_instructionEmulator.Emulate(block.Instructions, 0, block.Instructions.Count); _instructionEmulator.Emulate(block.Instructions, 0, block.Instructions.Count);
if (_instructionEmulator.Peek().IsUnknown()) if (_instructionEmulator.Peek().IsUnknown())
throw new Exception("CRITICAL ERROR: STACK VALUE UNKNOWN"); throw new Exception("CRITICAL ERROR: STACK VALUE UNKNOWN");
int? key = CalculateKey(); int? key = CalculateKey();
if (!key.HasValue) if (!key.HasValue)
throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE"); throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE");
int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value); int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value);
if (targets.Count < switchCaseIndex) if (targets.Count < switchCaseIndex)
throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE"); throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE");
@ -88,7 +85,6 @@ namespace de4dot.code.deobfuscators.ConfuserEx
block.ReplaceLastNonBranchWithBranch(0, targetBlock); block.ReplaceLastNonBranchWithBranch(0, targetBlock);
ProcessFallThroughs(switchCaseBlocks, switchBlock, targetBlock, key.Value); ProcessFallThroughs(switchCaseBlocks, switchBlock, targetBlock, key.Value);
block.Processed = true; block.Processed = true;
} }
@ -110,12 +106,10 @@ namespace de4dot.code.deobfuscators.ConfuserEx
throw new Exception("CRITICAL ERROR: STACK VALUE UNKNOWN"); throw new Exception("CRITICAL ERROR: STACK VALUE UNKNOWN");
int? key = CalculateKey(); int? key = CalculateKey();
if (!key.HasValue) if (!key.HasValue)
throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE"); throw new Exception("CRITICAL ERROR: KEY HAS NO VALUE");
int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value); int switchCaseIndex = CalculateSwitchCaseIndex(switchBlock, key.Value);
if (targets.Count < switchCaseIndex) if (targets.Count < switchCaseIndex)
throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE"); throw new Exception("CRITICAL ERROR: KEY OUT OF RANGE");
@ -182,9 +176,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
while (blocksLeft > 0) while (blocksLeft > 0)
{ {
if (blockIndex > switchFallThroughs.Count - 1) if (blockIndex > switchFallThroughs.Count - 1)
{
blockIndex = 0; blockIndex = 0;
}
if (failedCount > switchFallThroughs.Count) if (failedCount > switchFallThroughs.Count)
{ {
@ -193,7 +185,6 @@ namespace de4dot.code.deobfuscators.ConfuserEx
} }
Block switchCaseBlock = switchFallThroughs[blockIndex]; Block switchCaseBlock = switchFallThroughs[blockIndex];
if (switchCaseBlock.Processed) if (switchCaseBlock.Processed)
{ {
blockIndex++; blockIndex++;
@ -211,12 +202,10 @@ namespace de4dot.code.deobfuscators.ConfuserEx
SetLocalSwitchKey(switchCaseBlock.SwitchData.Key.Value); SetLocalSwitchKey(switchCaseBlock.SwitchData.Key.Value);
} }
if (switchCaseBlock.IsTernary()) if (switchCaseBlock.IsTernary()) {
{
ProcessTernaryBlock(switchFallThroughs, switchCaseBlock, switchBlock); ProcessTernaryBlock(switchFallThroughs, switchCaseBlock, switchBlock);
} }
else else {
{
ProcessBlock(switchFallThroughs, switchCaseBlock, switchBlock); ProcessBlock(switchFallThroughs, switchCaseBlock, switchBlock);
} }
@ -236,11 +225,13 @@ namespace de4dot.code.deobfuscators.ConfuserEx
{ {
if (block.LastInstr.OpCode.Code != Code.Switch || ((Instruction[])block.LastInstr.Operand)?.Length == 0) if (block.LastInstr.OpCode.Code != Code.Switch || ((Instruction[])block.LastInstr.Operand)?.Length == 0)
return false; return false;
if (!block.SwitchData.IsNative()) if (!block.SwitchData.IsNative())
return false; return false;
_nativeMethod = new X86Method(block.SwitchData.GetNativeMethod(), _blocks.Method.Module as ModuleDefMD); //TODO: Possible null MethodDef nativeMethod = block.SwitchData.GetNativeMethod();
_nativeMethod = new X86Method(nativeMethod, _blocks.Method.Module as ModuleDefMD); //TODO: Possible null
if (!NativeMethods.Contains(nativeMethod))
NativeMethods.Add(nativeMethod);
return true; return true;
} }
@ -270,15 +261,12 @@ namespace de4dot.code.deobfuscators.ConfuserEx
{ {
if (_processedFallThroughs.Contains(targetBlock)) if (_processedFallThroughs.Contains(targetBlock))
return; return;
_processedFallThroughs.Add(targetBlock); _processedFallThroughs.Add(targetBlock);
if (targetBlock.FallThrough == switchBlock && switchCaseBlocks.Contains(targetBlock) && !targetBlock.SwitchData.Key.HasValue) if (targetBlock.FallThrough == switchBlock && switchCaseBlocks.Contains(targetBlock) && !targetBlock.SwitchData.Key.HasValue)
targetBlock.SwitchData.Key = switchKey; targetBlock.SwitchData.Key = switchKey;
var fallThrough = targetBlock.FallThrough; var fallThrough = targetBlock.FallThrough;
if (fallThrough == null) if (fallThrough == null)
return; return;

View File

@ -58,12 +58,13 @@ namespace de4dot.code.deobfuscators.ConfuserEx
class Deobfuscator : DeobfuscatorBase class Deobfuscator : DeobfuscatorBase
{ {
private bool _detectedConfuserExAttribute = false, _deobfuscating = false;
bool detectedConfuserExAttribute = false, deobfuscating = false; private string _version = "";
string version = ""; private LzmaFinder _lzmaFinder;
LzmaFinder lzmaFinder; private ConstantsDecrypter _constantDecrypter;
ConstantsDecrypter constantDecrypter; private ResourceDecrypter _resourceDecrypter;
ResourceDecrypter resourceDecrypter; private ProxyCallFixer _proxyCallFixer;
private ControlFlowFixer _controlFlowFixer = new ControlFlowFixer();
#region ConstantInliners #region ConstantInliners
@ -97,7 +98,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
public override string Name public override string Name
{ {
get { return $"{TypeLong} {version}"; } get { return $"{TypeLong} {_version}"; }
} }
public Deobfuscator(Options options) public Deobfuscator(Options options)
@ -108,28 +109,33 @@ namespace de4dot.code.deobfuscators.ConfuserEx
protected override int DetectInternal() protected override int DetectInternal()
{ {
int val = 0; int val = 0;
if (detectedConfuserExAttribute) val += 0; if (_detectedConfuserExAttribute) val += 0;
if (lzmaFinder.FoundLzma) val += 10; if (_lzmaFinder.FoundLzma) val += 10;
if (constantDecrypter.Detected) val += 10; if (_constantDecrypter.Detected) val += 10;
if (resourceDecrypter.Detected) val += 10; if (_resourceDecrypter.Detected) val += 10;
return val; return val;
} }
protected override void ScanForObfuscator() protected override void ScanForObfuscator()
{ {
lzmaFinder = new LzmaFinder(module, DeobfuscatedFile); _lzmaFinder = new LzmaFinder(module, DeobfuscatedFile);
lzmaFinder.Find(); _lzmaFinder.Find();
constantDecrypter = new ConstantsDecrypter(module, lzmaFinder.Method, DeobfuscatedFile); _constantDecrypter = new ConstantsDecrypter(module, _lzmaFinder.Method, DeobfuscatedFile);
resourceDecrypter = new ResourceDecrypter(module, lzmaFinder.Method, DeobfuscatedFile); _resourceDecrypter = new ResourceDecrypter(module, _lzmaFinder.Method, DeobfuscatedFile);
if (lzmaFinder.FoundLzma) if (_lzmaFinder.FoundLzma)
{ {
constantDecrypter.Find(); _constantDecrypter.Find();
resourceDecrypter.Find(); _resourceDecrypter.Find();
} }
_proxyCallFixer = new ProxyCallFixer(module, DeobfuscatedFile);
_proxyCallFixer.FindDelegateCreatorMethod();
_proxyCallFixer.Find();
DetectConfuserExAttribute(); DetectConfuserExAttribute();
} }
public void DetectConfuserExAttribute() private void DetectConfuserExAttribute()
{ {
var versions = new List<string>(); var versions = new List<string>();
foreach (var attribute in module.CustomAttributes) foreach (var attribute in module.CustomAttributes)
@ -143,8 +149,8 @@ namespace de4dot.code.deobfuscators.ConfuserEx
var value = argument.Value.ToString(); var value = argument.Value.ToString();
if (!value.Contains("ConfuserEx")) if (!value.Contains("ConfuserEx"))
continue; continue;
detectedConfuserExAttribute = true; _detectedConfuserExAttribute = true;
version = value.Replace("ConfuserEx", ""); _version = value.Replace("ConfuserEx", "");
return; return;
} }
} }
@ -152,8 +158,10 @@ namespace de4dot.code.deobfuscators.ConfuserEx
public override void DeobfuscateBegin() public override void DeobfuscateBegin()
{ {
if (constantDecrypter.Detected) if (_constantDecrypter.Detected)
{ {
Logger.w("Constants encryption detected! Please note that the decryption method has to be set manually!"); //TODO: Remove
sbyteValueInliner = new SByteValueInliner(); sbyteValueInliner = new SByteValueInliner();
byteValueInliner = new ByteValueInliner(); byteValueInliner = new ByteValueInliner();
int16ValueInliner = new Int16ValueInliner(); int16ValueInliner = new Int16ValueInliner();
@ -165,37 +173,41 @@ namespace de4dot.code.deobfuscators.ConfuserEx
singleValueInliner = new SingleValueInliner(); singleValueInliner = new SingleValueInliner();
doubleValueInliner = new DoubleValueInliner(); doubleValueInliner = new DoubleValueInliner();
arrayValueInliner = new ArrayValueInliner(initializedDataCreator); arrayValueInliner = new ArrayValueInliner(initializedDataCreator);
foreach (var info in constantDecrypter.Decrypters) foreach (var info in _constantDecrypter.Decrypters)
{ {
staticStringInliner.Add(info.Method, staticStringInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptString(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptString(info, gim, (uint) args[0]));
sbyteValueInliner.Add(info.Method, sbyteValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptSByte(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptSByte(info, gim, (uint) args[0]));
byteValueInliner.Add(info.Method, byteValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptByte(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptByte(info, gim, (uint) args[0]));
int16ValueInliner.Add(info.Method, int16ValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptInt16(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptInt16(info, gim, (uint) args[0]));
uint16ValueInliner.Add(info.Method, uint16ValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptUInt16(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptUInt16(info, gim, (uint) args[0]));
int32ValueInliner.Add(info.Method, int32ValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptInt32(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptInt32(info, gim, (uint) args[0]));
uint32ValueInliner.Add(info.Method, uint32ValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptUInt32(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptUInt32(info, gim, (uint) args[0]));
int64ValueInliner.Add(info.Method, int64ValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptInt64(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptInt64(info, gim, (uint) args[0]));
uint64ValueInliner.Add(info.Method, uint64ValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptUInt64(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptUInt64(info, gim, (uint) args[0]));
singleValueInliner.Add(info.Method, singleValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptSingle(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptSingle(info, gim, (uint) args[0]));
doubleValueInliner.Add(info.Method, doubleValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptDouble(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptDouble(info, gim, (uint) args[0]));
arrayValueInliner.Add(info.Method, arrayValueInliner.Add(info.Method,
(method, gim, args) => constantDecrypter.DecryptArray(info, gim, (uint) args[0])); (method, gim, args) => _constantDecrypter.DecryptArray(info, gim, (uint) args[0]));
} }
deobfuscating = true; _deobfuscating = true;
} }
if (resourceDecrypter.Detected) if (_resourceDecrypter.Detected)
resourceDecrypter.Fix(); {
Logger.w("Resource encryption detected! Please note that the decryption method has to be set manually!"); //TODO: Remove
_resourceDecrypter.Fix();
}
base.DeobfuscateBegin(); base.DeobfuscateBegin();
} }
@ -204,9 +216,9 @@ namespace de4dot.code.deobfuscators.ConfuserEx
get get
{ {
var list = new List<IBlocksDeobfuscator>(); var list = new List<IBlocksDeobfuscator>();
list.Add(new ControlFlowSolver()); list.Add(_controlFlowFixer);
if (deobfuscating && int32ValueInliner != null) if (_deobfuscating && int32ValueInliner != null)
list.Add(new ConstantsInliner(sbyteValueInliner, byteValueInliner, int16ValueInliner, list.Add(new ConstantsInliner(sbyteValueInliner, byteValueInliner, int16ValueInliner,
uint16ValueInliner, uint16ValueInliner,
int32ValueInliner, uint32ValueInliner, int64ValueInliner, uint64ValueInliner, int32ValueInliner, uint32ValueInliner, int64ValueInliner, uint64ValueInliner,
@ -216,7 +228,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
} }
} }
bool CanRemoveLzma = true; bool _canRemoveLzma = true;
public override void DeobfuscateEnd() public override void DeobfuscateEnd()
{ {
@ -224,38 +236,48 @@ namespace de4dot.code.deobfuscators.ConfuserEx
List<MethodDef> toRemoveFromCctor = new List<MethodDef>(); List<MethodDef> toRemoveFromCctor = new List<MethodDef>();
if (constantDecrypter.Detected) if (_constantDecrypter.Detected)
if (CanRemoveStringDecrypterType) if (CanRemoveStringDecrypterType)
{ {
toRemoveFromCctor.Add(constantDecrypter.Method); toRemoveFromCctor.Add(_constantDecrypter.Method);
AddMethodToBeRemoved(constantDecrypter.Method, "Constant Decrypter Initializer"); AddMethodToBeRemoved(_constantDecrypter.Method, "Constant Decrypter Initializer");
foreach (var dec in constantDecrypter.Decrypters) foreach (var dec in _constantDecrypter.Decrypters)
AddMethodToBeRemoved(dec.Method, "Constant Decrypter Method"); AddMethodToBeRemoved(dec.Method, "Constant Decrypter Method");
AddFieldsToBeRemoved(constantDecrypter.Fields, "Constant Decrypter Fields"); AddFieldsToBeRemoved(_constantDecrypter.Fields, "Constant Decrypter Fields");
AddTypeToBeRemoved(constantDecrypter.Type, "Array field signature type"); AddTypeToBeRemoved(_constantDecrypter.Type, "Array field signature type");
} }
else else
CanRemoveLzma = false; _canRemoveLzma = false;
if (resourceDecrypter.Detected && resourceDecrypter.CanRemoveLzma) if (_resourceDecrypter.Detected && _resourceDecrypter.CanRemoveLzma)
{ {
toRemoveFromCctor.Add(resourceDecrypter.Method); toRemoveFromCctor.Add(_resourceDecrypter.Method);
AddMethodToBeRemoved(resourceDecrypter.Method, "Resource decrypter Initializer method"); AddMethodToBeRemoved(_resourceDecrypter.Method, "Resource decrypter Initializer method");
AddMethodToBeRemoved(resourceDecrypter.AssembyResolveMethod, AddMethodToBeRemoved(_resourceDecrypter.AssembyResolveMethod,
"Resource decrypter AssemblyResolve method"); "Resource decrypter AssemblyResolve method");
AddFieldsToBeRemoved(resourceDecrypter.Fields, "Constant Decrypter Fields"); AddFieldsToBeRemoved(_resourceDecrypter.Fields, "Constant Decrypter Fields");
AddTypeToBeRemoved(resourceDecrypter.Type, "Array field signature type"); AddTypeToBeRemoved(_resourceDecrypter.Type, "Array field signature type");
} }
if (!constantDecrypter.CanRemoveLzma || !resourceDecrypter.CanRemoveLzma) if (!_constantDecrypter.CanRemoveLzma || !_resourceDecrypter.CanRemoveLzma)
CanRemoveLzma = false; _canRemoveLzma = false;
if (lzmaFinder.FoundLzma && CanRemoveLzma) if (_lzmaFinder.FoundLzma && _canRemoveLzma)
{ {
AddMethodToBeRemoved(lzmaFinder.Method, "Lzma Decompress method"); AddMethodToBeRemoved(_lzmaFinder.Method, "Lzma Decompress method");
AddTypesToBeRemoved(lzmaFinder.Types, "Lzma Nested Types"); AddTypesToBeRemoved(_lzmaFinder.Types, "Lzma Nested Types");
} }
if (_proxyCallFixer.Detected)
{
AddTypesToBeRemoved(_proxyCallFixer.DelegateTypes, "Proxy delegates");
AddMethodsToBeRemoved(_proxyCallFixer.DelegateCreatorMethods, "Proxy creator methods");
AddTypesToBeRemoved(_proxyCallFixer.AttributeTypes, "Proxy creator attributes");
AddMethodsToBeRemoved(_proxyCallFixer.NativeMethods, "Proxy native methods");
}
AddMethodsToBeRemoved(_controlFlowFixer.NativeMethods, "Control flow native methods");
var moduleCctor = DotNetUtils.GetModuleTypeCctor(module); var moduleCctor = DotNetUtils.GetModuleTypeCctor(module);
foreach (var instr in moduleCctor.Body.Instructions) foreach (var instr in moduleCctor.Body.Instructions)
if (instr.OpCode == OpCodes.Call && instr.Operand is MethodDef && if (instr.OpCode == OpCodes.Call && instr.Operand is MethodDef &&
@ -273,6 +295,12 @@ namespace de4dot.code.deobfuscators.ConfuserEx
var list = new List<int>(); var list = new List<int>();
return list; return list;
} }
public override void DeobfuscateMethodEnd(Blocks blocks)
{
_proxyCallFixer.Deobfuscate(blocks);
base.DeobfuscateMethodEnd(blocks);
}
} }
} }
} }

View File

@ -0,0 +1,415 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
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 Context
{
public uint FieldToken;
public int ByteNum;
public MethodDef CreateMethod;
public Context(uint fieldToken, int byteNum, MethodDef createMethod)
{
this.FieldToken = fieldToken;
this.ByteNum = byteNum; // 2nd parameter of the Delegate CreateMethod
this.CreateMethod = createMethod;
}
}
class ProxyCallFixer : ProxyCallFixer4
{
public List<MethodDef> NativeMethods = new List<MethodDef>();
public List<TypeDef> AttributeTypes = new List<TypeDef>();
public List<MethodDef> DelegateCreatorMethods = new List<MethodDef>();
private readonly InstructionEmulator _instructionEmulator = new InstructionEmulator();
private readonly ISimpleDeobfuscator _simpleDeobfuscator;
private readonly List<MethodDef> _processedMethods = new List<MethodDef>();
public ProxyCallFixer(ModuleDefMD module, ISimpleDeobfuscator simpleDeobfuscator) : base(module)
{
_simpleDeobfuscator = simpleDeobfuscator;
}
public ProxyCallFixer(ModuleDefMD module, ProxyCallFixer4 oldOne) : base(module, oldOne)
{
}
protected override object CheckCctor(TypeDef type, MethodDef cctor)
{
if (!_processedMethods.Contains(cctor))
{
_simpleDeobfuscator.Deobfuscate(cctor);
_processedMethods.Add(cctor);
}
List<Context> contexts = new List<Context>();
var instructions = cctor.Body.Instructions;
instructions.SimplifyMacros(cctor.Body.Variables, cctor.Parameters);
for (int i = 0; i < instructions.Count; i++)
{
var instrs = DotNetUtils.GetInstructions(instructions, i, OpCodes.Ldtoken, OpCodes.Ldc_I4, OpCodes.Call);
if (instrs == null)
continue;
uint fieldToken = ((IField) instrs[0].Operand).MDToken.ToUInt32();
int byteNum = (int)instrs[1].Operand;
var createMethod = instrs[2].Operand as MethodDef;
if(!DelegateCreatorMethods.Contains(createMethod))
DelegateCreatorMethods.Add(createMethod);
contexts.Add(new Context(fieldToken, byteNum, createMethod));
}
return contexts.Count == 0 ? null : contexts;
}
private void DeobfuscateIfNeeded(MethodDef method)
{
if (!_processedMethods.Contains(method))
{
_simpleDeobfuscator.Deobfuscate(method);
_processedMethods.Add(method);
}
}
private byte[] GetExtraDataToken(byte[] sigData)
{
byte[] extraData = new byte[4];
// [original signature] [extra signature]
// ... X C0 X X X
Array.Copy(sigData, sigData.Length - 3, extraData, 1, 3); // last 3 bytes of signature
extraData[0] = sigData[sigData.Length - 5]; // the byte before C0
Array.Reverse(extraData); // decryptorMethod reads the bytes backwards
return extraData;
}
protected override void GetCallInfo(object context, FieldDef field, out IMethod calledMethod, out OpCode callOpcode)
{
var contexts = (List<Context>) context;
var ctx = contexts.First(c => c.FieldToken == field.MDToken.ToInt32());
var originalMethod = DotNetUtils.Clone(ctx.CreateMethod); // backup original method and restore because changes are not universal
DeobfuscateIfNeeded(ctx.CreateMethod);
var instructions = ctx.CreateMethod.Body.Instructions;
var variables = ctx.CreateMethod.Body.Variables;
var parameters = ctx.CreateMethod.Parameters;
instructions.SimplifyMacros(variables, parameters);
byte[] sigData = module.ReadBlob(ctx.FieldToken);
byte[] extraDataToken = GetExtraDataToken(sigData);
int modifierMDToken = ((CModOptSig)field.FieldType).Modifier.MDToken.ToInt32();
ReplaceMetadataToken(ref instructions, modifierMDToken, variables[0]);
ReplaceFieldNameChars(ref instructions, field.Name, variables[0]);
InlineArrays(ref instructions, extraDataToken, variables[1], variables[2]);
RemoveDecrementorBlock(ref instructions, variables[2]);
int firstInstruction = GetEmulationStartIndex(instructions, variables[1], variables[2]);
int lastInstruction =
instructions.IndexOf(
instructions.First(
i => i.OpCode == OpCodes.Callvirt && i.Operand.ToString().Contains("GetCustomAttributes"))) - 4;
bool nativeMode = false;
if (instructions[lastInstruction - 1].OpCode == OpCodes.Call) // x86 protection
{
lastInstruction--; // don't try emulating native method
nativeMode = true;
}
int result = EmulateManagedMethod(ctx.CreateMethod, firstInstruction, lastInstruction);
if (nativeMode)
{
MethodDef nativeMethod = (MethodDef) instructions[lastInstruction].Operand;
if (!NativeMethods.Contains(nativeMethod))
NativeMethods.Add(nativeMethod);
result = EmulateNativeMethod(nativeMethod, result);
}
result *= GetMagicNumber(field.CustomAttributes[0]);
calledMethod = module.ResolveMemberRef(new MDToken(result).Rid);
if(calledMethod == null)
throw new Exception();
int charNum = GetCharNum(instructions, parameters.Last());
callOpcode = GetCallOpCode(calledMethod, charNum, ctx.ByteNum);
ctx.CreateMethod.Body = originalMethod.Body; // restore
}
private OpCode GetCallOpCode(IMethod calledMethod, int charNum, int byteNum)
{
if (calledMethod.ResolveMethodDef().IsStatic) {
return OpCodes.Call;
}
byte charOpCode = (byte)(charNum ^ byteNum);
if (charOpCode == 0x28)
return OpCodes.Call;
else if (charOpCode == 0x6F)
return OpCodes.Callvirt;
else if (charOpCode == 0x73)
return OpCodes.Newobj;
else
throw new Exception();
}
private int EmulateNativeMethod(MethodDef externalMethod, int parameter)
{
var nativeMethod = new X86Method(externalMethod, module); //TODO: Possible null
return nativeMethod.Execute(parameter);
}
private int EmulateManagedMethod(MethodDef method, int startIndex, int endIndex, params Tuple<Parameter, int>[] parameters)
{
_instructionEmulator.Initialize(method, false);
foreach(var parameter in parameters)
_instructionEmulator.SetArg(parameter.Item1, new Int32Value(parameter.Item2));
for (int i = startIndex; i < endIndex; i++) {
_instructionEmulator.Emulate(method.Body.Instructions[i]);
}
return ((Int32Value) _instructionEmulator.Pop()).Value;
}
private int GetMagicNumber(CustomAttribute customAttribute)
{
TypeDef attributeType = customAttribute.AttributeType.ResolveTypeDef();
if(!AttributeTypes.Contains(attributeType))
AttributeTypes.Add(attributeType);
var ctor = attributeType.FindConstructors().First();
DeobfuscateIfNeeded(ctor);
int magicNum = Convert.ToInt32(customAttribute.ConstructorArguments[0].Value);
var parameter = new Tuple<Parameter, int>();
parameter.Item1 = ctor.Parameters[1];
parameter.Item2 = magicNum;
return EmulateManagedMethod(ctor, 3, ctor.Body.Instructions.Count - 2, parameter);
}
public void FindDelegateCreatorMethod()
{
var globalType = module.GlobalType;
foreach (
var method in
globalType.Methods.Where(
m => m.Parameters.Count == 2 && m.Parameters[0].Type.TypeName == "RuntimeFieldHandle"))
{
_simpleDeobfuscator.Deobfuscate(method);
SetDelegateCreatorMethod(method);
}
} //TODO: Improve detection
/* 0x000005B7 6F1500000A IL_001F: callvirt instance uint8[][mscorlib] System.Reflection.Module::ResolveSignature(int32)
0x000005BC FE0E0100 IL_0024: stloc.1
0x000005C0 FE0C0100 IL_0028: ldloc.1
0x000005C4 8E IL_002C: ldlen
0x000005C5 69 IL_002D: conv.i4
0x000005C6 FE0E0200 IL_002E: stloc.2 */
private int GetEmulationStartIndex(IList<Instruction> instructions, Local localArray, Local localArraySize)
{
for (int i = 0; i < instructions.Count; i++)
{
var instrs = DotNetUtils.GetInstructions(instructions, i, OpCodes.Callvirt, OpCodes.Stloc,
OpCodes.Ldloc, OpCodes.Ldlen, OpCodes.Conv_I4, OpCodes.Stloc);
if (instrs == null)
continue;
if (!instrs[0].Operand.ToString().Contains("ResolveSignature"))
continue;
if ((Local)instrs[1].Operand != localArray)
continue;
if ((Local)instrs[2].Operand != localArray)
continue;
if ((Local)instrs[5].Operand != localArraySize)
continue;
return i + 6;
}
return -1;
}
/* 0x000008F3 03 IL_02BB: ldarg.1
0x000008F4 61 IL_02BC: xor */
private int GetCharNum(IList<Instruction> instructions, Parameter byteParam)
{
for (int i = 0; i < instructions.Count; i++)
{
var instrs = DotNetUtils.GetInstructions(instructions, i, OpCodes.Ldarg, OpCodes.Xor);
if (instrs == null)
continue;
if ((Parameter) instrs[0].Operand != byteParam)
continue;
return (int) instructions[i - 5].Operand;
}
throw new Exception();
}
private void ReplaceFieldNameChars(ref IList<Instruction> instructions, string fieldName, Local fieldLocal)
{
bool foundInstrs;
do {
foundInstrs = ReplaceFieldNameChar(ref instructions, fieldName, fieldLocal);
} while (foundInstrs);
}
/* 0x00000375 06 IL_007D: ldloc.0
0x00000376 6F1500000A IL_007E: callvirt
0x0000037B 19 IL_0083: ldc.i4.3
0x0000037C 6F1600000A IL_0084: callvirt */
private bool ReplaceFieldNameChar(ref IList<Instruction> instructions, string fieldName, Local fieldLocal)
{
for (int i = 0; i < instructions.Count; i++)
{
var instrs = DotNetUtils.GetInstructions(instructions, i, OpCodes.Ldloc, OpCodes.Callvirt,
OpCodes.Ldc_I4, OpCodes.Callvirt);
if(instrs == null)
continue;
if ((Local)instrs[0].Operand != fieldLocal)
continue;
if (!instrs[1].Operand.ToString().Contains("get_Name"))
continue;
if (!instrs[3].Operand.ToString().Contains("get_Chars"))
continue;
int charIndex = (int)instrs[2].Operand;
int @char = fieldName[charIndex];
instructions[i].OpCode = OpCodes.Ldc_I4;
instructions[i].Operand = @char;
instructions[i+1].OpCode = OpCodes.Nop;
instructions[i+2].OpCode = OpCodes.Nop;
instructions[i+3].OpCode = OpCodes.Nop;
return true;
}
return false;
}
/* 0x0000034A 08 IL_0052: ldloc.2
0x0000034B 17 IL_0053: ldc.i4.1
0x0000034C 59 IL_0054: sub
0x0000034D 25 IL_0055: dup
0x0000034E 0C IL_0056: stloc.2
0x0000034F 91 IL_0057: ldelem.u1 */
private void InlineArrays(ref IList<Instruction> instructions, byte[] values, Local localArray, Local localInt)
{
bool foundInstrs;
int i = 0;
do {
foundInstrs = InlineArray(ref instructions, values[i++], localArray, localInt);
} while (i < 4 && foundInstrs);
}
private bool InlineArray(ref IList<Instruction> instructions, int value, Local localArray, Local localInt)
{
for (int i = 0; i < instructions.Count; i++)
{
var instrs = DotNetUtils.GetInstructions(instructions, i, OpCodes.Ldloc, OpCodes.Ldloc, OpCodes.Ldc_I4,
OpCodes.Sub, OpCodes.Dup, OpCodes.Stloc, OpCodes.Ldelem_U1);
if (instrs == null)
continue;
if ((Local)instrs[0].Operand != localArray)
continue;
if ((Local)instrs[1].Operand != localInt)
continue;
if ((int)instrs[2].Operand != 1)
continue;
if ((Local)instrs[5].Operand != localInt)
continue;
instructions[i].OpCode = OpCodes.Ldc_I4;
instructions[i].Operand = value;
instructions[i + 1].OpCode = OpCodes.Nop;
instructions[i + 2].OpCode = OpCodes.Nop;
instructions[i + 3].OpCode = OpCodes.Nop;
instructions[i + 4].OpCode = OpCodes.Nop;
instructions[i + 5].OpCode = OpCodes.Nop;
instructions[i + 6].OpCode = OpCodes.Nop;
return true;
}
return false;
}
/* 0x00000371 08 IL_0079: ldloc.2
0x00000372 17 IL_007A: ldc.i4.1
0x00000373 59 IL_007B: sub
0x00000374 0C IL_007C: stloc.2 */
private void RemoveDecrementorBlock(ref IList<Instruction> instructions, Local localInt)
{
for (int i = 0; i < instructions.Count; i++)
{
var instrs = DotNetUtils.GetInstructions(instructions, i, OpCodes.Ldloc, OpCodes.Ldc_I4, OpCodes.Sub, OpCodes.Stloc);
if (instrs == null)
continue;
if ((Local)instrs[0].Operand != localInt)
continue;
if ((int)instrs[1].Operand != 1)
continue;
if ((Local)instrs[3].Operand != localInt)
continue;
instructions[i].OpCode = OpCodes.Nop;
instructions[i + 1].OpCode = OpCodes.Nop;
instructions[i + 2].OpCode = OpCodes.Nop;
instructions[i + 3].OpCode = OpCodes.Nop;
return;
}
}
/* 0x000005CF FE0C0000 IL_0037: ldloc.0
0x000005D3 6F1600000A IL_003B: callvirt instance class [mscorlib] System.Type[][mscorlib] System.Reflection.FieldInfo::GetOptionalCustomModifiers()
0x000005D8 2000000000 IL_0040: ldc.i4.0
0x000005DD 9A IL_0045: ldelem.ref
0x000005DE 6F1400000A IL_0046: callvirt instance int32[mscorlib] System.Reflection.MemberInfo::get_MetadataToken() */
private void ReplaceMetadataToken(ref IList<Instruction> instructions, int metadataToken, Local fieldLocal)
{
for (int i = 0; i < instructions.Count; i++)
{
var instrs = DotNetUtils.GetInstructions(instructions, i, OpCodes.Ldloc, OpCodes.Callvirt, OpCodes.Ldc_I4,
OpCodes.Ldelem_Ref, OpCodes.Callvirt);
if (instrs == null)
continue;
if ((Local)instrs[0].Operand != fieldLocal)
continue;
if (!instrs[1].Operand.ToString().Contains("GetOptionalCustomModifiers"))
continue;
if ((int)instrs[2].Operand != 0)
continue;
if (!instrs[4].Operand.ToString().Contains("get_MetadataToken"))
continue;
instructions[i].OpCode = OpCodes.Ldc_I4;
instructions[i].Operand = metadataToken;
instructions[i + 1].OpCode = OpCodes.Nop;
instructions[i + 2].OpCode = OpCodes.Nop;
instructions[i + 3].OpCode = OpCodes.Nop;
instructions[i + 4].OpCode = OpCodes.Nop;
return;
}
}
}
}

View File

@ -171,7 +171,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
Buffer.BlockCopy(array, 0, buffer, 0, array.Length * l1); Buffer.BlockCopy(array, 0, buffer, 0, array.Length * l1);
return buffer; return buffer;
} }
private void DecryptArray(uint[] array) private void DecryptArray(uint[] array) //TODO: Automatic detection
{ {
int num = array.Length; int num = array.Length;
uint[] array2 = new uint[16]; uint[] array2 = new uint[16];

View File

@ -525,4 +525,242 @@ namespace de4dot.code.deobfuscators {
return instr.Operand as IMethod; return instr.Operand as IMethod;
} }
} }
//
// Combines the above 1st and 2nd templates
//
public abstract class ProxyCallFixer4 : ProxyCallFixerBase
{
FieldDefAndDeclaringTypeDict<DelegateInfo> fieldToDelegateInfo = new FieldDefAndDeclaringTypeDict<DelegateInfo>();
MethodDefAndDeclaringTypeDict<DelegateInfo> proxyMethodToDelegateInfo = new MethodDefAndDeclaringTypeDict<DelegateInfo>();
protected ProxyCallFixer4(ModuleDefMD module)
: base(module)
{
}
protected ProxyCallFixer4(ModuleDefMD module, ProxyCallFixer4 oldOne)
: base(module, oldOne)
{
foreach (var key in oldOne.fieldToDelegateInfo.GetKeys())
fieldToDelegateInfo.Add(Lookup(key, "Could not find field"), Copy(oldOne.fieldToDelegateInfo.Find(key)));
foreach (var oldMethod in oldOne.proxyMethodToDelegateInfo.GetKeys())
{
var oldDi = oldOne.proxyMethodToDelegateInfo.Find(oldMethod);
var method = Lookup(oldMethod, "Could not find proxy method");
proxyMethodToDelegateInfo.Add(method, Copy(oldDi));
}
}
protected void AddDelegateInfo(DelegateInfo di)
{
fieldToDelegateInfo.Add(di.field, di);
}
protected DelegateInfo GetDelegateInfo(IField field)
{
if (field == null)
return null;
return fieldToDelegateInfo.Find(field);
}
public void Find()
{
if (delegateCreatorMethods.Count == 0)
return;
Logger.v("Finding all proxy delegates");
foreach (var type in GetDelegateTypes())
{
var cctor = type.FindStaticConstructor();
if (cctor == null || !cctor.HasBody)
continue;
if (!type.HasFields)
continue;
object context = CheckCctor(type, cctor);
if (context == null)
continue;
Logger.v("Found proxy delegate: {0} ({1:X8})", Utils.RemoveNewlines(type), type.MDToken.ToUInt32());
RemovedDelegateCreatorCalls++;
var fieldToMethod = GetFieldToMethodDictionary(type);
Logger.Instance.Indent();
foreach (var field in type.Fields)
{
MethodDef proxyMethod;
bool supportType1 = fieldToMethod.TryGetValue(field, out proxyMethod);
bool supportType2 = field.IsStatic;
if (!supportType1 && !supportType2)
continue;
IMethod calledMethod;
OpCode callOpcode;
GetCallInfo(context, field, out calledMethod, out callOpcode);
if (calledMethod == null)
continue;
if (supportType1)
{
Add2(proxyMethod, new DelegateInfo(field, calledMethod, callOpcode));
}
if (supportType2)
{
AddDelegateInfo(new DelegateInfo(field, calledMethod, callOpcode));
}
Logger.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})",
Utils.RemoveNewlines(field.Name),
callOpcode,
Utils.RemoveNewlines(calledMethod),
calledMethod.MDToken.Raw);
}
Logger.Instance.DeIndent();
delegateTypesDict[type] = true;
}
}
protected void Add2(MethodDef method, DelegateInfo di)
{
proxyMethodToDelegateInfo.Add(method, di);
}
protected abstract object CheckCctor(TypeDef type, MethodDef cctor);
protected abstract void GetCallInfo(object context, FieldDef field, out IMethod calledMethod, out OpCode callOpcode);
Dictionary<FieldDef, MethodDef> GetFieldToMethodDictionary(TypeDef type)
{
var dict = new Dictionary<FieldDef, MethodDef>();
foreach (var method in type.Methods)
{
if (!method.IsStatic || !method.HasBody || method.Name == ".cctor")
continue;
var instructions = method.Body.Instructions;
for (int i = 0; i < instructions.Count; i++)
{
var instr = instructions[i];
if (instr.OpCode.Code != Code.Ldsfld)
continue;
var field = instr.Operand as FieldDef;
if (field == null)
continue;
dict[field] = method;
break;
}
}
return dict;
}
protected override bool Deobfuscate(Blocks blocks, IList<Block> allBlocks)
{
var removeInfos = new Dictionary<Block, List<RemoveInfo>>();
foreach (var block in allBlocks)
{
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++)
{
var instr = instrs[i];
if (instr.OpCode == OpCodes.Call)
{
var method = instr.Operand as IMethod;
if (method == null)
continue;
var di = proxyMethodToDelegateInfo.Find(method);
if (di == null)
continue;
Add(removeInfos, block, i, di);
}
else if (instr.OpCode == OpCodes.Ldsfld)
{
var di = GetDelegateInfo(instr.Operand as IField);
if (di == null)
continue;
var callInfo = FindProxyCall(di, block, i);
if (callInfo != null)
{
Add(removeInfos, block, i, null);
Add(removeInfos, callInfo.Block, callInfo.Index, di);
}
else
{
errors++;
Logger.w("Could not fix proxy call. Method: {0} ({1:X8}), Proxy type: {2} ({3:X8})",
Utils.RemoveNewlines(blocks.Method),
blocks.Method.MDToken.ToInt32(),
Utils.RemoveNewlines(di.field.DeclaringType),
di.field.DeclaringType.MDToken.ToInt32());
}
}
}
}
return FixProxyCalls(blocks.Method, removeInfos);
}
protected virtual BlockInstr FindProxyCall(DelegateInfo di, Block block, int index)
{
return FindProxyCall(di, block, index, new Dictionary<Block, bool>(), 1);
}
BlockInstr FindProxyCall(DelegateInfo di, Block block, int index, Dictionary<Block, bool> visited, int stack)
{
if (visited.ContainsKey(block))
return null;
if (index <= 0)
visited[block] = true;
var instrs = block.Instructions;
for (int i = index + 1; i < instrs.Count; i++)
{
if (stack <= 0)
return null;
var instr = instrs[i];
instr.Instruction.UpdateStack(ref stack, false);
if (stack < 0)
return null;
if (instr.OpCode != OpCodes.Call && instr.OpCode != OpCodes.Callvirt)
{
if (stack <= 0)
return null;
continue;
}
var calledMethod = instr.Operand as IMethod;
if (calledMethod == null)
return null;
if (stack != (DotNetUtils.HasReturnValue(calledMethod) ? 1 : 0))
continue;
if (calledMethod.Name != "Invoke")
return null;
return new BlockInstr
{
Block = block,
Index = i,
};
}
if (stack <= 0)
return null;
foreach (var target in block.GetTargets())
{
var info = FindProxyCall(di, target, -1, visited, stack);
if (info != null)
return info;
}
return null;
}
}
} }

View File

@ -124,7 +124,9 @@ namespace de4dot.cui {
Logger.Instance.LogErrorDontIgnore("{0}", ex.Message); Logger.Instance.LogErrorDontIgnore("{0}", ex.Message);
exitCode = 1; exitCode = 1;
} }
catch (Exception ex) { /*catch (Exception ex)
{
throw;
if (PrintFullStackTrace()) { if (PrintFullStackTrace()) {
PrintStackTrace(ex); PrintStackTrace(ex);
Logger.Instance.LogErrorDontIgnore("\nTry the latest version!"); Logger.Instance.LogErrorDontIgnore("\nTry the latest version!");
@ -134,7 +136,7 @@ namespace de4dot.cui {
Logger.Instance.LogErrorDontIgnore("Hmmmm... something didn't work. Try the latest version."); Logger.Instance.LogErrorDontIgnore("Hmmmm... something didn't work. Try the latest version.");
} }
exitCode = 1; exitCode = 1;
} }*/
if (Logger.Instance.NumIgnoredMessages > 0) { if (Logger.Instance.NumIgnoredMessages > 0) {
if (Logger.Instance.NumIgnoredMessages == 1) if (Logger.Instance.NumIgnoredMessages == 1)