Skip to content

Commit

Permalink
Enable attribute restoration for arm64
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Byass committed Oct 24, 2021
1 parent 0514bcc commit 80bc423
Show file tree
Hide file tree
Showing 17 changed files with 269 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using Cpp2IL.Core.Analysis.Actions.Base;
using Cpp2IL.Core.Analysis.ResultModels;
using Gee.External.Capstone.Arm64;
using LibCpp2IL;
using Mono.Cecil;

namespace Cpp2IL.Core.Analysis.Actions.ARM64
{
public class Arm64LoadAttributeFromAttributeListAction : AbstractAttributeLoadFromListAction<Arm64Instruction>
{
public Arm64LoadAttributeFromAttributeListAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction, List<TypeDefinition> attributes) : base(context, instruction)
{
var ptrSize = LibCpp2IlMain.Binary!.is32Bit ? 4 : 8;
OffsetInList = instruction.MemoryOffset() / ptrSize;

if(OffsetInList < 0 || OffsetInList >= attributes.Count)
return;

_attributeType = attributes[(int) OffsetInList];

var destReg = Utils.GetRegisterNameNew(instruction.Details.Operands[0].Register.Id);
LocalMade = context.MakeLocal(_attributeType, reg: destReg);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ public class Arm64MetadataUsageFieldToRegisterAction : BaseAction<Arm64Instructi
public Arm64MetadataUsageFieldToRegisterAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
if(context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.MemoryBase()!.Id)) is not {Value: long pageAddress})
return;
if (instruction.Details.Operands[1].Type == Arm64OperandType.Register && context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.Details.Operands[1].Register.Id)) is { Value: long pageAddr2 })
pageAddress = pageAddr2;
else
return;

_pointer = (ulong) (pageAddress + instruction.MemoryOffset());
_pointer = (ulong) (pageAddress + (instruction.MemoryOperand() != null ? instruction.MemoryOffset() : instruction.Details.Operands[2].Immediate));
_metadataUsage = LibCpp2IlMain.GetAnyGlobalByAddress(_pointer);

if (_metadataUsage == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ public class Arm64MetadataUsageLiteralToRegisterAction : BaseAction<Arm64Instruc
public Arm64MetadataUsageLiteralToRegisterAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
if(context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.MemoryBase()!.Id)) is not {Value: long pageAddress})
return;
if (instruction.Details.Operands[1].Type == Arm64OperandType.Register && context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.Details.Operands[1].Register.Id)) is { Value: long pageAddr2 })
pageAddress = pageAddr2;
else
return;

_pointer = (ulong) (pageAddress + instruction.MemoryOffset());
_pointer = (ulong) (pageAddress + (instruction.MemoryOperand() != null ? instruction.MemoryOffset() : instruction.Details.Operands[2].Immediate));
_metadataUsage = LibCpp2IlMain.GetAnyGlobalByAddress(_pointer);

if (_metadataUsage == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ public class Arm64MetadataUsageMethodDefToRegisterAction : BaseAction<Arm64Instr
public Arm64MetadataUsageMethodDefToRegisterAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
if(context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.MemoryBase()!.Id)) is not {Value: long pageAddress})
return;
if (instruction.Details.Operands[1].Type == Arm64OperandType.Register && context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.Details.Operands[1].Register.Id)) is { Value: long pageAddr2 })
pageAddress = pageAddr2;
else
return;

_pointer = (ulong) (pageAddress + instruction.MemoryOffset());
_pointer = (ulong) (pageAddress + (instruction.MemoryOperand() != null ? instruction.MemoryOffset() : instruction.Details.Operands[2].Immediate));
_metadataUsage = LibCpp2IlMain.GetAnyGlobalByAddress(_pointer);

if (_metadataUsage == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ public class Arm64MetadataUsageMethodRefToRegisterAction : BaseAction<Arm64Instr
public Arm64MetadataUsageMethodRefToRegisterAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
if (context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.MemoryBase()!.Id)) is not { Value: long pageAddress })
return;
if (instruction.Details.Operands[1].Type == Arm64OperandType.Register && context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.Details.Operands[1].Register.Id)) is { Value: long pageAddr2 })
pageAddress = pageAddr2;
else
return;

_pointer = (ulong)(pageAddress + instruction.MemoryOffset());
_pointer = (ulong) (pageAddress + (instruction.MemoryOperand() != null ? instruction.MemoryOffset() : instruction.Details.Operands[2].Immediate));
_metadataUsage = LibCpp2IlMain.GetAnyGlobalByAddress(_pointer);

if (_metadataUsage == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ public class Arm64MetadataUsageTypeToRegisterAction : BaseAction<Arm64Instructio

public Arm64MetadataUsageTypeToRegisterAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
if(context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.MemoryBase()!.Id)) is not {Value: long pageAddress})
return;

_pointer = (ulong) (pageAddress + instruction.MemoryOffset());
if (context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.MemoryBase()!.Id)) is not { Value: long pageAddress })
if (instruction.Details.Operands[1].Type == Arm64OperandType.Register && context.GetConstantInReg(Utils.GetRegisterNameNew(instruction.Details.Operands[1].Register.Id)) is { Value: long pageAddr2 })
pageAddress = pageAddr2;
else
return;

_pointer = (ulong) (pageAddress + (instruction.MemoryOperand() != null ? instruction.MemoryOffset() : instruction.Details.Operands[2].Immediate));
_metadataUsage = LibCpp2IlMain.GetAnyGlobalByAddress(_pointer);

if (_metadataUsage == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Cpp2IL.Core.Analysis.Actions.Base;
using Cpp2IL.Core.Analysis.ResultModels;
using Gee.External.Capstone.Arm64;
using LibCpp2IL;
using Mono.Cecil.Cil;

namespace Cpp2IL.Core.Analysis.Actions.ARM64
{
public class Arm64UnmanagedToManagedStringAction : BaseAction<Arm64Instruction>
{
private string? _stringValue;
private LocalDefinition? _localMade;

public Arm64UnmanagedToManagedStringAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
var stringConstant = context.GetConstantInReg("x0");

if (LibCpp2IlMain.Binary!.is32Bit && stringConstant != null)
context.Stack.Pop();

_stringValue = (stringConstant?.Value as Il2CppString)?.ContainedString;

if(_stringValue == null)
return;

_localMade = context.MakeLocal(Utils.StringReference, reg: "x0", knownInitialValue: _stringValue);
}

public override Mono.Cecil.Cil.Instruction[] ToILInstructions(MethodAnalysis<Arm64Instruction> context, ILProcessor processor)
{
throw new System.NotImplementedException();
}

public override string? ToPsuedoCode()
{
return $"System.String {_localMade?.GetPseudocodeRepresentation()} = \"{_stringValue}\"";
}

public override string ToTextSummary()
{
if (_localMade == null)
return "[!!] Calls il2cpp_string_new with unknown string literal!";

return $"[!] Creates a new System.String with the value \"{_stringValue}\" and stores it in new local {_localMade?.Name}";
}

public override bool IsImportant()
{
return true;
}
}
}
73 changes: 71 additions & 2 deletions Cpp2IL.Core/Analysis/AsmAnalyzerArmV8A.InstructionChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ private void CheckForSingleOpInstruction(Arm64Instruction instruction)
{
Analysis.Actions.Add(new Arm64NewObjectAction(Analysis, instruction));
}
else if (jumpTarget == _keyFunctionAddresses.il2cpp_string_new || jumpTarget == _keyFunctionAddresses.il2cpp_vm_string_new || jumpTarget == _keyFunctionAddresses.il2cpp_string_new_wrapper
|| jumpTarget == _keyFunctionAddresses.il2cpp_codegen_string_new_wrapper || jumpTarget == _keyFunctionAddresses.il2cpp_vm_string_newWrapper)
{
//Creates a mono string from a string global
Analysis.Actions.Add(new Arm64UnmanagedToManagedStringAction(Analysis, instruction));
}
else if (LibCpp2IlMain.Binary!.ConcreteGenericImplementationsByAddress.ContainsKey(jumpTarget))
{
//Call concrete generic function
Expand Down Expand Up @@ -163,6 +169,10 @@ private void CheckForTwoOpInstruction(Arm64Instruction instruction)
case "cmp":
Analysis.Actions.Add(new Arm64ComparisonAction(Analysis, instruction));
break;
case "ldr" when t1 == Arm64OperandType.Memory && t0 == Arm64OperandType.Register && memVar is LocalDefinition potentialDummyAttributeList && potentialDummyAttributeList.Type?.Resolve() == AttributeRestorer.DummyTypeDefForAttributeList:
//Load attribute from attribute list.
Analysis.Actions.Add(new Arm64LoadAttributeFromAttributeListAction(Analysis, instruction, AttributesForRestoration));
break;
case "ldr" when t0 is Arm64OperandType.Register && t1 is Arm64OperandType.Memory && memVar is LocalDefinition && memoryOffset != 0:
//Field read - non-zero memory offset on local to register.
Analysis.Actions.Add(new Arm64FieldReadToRegAction(Analysis, instruction));
Expand All @@ -173,8 +183,7 @@ private void CheckForTwoOpInstruction(Arm64Instruction instruction)
//MUST Check for non-cpp type
if (Analysis.GetLocalInReg(Utils.GetRegisterNameNew(memoryBase)) != null)
{
Analysis.Actions.Add(new Arm64ClassPointerLoadAction(Analysis, instruction)); //We have a managed local type, we can load the class pointer for it
Logger.InfoNewline(instruction.GetInstructionAddress().ToString());
Analysis.Actions.Add(new Arm64ClassPointerLoadAction(Analysis, instruction)); //We have a managed local type, we can load the class pointer for it
}
return;
}
Expand Down Expand Up @@ -323,6 +332,66 @@ private void CheckForThreeOpInstruction(Arm64Instruction instruction)
//ORR dest, xzr, #n
//dest = n, basically. Technically 0 | n, but that's the same.
Analysis.Actions.Add(new Arm64OrZeroAndImmAction(Analysis, instruction));
break;
case "add" when t0 is Arm64OperandType.Register && t1 is Arm64OperandType.Register && t2 == Arm64OperandType.Immediate && var0 is ConstantDefinition { Value: long pageAddress } && imm2 < 0x4000:
//Combined with adrp to load a global. The adrp loads the page, and this adds an additional offset to resolve a specific memory value.
var globalAddress = (ulong)(pageAddress + imm2);
MetadataUsage global = null;
if (LibCpp2IlMain.GetAnyGlobalByAddress(globalAddress) is { IsValid: true } global2)
global = global2;
else
{
//Try pointer to global
try
{
var possiblePtr = LibCpp2IlMain.Binary!.ReadClassAtVirtualAddress<ulong>(globalAddress);
if (LibCpp2IlMain.GetAnyGlobalByAddress(possiblePtr) is { IsValid: true } global3)
global = global3;
}
catch (Exception)
{
//Nothing
}
}

if (global != null)
{
//Have a global here.
switch (global.Type)
{
case MetadataUsageType.Type:
case MetadataUsageType.TypeInfo:
Analysis.Actions.Add(new Arm64MetadataUsageTypeToRegisterAction(Analysis, instruction));
break;
case MetadataUsageType.MethodDef:
Analysis.Actions.Add(new Arm64MetadataUsageMethodDefToRegisterAction(Analysis, instruction));
break;
case MetadataUsageType.MethodRef:
Analysis.Actions.Add(new Arm64MetadataUsageMethodRefToRegisterAction(Analysis, instruction));
break;
case MetadataUsageType.FieldInfo:
Analysis.Actions.Add(new Arm64MetadataUsageFieldToRegisterAction(Analysis, instruction));
break;
case MetadataUsageType.StringLiteral:
Analysis.Actions.Add(new Arm64MetadataUsageLiteralToRegisterAction(Analysis, instruction));
break;
}

return;
}

//Unknown global or string
var potentialLiteral = Utils.TryGetLiteralAt(LibCpp2IlMain.Binary!, (ulong)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(globalAddress));
if (potentialLiteral != null && instruction.Details.Operands[0].RegisterSafe()?.Name[0] != 'v')
{
Analysis.Actions.Add(new Arm64UnmanagedLiteralToConstantAction(Analysis, instruction, potentialLiteral, globalAddress));
}
else
{
//Unknown global
Analysis.Actions.Add(new Arm64UnknownGlobalToConstantAction(Analysis, instruction, globalAddress));
}

break;
}
}
Expand Down
3 changes: 1 addition & 2 deletions Cpp2IL.Core/Analysis/AsmAnalyzerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Cpp2IL.Core.Analysis
{
public abstract class AsmAnalyzerBase<T> : IAsmAnalyzer
{
public IList<T> Instructions { get; }
public IList<T> Instructions => _instructions;
protected MethodDefinition? MethodDefinition;
protected ulong MethodEnd;
protected Il2CppBinary CppAssembly;
Expand Down Expand Up @@ -50,7 +50,6 @@ internal AsmAnalyzerBase(ulong methodPointer, IEnumerable<T> instructions, BaseK

internal AsmAnalyzerBase(MethodDefinition definition, ulong methodPointer, IList<T> instructions, BaseKeyFunctionAddresses baseKeyFunctionAddresses) : this(methodPointer, instructions, baseKeyFunctionAddresses)
{
Instructions = instructions;
MethodDefinition = definition;
MethodDefinition.Body = new(MethodDefinition);
IsGenuineMethod = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public override void PostProcess(MethodAnalysis<T> analysis, MethodBody body)
for (int i = 0; i < instructions.Count; i++)
{
Instruction instruction = instructions[i];
Logger.InfoNewline(instruction.OpCode.Code.ToString());
Logger.InfoNewline(instruction.Operand.ToString());
// Logger.InfoNewline(instruction.OpCode.Code.ToString());
// Logger.InfoNewline(instruction.Operand.ToString());
}
}
for (int i = 0; i < instructions.Count-1; i++)
Expand All @@ -30,8 +30,9 @@ public override void PostProcess(MethodAnalysis<T> analysis, MethodBody body)
Instruction nextInstruction = instructions[i+1];
if (instruction.OpCode.Code == Code.Ldc_I4 && nextInstruction.OpCode.Code == Code.Ret)
{
Logger.InfoNewline(analysis.DeclaringType.FullName);
Logger.InfoNewline(instruction.Operand.GetType().FullName);
//TODO: FM wanted to do something here
// Logger.InfoNewline(analysis.DeclaringType.FullName);
// Logger.InfoNewline(instruction.Operand.GetType().FullName);
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions Cpp2IL.Core/Analysis/ResultModels/MethodAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ internal MethodAnalysis(MethodDefinition method, ulong methodStart, ulong initia
if (LibCpp2IlMain.Binary!.InstructionSet == InstructionSet.ARM64)
{
HandleArm64Parameters();
return; //TODO handle stack params
}
else if (LibCpp2IlMain.Binary.InstructionSet != InstructionSet.X86_32)
{
Expand Down Expand Up @@ -236,6 +237,23 @@ internal void AddParameter(ParameterDefinition arg)
{
//TODO Make this work for arm. Realistically we should be ok to just insert starting from x0, because this is only used for attribute restoration and those all return void (right? check it)
//TODO and, hell, realistically, this is only called once when we're analyzing arm, on a method with no params anyway, so it can just go in x0.

if (LibCpp2IlMain.Binary!.InstructionSet == InstructionSet.ARM64)
{
//Let's be lazy because I really can't be arsed right now. - 2021-10-24
if (GetOperandInRegister("x0") is { })
throw new("X0 is already taken when calling AddParameter. Can't be lazy this time, Samboy");

if (arg.ParameterType.ShouldBeInFloatingPointRegister())
throw new("AddParameter: Type should be in a floating point. Still can't be lazy, Samboy.");

var name = arg.Name;
if (string.IsNullOrWhiteSpace(name))
name = arg.Name = $"cpp2il__autoParamName__idx_{_numParamsAdded}";

FunctionArgumentLocals.Add(MakeLocal(arg.ParameterType, name, "x0").WithParameter(arg));
return;
}

if (_parameterDestRegList.Count > 0)
{
Expand Down
Loading

0 comments on commit 80bc423

Please sign in to comment.