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:
parent
23477ccb5f
commit
e0a2e805d4
|
@ -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" />
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
415
de4dot.code/deobfuscators/ConfuserEx/ProxyCallFixer.cs
Normal file
415
de4dot.code/deobfuscators/ConfuserEx/ProxyCallFixer.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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];
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user