Implement new GUI and CLI, fix misc. smaller issues (#22)
* Initial commit of new UI c# component * Initial commit of new UI frontend component * target WinExe to hide console window in release mode, move ui exe into resources * force single file publishing and add initial gh workflow for publishing ui * fix workflow errors * update dependencies and remove cxxdemangler, as it was outdated * fix c# single file output due to invalid output path * smaller tweaks, hack around loops in cpp type layouting * process other queued exports even if one fails and show error message * add basic support for processing LC_DYLD_CHAINED_FIXUPS * ELF loading should not use the file offset for loading the dynamic section * fix symbol table loading in some modified elfs * add "start export" button on format selection screen, clear all toasts after selecting an export format * embed ui executable directly into c# assembly * only build tauri component in c# release builds * add il2cpp file (binary, metadata) export to advanced tab * fix and enable binary ninja fake string segment support * add support for metadata * unify logic for getting element type index * fix new ui not allowing script exports other than ida * new ui: clear out loaded binary if no IL2CPP images could be loaded * fix toAddr calls in ghidra script target * remove dependency on a section being named .text in loaded pe files * tweak symbol reading a bit and remove sht relocation reading * add initial support for required forward references in il2cpp types, also fix issues with type names clashing with il2cpp api types * reduce clang errors for header file, fix better array size struct, emit required forward definitions in header * expose forward definitions in AppModel, fix issue with method-only used types not being emitted * remove debug log line * fix spelling mistakes in gui outputs * fix il2cpp_array_size_t not being an actual type for later method definitions * change the default port for new ui dev to 5000 * show current version and hash in new ui footer * seperate redux ui impl into FrontendCore project * make inspector version a server api, split up output subtypes and tweak some option names * add redux CLI based on redux GUI output formats * replace all Console.WriteLine calls in core inspector with AnsiConsole calls * add workflow for new cli and add back old gui workflow * disable aot publish and enable single file for redux cli
This commit is contained in:
38
Il2CppInspector.Redux.CLI/Commands/BaseCommand.cs
Normal file
38
Il2CppInspector.Redux.CLI/Commands/BaseCommand.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Il2CppInspector.Redux.FrontendCore;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Il2CppInspector.Redux.CLI.Commands;
|
||||
|
||||
internal abstract class BaseCommand<T>(PortProvider portProvider) : AsyncCommand<T> where T : CommandSettings
|
||||
{
|
||||
private const string HubPath = "/il2cpp"; // TODO: Make this into a shared constant
|
||||
|
||||
private readonly int _serverPort = portProvider.Port;
|
||||
|
||||
protected abstract Task<int> ExecuteAsync(CliClient client, T settings);
|
||||
|
||||
public override async Task<int> ExecuteAsync(CommandContext context, T settings)
|
||||
{
|
||||
var connection = new HubConnectionBuilder().WithUrl($"http://localhost:{_serverPort}{HubPath}")
|
||||
.AddJsonProtocol(options =>
|
||||
{
|
||||
options.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0,
|
||||
FrontendCoreJsonSerializerContext.Default);
|
||||
})
|
||||
.Build();
|
||||
|
||||
await connection.StartAsync();
|
||||
|
||||
int result;
|
||||
using (var client = new CliClient(connection))
|
||||
{
|
||||
await client.OnUiLaunched();
|
||||
result = await ExecuteAsync(client, settings);
|
||||
}
|
||||
|
||||
await connection.StopAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
17
Il2CppInspector.Redux.CLI/Commands/InteractiveCommand.cs
Normal file
17
Il2CppInspector.Redux.CLI/Commands/InteractiveCommand.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Il2CppInspector.Redux.CLI.Commands;
|
||||
|
||||
internal class InteractiveCommand(PortProvider portProvider) : BaseCommand<InteractiveCommand.Options>(portProvider)
|
||||
{
|
||||
public class Options : CommandSettings;
|
||||
|
||||
protected override async Task<int> ExecuteAsync(CliClient client, Options settings)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
await AnsiConsole.AskAsync<string>("meow?");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
21
Il2CppInspector.Redux.CLI/Commands/ManualCommand.cs
Normal file
21
Il2CppInspector.Redux.CLI/Commands/ManualCommand.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Il2CppInspector.Redux.CLI.Commands;
|
||||
|
||||
internal abstract class ManualCommand<T>(PortProvider portProvider) : BaseCommand<T>(portProvider) where T : ManualCommandOptions
|
||||
{
|
||||
public override ValidationResult Validate(CommandContext context, T settings)
|
||||
{
|
||||
foreach (var inputPath in settings.InputPaths)
|
||||
{
|
||||
if (!Path.Exists(inputPath))
|
||||
return ValidationResult.Error($"Provided input path {inputPath} does not exit.");
|
||||
}
|
||||
|
||||
if (File.Exists(settings.OutputPath))
|
||||
return ValidationResult.Error("Provided output path already exists as a file.");
|
||||
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
}
|
||||
15
Il2CppInspector.Redux.CLI/Commands/ManualCommandOptions.cs
Normal file
15
Il2CppInspector.Redux.CLI/Commands/ManualCommandOptions.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Il2CppInspector.Redux.CLI.Commands;
|
||||
|
||||
internal class ManualCommandOptions : CommandSettings
|
||||
{
|
||||
[CommandArgument(0, "<InputPath>")]
|
||||
[Description("Paths to the input files. Will be subsequently loaded until binary and metadata were found.")]
|
||||
public string[] InputPaths { get; init; } = [];
|
||||
|
||||
[CommandOption("-o|--output")]
|
||||
[Description("Path to the output folder")]
|
||||
public string OutputPath { get; init; } = "";
|
||||
}
|
||||
172
Il2CppInspector.Redux.CLI/Commands/ProcessCommand.cs
Normal file
172
Il2CppInspector.Redux.CLI/Commands/ProcessCommand.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
using Il2CppInspector.Cpp;
|
||||
using Il2CppInspector.Redux.FrontendCore.Outputs;
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Il2CppInspector.Redux.CLI.Commands;
|
||||
|
||||
internal class ProcessCommand(PortProvider portProvider) : ManualCommand<ProcessCommand.Option>(portProvider)
|
||||
{
|
||||
// NOTE: There might be a better option than replicating all available flags here (and in the TS UI).
|
||||
// Investigate this in the future.
|
||||
|
||||
public class Option : ManualCommandOptions
|
||||
{
|
||||
// C++ Scaffolding
|
||||
[CommandOption("--output-cpp-scaffolding")]
|
||||
public bool CppScaffolding { get; init; } = false;
|
||||
|
||||
[CommandOption("--unity-version")]
|
||||
public string? UnityVersion { get; init; }
|
||||
|
||||
[CommandOption("--compiler-type")]
|
||||
public CppCompilerType CompilerType { get; init; } = CppCompilerType.GCC;
|
||||
|
||||
// C# stub
|
||||
[CommandOption("-s|--output-csharp-stub")]
|
||||
public bool CSharpStubs { get; init; } = false;
|
||||
|
||||
[CommandOption("--layout")]
|
||||
public CSharpLayout Layout { get; init; } = CSharpLayout.SingleFile;
|
||||
|
||||
[CommandOption("--flatten-hierarchy")]
|
||||
public bool FlattenHierarchy { get; init; } = false;
|
||||
|
||||
[CommandOption("--sorting-mode")]
|
||||
public TypeSortingMode SortingMode { get; init; } = TypeSortingMode.Alphabetical;
|
||||
|
||||
[CommandOption("--suppress-metadata")]
|
||||
public bool SuppressMetadata { get; init; } = false;
|
||||
|
||||
[CommandOption("--compilable")]
|
||||
public bool MustCompile { get; init; } = false;
|
||||
|
||||
[CommandOption("--separate-assembly-attributes")]
|
||||
public bool SeparateAssemblyAttributes { get; init; } = true;
|
||||
|
||||
// Disassembler metadata
|
||||
[CommandOption("-m|--output-disassembler-metadata")]
|
||||
public bool DisassemblerMetadata { get; init; } = false;
|
||||
|
||||
[CommandOption("--disassembler")]
|
||||
public DisassemblerType Disassembler { get; init; } = DisassemblerType.IDA;
|
||||
|
||||
// Dummy DLL output
|
||||
[CommandOption("-d|--output-dummy-dlls")]
|
||||
public bool DummyDlls { get; init; } = false;
|
||||
|
||||
// Visual Studio solution
|
||||
[CommandOption("--output-vs-solution")]
|
||||
public bool VsSolution { get; init; } = false;
|
||||
|
||||
[CommandOption("--unity-path")]
|
||||
public string? UnityPath { get; init; }
|
||||
|
||||
[CommandOption("--unity-assemblies-path")]
|
||||
public string? UnityAssembliesPath { get; init; }
|
||||
|
||||
[CommandOption("--extract-il2cpp-files")]
|
||||
public string? ExtractIl2CppFilesPath { get; init; }
|
||||
}
|
||||
|
||||
protected override async Task<int> ExecuteAsync(CliClient client, Option settings)
|
||||
{
|
||||
var inspectorVersion = await client.GetInspectorVersion();
|
||||
AnsiConsole.MarkupLineInterpolated($"Using inspector [gray]{inspectorVersion}[/]");
|
||||
|
||||
await client.SubmitInputFiles(settings.InputPaths.ToList());
|
||||
await client.WaitForLoadingToFinishAsync();
|
||||
if (!client.ImportCompleted)
|
||||
{
|
||||
AnsiConsole.MarkupLine("[bold][red]FAILED[/] to load IL2CPP data from the given inputs.[/]");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (settings.ExtractIl2CppFilesPath != null)
|
||||
{
|
||||
await client.ExportIl2CppFiles(settings.ExtractIl2CppFilesPath);
|
||||
await client.WaitForLoadingToFinishAsync();
|
||||
}
|
||||
|
||||
var unityVersions = await client.GetPotentialUnityVersions();
|
||||
|
||||
if (settings.CppScaffolding)
|
||||
{
|
||||
var directory = Path.Join(settings.OutputPath, "cpp");
|
||||
await client.QueueExport(CppScaffoldingOutput.Id, directory, new Dictionary<string, string>
|
||||
{
|
||||
["unityversion"] = settings.UnityVersion ?? unityVersions.First(),
|
||||
["compilertype"] = settings.CompilerType.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.CSharpStubs)
|
||||
{
|
||||
var directory = Path.Join(settings.OutputPath, "cs");
|
||||
await client.QueueExport(CSharpStubOutput.Id, directory, new Dictionary<string, string>
|
||||
{
|
||||
["layout"] = settings.Layout.ToString(),
|
||||
["flattenhierarchy"] = settings.FlattenHierarchy.ToString(),
|
||||
["sortingmode"] = settings.SortingMode.ToString(),
|
||||
["suppressmetadata"] = settings.SuppressMetadata.ToString(),
|
||||
["mustcompile"] = settings.MustCompile.ToString(),
|
||||
["separateassemblyattributes"] = settings.SeparateAssemblyAttributes.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.DisassemblerMetadata)
|
||||
{
|
||||
await client.QueueExport(DisassemblerMetadataOutput.Id, settings.OutputPath,
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
["disassembler"] = settings.Disassembler.ToString(),
|
||||
["unityversion"] = settings.UnityVersion ?? unityVersions.First()
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.DummyDlls)
|
||||
{
|
||||
var directory = Path.Join(settings.OutputPath, "dll");
|
||||
await client.QueueExport(DummyDllOutput.Id, directory, new Dictionary<string, string>
|
||||
{
|
||||
["suppressmetadata"] = settings.SuppressMetadata.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.VsSolution)
|
||||
{
|
||||
var directory = Path.Join(settings.OutputPath, "vs");
|
||||
await client.QueueExport(VsSolutionOutput.Id, directory, new Dictionary<string, string>
|
||||
{
|
||||
["unitypath"] = settings.UnityPath ?? "",
|
||||
["unityassembliespath"] = settings.UnityAssembliesPath ?? ""
|
||||
});
|
||||
}
|
||||
|
||||
await client.StartExport();
|
||||
await client.WaitForLoadingToFinishAsync();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override ValidationResult Validate(CommandContext context, Option settings)
|
||||
{
|
||||
if (settings.UnityPath != null && !Path.Exists(settings.UnityPath))
|
||||
return ValidationResult.Error($"Provided Unity path {settings.UnityPath} does not exist.");
|
||||
|
||||
if (settings.UnityAssembliesPath != null && !Path.Exists(settings.UnityAssembliesPath))
|
||||
return ValidationResult.Error($"Provided Unity assemblies path {settings.UnityAssembliesPath} does not exist.");
|
||||
|
||||
if (settings.ExtractIl2CppFilesPath != null && File.Exists(settings.ExtractIl2CppFilesPath))
|
||||
return ValidationResult.Error(
|
||||
$"Provided extracted IL2CPP files path {settings.ExtractIl2CppFilesPath} already exists as a file.");
|
||||
|
||||
if (settings is
|
||||
{
|
||||
CppScaffolding: false, CSharpStubs: false, DisassemblerMetadata: false, DummyDlls: false,
|
||||
VsSolution: false
|
||||
})
|
||||
return ValidationResult.Error("At least one output format must be specified.");
|
||||
|
||||
return base.Validate(context, settings);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user