diff --git a/Architecture/CustomArchitectureRegistration.cs b/Architecture/CustomArchitectureRegistration.cs new file mode 100644 index 0000000..a9609f7 --- /dev/null +++ b/Architecture/CustomArchitectureRegistration.cs @@ -0,0 +1,179 @@ +using System; +using System.Runtime.InteropServices; + +namespace BinaryNinja +{ + public abstract partial class CustomArchitecture + { + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)] + private delegate void InitCallback(IntPtr context, IntPtr architecture); + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)] + private delegate Endianness GetEndiannessCallback(IntPtr context); + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)] + private delegate ulong GetSizeCallback(IntPtr context); + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)] + private delegate IntPtr GetAssociatedArchitectureCallback( + IntPtr context, + ref ulong address); + + private readonly object registrationLock = new object(); + private Architecture? registeredArchitecture; + + /// + /// Registers this architecture with the core for the lifetime of the process. + /// + public Architecture Register(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentException("An architecture name is required.", nameof(name)); + } + + lock (this.registrationLock) + { + if (null != this.registeredArchitecture) + { + throw new InvalidOperationException("This architecture is already registered."); + } + + BNCustomArchitecture callbacks = new BNCustomArchitecture + { + context = IntPtr.Zero, + init = UnsafeUtils.PinCallback(this.InitAdapter), + getEndianness = UnsafeUtils.PinCallback( + this.GetEndiannessAdapter), + getAddressSize = UnsafeUtils.PinCallback( + this.GetAddressSizeAdapter), + getDefaultIntegerSize = UnsafeUtils.PinCallback( + this.GetDefaultIntegerSizeAdapter), + getInstructionAlignment = UnsafeUtils.PinCallback( + this.GetInstructionAlignmentAdapter), + getMaxInstructionLength = UnsafeUtils.PinCallback( + this.GetMaxInstructionLengthAdapter), + getOpcodeDisplayLength = UnsafeUtils.PinCallback( + this.GetOpcodeDisplayLengthAdapter), + getAssociatedArchitectureByAddress = + UnsafeUtils.PinCallback( + this.GetAssociatedArchitectureAdapter) + }; + + using (ScopedAllocator allocator = new ScopedAllocator()) + { + IntPtr handle = NativeMethods.BNRegisterArchitecture( + name, + allocator.AllocStruct(callbacks)); + this.registeredArchitecture = Architecture.MustFromHandle(handle); + return Architecture.MustFromHandle(handle); + } + } + } + + private void InitAdapter(IntPtr context, IntPtr architectureHandle) + { + try + { + Architecture architecture = Architecture.MustFromHandle(architectureHandle); + this.registeredArchitecture = architecture; + this.Init(architecture); + } + catch (Exception exception) + { + Core.LogError("Unhandled exception in CustomArchitecture.Init: {0}", exception); + } + } + + private Endianness GetEndiannessAdapter(IntPtr context) + { + try + { + return this.GetEndianness(); + } + catch (Exception exception) + { + Core.LogError( + "Unhandled exception in CustomArchitecture.GetEndianness: {0}", + exception); + return Endianness.LittleEndian; + } + } + + private ulong GetAddressSizeAdapter(IntPtr context) + { + return this.InvokeSizeCallback(this.GetAddressSize, "GetAddressSize"); + } + + private ulong GetDefaultIntegerSizeAdapter(IntPtr context) + { + return this.InvokeSizeCallback( + this.GetDefaultIntegerSize, + "GetDefaultIntegerSize"); + } + + private ulong GetInstructionAlignmentAdapter(IntPtr context) + { + return this.InvokeSizeCallback( + this.GetInstructionAlignment, + "GetInstructionAlignment"); + } + + private ulong GetMaxInstructionLengthAdapter(IntPtr context) + { + return this.InvokeSizeCallback( + this.GetMaxInstructionLength, + "GetMaxInstructionLength"); + } + + private ulong GetOpcodeDisplayLengthAdapter(IntPtr context) + { + return this.InvokeSizeCallback( + this.GetOpcodeDisplayLength, + "GetOpcodeDisplayLength"); + } + + private ulong InvokeSizeCallback(Func callback, string callbackName) + { + try + { + return callback(); + } + catch (Exception exception) + { + Core.LogError( + "Unhandled exception in CustomArchitecture.{0}: {1}", + callbackName, + exception); + return 0; + } + } + + private IntPtr GetAssociatedArchitectureAdapter( + IntPtr context, + ref ulong address) + { + try + { + Architecture? architecture = this.GetAssociatedArchitectureByAddress(ref address); + if (null == architecture) + { + architecture = this.registeredArchitecture; + } + + return null == architecture + ? IntPtr.Zero + : architecture.DangerousGetHandle(); + } + catch (Exception exception) + { + Core.LogError( + "Unhandled exception in CustomArchitecture.GetAssociatedArchitectureByAddress: {0}", + exception); + return null == this.registeredArchitecture + ? IntPtr.Zero + : this.registeredArchitecture.DangerousGetHandle(); + } + } + } +} diff --git a/Struct/BNCustomArchitecture.cs b/Struct/BNCustomArchitecture.cs index 5695b85..f20076e 100644 --- a/Struct/BNCustomArchitecture.cs +++ b/Struct/BNCustomArchitecture.cs @@ -334,7 +334,7 @@ internal unsafe struct BNCustomArchitecture internal IntPtr skipAndReturnValue; } - public abstract class CustomArchitecture + public abstract partial class CustomArchitecture { internal delegate void InitDelegate( Architecture arch @@ -998,4 +998,4 @@ ulong value #endregion } -} \ No newline at end of file +}