-
-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using System; | ||
using System.Reflection; | ||
using LibCpp2IL; | ||
|
||
namespace Cpp2IL.Core.Model.Contexts; | ||
|
||
public sealed class NativeMethodAnalysisContext : MethodAnalysisContext | ||
{ | ||
public override ulong UnderlyingPointer { get; } | ||
|
||
public override string DefaultName { get; } | ||
|
||
public override bool IsStatic => true; | ||
|
||
public override bool IsVoid { get; } | ||
|
||
public override MethodAttributes Attributes => MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig; | ||
|
||
protected override int CustomAttributeIndex => -1; | ||
|
||
public NativeMethodAnalysisContext(TypeAnalysisContext parent, ulong address, bool voidReturn) : base(null, parent) | ||
{ | ||
if (address == 0) | ||
throw new ArgumentOutOfRangeException(nameof(address)); | ||
|
||
IsVoid = voidReturn; | ||
UnderlyingPointer = address; | ||
if (LibCpp2IlMain.Binary?.TryGetExportedFunctionName(UnderlyingPointer, out var name) ?? false) | ||
{ | ||
DefaultName = name; | ||
} | ||
else | ||
{ | ||
DefaultName = $"NativeMethod_0x{UnderlyingPointer:X}"; | ||
} | ||
RawBytes = AppContext.InstructionSet.GetRawBytesForMethod(this, false); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Cpp2IL.Core.Api; | ||
using Cpp2IL.Core.ISIL; | ||
using Cpp2IL.Core.Model.Contexts; | ||
|
||
namespace Cpp2IL.Core.ProcessingLayers; | ||
|
||
public class NativeMethodDetectionProcessingLayer : Cpp2IlProcessingLayer | ||
{ | ||
public override string Name => "Native Method Detection"; | ||
|
||
public override string Id => "nativemethoddetector"; | ||
|
||
public override void Process(ApplicationAnalysisContext appContext, Action<int, int>? progressCallback = null) | ||
{ | ||
var nativeMethodInfoStack = new Stack<(ulong, bool)>(); | ||
var cppNativeMethodsType = appContext.AssembliesByName["mscorlib"].InjectType("Cpp2ILInjected", "CppNativeMethods", null); | ||
foreach (var assemblyAnalysisContext in appContext.Assemblies) | ||
{ | ||
foreach (var m in assemblyAnalysisContext.Types.SelectMany(t => t.Methods)) | ||
{ | ||
AnalyzeMethod(appContext, m, nativeMethodInfoStack); | ||
} | ||
} | ||
while (nativeMethodInfoStack.Count > 0) | ||
{ | ||
(var address, var isVoid) = nativeMethodInfoStack.Pop(); | ||
if (!appContext.MethodsByAddress.ContainsKey(address)) | ||
{ | ||
var m = new NativeMethodAnalysisContext(cppNativeMethodsType, address, isVoid); | ||
cppNativeMethodsType.Methods.Add(m); | ||
m.InjectedReturnType = isVoid ? appContext.SystemTypes.SystemVoidType : appContext.SystemTypes.SystemObjectType; | ||
appContext.MethodsByAddress.Add(address, new(1) { m }); | ||
AnalyzeMethod(appContext, m, nativeMethodInfoStack); | ||
} | ||
} | ||
} | ||
|
||
private static void AnalyzeMethod(ApplicationAnalysisContext appContext, MethodAnalysisContext m, Stack<(ulong, bool)> nativeMethodInfoStack) | ||
{ | ||
if (m.UnderlyingPointer == 0) | ||
return; | ||
|
||
try | ||
{ | ||
m.Analyze(); | ||
} | ||
catch (Exception ex) | ||
Check warning on line 50 in Cpp2IL.Core/ProcessingLayers/NativeMethodDetectionProcessingLayer.cs GitHub Actions / Build - Windows .NET Framework Zip
Check warning on line 50 in Cpp2IL.Core/ProcessingLayers/NativeMethodDetectionProcessingLayer.cs GitHub Actions / Build Single-File Artifact (osx-x64, Cpp2IL)
Check warning on line 50 in Cpp2IL.Core/ProcessingLayers/NativeMethodDetectionProcessingLayer.cs GitHub Actions / Build Single-File Artifact (osx-x64, Cpp2IL.Gui)
Check warning on line 50 in Cpp2IL.Core/ProcessingLayers/NativeMethodDetectionProcessingLayer.cs GitHub Actions / Build Single-File Artifact (linux-x64, Cpp2IL)
Check warning on line 50 in Cpp2IL.Core/ProcessingLayers/NativeMethodDetectionProcessingLayer.cs GitHub Actions / Build Single-File Artifact (win-x64, Cpp2IL)
Check warning on line 50 in Cpp2IL.Core/ProcessingLayers/NativeMethodDetectionProcessingLayer.cs GitHub Actions / Build Single-File Artifact (win-x64, Cpp2IL.Gui)
Check warning on line 50 in Cpp2IL.Core/ProcessingLayers/NativeMethodDetectionProcessingLayer.cs GitHub Actions / Build Single-File Artifact (linux-x64, Cpp2IL.Gui)
Check warning on line 50 in Cpp2IL.Core/ProcessingLayers/NativeMethodDetectionProcessingLayer.cs GitHub Actions / Run Tests & Publish Dev Package
|
||
{ | ||
#if DEBUG | ||
if (ex.Message is not "Failed to convert to ISIL. Reason: Jump target not found in method. Ruh roh" && !ex.Message.StartsWith("Instruction ")) | ||
{ | ||
} | ||
#endif | ||
m.ConvertedIsil = null; | ||
return; | ||
} | ||
|
||
if (m.ConvertedIsil is { Count: 0 }) | ||
{ | ||
return; | ||
} | ||
|
||
foreach (var instruction in m.ConvertedIsil) | ||
{ | ||
if (instruction.OpCode == InstructionSetIndependentOpCode.Call) | ||
{ | ||
if (TryGetAddressFromInstruction(instruction, out var address) && !appContext.MethodsByAddress.ContainsKey(address)) | ||
{ | ||
nativeMethodInfoStack.Push((address, true)); | ||
} | ||
} | ||
else if (instruction.OpCode == InstructionSetIndependentOpCode.CallNoReturn) | ||
{ | ||
if (TryGetAddressFromInstruction(instruction, out var address) && !appContext.MethodsByAddress.ContainsKey(address)) | ||
{ | ||
nativeMethodInfoStack.Push((address, m.IsVoid)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private static bool TryGetAddressFromInstruction(InstructionSetIndependentInstruction instruction, out ulong address) | ||
{ | ||
if (instruction.Operands.Length > 0 && instruction.Operands[0].Data is IsilImmediateOperand operand) | ||
{ | ||
address = operand.Value.ToUInt64(null); | ||
return true; | ||
} | ||
address = default; | ||
return false; | ||
} | ||
} |