GUI: Add load options dialog with ELF image base option

This commit is contained in:
Katy Coe
2020-12-12 20:14:48 +01:00
parent 477a6b7698
commit c0f8e0eb17
8 changed files with 256 additions and 87 deletions

View File

@@ -10,6 +10,6 @@ namespace Il2CppInspector
public class LoadOptions
{
// For dumped ELF files, the virtual address to which we should rebase - ignored for other file types
public ulong? ImageBase;
public ulong? ImageBase { get; set; }
}
}

View File

@@ -3,6 +3,67 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<!-- Our favourite colours -->
<SolidColorBrush x:Key="MicrosoftBlue" Color="#00A2ED"/>
<SolidColorBrush x:Key="MicrosoftGreen" Color="#7DB700"/>
<SolidColorBrush x:Key="WindowsBlue" Color="#357EC7"/>
<!-- Light box button -->
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" StrokeDashArray="1 2" SnapsToDevicePixels="true" StrokeThickness="1" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
<SolidColorBrush x:Key="Button.Static.Border" Color="Gray"/>
<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
<SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
<SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
<SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
<SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
<SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
<SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
<Style x:Key="LightBoxButton" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
<Setter Property="Foreground" Value="{StaticResource MicrosoftBlue}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="FontSize" Value="28"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" Background="White" BorderThickness="2" CornerRadius="2" BorderBrush="{TemplateBinding BorderBrush}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsDefaulted" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>

View File

@@ -34,6 +34,8 @@ namespace Il2CppInspectorGUI
}
}
public LoadOptions LoadOptions { get; private set; } = null;
public List<AppModel> AppModels { get; } = new List<AppModel>();
public Exception LastException { get; private set; }
@@ -43,8 +45,14 @@ namespace Il2CppInspectorGUI
private void StatusUpdate(object sender, string status) => OnStatusUpdate?.Invoke(sender, status);
public void ResetLoadOptions() {
LoadOptions = new LoadOptions {
ImageBase = 0ul
};
}
// Attempt to load an IL2CPP application package (APK or IPA)
public async Task<bool> LoadPackageAsync(IEnumerable<string> packageFiles, LoadOptions loadOptions) {
public async Task<bool> LoadPackageAsync(IEnumerable<string> packageFiles) {
IsExtractedFromPackage = false;
try {
@@ -54,7 +62,7 @@ namespace Il2CppInspectorGUI
if (streams == null)
throw new InvalidOperationException("The supplied package is not an APK or IPA file, or does not contain a complete IL2CPP application");
IsExtractedFromPackage = await LoadMetadataAsync(streams.Value.Metadata) && await LoadBinaryAsync(streams.Value.Binary, loadOptions);
IsExtractedFromPackage = await LoadMetadataAsync(streams.Value.Metadata) && await LoadBinaryAsync(streams.Value.Binary);
return IsExtractedFromPackage;
}
catch (Exception ex) {
@@ -85,18 +93,18 @@ namespace Il2CppInspectorGUI
});
// Attempt to load an IL2CPP binary file
public async Task<bool> LoadBinaryAsync(string binaryFile, LoadOptions loadOptions) {
public async Task<bool> LoadBinaryAsync(string binaryFile) {
var stream = new MemoryStream(await File.ReadAllBytesAsync(binaryFile));
return await LoadBinaryAsync(stream, loadOptions);
return await LoadBinaryAsync(stream);
}
public Task<bool> LoadBinaryAsync(Stream binaryStream, LoadOptions loadOptions) =>
public Task<bool> LoadBinaryAsync(Stream binaryStream) =>
Task.Run(() => {
try {
OnStatusUpdate?.Invoke(this, "Processing binary");
// This may throw other exceptions from the individual loaders as well
IFileFormatReader stream = FileFormatReader.Load(binaryStream, loadOptions, StatusUpdate);
IFileFormatReader stream = FileFormatReader.Load(binaryStream, LoadOptions, StatusUpdate);
if (stream == null) {
throw new InvalidOperationException("Could not determine the binary file format");
}

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2020 Katy Coe - https://www.djkaty.com - https://github.com/djkaty
// All rights reserved
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Data;
namespace Il2CppInspector.GUI
{
internal class HexStringValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
if (value == null || targetType != typeof(string))
return DependencyProperty.UnsetValue;
return ((ulong) value).ToString("x16");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
if (value == null || targetType != typeof(ulong?))
return DependencyProperty.UnsetValue;
try {
return System.Convert.ToUInt64((string) value, 16);
}
catch {
return DependencyProperty.UnsetValue;
}
}
}
}

View File

@@ -0,0 +1,76 @@
<Window x:Class="Il2CppInspector.GUI.LoadOptionsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Il2CppInspector.GUI"
mc:Ignorable="d"
Title="IL2CPP Load Options"
ResizeMode="NoResize"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
Height="150" Width="400"
FocusManager.FocusedElement="{Binding ElementName=txtImageBase}">
<Window.Resources>
<local:HexStringValueConverter x:Key="HexStringValueConverter" />
</Window.Resources>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Grid}">
<Setter Property="Margin" Value="15" />
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Margin" Value="0,3,10,5" />
<Setter Property="Padding" Value="0,0,0,5" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="0,0,0,5" />
<Style.Triggers>
<!--<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>-->
</Style.Triggers>
</Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="70" />
<Setter Property="Height" Value="25" />
<Setter Property="Margin" Value="5,0,0,0" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0">Dumped ELF image base:</Label>
<DockPanel Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch">
<Label Margin="0,3,3,5">0x</Label>
<TextBox Name="txtImageBase" Text="{Binding Path=ImageBase, Converter={StaticResource HexStringValueConverter}, UpdateSourceTrigger=PropertyChanged}">
<TextBox.ToolTip>
<ToolTip Background="LightYellow">
<TextBlock>
For ELF binaries that have been dumped from memory, specify the base address of the dump<LineBreak/>Ignored for normal ELF binaries
</TextBlock>
</ToolTip>
</TextBox.ToolTip>
</TextBox>
</DockPanel>
<!-- Accept or Cancel -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" VerticalAlignment="Bottom">
<Button Name="okButton" Click="okButton_Click" IsDefault="True">OK</Button>
<Button Name="cancelButton" IsCancel="True">Cancel</Button>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2020 Katy Coe - https://www.djkaty.com - https://github.com/djkaty
// All rights reserved
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Il2CppInspectorGUI;
namespace Il2CppInspector.GUI
{
/// <summary>
/// Interaction logic for LoadOptionsDialog.xaml
/// </summary>
public partial class LoadOptionsDialog : Window
{
public LoadOptionsDialog() {
InitializeComponent();
var app = (App) Application.Current;
if (app.LoadOptions == null)
app.ResetLoadOptions();
DataContext = app.LoadOptions;
}
private void okButton_Click(object sender, RoutedEventArgs e) {
// Closes dialog box automatically
DialogResult = true;
}
}
}

View File

@@ -6,74 +6,11 @@
xmlns:local="clr-namespace:Il2CppInspectorGUI"
xmlns:gif="https://github.com/XamlAnimatedGif/XamlAnimatedGif"
mc:Ignorable="d"
Title="Il2CppInspector" Height="850" Width="1080" Background="White"
Title="Il2CppInspector" Height="850" Width="1100" Background="White"
WindowStartupLocation="CenterScreen"
ContentRendered="MainWindow_OnContentRendered"
Drop="MainWindow_OnDrop">
<Window.Resources>
<!-- Our favourite colours -->
<SolidColorBrush x:Key="MicrosoftBlue" Color="#00A2ED"/>
<SolidColorBrush x:Key="MicrosoftGreen" Color="#7DB700"/>
<SolidColorBrush x:Key="WindowsBlue" Color="#357EC7"/>
<!-- Light box button -->
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" StrokeDashArray="1 2" SnapsToDevicePixels="true" StrokeThickness="1" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
<SolidColorBrush x:Key="Button.Static.Border" Color="Gray"/>
<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
<SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
<SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
<SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
<SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
<SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
<SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
<Style x:Key="LightBoxButton" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
<Setter Property="Foreground" Value="{StaticResource MicrosoftBlue}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="FontSize" Value="28"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" Background="White" BorderThickness="2" CornerRadius="2" BorderBrush="{TemplateBinding BorderBrush}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsDefaulted" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Image list -->
<DataTemplate x:Key="ImageListTemplate">
<TextBlock>
@@ -116,7 +53,7 @@
<RowDefinition Height ="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"></ColumnDefinition>
<ColumnDefinition Width="330"></ColumnDefinition>
<ColumnDefinition Width="25"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
@@ -475,9 +412,10 @@
<Grid.RowDefinitions>
<RowDefinition Height ="*" />
<RowDefinition Height ="*" />
<RowDefinition Height ="Auto" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Name="btnSelectMetadataFile" Style="{StaticResource LightBoxButton}" Margin="100,100,100,50" Click="BtnSelectMetadataFile_OnClick">
<Button Grid.Row="0" Name="btnSelectMetadataFile" Style="{StaticResource LightBoxButton}" Margin="100,100,100,25" Click="BtnSelectMetadataFile_OnClick">
<TextBlock TextAlignment="Center">
<TextBlock FontSize="22">Option 1</TextBlock>
<LineBreak/>
@@ -486,7 +424,7 @@
<TextBlock FontSize="16">You can drag &amp; drop both the metadata and binary together</TextBlock>
</TextBlock>
</Button>
<Button Grid.Row="1" Name="btnSelectPackageFile" Style="{StaticResource LightBoxButton}" Margin="100,50,100,100" Click="BtnSelectPackageFile_OnClick">
<Button Grid.Row="1" Name="btnSelectPackageFile" Style="{StaticResource LightBoxButton}" Margin="100,75,100,50" Click="BtnSelectPackageFile_OnClick">
<TextBlock TextAlignment="Center">
<TextBlock FontSize="22">Option 2</TextBlock>
<LineBreak/>
@@ -495,11 +433,14 @@
<TextBlock FontSize="16">Encrypted IPA files are not supported</TextBlock>
</TextBlock>
</Button>
<!-- Load options -->
<Button Grid.Row="2" Name="btnLoadOptions" Style="{StaticResource LightBoxButton}" Click="BtnLoadOptions_Click" Margin="0,0,10,10" Padding="5" HorizontalAlignment="Right" VerticalAlignment="Bottom" FontSize="18" Width="180" Content="Import options..."/>
</Grid>
<Button Name="btnSelectBinaryFile" Style="{StaticResource LightBoxButton}" Margin="100" Click="BtnSelectBinaryFile_OnClick" Visibility="Hidden">Select or drag &amp; drop an IL2CPP binary file</Button>
<!-- Back button -->
<Button Name="btnBack" Margin="7" HorizontalAlignment="Left" VerticalAlignment="Bottom" FontSize="18" Width="120" Click="BtnBack_OnClick" Content="&lt;&lt; Back">
<Button Name="btnBack" Margin="7" Padding="2" HorizontalAlignment="Left" VerticalAlignment="Bottom" FontSize="18" Width="120" Click="BtnBack_OnClick" Content="&lt;&lt; Back">
<Button.Style>
<Style BasedOn="{StaticResource LightBoxButton}" TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Hidden"></Setter>

View File

@@ -71,6 +71,15 @@ namespace Il2CppInspectorGUI
Process.Start(new ProcessStartInfo {FileName = e.Uri.ToString(), UseShellExecute = true});
}
/// <summary>
/// Open Load Options dialog
/// </summary>
private void BtnLoadOptions_Click(object sender, RoutedEventArgs e) {
var loadOptionsDlg = new LoadOptionsDialog();
loadOptionsDlg.Owner = this;
loadOptionsDlg.ShowDialog();
}
/// <summary>
/// Select global metadata file
/// </summary>
@@ -114,19 +123,19 @@ namespace Il2CppInspectorGUI
};
if (openFileDialog.ShowDialog() == true) {
await LoadBinaryAsync(openFileDialog.FileName, null); // TODO: loadOptions
await LoadBinaryAsync(openFileDialog.FileName);
}
}
// Load the binary file
private async Task LoadBinaryAsync(string filename, LoadOptions loadOptions) {
private async Task LoadBinaryAsync(string filename) {
var app = (App) Application.Current;
areaBusyIndicator.Visibility = Visibility.Visible;
btnSelectBinaryFile.Visibility = Visibility.Hidden;
// Load the binary file
if (await app.LoadBinaryAsync(filename, loadOptions)) {
if (await app.LoadBinaryAsync(filename)) {
// Binary loaded successfully
areaBusyIndicator.Visibility = Visibility.Hidden;
@@ -151,20 +160,20 @@ namespace Il2CppInspectorGUI
};
if (openFileDialog.ShowDialog() == true) {
await LoadPackageAsync(openFileDialog.FileNames, null); // TODO: loadOptions
await LoadPackageAsync(openFileDialog.FileNames);
}
}
// Load the package file
private async Task LoadPackageAsync(string filename, LoadOptions loadOptions) => await LoadPackageAsync(new[] { filename }, loadOptions);
private async Task LoadPackageAsync(IEnumerable<string> filenames, LoadOptions loadOptions) {
private async Task LoadPackageAsync(string filename) => await LoadPackageAsync(new[] { filename });
private async Task LoadPackageAsync(IEnumerable<string> filenames) {
var app = (App) Application.Current;
areaBusyIndicator.Visibility = Visibility.Visible;
grdFirstPage.Visibility = Visibility.Hidden;
// Load the package
if (await app.LoadPackageAsync(filenames, loadOptions)) {
if (await app.LoadPackageAsync(filenames)) {
// Package loaded successfully
areaBusyIndicator.Visibility = Visibility.Hidden;
@@ -185,6 +194,7 @@ namespace Il2CppInspectorGUI
lstImages.ItemsSource = null;
btnSelectBinaryFile.Visibility = Visibility.Hidden;
grdFirstPage.Visibility = Visibility.Visible;
((App) Application.Current).ResetLoadOptions();
}
/// <summary>
@@ -594,7 +604,7 @@ namespace Il2CppInspectorGUI
break;
case var s when s.EndsWith(".apk") || s.EndsWith(".aab") || s.EndsWith(".ipa") || s.EndsWith(".xapk") || s.EndsWith(".zip"):
await LoadPackageAsync(s, null); // TODO: loadOptions
await LoadPackageAsync(s);
break;
}
}
@@ -607,17 +617,17 @@ namespace Il2CppInspectorGUI
// Only load binary if metadata was successful
if (btnSelectBinaryFile.Visibility == Visibility.Visible)
await LoadBinaryAsync(files[binaryIndex], null); // TODO: loadOptions
await LoadBinaryAsync(files[binaryIndex]);
}
// Split APK (files.Length >= 2)
else {
await LoadPackageAsync(files, null); // TODO: loadOptions
await LoadPackageAsync(files);
}
}
// Binary (on 2nd page)
else if (btnSelectBinaryFile.Visibility == Visibility.Visible)
if (files.Length == 1)
await LoadBinaryAsync(files[0], null); // TODO: loadOptions
await LoadBinaryAsync(files[0]);
}
}