From 52f550704e0b3b6186c39cd31d13e2363d2318d3 Mon Sep 17 00:00:00 2001 From: tinysec Date: Thu, 23 Jul 2026 11:36:39 +0800 Subject: [PATCH] Add custom architecture instruction text --- .../CustomArchitectureInstructionCallbacks.cs | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/Architecture/CustomArchitectureInstructionCallbacks.cs b/Architecture/CustomArchitectureInstructionCallbacks.cs index 7c73bf3..b3e2fb8 100644 --- a/Architecture/CustomArchitectureInstructionCallbacks.cs +++ b/Architecture/CustomArchitectureInstructionCallbacks.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; namespace BinaryNinja @@ -14,10 +15,208 @@ private delegate bool GetInstructionInfoCallback( ulong maximumLength, IntPtr result); + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool GetInstructionTextCallback( + IntPtr context, + IntPtr data, + ulong address, + ref ulong length, + out IntPtr tokens, + out ulong count); + + [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)] + private delegate void FreeInstructionTextCallback(IntPtr tokens, ulong count); + private void AddInstructionCallbacks(ref BNCustomArchitecture callbacks) { callbacks.getInstructionInfo = UnsafeUtils.PinCallback( this.GetInstructionInfoAdapter); + callbacks.getInstructionText = UnsafeUtils.PinCallback( + this.GetInstructionTextAdapter); + callbacks.freeInstructionText = UnsafeUtils.PinCallback( + this.FreeInstructionTextAdapter); + } + + private bool GetInstructionTextAdapter( + IntPtr context, + IntPtr data, + ulong address, + ref ulong length, + out IntPtr tokens, + out ulong count) + { + tokens = IntPtr.Zero; + count = 0; + + try + { + ulong maximumLength = length; + byte[] bytes = new byte[checked((int)maximumLength)]; + if (0 != bytes.Length) + { + Marshal.Copy(data, bytes, 0, bytes.Length); + } + + InstructionTextToken[] managedTokens = + this.GetInstructionText(bytes, address, out ulong decodedLength) + ?? Array.Empty(); + if (0 == decodedLength || maximumLength < decodedLength) + { + return false; + } + + tokens = this.AllocateInstructionText(managedTokens); + count = (ulong)managedTokens.Length; + length = decodedLength; + + return true; + } + catch (Exception exception) + { + Core.LogError( + "Unhandled exception in CustomArchitecture.GetInstructionText: {0}", + exception); + tokens = IntPtr.Zero; + count = 0; + + return false; + } + } + + private IntPtr AllocateInstructionText(InstructionTextToken[] tokens) + { + BNInstructionTextToken[] nativeTokens = new BNInstructionTextToken[tokens.Length]; + List allocatedStrings = new List(); + List allocatedArrays = new List(); + + try + { + for (int index = 0; index < tokens.Length; index++) + { + InstructionTextToken token = tokens[index]; + IntPtr text = NativeMethods.BNAllocString(token.Text); + allocatedStrings.Add(text); + + IntPtr typeNames = this.AllocateTypeNames( + token.TypeNames, + allocatedStrings); + if (IntPtr.Zero != typeNames) + { + allocatedArrays.Add(typeNames); + } + + nativeTokens[index] = new BNInstructionTextToken + { + type = token.Type, + text = text, + value = token.Value, + width = token.Width, + size = token.Size, + operand = token.Operand, + context = token.Context, + confidence = token.Confidence, + address = token.Address, + typeNames = typeNames, + namesCount = (ulong)token.TypeNames.Length, + exprIndex = token.ExpressionIndex + }; + } + + return UnsafeUtils.AllocStructArray(nativeTokens); + } + catch + { + this.FreeAllocatedInstructionText(allocatedStrings, allocatedArrays); + throw; + } + } + + private IntPtr AllocateTypeNames( + string[] typeNames, + List allocatedStrings) + { + if (0 == typeNames.Length) + { + return IntPtr.Zero; + } + + IntPtr result = Marshal.AllocHGlobal(checked(typeNames.Length * IntPtr.Size)); + try + { + for (int index = 0; index < typeNames.Length; index++) + { + IntPtr name = NativeMethods.BNAllocString(typeNames[index]); + allocatedStrings.Add(name); + Marshal.WriteIntPtr(result, checked(index * IntPtr.Size), name); + } + + return result; + } + catch + { + Marshal.FreeHGlobal(result); + throw; + } + } + + private void FreeAllocatedInstructionText( + List strings, + List arrays) + { + foreach (IntPtr text in strings) + { + if (IntPtr.Zero != text) + { + NativeMethods.BNFreeString(text); + } + } + + foreach (IntPtr array in arrays) + { + Marshal.FreeHGlobal(array); + } + } + + private void FreeInstructionTextAdapter(IntPtr tokens, ulong count) + { + if (IntPtr.Zero == tokens) + { + return; + } + + int tokenSize = Marshal.SizeOf(); + for (ulong index = 0; index < count; index++) + { + IntPtr tokenPointer = IntPtr.Add( + tokens, + checked((int)(index * (ulong)tokenSize))); + BNInstructionTextToken token = + Marshal.PtrToStructure(tokenPointer); + + if (IntPtr.Zero != token.text) + { + NativeMethods.BNFreeString(token.text); + } + + for (ulong nameIndex = 0; nameIndex < token.namesCount; nameIndex++) + { + IntPtr name = Marshal.ReadIntPtr( + token.typeNames, + checked((int)(nameIndex * (ulong)IntPtr.Size))); + if (IntPtr.Zero != name) + { + NativeMethods.BNFreeString(name); + } + } + + if (IntPtr.Zero != token.typeNames) + { + Marshal.FreeHGlobal(token.typeNames); + } + } + + Marshal.FreeHGlobal(tokens); } private bool GetInstructionInfoAdapter(