Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions de4dot.code/de4dot.code.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.8" Condition=" '$(De4DotNetFramework)' != 'true' " />
<PackageReference Include="BrotliSharpLib" Version="0.3.3" Condition=" '$(De4DotNetFramework)' == 'true' " />
</ItemGroup>

</Project>
40 changes: 39 additions & 1 deletion de4dot.code/deobfuscators/DeobUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,36 @@ You should have received a copy of the GNU General Public License
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using ICSharpCode.SharpZipLib.Zip.Compression;
#if NETFRAMEWORK
using BrotliSharpLib;
#endif
using de4dot.blocks;

namespace de4dot.code.deobfuscators {
public static class DeobUtils {
public static void DecryptAndAddResources(ModuleDef module, string encryptedName, Func<byte[]> decryptResource) {
Logger.v("Decrypting resources, name: {0}", Utils.ToCsharpString(encryptedName));
var decryptedResourceData = decryptResource();
AddDecryptedResources(module, decryptResource());
}

public static void DecryptAndAddResources(ModuleDef module, string encryptedName, Func<IEnumerable<byte[]>> decryptResources) {
Logger.v("Decrypting resources, name: {0}", Utils.ToCsharpString(encryptedName));
BadImageFormatException lastException = null;
foreach (var decryptedResourceData in decryptResources()) {
try {
AddDecryptedResources(module, decryptedResourceData);
return;
}
catch (BadImageFormatException ex) {
lastException = ex;
}
}
if (lastException != null)
throw lastException;
throw new BadImageFormatException();
}

static void AddDecryptedResources(ModuleDef module, byte[] decryptedResourceData) {
if (decryptedResourceData == null)
throw new ApplicationException("decryptedResourceData is null");
var resourceModule = ModuleDefMD.Load(decryptedResourceData);
Expand Down Expand Up @@ -163,6 +186,21 @@ public static byte[] Inflate(byte[] data, int start, int len, Inflater inflater)
return memStream.ToArray();
}

public static byte[] BrotliDecompress(byte[] data) {
#if NETFRAMEWORK
return Brotli.DecompressBuffer(data, 0, data.Length);
#else
using (var input = new MemoryStream(data, writable: false)) {
using (var brotli = new BrotliStream(input, CompressionMode.Decompress)) {
using (var output = new MemoryStream()) {
brotli.CopyTo(output);
return output.ToArray();
}
}
}
#endif
}

public static byte[] Gunzip(Stream input, int decompressedSize) {
using (var gzip = new GZipStream(input, CompressionMode.Decompress)) {
var decompressed = new byte[decompressedSize];
Expand Down
81 changes: 55 additions & 26 deletions de4dot.code/deobfuscators/dotNET_Reactor/v4/ResourceResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,34 +151,63 @@ MethodDef FindInitMethod(ISimpleDeobfuscator simpleDeobfuscator) {
public EmbeddedResource MergeResources() {
if (encryptedResource.Resource == null)
return null;
DeobUtils.DecryptAndAddResources(module, encryptedResource.Resource.Name.String, () => {
byte[] decrypted;
try {
decrypted = encryptedResource.Decrypt();
}
catch (Exception ex) {
Logger.e("Resource decryption failed:\n{0}", ex);
return null;
}
byte[] decrypted;
try {
decrypted = encryptedResource.Decrypt();
}
catch (Exception ex) {
Logger.e("Resource decryption failed:\n{0}", ex);
return null;
}
DeobUtils.DecryptAndAddResources(module, encryptedResource.Resource.Name.String,
() => GetDecompressedResources(decrypted));
return encryptedResource.Resource;
}

if (decrypted.Length < 64)
throw new Exception("Decrypted resource data has length " + decrypted.Length);
if (decrypted[0] == 0x4D && decrypted[1] == 0x5A && decrypted[62] == 0 && decrypted[63] == 0)
return decrypted;
static IEnumerable<byte[]> GetDecompressedResources(byte[] decrypted) {
if (decrypted.Length >= 2 && decrypted[0] == 0x4D && decrypted[1] == 0x5A)
yield return decrypted;

try {
return QuickLZ.Decompress(decrypted);
}
catch {
try {
return DeobUtils.Inflate(decrypted, true);
}
catch {
return null;
}
}
});
return encryptedResource.Resource;
if (TryQuickLZDecompress(decrypted, out var decompressed))
yield return decompressed;
if (TryInflate(decrypted, out var inflated))
yield return inflated;

if (TryBrotliDecompress(decrypted, out var brotli))
yield return brotli;
}

static bool TryQuickLZDecompress(byte[] data, out byte[] decompressed) {
try {
decompressed = QuickLZ.Decompress(data);
return true;
}
catch {
decompressed = null;
return false;
}
}

static bool TryInflate(byte[] data, out byte[] inflated) {
try {
inflated = DeobUtils.Inflate(data, true);
return true;
}
catch {
inflated = null;
return false;
}
}

static bool TryBrotliDecompress(byte[] data, out byte[] brotli) {
try {
brotli = DeobUtils.BrotliDecompress(data);
return true;
}
catch {
brotli = null;
return false;
}
}
}
}
Loading