Skip to content

Decompiler #481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
packages/

\.idea/
.vscode/

bin/
obj/
Expand Down
48 changes: 28 additions & 20 deletions Cpp2IL.Core.Tests/Graphing/BasicGraph.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Cpp2IL.Core.Graphs;
using Cpp2IL.Core.ISIL;

Expand All @@ -10,29 +11,36 @@ public class BasicGraph
[SetUp]
public void Setup()
{
var isilBuilder = new IsilBuilder();
var instructions = new List<Instruction>();
void Add(int index, OpCode opCode, params object[] operands) => instructions.Add(new Instruction(index, opCode, operands));

isilBuilder.ShiftStack(0x0000, -40);
isilBuilder.Compare(0x0001, InstructionSetIndependentOperand.MakeRegister("test1"), InstructionSetIndependentOperand.MakeRegister("test2"));
isilBuilder.JumpIfNotEqual(0x0002, 0x0006);
isilBuilder.Move(0x0003, InstructionSetIndependentOperand.MakeRegister("test3"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Call(0x0004, 0xDEADBEEF);
isilBuilder.Move(0x0005, InstructionSetIndependentOperand.MakeRegister("test4"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Move(0x0006, InstructionSetIndependentOperand.MakeRegister("test5"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Compare(0x0007, InstructionSetIndependentOperand.MakeRegister("test1"), InstructionSetIndependentOperand.MakeRegister("test2"));
isilBuilder.JumpIfEqual(0x0008, 0x000C);
isilBuilder.Compare(0x0009, InstructionSetIndependentOperand.MakeRegister("test1"), InstructionSetIndependentOperand.MakeRegister("test2"));
isilBuilder.JumpIfNotEqual(0x000A, 0x000C);
isilBuilder.Call(0x000B, 0xDEADBEEF);
isilBuilder.Move(0x000C, InstructionSetIndependentOperand.MakeRegister("test4"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Move(0x000D, InstructionSetIndependentOperand.MakeRegister("test5"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.ShiftStack(0x000E, 40);
isilBuilder.Call(0x000F, 0xDEADBEEF);
Add(00, OpCode.ShiftStack, -40);
Add(01, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "test1"), new Register(null, "test2"));
Add(02, OpCode.Not, new Register(null, "zf"), new Register(null, "zf"));
Add(03, OpCode.ConditionalJump, 7, new Register(null, "zf"));
Add(04, OpCode.Move, new Register(null, "test3"), 0);
Add(05, OpCode.Call, 0xDEADBEEF);
Add(06, OpCode.Move, new Register(null, "test4"), 0);
Add(07, OpCode.Move, new Register(null, "test5"), 0);
Add(08, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "test1"), new Register(null, "test2"));
Add(09, OpCode.ConditionalJump, 14, new Register(null, "zf"));
Add(10, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "test1"), new Register(null, "test2"));
Add(11, OpCode.Not, new Register(null, "zf"), new Register(null, "zf"));
Add(12, OpCode.ConditionalJump, 14, new Register(null, "zf"));
Add(13, OpCode.Call, 0xDEADBEEF);
Add(14, OpCode.Move, new Register(null, "test4"), 0);
Add(15, OpCode.Move, new Register(null, "test5"), 0);
Add(16, OpCode.ShiftStack, 40);
Add(17, OpCode.Call, 0xDEADBEEF);

isilBuilder.FixJumps();
foreach (var instruction in instructions)
{
if (instruction.OpCode != OpCode.Jump && instruction.OpCode != OpCode.ConditionalJump)
continue;
instruction.Operands[0] = instructions[(int)instruction.Operands[0]];
}

graph = new();
graph.Build(isilBuilder.BackingStatementList);
graph = new ISILControlFlowGraph(instructions);
}

[Test]
Expand Down
123 changes: 67 additions & 56 deletions Cpp2IL.Core.Tests/Graphing/ExceptionThrowingGraph.cs
Original file line number Diff line number Diff line change
@@ -1,78 +1,89 @@
using System.Collections.Generic;
using Cpp2IL.Core.Graphs;
using Cpp2IL.Core.ISIL;

namespace Cpp2IL.Core.Tests.Graphing;

public class ExceptionThrowingGraph
{
ISILControlFlowGraph graph;

[SetUp]
public void Setup()
{
var isilBuilder = new IsilBuilder();
var instructions = new List<Instruction>();
void Add(int index, OpCode opCode, params object[] operands) => instructions.Add(new Instruction(index, opCode, operands));

isilBuilder.Push(001, InstructionSetIndependentOperand.MakeRegister("sp"), InstructionSetIndependentOperand.MakeRegister("reg1"));
isilBuilder.ShiftStack(002, -80);
isilBuilder.Compare(003, InstructionSetIndependentOperand.MakeRegister("reg2"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Move(004, InstructionSetIndependentOperand.MakeRegister("reg3"), InstructionSetIndependentOperand.MakeRegister("reg4"));
isilBuilder.JumpIfNotEqual(005, 9);
isilBuilder.Move(006, InstructionSetIndependentOperand.MakeRegister("reg5"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Call(007, 0xDEADBEEF);
isilBuilder.Move(008, InstructionSetIndependentOperand.MakeRegister("reg6"), InstructionSetIndependentOperand.MakeImmediate(1));
isilBuilder.Compare(009, InstructionSetIndependentOperand.MakeRegister("reg7"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.JumpIfEqual(010, 35);
isilBuilder.Move(011, InstructionSetIndependentOperand.MakeRegister("reg8"), InstructionSetIndependentOperand.MakeImmediate(1));
isilBuilder.Move(012, InstructionSetIndependentOperand.MakeRegister("reg9"), InstructionSetIndependentOperand.MakeImmediate(2));
isilBuilder.Move(013, InstructionSetIndependentOperand.MakeRegister("reg10"), InstructionSetIndependentOperand.MakeImmediate(3));
isilBuilder.Move(014, InstructionSetIndependentOperand.MakeStack(0x40), InstructionSetIndependentOperand.MakeRegister("reg11"));
isilBuilder.Move(015, InstructionSetIndependentOperand.MakeRegister("reg12"), InstructionSetIndependentOperand.MakeImmediate("input"));
isilBuilder.Move(016, InstructionSetIndependentOperand.MakeStack(0x30), InstructionSetIndependentOperand.MakeRegister("reg13"));
isilBuilder.Compare(017, InstructionSetIndependentOperand.MakeRegister("reg14"), InstructionSetIndependentOperand.MakeImmediate(2));
isilBuilder.Move(018, InstructionSetIndependentOperand.MakeStack(0x20), InstructionSetIndependentOperand.MakeRegister("reg15"));
isilBuilder.Move(019, InstructionSetIndependentOperand.MakeStack(0x40), InstructionSetIndependentOperand.MakeImmediate(1));
isilBuilder.Move(020, InstructionSetIndependentOperand.MakeStack(0x38), InstructionSetIndependentOperand.MakeRegister("reg16"));
isilBuilder.JumpIfEqual(021, 25);
isilBuilder.Compare(022, InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(InstructionSetIndependentOperand.MakeRegister("reg17"), 224)), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.JumpIfNotEqual(023, 25);
isilBuilder.Call(024, 0xDEADBEEF);
isilBuilder.Move(025, InstructionSetIndependentOperand.MakeRegister("reg18"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.LoadAddress(026, InstructionSetIndependentOperand.MakeRegister("reg19"), InstructionSetIndependentOperand.MakeStack(0x20));
isilBuilder.Move(027, InstructionSetIndependentOperand.MakeRegister("reg20"), InstructionSetIndependentOperand.MakeRegister("reg21"));
isilBuilder.Call(028, 0xDEADBEEF);
isilBuilder.Compare(029, InstructionSetIndependentOperand.MakeRegister("reg22"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.JumpIfEqual(030, 46);
isilBuilder.Move(031, InstructionSetIndependentOperand.MakeRegister("reg23"), InstructionSetIndependentOperand.MakeStack(0x20));
isilBuilder.ShiftStack(032, 80);
isilBuilder.Pop(033, InstructionSetIndependentOperand.MakeRegister("sp"), InstructionSetIndependentOperand.MakeRegister("reg24"));
isilBuilder.Return(034, InstructionSetIndependentOperand.MakeRegister("reg25"));
isilBuilder.Move(035, InstructionSetIndependentOperand.MakeRegister("reg26"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Call(036, 0xDEADBEEF);
isilBuilder.Move(037, InstructionSetIndependentOperand.MakeRegister("reg27"), InstructionSetIndependentOperand.MakeImmediate("input"));
isilBuilder.Move(038, InstructionSetIndependentOperand.MakeRegister("reg28"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Move(039, InstructionSetIndependentOperand.MakeRegister("reg29"), InstructionSetIndependentOperand.MakeRegister("reg30"));
isilBuilder.Move(040, InstructionSetIndependentOperand.MakeRegister("reg31"), InstructionSetIndependentOperand.MakeRegister("reg32"));
isilBuilder.Call(041, 0xDEADBEEF);
isilBuilder.Move(042, InstructionSetIndependentOperand.MakeRegister("reg33"), InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(0xDEADBEEF)));
isilBuilder.Move(043, InstructionSetIndependentOperand.MakeRegister("reg34"), InstructionSetIndependentOperand.MakeRegister("reg35"));
isilBuilder.Call(044, 0xDEADBEEF);
isilBuilder.Interrupt(045);
isilBuilder.Move(046, InstructionSetIndependentOperand.MakeRegister("reg36"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.LoadAddress(047, InstructionSetIndependentOperand.MakeRegister("reg37"), InstructionSetIndependentOperand.MakeStack(0x20));
isilBuilder.Call(048, 0xDEADBEEF);
isilBuilder.Move(049, InstructionSetIndependentOperand.MakeRegister("reg38"), InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(0x1809C39E0)));
isilBuilder.Move(050, InstructionSetIndependentOperand.MakeRegister("reg39"), InstructionSetIndependentOperand.MakeRegister("reg40"));
isilBuilder.Call(051, 0xDEADBEEF);
Add(001, OpCode.ShiftStack, -8);
Add(002, OpCode.Move, new StackOffset(0), new Register(null, "reg1"));
Add(003, OpCode.ShiftStack, -80);
Add(004, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "reg2"), 0);
Add(005, OpCode.Move, new Register(null, "reg3"), new Register(null, "reg4"));
Add(006, OpCode.Not, new Register(null, "zf"), new Register(null, "zf"));
Add(007, OpCode.ConditionalJump, 11, new Register(null, "zf"));
Add(008, OpCode.Move, new Register(null, "reg5"), 0);
Add(009, OpCode.Call, 0xDEADBEEF);
Add(010, OpCode.Move, new Register(null, "reg6"), 1);
Add(011, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "reg7"), 0);
Add(012, OpCode.ConditionalJump, 38, new Register(null, "zf"));
Add(013, OpCode.Move, new Register(null, "reg8"), 1);
Add(014, OpCode.Move, new Register(null, "reg9"), 2);
Add(015, OpCode.Move, new Register(null, "reg10"), 3);
Add(016, OpCode.Move, new StackOffset(0x40), new Register(null, "reg11"));
Add(017, OpCode.Move, new Register(null, "reg12"), "input");
Add(018, OpCode.Move, new StackOffset(0x30), new Register(null, "reg13"));
Add(019, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "reg14"), 2);
Add(020, OpCode.Move, new StackOffset(0x20), new Register(null, "reg15"));
Add(021, OpCode.Move, new StackOffset(0x40), 1);
Add(022, OpCode.Move, new StackOffset(0x38), new Register(null, "reg16"));
Add(023, OpCode.ConditionalJump, 28, new Register(null, "zf"));
Add(024, OpCode.CheckEqual, new Register(null, "zf"), new MemoryOperand(new Register(null, "reg17"), addend: 224), 0);
Add(025, OpCode.Not, new Register(null, "zf"), new Register(null, "zf"));
Add(026, OpCode.ConditionalJump, 28, new Register(null, "zf"));
Add(027, OpCode.Call, 0xDEADBEEF);
Add(028, OpCode.Move, new Register(null, "reg18"), 0);
Add(029, OpCode.Move, new Register(null, "reg19"), new StackOffset(0x20));
Add(030, OpCode.Move, new Register(null, "reg20"), new Register(null, "reg21"));
Add(031, OpCode.Call, 0xDEADBEEF);
Add(032, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "reg22"), 0);
Add(033, OpCode.ConditionalJump, 50, new Register(null, "zf"));
Add(034, OpCode.Move, new Register(null, "reg23"), new StackOffset(0x20));
Add(035, OpCode.ShiftStack, 80);
Add(036, OpCode.Move, new Register(null, "reg24"), new StackOffset(0));
Add(037, OpCode.ShiftStack, 8);
Add(038, OpCode.Return, new Register(null, "reg25"));
Add(039, OpCode.Move, new Register(null, "reg26"), 0);
Add(040, OpCode.Call, 0xDEADBEEF);
Add(041, OpCode.Move, new Register(null, "reg27"), "input");
Add(042, OpCode.Move, new Register(null, "reg28"), 0);
Add(043, OpCode.Move, new Register(null, "reg29"), new Register(null, "reg30"));
Add(044, OpCode.Move, new Register(null, "reg31"), new Register(null, "reg32"));
Add(045, OpCode.Call, 0xDEADBEEF);
Add(046, OpCode.Move, new Register(null, "reg33"), new MemoryOperand(addend: 0xDEADBEEF));
Add(047, OpCode.Move, new Register(null, "reg34"), new Register(null, "reg35"));
Add(048, OpCode.Call, 0xDEADBEEF);
Add(049, OpCode.Interrupt);
Add(050, OpCode.Move, new Register(null, "reg36"), 0);
Add(051, OpCode.Move, new Register(null, "reg37"), new StackOffset(0x20));
Add(052, OpCode.Call, 0xDEADBEEF);
Add(053, OpCode.Move, new Register(null, "reg38"), new MemoryOperand(addend: 0x1809C39E0));
Add(054, OpCode.Move, new Register(null, "reg39"), new Register(null, "reg40"));
Add(055, OpCode.Call, 0xDEADBEEF);

isilBuilder.FixJumps();
foreach (var instruction in instructions)
{
if (instruction.OpCode != OpCode.Jump && instruction.OpCode != OpCode.ConditionalJump)
continue;
instruction.Operands[0] = instructions[(int)instruction.Operands[0]];
}

graph = new();
graph.Build(isilBuilder.BackingStatementList);
graph = new ISILControlFlowGraph(instructions);
}

[Test]
public void VerifyNumberOfBlocks()
{
Assert.That(graph.Blocks.Count == 18);
Assert.That(graph.Blocks.Count == 19);
}

[Test]
Expand Down
42 changes: 42 additions & 0 deletions Cpp2IL.Core/Actions/ApplyMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Cpp2IL.Core.ISIL;
using Cpp2IL.Core.Model.Contexts;
using Cpp2IL.Core.Utils;
using LibCpp2IL;

namespace Cpp2IL.Core.Actions;

public class ApplyMetadata : IAction
{
public void Apply(MethodAnalysisContext method)
{
foreach (var instruction in method.ControlFlowGraph!.Instructions)
{
if (instruction.OpCode != OpCode.Move)
continue;

if ((instruction.Operands[0] is not LocalVariable) || (instruction.Operands[1] is not MemoryOperand memory))
continue;

if (memory.Base == null && memory.Index == null && memory.Scale == 0)
{
var stringLiteral = LibCpp2IlMain.GetLiteralByAddress((ulong)memory.Addend);

if (stringLiteral == null)
{
// Try instead check if its type metadata usage
var metadataUsage = LibCpp2IlMain.GetTypeGlobalByAddress((ulong)memory.Addend);
if (metadataUsage != null && method.DeclaringType is not null)
{
var typeAnalysisContext = metadataUsage.ToContext(method.DeclaringType!.DeclaringAssembly);
if (typeAnalysisContext != null)
instruction.Operands[1] = typeAnalysisContext;
}

continue;
}

instruction.Operands[1] = stringLiteral;
}
}
}
}
Loading
Loading