From babbd935a1d33422ca1fc2a7cffbad5bdf7ab88e Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 11 Sep 2020 14:43:35 +0100 Subject: [PATCH] Migrate new analysis engine over to use ICED --- Cpp2IL/Analysis/ASMAnalyzer.cs | 215 ++++++++++++------ .../Analysis/Actions/AllocateArrayAction.cs | 2 +- .../Actions/AllocateInstanceAction.cs | 4 +- .../Actions/ArrayOffsetToLocalAction.cs | 2 +- Cpp2IL/Analysis/Actions/BaseAction.cs | 2 +- Cpp2IL/Analysis/Actions/BoxValueAction.cs | 2 +- Cpp2IL/Analysis/Actions/CallBailOutAction.cs | 2 +- .../Analysis/Actions/CallInitClassAction.cs | 2 +- .../Analysis/Actions/CallInitMethodAction.cs | 2 +- .../Actions/CallManagedFunctionAction.cs | 8 +- .../Actions/CallManagedFunctionInRegAction.cs | 45 ++++ .../Actions/CallNativeMethodFailureAction.cs | 2 +- .../Actions/CallVirtualMethodAction.cs | 12 +- .../Actions/ClassPointerLoadAction.cs | 8 +- Cpp2IL/Analysis/Actions/ClearRegAction.cs | 5 +- Cpp2IL/Analysis/Actions/ComparisonAction.cs | 8 +- .../Analysis/Actions/ConditionalJumpAction.cs | 2 +- .../Analysis/Actions/ConstantToFieldAction.cs | 2 +- .../Analysis/Actions/ConstantToRegAction.cs | 2 +- .../Analysis/Actions/ConstantToStackAction.cs | 2 +- Cpp2IL/Analysis/Actions/FieldToLocalAction.cs | 2 +- .../GlobalMethodRefToConstantAction.cs | 6 +- .../GlobalStringRefToConstantAction.cs | 6 +- .../Actions/GlobalTypeRefToConstantAction.cs | 13 +- .../Actions/InterfaceOffsetsReadAction.cs | 41 ++++ .../Actions/JumpIfNonZeroOrNonNullAction.cs | 6 +- .../Actions/JumpIfZeroOrNullAction.cs | 6 +- .../Actions/LoadInterfaceMethodDataAction.cs | 51 +++++ .../LoadVirtualFunctionPointerAction.cs | 17 +- Cpp2IL/Analysis/Actions/LocalToFieldAction.cs | 2 +- .../LocateSpecificInterfaceOffsetAction.cs | 43 ++++ .../Actions/LookupNativeFunctionAction.cs | 2 +- Cpp2IL/Analysis/Actions/RegToRegMoveAction.cs | 6 +- .../Actions/ReturnFromFunctionAction.cs | 2 +- Cpp2IL/Analysis/Actions/SafeCastAction.cs | 2 +- .../Analysis/Actions/StackToRegCopyAction.cs | 2 +- Cpp2IL/Analysis/Actions/ThrowAction.cs | 2 +- .../Analysis/ResultModels/MethodAnalysis.cs | 13 ++ Cpp2IL/Cpp2IL.csproj | 1 + Cpp2IL/KeyFunctionAddresses.cs | 8 +- Cpp2IL/Utils.cs | 18 +- LibCpp2IL/Extensions.cs | 2 +- LibCpp2IL/PlusSearch.cs | 2 +- 43 files changed, 434 insertions(+), 148 deletions(-) create mode 100644 Cpp2IL/Analysis/Actions/CallManagedFunctionInRegAction.cs create mode 100644 Cpp2IL/Analysis/Actions/InterfaceOffsetsReadAction.cs create mode 100644 Cpp2IL/Analysis/Actions/LoadInterfaceMethodDataAction.cs create mode 100644 Cpp2IL/Analysis/Actions/LocateSpecificInterfaceOffsetAction.cs diff --git a/Cpp2IL/Analysis/ASMAnalyzer.cs b/Cpp2IL/Analysis/ASMAnalyzer.cs index 2aff8d43..8cceee30 100644 --- a/Cpp2IL/Analysis/ASMAnalyzer.cs +++ b/Cpp2IL/Analysis/ASMAnalyzer.cs @@ -1,28 +1,36 @@ +//Feature flags + +// #define DEBUG_PRINT_OPERAND_DATA + // #define USE_NEW_ANALYSIS_METHOD using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Text; -using System.Text.RegularExpressions; -using Cpp2IL.Analysis.Actions; + using Cpp2IL.Analysis.ResultModels; using LibCpp2IL; using LibCpp2IL.PE; using Mono.Cecil; -using SharpDisasm; using SharpDisasm.Udis86; +#if !USE_NEW_ANALYSIS_METHOD +using SharpDisasm; +using System.Globalization; +using System.Text.RegularExpressions; +using Instruction = SharpDisasm.Instruction; +#else +using LibCpp2IL.Metadata; +using Cpp2IL.Analysis.Actions; +using Iced.Intel; +#endif + namespace Cpp2IL.Analysis { internal partial class AsmDumper { - //Feature flags - - // #define DEBUG_PRINT_OPERAND_DATA - private static readonly TypeDefinition TypeReference = Utils.TryLookupTypeDefKnownNotGeneric("System.Type"); private static readonly TypeDefinition StringReference = Utils.TryLookupTypeDefKnownNotGeneric("System.String"); private static readonly TypeDefinition BooleanReference = Utils.TryLookupTypeDefKnownNotGeneric("System.Boolean"); @@ -40,7 +48,11 @@ internal partial class AsmDumper private ulong _methodEnd; private readonly KeyFunctionAddresses _keyFunctionAddresses; private readonly PE _cppAssembly; +#if !USE_NEW_ANALYSIS_METHOD private List _instructions; +#else + private InstructionList _instructions; +#endif private MethodAnalysis _analysis; @@ -71,6 +83,7 @@ internal partial class AsmDumper private TypeDefinition? interfaceOffsetTargetInterface; +#if !USE_NEW_ANALYSIS_METHOD private readonly ud_mnemonic_code[] _inlineArithmeticOpcodes = { ud_mnemonic_code.UD_Imul, //Multiply @@ -97,6 +110,7 @@ internal partial class AsmDumper ud_mnemonic_code.UD_Ilea, //Load effective address ud_mnemonic_code.UD_Imovups }; +#endif internal AsmDumper(MethodDefinition methodDefinition, CppMethodData method, ulong methodStart, KeyFunctionAddresses keyFunctionAddresses, PE cppAssembly) { @@ -107,9 +121,14 @@ internal AsmDumper(MethodDefinition methodDefinition, CppMethodData method, ulon _cppAssembly = cppAssembly; //Pass 0: Disassemble +#if USE_NEW_ANALYSIS_METHOD + _instructions = LibCpp2ILUtils.DisassembleBytesNew(LibCpp2IlMain.ThePe.is32Bit, method.MethodBytes, methodStart); +#else _instructions = Utils.DisassembleBytes(LibCpp2IlMain.ThePe.is32Bit, method.MethodBytes); +#endif } +#if !USE_NEW_ANALYSIS_METHOD private void TaintMethod(TaintReason reason) { if (_taintReason != TaintReason.UNTAINTED) return; @@ -119,7 +138,7 @@ private void TaintMethod(TaintReason reason) _psuedoCode.Append($"{Utils.Repeat("\t", _blockDepth)}//!!!METHOD TAINTED HERE: {reason} (COMPLEXITY {(int) reason})!!!\n"); _methodFunctionality.Append($"{Utils.Repeat("\t", _blockDepth + 2)}!!! METHOD TAINTED HERE: {reason} (COMPLEXITY {(int) reason}) !!!\n"); } - + private List TrimOutIl2CppCrap(List instructions) { var ret = new List(); @@ -200,6 +219,7 @@ private List TrimOutIl2CppCrap(List instructions) return ret; } +#endif internal TaintReason AnalyzeMethod(StringBuilder typeDump, ref List allUsedMnemonics) { @@ -215,9 +235,12 @@ internal TaintReason AnalyzeMethod(StringBuilder typeDump, ref List SharedState.MethodsByAddress.ContainsKey(i.PC + _methodStart)); if (lastInstructionInThisMethod > 0) @@ -235,11 +258,16 @@ internal TaintReason AnalyzeMethod(StringBuilder typeDump, ref List $"\t\t\t0x{s:X}"))).Append("\n"); - _methodFunctionality.Append(string.Join("\n", _analysis.Actions.Select(a => "\t\t" + a.ToTextSummary()))); + _methodFunctionality.Append(string.Join("\n", _analysis.Actions.Select(a => "\t\t" + a.ToTextSummary()))); #endif Console.WriteLine("Processed " + _methodDefinition.FullName); @@ -408,45 +443,53 @@ private void PopBlock() _blockDepth--; } - private void CheckForZeroOpInstruction(Instruction instruction) + #if USE_NEW_ANALYSIS_METHOD + private void CheckForZeroOpInstruction(Iced.Intel.Instruction instruction) { switch (instruction.Mnemonic) { - case ud_mnemonic_code.UD_Iret: + case Mnemonic.Ret: _analysis.Actions.Add(new ReturnFromFunctionAction(_analysis, instruction)); break; } } - private void CheckForSingleOpInstruction(Instruction instruction) + private void CheckForSingleOpInstruction(Iced.Intel.Instruction instruction) { - var reg = Utils.GetRegisterName(instruction.Operands[0]); + var reg = Utils.GetRegisterNameNew(instruction.Op0Register == Register.None ? instruction.MemoryBase : instruction.Op0Register); var operand = _analysis.GetOperandInRegister(reg); switch (instruction.Mnemonic) { - case ud_mnemonic_code.UD_Ipush: + case Mnemonic.Push: break; - case ud_mnemonic_code.UD_Ipop: + case Mnemonic.Pop: break; - case ud_mnemonic_code.UD_Ijmp when instruction.Operands[0].Type != ud_type.UD_OP_REG: + case Mnemonic.Jmp when instruction.Op0Kind == OpKind.Memory && instruction.MemoryDisplacement == 0 && operand is ConstantDefinition callRegCons && callRegCons.Value is MethodDefinition methodToCallInReg: + _analysis.Actions.Add(new CallManagedFunctionInRegAction(_analysis, instruction)); + //This is a jmp, so return + _analysis.Actions.Add(new ReturnFromFunctionAction(_analysis, instruction)); + break; + case Mnemonic.Jmp when instruction.Op0Kind != OpKind.Register: { - var jumpTarget = Utils.GetJumpTarget(instruction, instruction.PC + _methodStart); + var jumpTarget = instruction.NearBranchTarget; if (SharedState.MethodsByAddress.ContainsKey(jumpTarget)) { //Call a managed function _analysis.Actions.Add(new CallManagedFunctionAction(_analysis, instruction)); _analysis.Actions.Add(new ReturnFromFunctionAction(_analysis, instruction)); //JMP is an implicit return } + break; } - case ud_mnemonic_code.UD_Icall when instruction.Operands[0].Type == ud_type.UD_OP_MEM && Utils.GetOperandMemoryOffset(instruction.Operands[0]) > 0x128 && operand is ConstantDefinition checkForVirtualCallCons && checkForVirtualCallCons.Value is Il2CppClassIdentifier checkForVirtualCallClassPtr: + case Mnemonic.Call when instruction.Op0Kind == OpKind.Memory && instruction.MemoryDisplacement > 0x128 && operand is ConstantDefinition checkForVirtualCallCons && + checkForVirtualCallCons.Value is Il2CppClassIdentifier checkForVirtualCallClassPtr: //Virtual method call _analysis.Actions.Add(new CallVirtualMethodAction(_analysis, instruction)); break; - case ud_mnemonic_code.UD_Icall when instruction.Operands[0].Type != ud_type.UD_OP_REG: + case Mnemonic.Call when instruction.Op0Kind != OpKind.Register: { - var jumpTarget = Utils.GetJumpTarget(instruction, instruction.PC + _methodStart); + var jumpTarget = instruction.NearBranchTarget; if (jumpTarget == _keyFunctionAddresses.AddrBailOutFunction) { @@ -508,64 +551,86 @@ private void CheckForSingleOpInstruction(Instruction instruction) //Call a managed function _analysis.Actions.Add(new CallManagedFunctionAction(_analysis, instruction)); } + else if (_analysis.GetConstantInReg("rcx") is {} castConstant + && castConstant.Value is NewSafeCastResult castResult //We have a cast result + && _analysis.GetConstantInReg("rdx") is {} interfaceConstant + && interfaceConstant.Value is TypeDefinition interfaceType //we have a type + && _analysis.GetConstantInReg("r8") is {} slotConstant + && slotConstant.Value is int slot // We have a slot + && _analysis.Actions.Any(a => a is LocateSpecificInterfaceOffsetAction) //We've looked up an interface offset + && (!_analysis.Actions.Any(a => a is LoadInterfaceMethodDataAction) //Either we don't have any load method datas... + || _analysis.Actions.FindLastIndex(a => a is LocateSpecificInterfaceOffsetAction) > _analysis.Actions.FindLastIndex(a => a is LoadInterfaceMethodDataAction))) //Or the last load offset is after the last load method data + { + //Unknown function call but matches values for a Interface lookup + _analysis.Actions.Add(new LoadInterfaceMethodDataAction(_analysis, instruction)); + } //TODO: Handle the managed throw getters. break; } - case ud_mnemonic_code.UD_Iinc: + case Mnemonic.Inc: break; - case ud_mnemonic_code.UD_Ijz: + case Mnemonic.Je when _analysis.Actions.LastOrDefault() is LocateSpecificInterfaceOffsetAction: + //Can be ignored. + break; + case Mnemonic.Je: _analysis.Actions.Add(new JumpIfZeroOrNullAction(_analysis, instruction)); break; - case ud_mnemonic_code.UD_Ijnz: + case Mnemonic.Jne: _analysis.Actions.Add(new JumpIfNonZeroOrNonNullAction(_analysis, instruction)); break; //TODO Conditional jumps } } - private void CheckForTwoOpInstruction(Instruction instruction) + private void CheckForTwoOpInstruction(Iced.Intel.Instruction instruction) { - var r0 = Utils.GetRegisterName(instruction.Operands[0]); - var r1 = Utils.GetRegisterName(instruction.Operands[1]); + var r0 = Utils.GetRegisterNameNew(instruction.Op0Register); + var r1 = Utils.GetRegisterNameNew(instruction.Op1Register); + var memR = Utils.GetRegisterNameNew(instruction.MemoryBase); var op0 = _analysis.GetOperandInRegister(r0); var op1 = _analysis.GetOperandInRegister(r1); + var memOp = _analysis.GetOperandInRegister(memR); - var offset0 = Utils.GetOffsetFromMemoryAccess(instruction, instruction.Operands[0]); - var offset1 = Utils.GetOffsetFromMemoryAccess(instruction, instruction.Operands[1]); + var offset0 = instruction.MemoryDisplacement; + var offset1 = offset0; //todo? - var type0 = instruction.Operands[0].Type; - var type1 = instruction.Operands[1].Type; + var type0 = instruction.Op0Kind; + var type1 = instruction.Op1Kind; switch (instruction.Mnemonic) { - case ud_mnemonic_code.UD_Imov when type1 == ud_type.UD_OP_REG && offset0 == 0 && offset1 == 0 && op1 != null: + case Mnemonic.Mov when type1 == OpKind.Register && offset0 == 0 && offset1 == 0 && op1 != null: //Both zero offsets and a known secondary operand = Register content copy _analysis.Actions.Add(new RegToRegMoveAction(_analysis, instruction)); return; - case ud_mnemonic_code.UD_Imov when type1 == ud_type.UD_OP_REG && r0 == "rsp" && offset1 == 0 && op1 != null: + case Mnemonic.Mov when type1 == OpKind.Register && r0 == "rsp" && offset1 == 0 && op1 != null: //Second operand is a reg, no offset, moving into the stack = Copy reg content to stack. _analysis.Actions.Add(new StackToRegCopyAction(_analysis, instruction)); return; - case ud_mnemonic_code.UD_Imov when type1 == ud_type.UD_OP_MEM && (offset0 == 0 || r0 == "rsp") && offset1 == 0 && op1 != null: + case Mnemonic.Mov when type1 == OpKind.Memory && (offset0 == 0 || r0 == "rsp") && offset1 == 0 && memOp != null: { //Zero offsets, but second operand is a memory pointer -> class pointer move. //MUST Check for non-cpp type _analysis.Actions.Add(new ClassPointerLoadAction(_analysis, instruction)); return; } - case ud_mnemonic_code.UD_Imov when type1 == ud_type.UD_OP_MEM && offset1 > 0x128 && op1 is ConstantDefinition virtualPointerCheckCons && virtualPointerCheckCons.Value is Il2CppClassIdentifier virtualPointerCheckKlassPtr: + case Mnemonic.Mov when type1 == OpKind.Memory && offset1 == 0xb0 && memOp is ConstantDefinition interfaceOffsetCheckCons && interfaceOffsetCheckCons.Value is Il2CppClassIdentifier interfaceOffsetCheckKlassPtr: + //Class pointer interface offset read + _analysis.Actions.Add(new InterfaceOffsetsReadAction(_analysis, instruction)); + break; + case Mnemonic.Mov when type1 == OpKind.Memory && offset1 > 0x128 && memOp is ConstantDefinition virtualPointerCheckCons && virtualPointerCheckCons.Value is Il2CppClassIdentifier virtualPointerCheckKlassPtr: { //Virtual method pointer load _analysis.Actions.Add(new LoadVirtualFunctionPointerAction(_analysis, instruction)); break; } - case ud_mnemonic_code.UD_Imov when type1 == ud_type.UD_OP_MEM && (offset0 == 0 || r0 == "rsp") && r1 == "rip": + case Mnemonic.Mov when type1 == OpKind.Memory && instruction.MemoryBase == Register.RIP: { //Global to stack or reg. Could be metadata literal, non-metadata literal, metadata type, or metadata method. - var globalAddress = _methodStart + Utils.GetOffsetFromMemoryAccess(instruction, instruction.Operands[1]); + var globalAddress = instruction.GetRipBasedInstructionMemoryAddress(); if (SharedState.GlobalsByOffset.TryGetValue(globalAddress, out var global)) { //Have a global here. @@ -587,67 +652,73 @@ private void CheckForTwoOpInstruction(Instruction instruction) } else { - var potentialLiteral = Utils.TryGetLiteralAt(LibCpp2IlMain.ThePe, Utils.GetOffsetFromMemoryAccess(instruction, instruction.Operands[1])); + var potentialLiteral = Utils.TryGetLiteralAt(LibCpp2IlMain.ThePe, (ulong) LibCpp2IlMain.ThePe.MapVirtualAddressToRaw(instruction.GetRipBasedInstructionMemoryAddress())); if (potentialLiteral != null) { - if (r0 == "rsp") - _analysis.Actions.Add(new ConstantToStackAction(_analysis, instruction)); - else - _analysis.Actions.Add(new ConstantToRegAction(_analysis, instruction)); + // if (r0 == "rsp") + // _analysis.Actions.Add(new ConstantToStackAction(_analysis, instruction)); + // else + // _analysis.Actions.Add(new ConstantToRegAction(_analysis, instruction)); } } return; } - case ud_mnemonic_code.UD_Imov when type1 == ud_type.UD_OP_IMM && offset0 == 0 && type0 == ud_type.UD_OP_REG: + case Mnemonic.Mov when type1 >= OpKind.Immediate8 && type1 <= OpKind.Immediate32to64 && offset0 == 0 && type0 == OpKind.Register: //Constant move to reg _analysis.Actions.Add(new ConstantToRegAction(_analysis, instruction)); return; - case ud_mnemonic_code.UD_Imov when type1 == ud_type.UD_OP_IMM && offset0 != 0 && type0 != ud_type.UD_OP_REG && r0 != "rip": + case Mnemonic.Mov when type1 >= OpKind.Immediate8 && type1 <= OpKind.Immediate32to64 && offset0 != 0 && type0 != OpKind.Register && r0 != "rip": //Constant move to field _analysis.Actions.Add(new ConstantToFieldAction(_analysis, instruction)); return; //TODO Everything from CheckForFieldArrayAndStackReads //TODO Arithmetic - case ud_mnemonic_code.UD_Ixor: - case ud_mnemonic_code.UD_Ixorps: + case Mnemonic.Xor: + case Mnemonic.Xorps: { //PROBABLY clear register - if(r0 == r1) + if (r0 == r1) _analysis.Actions.Add(new ClearRegAction(_analysis, instruction)); break; } - case ud_mnemonic_code.UD_Itest: - case ud_mnemonic_code.UD_Icmp: + case Mnemonic.Cmp when memOp is ConstantDefinition interfaceOffsetReadTestCons && interfaceOffsetReadTestCons.Value is Il2CppInterfaceOffset[] interfaceOffsetReadTestOffsets: + //Format is generally something like `cmp [r9+rax*8], r10`, where r9 is the interface offset array we have here, rax is the current loop index, and r10 is the target interface + if (instruction.MemoryIndexScale == 0x8 && op1 is ConstantDefinition interfaceOffsetReadTypeCons && interfaceOffsetReadTypeCons.Value is TypeDefinition interfaceType) + { + _analysis.Actions.Add(new LocateSpecificInterfaceOffsetAction(_analysis, instruction)); + } + + break; + case Mnemonic.Test: + case Mnemonic.Cmp: //Condition _analysis.Actions.Add(new ComparisonAction(_analysis, instruction)); break; } } - private void PerformInstructionChecks(Instruction instruction) + private void PerformInstructionChecks(Iced.Intel.Instruction instruction) { -#if USE_NEW_ANALYSIS_METHOD - var operandCount = instruction.Operands.Length; + var operandCount = instruction.OpCount; - if (operandCount == 0) + switch (operandCount) { - CheckForZeroOpInstruction(instruction); - return; - } - - if (operandCount == 1) - { - CheckForSingleOpInstruction(instruction); - return; - } - - if (operandCount == 2) - { - CheckForTwoOpInstruction(instruction); - return; + case 0: + CheckForZeroOpInstruction(instruction); + return; + case 1: + CheckForSingleOpInstruction(instruction); + return; + case 2: + CheckForTwoOpInstruction(instruction); + return; } + } #else + private void PerformInstructionChecks(Instruction instruction) + { + //Detect field writes CheckForFieldWrites(instruction); @@ -686,9 +757,10 @@ private void PerformInstructionChecks(Instruction instruction) //Check for RET CheckForReturn(instruction); -#endif } +#endif +#if !USE_NEW_ANALYSIS_METHOD private void HandleFunctionCall(MethodDefinition target, bool processReturnType, Instruction instruction, TypeDefinition returnType = null) { if (returnType == null) @@ -3014,6 +3086,7 @@ private void CheckForReturn(Instruction instruction) return null; } +#endif private enum BlockType { diff --git a/Cpp2IL/Analysis/Actions/AllocateArrayAction.cs b/Cpp2IL/Analysis/Actions/AllocateArrayAction.cs index 92566c0e..4fb3b2d1 100644 --- a/Cpp2IL/Analysis/Actions/AllocateArrayAction.cs +++ b/Cpp2IL/Analysis/Actions/AllocateArrayAction.cs @@ -1,6 +1,6 @@ using Cpp2IL.Analysis.ResultModels; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/AllocateInstanceAction.cs b/Cpp2IL/Analysis/Actions/AllocateInstanceAction.cs index ef43df24..5324bde4 100644 --- a/Cpp2IL/Analysis/Actions/AllocateInstanceAction.cs +++ b/Cpp2IL/Analysis/Actions/AllocateInstanceAction.cs @@ -1,6 +1,6 @@ using Cpp2IL.Analysis.ResultModels; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -34,7 +34,7 @@ public override string ToPsuedoCode() public override string ToTextSummary() { - return $"Allocates an instance of type {TypeCreated} and stores it as {LocalReturned?.Name} in rax.\n"; + return $"[!] Allocates an instance of type {TypeCreated} and stores it as {LocalReturned?.Name} in rax.\n"; } } } \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/ArrayOffsetToLocalAction.cs b/Cpp2IL/Analysis/Actions/ArrayOffsetToLocalAction.cs index 8846b4ce..e367d75f 100644 --- a/Cpp2IL/Analysis/Actions/ArrayOffsetToLocalAction.cs +++ b/Cpp2IL/Analysis/Actions/ArrayOffsetToLocalAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/BaseAction.cs b/Cpp2IL/Analysis/Actions/BaseAction.cs index d9b2e3cd..23914a85 100644 --- a/Cpp2IL/Analysis/Actions/BaseAction.cs +++ b/Cpp2IL/Analysis/Actions/BaseAction.cs @@ -1,6 +1,6 @@ using System.Text; using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/BoxValueAction.cs b/Cpp2IL/Analysis/Actions/BoxValueAction.cs index e3b028a6..daed3f31 100644 --- a/Cpp2IL/Analysis/Actions/BoxValueAction.cs +++ b/Cpp2IL/Analysis/Actions/BoxValueAction.cs @@ -1,6 +1,6 @@ using Cpp2IL.Analysis.ResultModels; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/CallBailOutAction.cs b/Cpp2IL/Analysis/Actions/CallBailOutAction.cs index 275a6d95..1f7c60ab 100644 --- a/Cpp2IL/Analysis/Actions/CallBailOutAction.cs +++ b/Cpp2IL/Analysis/Actions/CallBailOutAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/CallInitClassAction.cs b/Cpp2IL/Analysis/Actions/CallInitClassAction.cs index 02f67830..b697b504 100644 --- a/Cpp2IL/Analysis/Actions/CallInitClassAction.cs +++ b/Cpp2IL/Analysis/Actions/CallInitClassAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/CallInitMethodAction.cs b/Cpp2IL/Analysis/Actions/CallInitMethodAction.cs index 05e5e677..7794c0ea 100644 --- a/Cpp2IL/Analysis/Actions/CallInitMethodAction.cs +++ b/Cpp2IL/Analysis/Actions/CallInitMethodAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs b/Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs index 5efd42a1..77eb708b 100644 --- a/Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs +++ b/Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs @@ -4,7 +4,7 @@ using LibCpp2IL; using LibCpp2IL.Metadata; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -36,7 +36,7 @@ private bool CheckParameters(Il2CppMethodDefinition method, MethodAnalysis conte } } - if (actualArgs.Any(a => a != null)) + if (actualArgs.Any(a => a != null && !context.IsEmptyRegArg(a))) return false; //Left over args - it's probably not this one return true; @@ -44,7 +44,7 @@ private bool CheckParameters(Il2CppMethodDefinition method, MethodAnalysis conte public CallManagedFunctionAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - var jumpTarget = Utils.GetJumpTarget(instruction, context.MethodStart + instruction.PC); + var jumpTarget = instruction.NearBranchTarget; var objectMethodBeingCalledOn = context.GetLocalInReg("rcx"); var listOfCallableMethods = LibCpp2IlMain.GetManagedMethodImplementationsAtAddress(jumpTarget); @@ -84,7 +84,7 @@ public override Mono.Cecil.Cil.Instruction[] ToILInstructions() public override string ToTextSummary() { - return $"Calls managed method {target?.FullName}\n"; + return $"[!] Calls managed method {target?.FullName}\n"; } } } \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/CallManagedFunctionInRegAction.cs b/Cpp2IL/Analysis/Actions/CallManagedFunctionInRegAction.cs new file mode 100644 index 00000000..1d64dd1a --- /dev/null +++ b/Cpp2IL/Analysis/Actions/CallManagedFunctionInRegAction.cs @@ -0,0 +1,45 @@ +using Cpp2IL.Analysis.ResultModels; +using Iced.Intel; +using Mono.Cecil; + +namespace Cpp2IL.Analysis.Actions +{ + public class CallManagedFunctionInRegAction : BaseAction + { + private MethodDefinition _targetMethod; + private LocalDefinition? _instanceCalledOn; + + public CallManagedFunctionInRegAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) + { + var regName = Utils.GetRegisterNameNew(instruction.MemoryBase); + var operand = context.GetConstantInReg(regName); + _targetMethod = (MethodDefinition) operand.Value; + + if (!_targetMethod.IsStatic) + { + _instanceCalledOn = context.GetLocalInReg("rcx"); + if (_instanceCalledOn == null) + { + var cons = context.GetConstantInReg("rcx"); + if (cons?.Value is NewSafeCastResult castResult) + _instanceCalledOn = castResult.original; + } + } + } + + public override Mono.Cecil.Cil.Instruction[] ToILInstructions() + { + throw new System.NotImplementedException(); + } + + public override string? ToPsuedoCode() + { + throw new System.NotImplementedException(); + } + + public override string ToTextSummary() + { + return $"[!] Calls method {_targetMethod.FullName} from a register, on instance {_instanceCalledOn} if applicable\n"; + } + } +} \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/CallNativeMethodFailureAction.cs b/Cpp2IL/Analysis/Actions/CallNativeMethodFailureAction.cs index 599fa529..f606afb6 100644 --- a/Cpp2IL/Analysis/Actions/CallNativeMethodFailureAction.cs +++ b/Cpp2IL/Analysis/Actions/CallNativeMethodFailureAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/CallVirtualMethodAction.cs b/Cpp2IL/Analysis/Actions/CallVirtualMethodAction.cs index b600ef1a..5ec2858c 100644 --- a/Cpp2IL/Analysis/Actions/CallVirtualMethodAction.cs +++ b/Cpp2IL/Analysis/Actions/CallVirtualMethodAction.cs @@ -3,7 +3,7 @@ using Cpp2IL.Analysis.ResultModels; using LibCpp2IL; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -15,14 +15,14 @@ public class CallVirtualMethodAction : BaseAction public CallVirtualMethodAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - var inReg = context.GetOperandInRegister(Utils.GetRegisterName(instruction.Operands[0])); + var inReg = context.GetOperandInRegister(Utils.GetRegisterNameNew(instruction.MemoryBase)); if (!(inReg is ConstantDefinition cons) || !(cons.Value is Il2CppClassIdentifier klass)) return; var classReadFrom = klass.backingType; - - var readOffset = Utils.GetOperandMemoryOffset(instruction.Operands[0]); - Called = Utils.GetMethodFromReadKlassOffset(readOffset); + + var readOffset = instruction.MemoryDisplacement; + Called = Utils.GetMethodFromReadKlassOffset((int) readOffset); if (Called == null) return; @@ -41,7 +41,7 @@ public override string ToPsuedoCode() public override string ToTextSummary() { - return $"Calls virtual function {Called?.FullName} on instance {CalledOn} with {Arguments.Count} arguments\n"; + return $"[!] Calls virtual function {Called?.FullName} on instance {CalledOn} with {Arguments.Count} arguments\n"; } } } \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/ClassPointerLoadAction.cs b/Cpp2IL/Analysis/Actions/ClassPointerLoadAction.cs index 6ade5253..66123bec 100644 --- a/Cpp2IL/Analysis/Actions/ClassPointerLoadAction.cs +++ b/Cpp2IL/Analysis/Actions/ClassPointerLoadAction.cs @@ -1,6 +1,6 @@ using System; using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; using SharpDisasm.Udis86; namespace Cpp2IL.Analysis.Actions @@ -13,11 +13,11 @@ public class ClassPointerLoadAction : BaseAction public ClassPointerLoadAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - destReg = Utils.GetRegisterName(instruction.Operands[0]); - if(instruction.Operands[0].Base == ud_type.UD_R_RSP) + destReg = Utils.GetRegisterNameNew(instruction.Op0Register); + if(instruction.Op0Register == Register.RSP) Console.WriteLine("WARNING: CLASS POINTER LOAD DEST IS STACK."); - var sourceReg = Utils.GetRegisterName(instruction.Operands[1]); + var sourceReg = Utils.GetRegisterNameNew(instruction.MemoryBase); var inReg = context.GetOperandInRegister(sourceReg); localCopiedFrom = inReg is LocalDefinition local ? local : inReg is ConstantDefinition cons && cons.Value is NewSafeCastResult result ? result.original : null; if (localCopiedFrom == null) return; diff --git a/Cpp2IL/Analysis/Actions/ClearRegAction.cs b/Cpp2IL/Analysis/Actions/ClearRegAction.cs index 46a75b8c..07bf6348 100644 --- a/Cpp2IL/Analysis/Actions/ClearRegAction.cs +++ b/Cpp2IL/Analysis/Actions/ClearRegAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -9,7 +9,8 @@ public class ClearRegAction : BaseAction public ClearRegAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - regCleared = Utils.GetRegisterName(instruction.Operands[0]); + regCleared = Utils.GetRegisterNameNew(instruction.Op0Register); + context.ZeroRegister(regCleared); } public override Mono.Cecil.Cil.Instruction[] ToILInstructions() diff --git a/Cpp2IL/Analysis/Actions/ComparisonAction.cs b/Cpp2IL/Analysis/Actions/ComparisonAction.cs index 2d348383..ad7961c4 100644 --- a/Cpp2IL/Analysis/Actions/ComparisonAction.cs +++ b/Cpp2IL/Analysis/Actions/ComparisonAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -10,8 +10,8 @@ public class ComparisonAction : BaseAction public ComparisonAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - var r0 = Utils.GetRegisterName(instruction.Operands[0]); - var r1 = Utils.GetRegisterName(instruction.Operands[1]); + var r0 = Utils.GetRegisterNameNew(instruction.Op0Register); + var r1 = Utils.GetRegisterNameNew(instruction.Op1Register); if (r0 != "rsp") ArgumentOne = context.GetOperandInRegister(r0); @@ -31,7 +31,7 @@ public override string ToPsuedoCode() public override string ToTextSummary() { - return $"Compares {ArgumentOne} and {ArgumentTwo}"; + return $"[!] Compares {ArgumentOne} and {ArgumentTwo}"; } } } \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/ConditionalJumpAction.cs b/Cpp2IL/Analysis/Actions/ConditionalJumpAction.cs index c0363091..988a1f0f 100644 --- a/Cpp2IL/Analysis/Actions/ConditionalJumpAction.cs +++ b/Cpp2IL/Analysis/Actions/ConditionalJumpAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/ConstantToFieldAction.cs b/Cpp2IL/Analysis/Actions/ConstantToFieldAction.cs index bf6ccd00..948a8273 100644 --- a/Cpp2IL/Analysis/Actions/ConstantToFieldAction.cs +++ b/Cpp2IL/Analysis/Actions/ConstantToFieldAction.cs @@ -1,6 +1,6 @@ using Cpp2IL.Analysis.ResultModels; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/ConstantToRegAction.cs b/Cpp2IL/Analysis/Actions/ConstantToRegAction.cs index 46121e00..bb2a45fd 100644 --- a/Cpp2IL/Analysis/Actions/ConstantToRegAction.cs +++ b/Cpp2IL/Analysis/Actions/ConstantToRegAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/ConstantToStackAction.cs b/Cpp2IL/Analysis/Actions/ConstantToStackAction.cs index ced4a253..3a20da1f 100644 --- a/Cpp2IL/Analysis/Actions/ConstantToStackAction.cs +++ b/Cpp2IL/Analysis/Actions/ConstantToStackAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/FieldToLocalAction.cs b/Cpp2IL/Analysis/Actions/FieldToLocalAction.cs index e477d328..8a296962 100644 --- a/Cpp2IL/Analysis/Actions/FieldToLocalAction.cs +++ b/Cpp2IL/Analysis/Actions/FieldToLocalAction.cs @@ -1,7 +1,7 @@ using System; using Cpp2IL.Analysis.ResultModels; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/GlobalMethodRefToConstantAction.cs b/Cpp2IL/Analysis/Actions/GlobalMethodRefToConstantAction.cs index 9557b11d..4e918877 100644 --- a/Cpp2IL/Analysis/Actions/GlobalMethodRefToConstantAction.cs +++ b/Cpp2IL/Analysis/Actions/GlobalMethodRefToConstantAction.cs @@ -4,7 +4,7 @@ using LibCpp2IL; using LibCpp2IL.Metadata; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; using SharpDisasm.Udis86; namespace Cpp2IL.Analysis.Actions @@ -17,7 +17,7 @@ public class GlobalMethodRefToConstantAction : BaseAction public GlobalMethodRefToConstantAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - var globalAddress = context.MethodStart + Utils.GetOffsetFromMemoryAccess(instruction, instruction.Operands[1]); + var globalAddress = instruction.GetRipBasedInstructionMemoryAddress(); MethodData = LibCpp2IlMain.GetMethodDefinitionByGlobalAddress(globalAddress); var (type, genericParams) = Utils.TryLookupTypeDefByName(MethodData!.DeclaringType.FullName); @@ -31,7 +31,7 @@ public GlobalMethodRefToConstantAction(MethodAnalysis context, Instruction instr if (ResolvedMethod == null) return; - var destReg = instruction.Operands[0].Type == ud_type.UD_OP_REG ? Utils.GetRegisterName(instruction.Operands[0]) : null; + var destReg = instruction.Op0Kind == OpKind.Register ? Utils.GetRegisterNameNew(instruction.Op0Register) : null; var name = ResolvedMethod.Name; ConstantWritten = context.MakeConstant(typeof(MethodDefinition), ResolvedMethod, name, destReg); diff --git a/Cpp2IL/Analysis/Actions/GlobalStringRefToConstantAction.cs b/Cpp2IL/Analysis/Actions/GlobalStringRefToConstantAction.cs index 20e7740a..ce3a65f0 100644 --- a/Cpp2IL/Analysis/Actions/GlobalStringRefToConstantAction.cs +++ b/Cpp2IL/Analysis/Actions/GlobalStringRefToConstantAction.cs @@ -1,7 +1,7 @@ using Cpp2IL.Analysis.ResultModels; using LibCpp2IL; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; using SharpDisasm.Udis86; namespace Cpp2IL.Analysis.Actions @@ -13,12 +13,12 @@ public class GlobalStringRefToConstantAction : BaseAction public GlobalStringRefToConstantAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - var globalAddress = context.MethodStart + Utils.GetOffsetFromMemoryAccess(instruction, instruction.Operands[1]); + var globalAddress = instruction.GetRipBasedInstructionMemoryAddress(); ResolvedString = LibCpp2IlMain.GetLiteralByAddress(globalAddress); if (ResolvedString == null) return; - var destReg = instruction.Operands[0].Type == ud_type.UD_OP_REG ? Utils.GetRegisterName(instruction.Operands[0]) : null; + var destReg = instruction.Op0Kind == OpKind.Register ? Utils.GetRegisterNameNew(instruction.Op0Register) : null; ConstantWritten = context.MakeConstant(typeof(string), ResolvedString, null, destReg); } diff --git a/Cpp2IL/Analysis/Actions/GlobalTypeRefToConstantAction.cs b/Cpp2IL/Analysis/Actions/GlobalTypeRefToConstantAction.cs index 11a01759..a4375986 100644 --- a/Cpp2IL/Analysis/Actions/GlobalTypeRefToConstantAction.cs +++ b/Cpp2IL/Analysis/Actions/GlobalTypeRefToConstantAction.cs @@ -2,7 +2,7 @@ using Cpp2IL.Analysis.ResultModels; using LibCpp2IL; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; using SharpDisasm.Udis86; namespace Cpp2IL.Analysis.Actions @@ -12,20 +12,21 @@ public class GlobalTypeRefToConstantAction : BaseAction public GlobalIdentifier GlobalRead; public TypeDefinition ResolvedType; public ConstantDefinition ConstantWritten; - + private string _destReg; + public GlobalTypeRefToConstantAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - var globalAddress = context.MethodStart + Utils.GetOffsetFromMemoryAccess(instruction, instruction.Operands[1]); + var globalAddress = instruction.GetRipBasedInstructionMemoryAddress(); var typeData = LibCpp2IlMain.GetTypeGlobalByAddress(globalAddress); var (type, genericParams) = Utils.TryLookupTypeDefByName(typeData!.ToString()); ResolvedType = type; if (ResolvedType == null) return; - var destReg = instruction.Operands[0].Type == ud_type.UD_OP_REG ? Utils.GetRegisterName(instruction.Operands[0]) : null; + _destReg = instruction.Op0Kind ==OpKind.Register ? Utils.GetRegisterNameNew(instruction.Op0Register) : null; var name = ResolvedType.Name; - ConstantWritten = context.MakeConstant(typeof(TypeDefinition), ResolvedType, name, destReg); + ConstantWritten = context.MakeConstant(typeof(TypeDefinition), ResolvedType, name, _destReg); } public override Mono.Cecil.Cil.Instruction[] ToILInstructions() @@ -40,7 +41,7 @@ public override string ToPsuedoCode() public override string ToTextSummary() { - return $"Loads the type definition for managed type {ResolvedType.FullName} as a constant \"{ConstantWritten.Name}\""; + return $"Loads the type definition for managed type {ResolvedType.FullName} as a constant \"{ConstantWritten.Name}\" in {_destReg}"; } } } \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/InterfaceOffsetsReadAction.cs b/Cpp2IL/Analysis/Actions/InterfaceOffsetsReadAction.cs new file mode 100644 index 00000000..381807b1 --- /dev/null +++ b/Cpp2IL/Analysis/Actions/InterfaceOffsetsReadAction.cs @@ -0,0 +1,41 @@ +using Cpp2IL.Analysis.ResultModels; +using Iced.Intel; +using LibCpp2IL.Metadata; + +namespace Cpp2IL.Analysis.Actions +{ + public class InterfaceOffsetsReadAction : BaseAction + { + internal Il2CppInterfaceOffset[] InterfaceOffsets; + private Il2CppClassIdentifier _loadedFor; + private ConstantDefinition _destinationConst; + private string _destReg; + + public InterfaceOffsetsReadAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) + { + var regName = Utils.GetRegisterNameNew(instruction.MemoryBase); + var regConstant = context.GetConstantInReg(regName); + + _loadedFor = (Il2CppClassIdentifier) regConstant.Value; + InterfaceOffsets = _loadedFor.backingType.InterfaceOffsets; + + _destReg = Utils.GetRegisterNameNew(instruction.Op0Register); + _destinationConst = context.MakeConstant(typeof(Il2CppInterfaceOffset[]), InterfaceOffsets, reg: _destReg); + } + + public override Mono.Cecil.Cil.Instruction[] ToILInstructions() + { + throw new System.NotImplementedException(); + } + + public override string? ToPsuedoCode() + { + throw new System.NotImplementedException(); + } + + public override string ToTextSummary() + { + return $"Loads the interface offsets for the class pointer to {_loadedFor.backingType.FullName}, which contains {InterfaceOffsets.Length} offsets, and stores them as a constant {_destinationConst.Name} in reg {_destReg}"; + } + } +} \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/JumpIfNonZeroOrNonNullAction.cs b/Cpp2IL/Analysis/Actions/JumpIfNonZeroOrNonNullAction.cs index 1909c950..f9d7662c 100644 --- a/Cpp2IL/Analysis/Actions/JumpIfNonZeroOrNonNullAction.cs +++ b/Cpp2IL/Analysis/Actions/JumpIfNonZeroOrNonNullAction.cs @@ -1,7 +1,7 @@ using System.Linq; using Cpp2IL.Analysis.ResultModels; using LibCpp2IL; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -14,9 +14,9 @@ public class JumpIfNonZeroOrNonNullAction : BaseAction public JumpIfNonZeroOrNonNullAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - jumpTarget = Utils.GetJumpTarget(instruction, instruction.PC + context.MethodStart); + jumpTarget = instruction.NearBranchTarget; - if (jumpTarget > context.MethodStart + instruction.PC && jumpTarget < context.AbsoluteMethodEnd) + if (jumpTarget > instruction.NextIP && jumpTarget < context.AbsoluteMethodEnd) { isIfStatement = true; if(!context.IdentifiedIfStatementStarts.Contains(jumpTarget)) diff --git a/Cpp2IL/Analysis/Actions/JumpIfZeroOrNullAction.cs b/Cpp2IL/Analysis/Actions/JumpIfZeroOrNullAction.cs index 63d9cd54..9bb1e610 100644 --- a/Cpp2IL/Analysis/Actions/JumpIfZeroOrNullAction.cs +++ b/Cpp2IL/Analysis/Actions/JumpIfZeroOrNullAction.cs @@ -1,7 +1,7 @@ using System.Linq; using Cpp2IL.Analysis.ResultModels; using LibCpp2IL; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -14,9 +14,9 @@ public class JumpIfZeroOrNullAction : BaseAction public JumpIfZeroOrNullAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - jumpTarget = Utils.GetJumpTarget(instruction, instruction.PC + context.MethodStart); + jumpTarget = instruction.NearBranchTarget; - if (jumpTarget > context.MethodStart + instruction.PC && jumpTarget < context.AbsoluteMethodEnd) + if (jumpTarget > instruction.NextIP && jumpTarget < context.AbsoluteMethodEnd) { isIfStatement = true; if(!context.IdentifiedIfStatementStarts.Contains(jumpTarget)) diff --git a/Cpp2IL/Analysis/Actions/LoadInterfaceMethodDataAction.cs b/Cpp2IL/Analysis/Actions/LoadInterfaceMethodDataAction.cs new file mode 100644 index 00000000..60a483ab --- /dev/null +++ b/Cpp2IL/Analysis/Actions/LoadInterfaceMethodDataAction.cs @@ -0,0 +1,51 @@ +using System.Linq; +using Cpp2IL.Analysis.ResultModels; +using Iced.Intel; +using Mono.Cecil; + +namespace Cpp2IL.Analysis.Actions +{ + public class LoadInterfaceMethodDataAction : BaseAction + { + private LocalDefinition _invokedOn; + private TypeDefinition _interfaceType; + private int _slotNumber; + private MethodDefinition resolvedMethod; + private ConstantDefinition _resultConstant; + + public LoadInterfaceMethodDataAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) + { + if (context.GetConstantInReg("rcx") is {} castConstant + && castConstant.Value is NewSafeCastResult castResult + && context.GetConstantInReg("rdx") is {} interfaceConstant + && interfaceConstant.Value is TypeDefinition interfaceType + && context.GetConstantInReg("r8") is {} slotConstant + && slotConstant.Value is int slot + && context.Actions.FirstOrDefault(a => a is LocateSpecificInterfaceOffsetAction) is LocateSpecificInterfaceOffsetAction locator + ) + { + _invokedOn = castResult.original; + _interfaceType = interfaceType; + _slotNumber = slot; + resolvedMethod = SharedState.VirtualMethodsBySlot[(ushort) (locator._matchingInterfaceOffset.offset + _slotNumber)]; + + _resultConstant = context.MakeConstant(typeof(MethodDefinition), resolvedMethod, reg: "rax"); + } + } + + public override Mono.Cecil.Cil.Instruction[] ToILInstructions() + { + throw new System.NotImplementedException(); + } + + public override string? ToPsuedoCode() + { + throw new System.NotImplementedException(); + } + + public override string ToTextSummary() + { + return $"Loads the pointer to the interface function defined in {_interfaceType.FullName} - specifically the implementation in {_invokedOn.Type?.FullName} - which has slot number {_slotNumber}, which resolves to {resolvedMethod?.FullName}, and stores in constant {_resultConstant.Name} in rax"; + } + } +} \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/LoadVirtualFunctionPointerAction.cs b/Cpp2IL/Analysis/Actions/LoadVirtualFunctionPointerAction.cs index 135caf12..ec5b0c55 100644 --- a/Cpp2IL/Analysis/Actions/LoadVirtualFunctionPointerAction.cs +++ b/Cpp2IL/Analysis/Actions/LoadVirtualFunctionPointerAction.cs @@ -3,7 +3,7 @@ using LibCpp2IL; using LibCpp2IL.Metadata; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -16,23 +16,24 @@ public class LoadVirtualFunctionPointerAction : BaseAction public LoadVirtualFunctionPointerAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - regReadFrom = Utils.GetRegisterName(instruction.Operands[1]); + regReadFrom = Utils.GetRegisterNameNew(instruction.MemoryBase); var inReg = context.GetOperandInRegister(regReadFrom); if (!(inReg is ConstantDefinition cons) || !(cons.Value is Il2CppClassIdentifier klass)) return; classReadFrom = klass.backingType; - - var readOffset = Utils.GetOperandMemoryOffset(instruction.Operands[1]); - methodPointerRead = Utils.GetMethodFromReadKlassOffset(readOffset); + + var readOffset = instruction.MemoryDisplacement; + methodPointerRead = Utils.GetMethodFromReadKlassOffset((int) readOffset); if (methodPointerRead == null) return; - var regPutInto = Utils.GetRegisterName(instruction.Operands[0]); + var regPutInto = Utils.GetRegisterNameNew(instruction.Op0Register); if (regPutInto == "rsp") { - var stackOffset = Utils.GetOperandMemoryOffset(instruction.Operands[0]); - context.PushToStack(context.MakeConstant(typeof(MethodDefinition), methodPointerRead), stackOffset); + //todo how do we handle this kind of instruction - does it even exist? + // var stackOffset = Utils.GetOperandMemoryOffset(instruction.Operands[0]); + // context.PushToStack(context.MakeConstant(typeof(MethodDefinition), methodPointerRead), stackOffset); } else { diff --git a/Cpp2IL/Analysis/Actions/LocalToFieldAction.cs b/Cpp2IL/Analysis/Actions/LocalToFieldAction.cs index d1188be3..e695809e 100644 --- a/Cpp2IL/Analysis/Actions/LocalToFieldAction.cs +++ b/Cpp2IL/Analysis/Actions/LocalToFieldAction.cs @@ -1,6 +1,6 @@ using Cpp2IL.Analysis.ResultModels; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/LocateSpecificInterfaceOffsetAction.cs b/Cpp2IL/Analysis/Actions/LocateSpecificInterfaceOffsetAction.cs new file mode 100644 index 00000000..38fcf920 --- /dev/null +++ b/Cpp2IL/Analysis/Actions/LocateSpecificInterfaceOffsetAction.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; +using Cpp2IL.Analysis.ResultModels; +using Iced.Intel; +using LibCpp2IL.Metadata; +using Mono.Cecil; + +namespace Cpp2IL.Analysis.Actions +{ + public class LocateSpecificInterfaceOffsetAction : BaseAction + { + private TypeDefinition _interfaceType; + private InterfaceOffsetsReadAction offsetReads; + public Il2CppInterfaceOffset _matchingInterfaceOffset; + + public LocateSpecificInterfaceOffsetAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) + { + var secondOpName = Utils.GetRegisterNameNew(instruction.Op1Register); + var secondOp = context.GetConstantInReg(secondOpName); + _interfaceType = (TypeDefinition) secondOp.Value; + + offsetReads = (InterfaceOffsetsReadAction) context.Actions.Last(a => a is InterfaceOffsetsReadAction); + + var cppType = SharedState.MonoToCppTypeDefs[_interfaceType]; + _matchingInterfaceOffset = offsetReads.InterfaceOffsets.First(i => i.type == cppType); + } + + public override Mono.Cecil.Cil.Instruction[] ToILInstructions() + { + throw new System.NotImplementedException(); + } + + public override string? ToPsuedoCode() + { + throw new System.NotImplementedException(); + } + + public override string ToTextSummary() + { + return $"Checks for specific interface offset of type {_interfaceType.FullName} which resolves to offset {_matchingInterfaceOffset.offset}"; + } + } +} \ No newline at end of file diff --git a/Cpp2IL/Analysis/Actions/LookupNativeFunctionAction.cs b/Cpp2IL/Analysis/Actions/LookupNativeFunctionAction.cs index ab44b35c..ff326876 100644 --- a/Cpp2IL/Analysis/Actions/LookupNativeFunctionAction.cs +++ b/Cpp2IL/Analysis/Actions/LookupNativeFunctionAction.cs @@ -1,6 +1,6 @@ using Cpp2IL.Analysis.ResultModels; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/RegToRegMoveAction.cs b/Cpp2IL/Analysis/Actions/RegToRegMoveAction.cs index 755090a0..e92c4448 100644 --- a/Cpp2IL/Analysis/Actions/RegToRegMoveAction.cs +++ b/Cpp2IL/Analysis/Actions/RegToRegMoveAction.cs @@ -1,6 +1,6 @@ using System; using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { @@ -15,8 +15,8 @@ public class RegToRegMoveAction : BaseAction public RegToRegMoveAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { - originalReg = Utils.GetRegisterName(instruction.Operands[1]); - newReg = Utils.GetRegisterName(instruction.Operands[0]); + originalReg = Utils.GetRegisterNameNew(instruction.Op1Register); + newReg = Utils.GetRegisterNameNew(instruction.Op0Register); beingMoved = context.GetOperandInRegister(originalReg); context.SetRegContent(newReg, beingMoved); diff --git a/Cpp2IL/Analysis/Actions/ReturnFromFunctionAction.cs b/Cpp2IL/Analysis/Actions/ReturnFromFunctionAction.cs index bbcdcb6b..38b02ec1 100644 --- a/Cpp2IL/Analysis/Actions/ReturnFromFunctionAction.cs +++ b/Cpp2IL/Analysis/Actions/ReturnFromFunctionAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/SafeCastAction.cs b/Cpp2IL/Analysis/Actions/SafeCastAction.cs index 5e5289d8..ee38cbfb 100644 --- a/Cpp2IL/Analysis/Actions/SafeCastAction.cs +++ b/Cpp2IL/Analysis/Actions/SafeCastAction.cs @@ -1,6 +1,6 @@ using Cpp2IL.Analysis.ResultModels; using Mono.Cecil; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/StackToRegCopyAction.cs b/Cpp2IL/Analysis/Actions/StackToRegCopyAction.cs index d6ef7397..c51b82a6 100644 --- a/Cpp2IL/Analysis/Actions/StackToRegCopyAction.cs +++ b/Cpp2IL/Analysis/Actions/StackToRegCopyAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/Actions/ThrowAction.cs b/Cpp2IL/Analysis/Actions/ThrowAction.cs index 6099122f..74cbb5f4 100644 --- a/Cpp2IL/Analysis/Actions/ThrowAction.cs +++ b/Cpp2IL/Analysis/Actions/ThrowAction.cs @@ -1,5 +1,5 @@ using Cpp2IL.Analysis.ResultModels; -using SharpDisasm; +using Iced.Intel; namespace Cpp2IL.Analysis.Actions { diff --git a/Cpp2IL/Analysis/ResultModels/MethodAnalysis.cs b/Cpp2IL/Analysis/ResultModels/MethodAnalysis.cs index bae92c93..8996fe92 100644 --- a/Cpp2IL/Analysis/ResultModels/MethodAnalysis.cs +++ b/Cpp2IL/Analysis/ResultModels/MethodAnalysis.cs @@ -13,6 +13,8 @@ public class MethodAnalysis public readonly List Actions = new List(); public readonly List IdentifiedIfStatementStarts = new List(); + private ConstantDefinition EmptyRegConstant; + internal ulong MethodStart; internal ulong AbsoluteMethodEnd; @@ -26,6 +28,7 @@ internal MethodAnalysis(MethodDefinition method, ulong methodStart, ulong initia _method = method; MethodStart = methodStart; AbsoluteMethodEnd = initialMethodEnd; + EmptyRegConstant = MakeConstant(typeof(int), 0, "0"); //Set up parameters in registers & as locals. var regList = new List {"rcx", "rdx", "r8", "r9"}; @@ -95,6 +98,11 @@ public void SetRegContent(string reg, IAnalysedOperand? content) RegisterData[reg] = content; } + public void ZeroRegister(string reg) + { + SetRegContent(reg, EmptyRegConstant); + } + public IAnalysedOperand PushToStack(IAnalysedOperand operand, int pos) { StackData[pos] = operand; @@ -128,5 +136,10 @@ public IAnalysedOperand PushToStack(IAnalysedOperand operand, int pos) return constant; } + + public bool IsEmptyRegArg(IAnalysedOperand analysedOperand) + { + return analysedOperand == EmptyRegConstant; + } } } \ No newline at end of file diff --git a/Cpp2IL/Cpp2IL.csproj b/Cpp2IL/Cpp2IL.csproj index ba0150b3..cc09539a 100644 --- a/Cpp2IL/Cpp2IL.csproj +++ b/Cpp2IL/Cpp2IL.csproj @@ -12,6 +12,7 @@ + diff --git a/Cpp2IL/KeyFunctionAddresses.cs b/Cpp2IL/KeyFunctionAddresses.cs index e4bf1428..9743215a 100644 --- a/Cpp2IL/KeyFunctionAddresses.cs +++ b/Cpp2IL/KeyFunctionAddresses.cs @@ -277,9 +277,9 @@ public static KeyFunctionAddresses Find(List<(TypeDefinition type, List t.type.Name == "Ray" && t.type.Namespace == "UnityEngine").methods; - method = methods.Find(m => m.MethodName == "ToString"); + Console.WriteLine("\t\t\tLooking for System.RuntimeType$GetGenericArgumentsInternal..."); + methods = methodData.Find(t => t.type.Name == "RuntimeType" && t.type.Namespace == "System").methods; + method = methods.Find(m => m.MethodName == "GetGenericArgumentsInternal" && LibCpp2IlMain.GetManagedMethodImplementationsAtAddress(m.MethodOffsetRam).FirstOrDefault()?.parameterCount == 0); Console.WriteLine($"\t\t\t\tSearching for a call to the safe cast function near offset 0x{method.MethodOffsetRam:X}..."); @@ -287,7 +287,7 @@ public static KeyFunctionAddresses Find(List<(TypeDefinition type, List insn.Mnemonic == ud_mnemonic_code.UD_Icall).ToArray(); - addr = Utils.GetJumpTarget(calls[3], method.MethodOffsetRam + calls[3].PC); + addr = Utils.GetJumpTarget(calls[2], method.MethodOffsetRam + calls[2].PC); Console.WriteLine($"\t\t\t\tLocated il2cpp_object_is_inst function at 0x{addr:X}"); ret.il2cpp_object_is_inst = addr; diff --git a/Cpp2IL/Utils.cs b/Cpp2IL/Utils.cs index d8b00c76..089e5fb5 100644 --- a/Cpp2IL/Utils.cs +++ b/Cpp2IL/Utils.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Text; using System.Text.RegularExpressions; +using Iced.Intel; using LibCpp2IL; using LibCpp2IL.Metadata; using LibCpp2IL.PE; @@ -12,6 +13,7 @@ using Mono.Cecil; using SharpDisasm; using SharpDisasm.Udis86; +using Instruction = SharpDisasm.Instruction; namespace Cpp2IL { @@ -603,7 +605,21 @@ public static string GetFloatingRegister(string original) } private static readonly ConcurrentDictionary CachedRegNames = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary CachedRegNamesNew = new ConcurrentDictionary(); + public static string GetRegisterNameNew(Register register) + { + if (register == Register.None) return ""; + + if (!CachedRegNamesNew.TryGetValue(register, out var ret)) + { + ret = UpscaleRegisters(register.ToString().ToLower()); + CachedRegNamesNew[register] = ret; + } + + return ret; + } + public static string GetRegisterName(Operand operand) { var theBase = operand.Base; @@ -612,7 +628,7 @@ public static string GetRegisterName(Operand operand) if (!CachedRegNames.TryGetValue(theBase, out var ret)) { - ret = Utils.UpscaleRegisters(theBase.ToString().Replace("UD_R_", "").ToLower()); + ret = UpscaleRegisters(theBase.ToString().Replace("UD_R_", "").ToLower()); CachedRegNames[theBase] = ret; } diff --git a/LibCpp2IL/Extensions.cs b/LibCpp2IL/Extensions.cs index 8c1fea33..4e41f588 100644 --- a/LibCpp2IL/Extensions.cs +++ b/LibCpp2IL/Extensions.cs @@ -7,7 +7,7 @@ namespace LibCpp2IL { public static class Extensions { - public static ulong GetInstructionMemoryAddress(this Instruction instruction) => instruction.NextIP + instruction.MemoryDisplacement64; + public static ulong GetRipBasedInstructionMemoryAddress(this Instruction instruction) => instruction.NextIP + instruction.MemoryDisplacement64; public static T[] SubArray(this T[] data, int index, int length) { diff --git a/LibCpp2IL/PlusSearch.cs b/LibCpp2IL/PlusSearch.cs index ac736a94..ed679dbd 100644 --- a/LibCpp2IL/PlusSearch.cs +++ b/LibCpp2IL/PlusSearch.cs @@ -178,7 +178,7 @@ internal ulong FindCodeRegistrationUsingMscorlib() while (sanity++ < 500) { var instruction = allSensibleInstructions.FirstOrDefault(i => - i.GetInstructionMemoryAddress() == codeGenAddr + i.GetRipBasedInstructionMemoryAddress() == codeGenAddr ); if (instruction != default) return codeGenAddr;