Browse Source

Support loading compressed Xamarin assemblies, see #2137

Extend class LoadedAssembly to detect and load compressed Xamarin assemblies if direct loading of assembly fails.

Requires Nuget pkg K4os.Compression.LZ4 for LZ4 decompression.
pull/2471/head
Christian Prähauser 4 years ago
parent
commit
39d230f022
  1. 1
      ILSpy/ILSpy.csproj
  2. 36
      ILSpy/LoadedAssembly.cs

1
ILSpy/ILSpy.csproj

@ -54,6 +54,7 @@ @@ -54,6 +54,7 @@
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.31" />
<PackageReference Include="TomsToolbox.Wpf.Styles" Version="2.5.5" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.6" />
</ItemGroup>
<ItemGroup>

36
ILSpy/LoadedAssembly.cs

@ -35,6 +35,8 @@ using ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -35,6 +35,8 @@ using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.Options;
using K4os.Compression.LZ4;
#nullable enable
namespace ICSharpCode.ILSpy
@ -323,6 +325,15 @@ namespace ICSharpCode.ILSpy @@ -323,6 +325,15 @@ namespace ICSharpCode.ILSpy
{
loadAssemblyException = ex;
}
// Maybe its a compressed Xamarin/Mono assembly, see https://github.com/xamarin/xamarin-android/pull/4686
try
{
return LoadCompressedAssembly(fileName);
}
catch (InvalidDataException)
{
// Not a compressed module, try other options below
}
// If it's not a .NET module, maybe it's a single-file bundle
var bundle = LoadedPackage.FromBundle(fileName);
if (bundle != null)
@ -365,6 +376,31 @@ namespace ICSharpCode.ILSpy @@ -365,6 +376,31 @@ namespace ICSharpCode.ILSpy
return new LoadResult(module);
}
LoadResult LoadCompressedAssembly(string filename)
{
const uint CompressedDataMagic = 0x5A4C4158; // Magic used for Xamarin compressed module header ('XALZ', little-endian)
using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
using (var fileReader = new BinaryReader(fileStream))
{
// Read compressed file header
var magic = fileReader.ReadUInt32();
if (magic != CompressedDataMagic)
throw new InvalidDataException($"Xamarin compressed module header magic {magic} does not match expected {CompressedDataMagic}");
var descIdx = fileReader.ReadUInt32();
var uncLen = fileReader.ReadUInt32();
// fileReader stream position is now at compressed module data
var src = fileReader.ReadBytes((int)uncLen); // compressed length must be smaller than uncompressed length
var dst = new byte[(int)uncLen];
// Decompress
LZ4Codec.Decode(src, 0, src.Length, dst, 0, dst.Length);
// Load module from decompressed data buffer
using (var modData = new MemoryStream(dst, writable: false))
{
return LoadAssembly(modData, PEStreamOptions.PrefetchEntireImage);
}
}
}
IDebugInfoProvider? LoadDebugInfo(PEFile module)
{
if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols)

Loading…
Cancel
Save