Skip to content

Commit

Permalink
Add --analyze-all option, update README for recent changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Byass committed Oct 11, 2021
1 parent b778940 commit 66c2151
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 43 deletions.
4 changes: 3 additions & 1 deletion Cpp2IL.Core/Cpp2IlApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,9 @@ void ProcessType(TypeDefinition type)
if (analysisLevel != AnalysisLevel.PSUEDOCODE_ONLY)
{
var total = AsmAnalyzerX86.SUCCESSFUL_METHODS + AsmAnalyzerX86.FAILED_METHODS;
var successPercent = AsmAnalyzerX86.SUCCESSFUL_METHODS * 100 / total;
var successPercent = 100;
if (total != 0)
successPercent = AsmAnalyzerX86.SUCCESSFUL_METHODS * 100 / total;

Logger.InfoNewline($"Overall analysis success rate: {successPercent}% ({AsmAnalyzerX86.SUCCESSFUL_METHODS}) of {total} methods.");
}
Expand Down
5 changes: 4 additions & 1 deletion Cpp2IL/CommandLineArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class CommandLineArgs
[Option("verbose", Required = false, HelpText = "Enable Verbose Logging.")]
public bool Verbose { get; set; }

[Option("experimental-enable-il-to-assembly-please")]
[Option("experimental-enable-il-to-assembly-please", HelpText = "Attempt to emit IL to the assembly saved to the output directory.")]
public bool EnableIlToAsm { get; set; }

[Option("suppress-attributes", HelpText = "Suppress generation of Cpp2ILInjected attributes.")]
Expand All @@ -55,6 +55,9 @@ public class CommandLineArgs

[Option("throw-safety-out-the-window", HelpText = "Throw safety out the window, and try and push all the IL we can to the DLL, *even if it might break things*. Only has an effect if IL-to-file is enabled.")]
public bool ThrowSafetyOutTheWindow { get; set; }

[Option("analyze-all", HelpText = "Analyze every single assembly in the application. Probably very slow, might break.")]
public bool AnalyzeAllAssemblies { get; set; }

internal bool AreForceOptionsValid
{
Expand Down
1 change: 1 addition & 0 deletions Cpp2IL/Cpp2IlRuntimeArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public struct Cpp2IlRuntimeArgs
public string PathToMetadata;

public string AssemblyToRunAnalysisFor;
public bool AnalyzeAllAssemblies;

//Feature flags
public bool EnableAnalysis;
Expand Down
27 changes: 21 additions & 6 deletions Cpp2IL/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ private static Cpp2IlRuntimeArgs GetRuntimeOptionsFromCommandLine(string[] comma
result.SuppressAttributes = options.SuppressAttributes;
result.Parallel = options.Parallel;
result.AssemblyToRunAnalysisFor = options.RunAnalysisForAssembly;
result.AnalyzeAllAssemblies = options.AnalyzeAllAssemblies;
result.IlToAsmContinueThroughErrors = options.ThrowSafetyOutTheWindow;

if (result.EnableIlToAsm)
Expand Down Expand Up @@ -265,7 +266,19 @@ public static int MainWithArgs(Cpp2IlRuntimeArgs runtimeArgs)
Cpp2IlApi.SaveAssemblies(runtimeArgs.OutputRootDirectory);

if (runtimeArgs.EnableAnalysis)
DoAssemblyCSharpAnalysis(runtimeArgs.AssemblyToRunAnalysisFor, runtimeArgs.AnalysisLevel, runtimeArgs.OutputRootDirectory, keyFunctionAddresses!, runtimeArgs.EnableIlToAsm, runtimeArgs.Parallel, runtimeArgs.IlToAsmContinueThroughErrors);
{
if (runtimeArgs.AnalyzeAllAssemblies)
{
foreach (var assemblyDefinition in Cpp2IlApi.GeneratedAssemblies)
{
DoAnalysisForAssembly(assemblyDefinition.Name.Name, runtimeArgs.AnalysisLevel, runtimeArgs.OutputRootDirectory, keyFunctionAddresses!, runtimeArgs.EnableIlToAsm, runtimeArgs.Parallel, runtimeArgs.IlToAsmContinueThroughErrors);
}
}
else
{
DoAnalysisForAssembly(runtimeArgs.AssemblyToRunAnalysisFor, runtimeArgs.AnalysisLevel, runtimeArgs.OutputRootDirectory, keyFunctionAddresses!, runtimeArgs.EnableIlToAsm, runtimeArgs.Parallel, runtimeArgs.IlToAsmContinueThroughErrors);
}
}

foreach (var p in _pathsToDeleteOnExit)
{
Expand All @@ -284,17 +297,19 @@ public static int MainWithArgs(Cpp2IlRuntimeArgs runtimeArgs)
return 0;
}

private static void DoAssemblyCSharpAnalysis(string assemblyName, AnalysisLevel analysisLevel, string rootDir, BaseKeyFunctionAddresses keyFunctionAddresses, bool doIlToAsm, bool parallel, bool continueThroughErrors)
private static void DoAnalysisForAssembly(string assemblyName, AnalysisLevel analysisLevel, string rootDir, BaseKeyFunctionAddresses keyFunctionAddresses, bool doIlToAsm, bool parallel, bool continueThroughErrors)
{
var assemblyCsharp = Cpp2IlApi.GetAssemblyByName(assemblyName);
var targetAssembly = Cpp2IlApi.GetAssemblyByName(assemblyName);

if (assemblyCsharp == null)
if (targetAssembly == null)
return;

Logger.InfoNewline($"Running Analysis for {assemblyName}.dll...");

Cpp2IlApi.AnalyseAssembly(analysisLevel, assemblyCsharp, keyFunctionAddresses, Path.Combine(rootDir, "types"), parallel, continueThroughErrors);
Cpp2IlApi.AnalyseAssembly(analysisLevel, targetAssembly, keyFunctionAddresses, Path.Combine(rootDir, "types"), parallel, continueThroughErrors);

if (doIlToAsm)
Cpp2IlApi.SaveAssemblies(rootDir, new List<AssemblyDefinition> { assemblyCsharp });
Cpp2IlApi.SaveAssemblies(rootDir, new List<AssemblyDefinition> { targetAssembly });
}
}
}
89 changes: 54 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@

WIP Tool to reverse Unity's IL2CPP build process back to the original managed DLLs.

The information below almost entirely applies to the CLI application available on github releases. For documentation on
using the "core" module - which the CLI is just a wrapper around - in your own projects, see [README_CORE.md](Cpp2IL.Core/README_CORE.md)
The information below almost entirely applies to the CLI application available on github releases. For documentation on
using the "core" module - which the CLI is just a wrapper around - in your own projects,
see [README_CORE.md](Cpp2IL.Core/README_CORE.md)

Uses [LibCpp2IL](LibCpp2IL) for the initial parsing and loading of metadata structures.
LibCpp2IL is obtainable from the build artifacts if you want to do something yourself with IL2CPP metadata,
and is released under the MIT license.
The link above will take you to the documentation for LibCpp2IL.
Uses [LibCpp2IL](LibCpp2IL) for the initial parsing and loading of metadata structures. LibCpp2IL is obtainable from the
build artifacts if you want to do something yourself with IL2CPP metadata, and is released under the MIT license. The
link above will take you to the documentation for LibCpp2IL.

## Command Line Options

### Basic Usage

The simplest usage of this application is for a windows x86 or x64 unity game. In that case you can just run `Cpp2IL-Win.exe --game-path=C:\Path\To\Your\Game`
and Cpp2IL will detect your unity version, locate the files it needs, and dump the output into a cpp2il_out folder wherever you ran the command from.
The simplest usage of this application is for a windows x86 or x64 unity game. In that case you can just
run `Cpp2IL-Win.exe --game-path=C:\Path\To\Your\Game`
and Cpp2IL will detect your unity version, locate the files it needs, and dump the output into a cpp2il_out folder
wherever you ran the command from.

Assuming you have a single APK file (not an APKM or XAPK), and are running at least cpp2il 2021.4.0 (or the pre-release for it), you
can use the same argument as above but pass in the path to the APK, and cpp2il will extract the files it needs from the APK.
Assuming you have a single APK file (not an APKM or XAPK), and are running at least cpp2il 2021.4.0, you can use the
same argument as above but pass in the path to the APK, and cpp2il will extract the files it needs from the APK.

### Supported Command Line Option Listing

Expand All @@ -41,35 +43,41 @@ can use the same argument as above but pass in the path to the APK, and cpp2il w
| --run-analysis-for-assembly | mscorlib | Run analysis for the specified assembly. Do not specify the `.dll` extension. |
| --output-root | cpp2il_out | Root directory to output to. Dummy DLLs will be put directly in here, and analysis results will be put in a types folder inside. |
| --throw-safety-out-the-window | &lt;None> | When paired with `--experimental-enable-il-to-assembly-please`, do not abort attempting to generate IL for a method if an error occurs. Instead, continue on with the next action, skipping only the one which errored. WILL PROBABLY BREAK THINGS. |
| --analyze-all (only available in pre-release builds) | &lt;None> | Analyze all assemblies in the application |

## Release Structure

Every single commit is built to a pre-release using Github Actions - the action file can be found in the .github folder,
if you want to reproduce the builds yourself. Be aware these may not be the most stable - while there are tests to ensure
compatibility with a range of games, sometimes things do break! These are versioned by the commit they were built from.
if you want to reproduce the builds yourself. Be aware these may not be the most stable - while there are tests to
ensure compatibility with a range of games, sometimes things do break! These are versioned by the commit they were built
from.

On top of this, I manually release "milestone" builds whenever I think a major set of improvements have been made. These
are NOT marked as pre-releases on github, and should (at least in theory) be stable and suitable for use on a range of games.
are NOT marked as pre-releases on github, and should (at least in theory) be stable and suitable for use on a range of
games.

## Terminal Colors and Debug Logging

From the first milestone build 2021.0, and onwards, Cpp2IL now outputs more rigidly-structured data to the console.
This includes log levels (VERB, INFO, WARN, FAIL) and associated colours (Grey for VERB, Blue for INFO, Yellow for
WARN, Red for FAIL).
From the first milestone build 2021.0, and onwards, Cpp2IL now outputs more rigidly-structured data to the console. This
includes log levels (VERB, INFO, WARN, FAIL) and associated colours (Grey for VERB, Blue for INFO, Yellow for WARN, Red
for FAIL).

As of milestone 2021.1, if Cpp2IL is able to detect that you're running in Wine/Proton, these ANSI colour codes are disabled,
as they are not supported by wine and look awful.
As of milestone 2021.1, if Cpp2IL is able to detect that you're running in Wine/Proton, these ANSI colour codes are
disabled, as they are not supported by wine and look awful.

VERB messages will only be logged if Cpp2IL is launched with the `--verbose` option, and it would be helpful if you
VERB messages will only be logged if Cpp2IL is launched with the `--verbose` option, and it would be helpful if you
could report issues with this flag enabled. For normal operation, they shouldn't be needed, unless you're curious.

If you do not wish for the output to be coloured, set the Environment Variable `NO_COLOR=true`.

## What Works (Features)

- [x] Loading of Metadata and Binaries using LibCpp2IL for IL2CPP versions 24 through 27.1 (unity 2018 to present-day)
- [x] "Dummy DLL" (Stub Assembly) generation, suitable for use with [Il2CppAssemblyUnhollower](https://github.com/knah/Il2CppAssemblyUnhollower/), for PE and ELF binaries, x86 and ARM instruction sets
- [x] Restoration of explicit override methods in managed types. This data is not explicitly saved to the Il2Cpp metadata, but is useful for Unhollower.
- [x] Loading of Metadata and Binaries using LibCpp2IL for IL2CPP versions 24 through 27.1 (unity 2018 to present-day)
- [x] "Dummy DLL" (Stub Assembly) generation, suitable for use
with [Il2CppAssemblyUnhollower](https://github.com/knah/Il2CppAssemblyUnhollower/), for PE and ELF binaries, x86 and
ARM instruction sets
- [x] Restoration of explicit override methods in managed types. This data is not explicitly saved to the Il2Cpp
metadata, but is useful for Unhollower.
- [x] Il2CPP Api Function Detection
- [x] Analysis of both x86_32 and x86_64 machine code for the following features:
- [x] Managed Function Calls (including virtual calls via vtable)
Expand All @@ -93,20 +101,29 @@ If you do not wish for the output to be coloured, set the Environment Variable `
- [x] Return statements, including returned variables
- [x] FPU (Floating-Point processor) support for x86_32 games.
- [x] RGCTX (Runtime Generic Context) Support
- [x] IL Generation to a text file (not saved to the DLL yet)
- [x] Analysis for ARMv8/ARM64 machine code for the following features (note a more limited set than above):
- [x] Managed function calls (but not virtual calls)
- [x] Managed function argument resolution
- [x] Object instantiation
- [x] String constant loads
- [x] Instance field assignments
- [x] Instance field reads
- [x] IL2CPP Exception Helper function detection, as above
- [x] Some If/While/Else detection
- [x] Able to save generated IL to the actual function body in the Assembly, allowing decompilation using dnSpy/ILSpy.
- [x] Significantly faster than both Il2CppDumper and Il2CppInspector (for DummyDLL Generation)


## What's work in progress (Roadmap)

(Subject to change)

- [ ] Save generated IL to the actual function body in the Assembly.
- [ ] Look into adding support for remaining Actions to improve analysis. Some key areas I'm focussing on:
- [ ] Ongoing: Wider support for actions to improve analysis accuracy. Some key points:
- [ ] Wider support for multiplication (IMUL instructions) as well as mathematical operations in general.
- [ ] Floating-point-related instructions.
- [ ] Machine code analysis for ARM instructions (long-term goal, want to do a lot more for x86 instruction set first)

- [ ] Feature parity for Arm64 with X86. Most importantly: static fields, full range of conditions, managed array
support, virtual functions, mathematical operations
- [ ] Armv7 analysis. A template is present, but nothing specific runs.
- [ ] Reworking this document to show a matrix of supported features per instruction set.

## Credits

Expand All @@ -120,15 +137,17 @@ It uses the following libraries, for which I am very thankful:
- [Mono.Cecil](https://github.com/jbevain/cecil/) to create and save the Dummy DLLs, and generate IL.
- [xUnit](https://github.com/xunit/xunit) for the unit tests.

It's (very loosely, at this point) based off of [Il2CppDumper](https://github.com/Perfare/Il2CppDumper), which I
forked in 2018 and removed a lot of code, rewrote a lot, and added a lot more. But at its core, it's still got some dumper
left in it.
It's (very loosely, at this point) based off of [Il2CppDumper](https://github.com/Perfare/Il2CppDumper), which I forked
in 2018 and removed a lot of code, rewrote a lot, and added a lot more. But at its core, it's still got some dumper left
in it.

It contains bits and pieces from [Il2CppInspector](https://github.com/djkaty/Il2CppInspector/), taken with permission
from djKaty, and I'd like to express my gratitude to her here for her invaluable help.

I'd like to thank the Audica Modding community and Discord for the initial inspiration for this project, lots of
support in the early days, and feature requests these days.
I'd like to thank the Audica Modding community and Discord for the initial inspiration for this project, lots of support
in the early days, and feature requests these days.

And finally, check out some other cool projects which link in with this one. Of course, I mentioned [Il2CppAssemblyUnhollower](https://github.com/knah/Il2CppAssemblyUnhollower/)
further up, but also check out [MelonLoader](https://github.com/LavaGang/MelonLoader/), which uses Cpp2IL for Dummy DLL generation.
And finally, check out some other cool projects which link in with this one. Of course, I
mentioned [Il2CppAssemblyUnhollower](https://github.com/knah/Il2CppAssemblyUnhollower/)
further up, but also check out [MelonLoader](https://github.com/LavaGang/MelonLoader/), which uses Cpp2IL for Dummy DLL
generation.

0 comments on commit 66c2151

Please sign in to comment.