From 56865bcec94ae72a0262ac01475239b925f45034 Mon Sep 17 00:00:00 2001 From: tinysec Date: Thu, 23 Jul 2026 11:30:15 +0800 Subject: [PATCH] Add custom architecture instruction info --- .../CustomArchitectureInstructionCallbacks.cs | 58 +++++++++ .../CustomArchitectureRegistration.cs | 1 + Struct/BNInstructionInfo.cs | 117 +++++++++++++----- 3 files changed, 144 insertions(+), 32 deletions(-) create mode 100644 Architecture/CustomArchitectureInstructionCallbacks.cs diff --git a/Architecture/CustomArchitectureInstructionCallbacks.cs b/Architecture/CustomArchitectureInstructionCallbacks.cs new file mode 100644 index 00000000..7c73bf35 --- /dev/null +++ b/Architecture/CustomArchitectureInstructionCallbacks.cs @@ -0,0 +1,58 @@ +using System; +using System.Runtime.InteropServices; + +namespace BinaryNinja +{ + public abstract partial class CustomArchitecture + { + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool GetInstructionInfoCallback( + IntPtr context, + IntPtr data, + ulong address, + ulong maximumLength, + IntPtr result); + + private void AddInstructionCallbacks(ref BNCustomArchitecture callbacks) + { + callbacks.getInstructionInfo = UnsafeUtils.PinCallback( + this.GetInstructionInfoAdapter); + } + + private bool GetInstructionInfoAdapter( + IntPtr context, + IntPtr data, + ulong address, + ulong maximumLength, + IntPtr result) + { + try + { + byte[] bytes = new byte[checked((int)maximumLength)]; + if (0 != bytes.Length) + { + Marshal.Copy(data, bytes, 0, bytes.Length); + } + + InstructionInfo? info = this.GetInstructionInfo(bytes, address); + if (null == info) + { + return false; + } + + Marshal.StructureToPtr(info.ToNative(), result, false); + + return true; + } + catch (Exception exception) + { + Core.LogError( + "Unhandled exception in CustomArchitecture.GetInstructionInfo: {0}", + exception); + + return false; + } + } + } +} diff --git a/Architecture/CustomArchitectureRegistration.cs b/Architecture/CustomArchitectureRegistration.cs index f417a50d..5492e3a9 100644 --- a/Architecture/CustomArchitectureRegistration.cs +++ b/Architecture/CustomArchitectureRegistration.cs @@ -61,6 +61,7 @@ public Architecture Register(string name) }; this.AddRegisterCallbacks(ref callbacks); this.AddFlagCallbacks(ref callbacks); + this.AddInstructionCallbacks(ref callbacks); using (ScopedAllocator allocator = new ScopedAllocator()) { diff --git a/Struct/BNInstructionInfo.cs b/Struct/BNInstructionInfo.cs index 58889a7b..500b5630 100644 --- a/Struct/BNInstructionInfo.cs +++ b/Struct/BNInstructionInfo.cs @@ -58,21 +58,23 @@ public unsafe struct BNInstructionInfo internal IntPtr branchArch_2; } - public sealed class InstructionInfo - { - public ulong Length { get;} = 0; - - public ulong BranchCount { get;} = 0; + public sealed class InstructionInfo + { + private const int MaximumBranchCount = 3; - public bool ArchTransitionByTargetAddr { get;} = false; - - public byte DelaySlots { get; } = 0; - - public BranchType[] BranchType { get;} = Array.Empty(); - - public ulong[] BranchTarget { get;} = Array.Empty(); - - public Architecture[] BranchArch { get;} = Array.Empty(); + public ulong Length { get; set; } = 0; + + public ulong BranchCount { get; private set; } = 0; + + public bool ArchTransitionByTargetAddr { get; set; } = false; + + public byte DelaySlots { get; set; } = 0; + + public BranchType[] BranchType { get; private set; } = Array.Empty(); + + public ulong[] BranchTarget { get; private set; } = Array.Empty(); + + public Architecture?[] BranchArch { get; private set; } = Array.Empty(); public InstructionInfo() { @@ -83,7 +85,7 @@ public InstructionInfo(BNInstructionInfo native) { this.Length = native.length; - this.BranchCount = native.branchCount; + this.BranchCount = Math.Min(native.branchCount, (ulong)MaximumBranchCount); this.ArchTransitionByTargetAddr = native.archTransitionByTargetAddr; @@ -116,38 +118,89 @@ public InstructionInfo(BNInstructionInfo native) this.BranchTarget = branchTargets.ToArray(); // BranchArch - List branchArches = new List(); + List branchArches = new List(); - if (this.BranchCount >= 1) + if (1 <= this.BranchCount) { - if (IntPtr.Zero != native.branchArch_0) - { - branchArches.Add( new Architecture( native.branchArch_0 ) ); - } + branchArches.Add(Architecture.FromHandle(native.branchArch_0)); } - if (this.BranchCount >= 2) + if (2 <= this.BranchCount) { - if (IntPtr.Zero != native.branchArch_1) - { - branchArches.Add( new Architecture( native.branchArch_1 ) ); - } + branchArches.Add(Architecture.FromHandle(native.branchArch_1)); } - if (this.BranchCount >= 3) + if (3 <= this.BranchCount) { - if (IntPtr.Zero != native.branchArch_2) - { - branchArches.Add( new Architecture( native.branchArch_2 ) ); - } + branchArches.Add(Architecture.FromHandle(native.branchArch_2)); } this.BranchArch = branchArches.ToArray(); } + public void AddBranch( + BranchType type, + ulong target = 0, + Architecture? architecture = null, + byte delaySlots = 0) + { + if (MaximumBranchCount <= this.BranchCount) + { + return; + } + + List branchTypes = new List(this.BranchType); + List branchTargets = new List(this.BranchTarget); + List branchArchitectures = + new List(this.BranchArch); + + branchTypes.Add(type); + branchTargets.Add(target); + branchArchitectures.Add(architecture); + + this.BranchType = branchTypes.ToArray(); + this.BranchTarget = branchTargets.ToArray(); + this.BranchArch = branchArchitectures.ToArray(); + this.BranchCount = (ulong)this.BranchType.Length; + this.DelaySlots = delaySlots; + } + + internal unsafe BNInstructionInfo ToNative() + { + BNInstructionInfo native = new BNInstructionInfo + { + length = this.Length, + branchCount = this.BranchCount, + archTransitionByTargetAddr = this.ArchTransitionByTargetAddr, + delaySlots = this.DelaySlots + }; + + for (int index = 0; index < this.BranchType.Length; index++) + { + native.branchType[index] = (byte)this.BranchType[index]; + native.branchTarget[index] = this.BranchTarget[index]; + } + + native.branchArch_0 = this.GetBranchArchitectureHandle(0); + native.branchArch_1 = this.GetBranchArchitectureHandle(1); + native.branchArch_2 = this.GetBranchArchitectureHandle(2); + + return native; + } + + private IntPtr GetBranchArchitectureHandle(int index) + { + if (this.BranchArch.Length <= index || null == this.BranchArch[index]) + { + return IntPtr.Zero; + } + + return this.BranchArch[index]!.DangerousGetHandle(); + } + internal static InstructionInfo FromNative(BNInstructionInfo native) { return new InstructionInfo(native); } } -} \ No newline at end of file +}