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:
Luke
2025-08-15 21:13:32 +02:00
committed by GitHub
parent e161e0f226
commit 3439ca912b
184 changed files with 13425 additions and 964 deletions

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<!-- todo: enable this once the app is aot compliant! -->
<PublishAot>false</PublishAot>
<OutputType Condition="'$(Configuration)' == 'Release'">WinExe</OutputType>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
<!-- todo: this needs to be adjusted for multiplatform support -->
<Target Name="BuildTauriFrontend" BeforeTargets="BeforeBuild" Condition="'$(Configuration)' == 'Release'">
<Exec Command="pnpm tauri build --no-bundle" WorkingDirectory="..\Il2CppInspector.Redux.GUI.UI" />
<ItemGroup>
<EmbeddedResource Include="..\Il2CppInspector.Redux.GUI.UI\src-tauri\target\release\il2cppinspectorredux.exe" />
</ItemGroup>
</Target>
<ItemGroup>
<ProjectReference Include="..\Il2CppInspector.Redux.FrontendCore\Il2CppInspector.Redux.FrontendCore.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,38 @@
using Il2CppInspector.Redux.FrontendCore;
using Il2CppInspector.Redux.GUI;
using Microsoft.AspNetCore.SignalR;
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(0, FrontendCoreJsonSerializerContext.Default);
});
builder.Services.Configure<JsonHubProtocolOptions>(options =>
{
options.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, FrontendCoreJsonSerializerContext.Default);
});
builder.Services.AddFrontendCore();
builder.Services.AddSingleton<UiProcessService>();
builder.Services.AddHostedService(p => p.GetRequiredService<UiProcessService>());
var app = builder.Build();
app.UseCors();
app.MapFrontendCore();
await app.StartAsync();
var serverUrl = app.Urls.First();
var port = new Uri(serverUrl).Port;
#if DEBUG
Console.WriteLine($"Listening on port {port}");
#else
app.Services.GetRequiredService<UiProcessService>().LaunchUiProcess(port);
#endif
await app.WaitForShutdownAsync();

View File

@@ -0,0 +1,13 @@
{
"profiles": {
"http": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5000"
}
},
"$schema": "https://json.schemastore.org/launchsettings.json"
}

View File

@@ -0,0 +1,62 @@
using System.Diagnostics;
namespace Il2CppInspector.Redux.GUI;
public class UiProcessService(IHostApplicationLifetime lifetime) : BackgroundService
{
// TODO: This needs to be adjusted for multiplatform support
private const string UiExecutableName = "il2cppinspectorredux.exe";
private Process? _uiProcess;
private string? _uiExectuablePath;
public void LaunchUiProcess(int port)
{
_uiExectuablePath ??= ExtractUiExecutable();
_uiProcess = Process.Start(new ProcessStartInfo(_uiExectuablePath, [port.ToString()]));
}
private static string ExtractUiExecutable()
{
try
{
using var executable =
typeof(UiProcessService).Assembly.GetManifestResourceStream(
$"{typeof(UiProcessService).Namespace!}.{UiExecutableName}");
if (executable == null)
throw new FileNotFoundException("Failed to open resource as stream.");
var tempDir = Directory.CreateTempSubdirectory("il2cppinspectorredux-ui");
var uiExePath = Path.Join(tempDir.FullName, UiExecutableName);
using var fs = File.Create(uiExePath);
executable.CopyTo(fs);
return uiExePath;
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to find embedded UI executable: {ex}");
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (_uiProcess == null)
await Task.Delay(TimeSpan.FromMilliseconds(10), stoppingToken);
await _uiProcess.WaitForExitAsync(stoppingToken);
lifetime.StopApplication();
}
public override Task StopAsync(CancellationToken cancellationToken)
{
if (_uiProcess is { HasExited: false })
_uiProcess.Kill();
if (_uiExectuablePath != null)
File.Delete(_uiExectuablePath);
return base.StopAsync(cancellationToken);
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}