Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions Architecture/CustomArchitectureAnalysisCallbacks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,27 @@ private delegate void AnalyzeBasicBlocksCallback(
IntPtr function,
IntPtr analysisContext);

[UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private delegate bool LiftFunctionCallback(
IntPtr context,
IntPtr function,
IntPtr lifterContext);

[UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
private delegate void FreeFunctionArchitectureContextCallback(
IntPtr context,
IntPtr functionContext);

private void AddAnalysisCallbacks(ref BNCustomArchitecture callbacks)
{
callbacks.analyzeBasicBlocks = UnsafeUtils.PinCallback<AnalyzeBasicBlocksCallback>(
this.AnalyzeBasicBlocksAdapter);
callbacks.liftFunction = UnsafeUtils.PinCallback<LiftFunctionCallback>(
this.LiftFunctionAdapter);
callbacks.freeFunctionArchContext =
UnsafeUtils.PinCallback<FreeFunctionArchitectureContextCallback>(
this.FreeFunctionArchitectureContextAdapter);
}

private void AnalyzeBasicBlocksAdapter(
Expand All @@ -38,5 +55,46 @@ private void AnalyzeBasicBlocksAdapter(
exception);
}
}

private bool LiftFunctionAdapter(
IntPtr context,
IntPtr functionHandle,
IntPtr lifterContextHandle)
{
try
{
using (LowLevelILFunction function =
this.CreateCallbackLowLevelIL(functionHandle))
{
FunctionLifterContext lifterContext = new FunctionLifterContext(
lifterContextHandle,
function);
return this.LiftFunction(function, lifterContext);
}
}
catch (Exception exception)
{
Core.LogError(
"Unhandled exception in CustomArchitecture.LiftFunction: {0}",
exception);
return false;
}
}

private void FreeFunctionArchitectureContextAdapter(
IntPtr context,
IntPtr functionContext)
{
try
{
this.FreeFunctionArchContext(functionContext);
}
catch (Exception exception)
{
Core.LogError(
"Unhandled exception in CustomArchitecture.FreeFunctionArchContext: {0}",
exception);
}
}
}
}
267 changes: 267 additions & 0 deletions Architecture/FunctionLifterContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
using System;
using System.Runtime.InteropServices;

namespace BinaryNinja
{
/// <summary>
/// Provides the native-owned context passed to custom architecture function lifting.
/// </summary>
public sealed class FunctionLifterContext
{
private readonly IntPtr handle;
private readonly LowLevelILFunction destination;

internal FunctionLifterContext(
IntPtr handle,
LowLevelILFunction destination)
{
if (IntPtr.Zero == handle)
{
throw new ArgumentNullException(nameof(handle));
}

this.handle = handle;
this.destination = destination
?? throw new ArgumentNullException(nameof(destination));
}

internal IntPtr DangerousGetHandle()
{
return this.handle;
}

private BNFunctionLifterContext Native
{
get
{
return Marshal.PtrToStructure<BNFunctionLifterContext>(this.handle);
}
}

/// <summary>
/// Gets an independently referenced wrapper for the target platform.
/// </summary>
public Platform Platform
{
get
{
return BinaryNinja.Platform.MustNewFromHandle(this.Native.platform);
}
}

/// <summary>
/// Gets an independently referenced wrapper for the analysis logger.
/// </summary>
public Logger Logger
{
get
{
return BinaryNinja.Logger.MustNewFromHandle(this.Native.logger);
}
}

/// <summary>
/// Gets independently referenced wrappers for the function's basic blocks.
/// </summary>
public BasicBlock[] BasicBlocks
{
get
{
BNFunctionLifterContext native = this.Native;
return UnsafeUtils.ReadHandleArray(
native.basicBlocks,
native.basicBlockCount,
BasicBlock.MustNewFromHandle);
}
}

public ArchitectureAndAddress[] InlinedRemappingKeys
{
get
{
BNFunctionLifterContext native = this.Native;
return this.ReadLocations(
native.inlinedRemappingKeys,
native.inlinedRemappingEntryCount);
}
}

public ArchitectureAndAddress[] InlinedRemappingValues
{
get
{
BNFunctionLifterContext native = this.Native;
return this.ReadLocations(
native.inlinedRemappingValues,
native.inlinedRemappingEntryCount);
}
}

public IndirectBranchInfo[] IndirectBranches
{
get
{
BNFunctionLifterContext native = this.Native;
return UnsafeUtils.ReadStructArray<BNIndirectBranchInfo, IndirectBranchInfo>(
native.indirectBranches,
native.indirectBranchesCount,
IndirectBranchInfo.FromNative);
}
}

public ArchitectureAndAddress[] NoReturnCalls
{
get
{
BNFunctionLifterContext native = this.Native;
return this.ReadLocations(
native.noReturnCalls,
native.noReturnCallsCount);
}
}

public ArchitectureAndAddress[] ContextualFunctionReturnLocations
{
get
{
BNFunctionLifterContext native = this.Native;
return this.ReadLocations(
native.contextualFunctionReturnLocations,
native.contextualFunctionReturnCount);
}
}

public bool[] ContextualFunctionReturnValues
{
get
{
BNFunctionLifterContext native = this.Native;
return UnsafeUtils.ReadBoolArray(
native.contextualFunctionReturnValues,
native.contextualFunctionReturnCount);
}
}

public ulong[] InlinedCalls
{
get
{
BNFunctionLifterContext native = this.Native;
return UnsafeUtils.ReadNumberArray<ulong>(
native.inlinedCalls,
native.inlinedCallsCount);
}
}

public IntPtr FunctionArchitectureContext
{
get
{
return this.Native.functionArchContext;
}
}

public bool ContainsInlinedFunctions
{
get
{
IntPtr value = this.Native.containsInlinedFunctions;
return IntPtr.Zero != value && UnsafeUtils.ReadBool(value);
}
set
{
IntPtr destination = this.Native.containsInlinedFunctions;
if (IntPtr.Zero == destination)
{
throw new InvalidOperationException(
"The lifter context does not provide an inline-result pointer.");
}

Marshal.WriteByte(destination, value ? (byte)1 : (byte)0);
}
}

public void PrepareBlockTranslation(
LowLevelILFunction function,
Architecture architecture,
ulong address)
{
if (null == function)
{
throw new ArgumentNullException(nameof(function));
}

if (null == architecture)
{
throw new ArgumentNullException(nameof(architecture));
}

NativeMethods.BNPrepareBlockTranslation(
function.DangerousGetHandle(),
architecture.DangerousGetHandle(),
address);
}

public unsafe BasicBlock[] PrepareToCopyForeignFunction(
LowLevelILFunction source)
{
if (null == source)
{
throw new ArgumentNullException(nameof(source));
}

ulong count = 0;
IntPtr blocks = NativeMethods.BNPrepareToCopyForeignFunction(
this.destination.DangerousGetHandle(),
source.DangerousGetHandle(),
(IntPtr)(&count));
try
{
return UnsafeUtils.ReadHandleArray(
blocks,
count,
BasicBlock.MustNewFromHandle);
}
finally
{
if (IntPtr.Zero != blocks)
{
NativeMethods.BNFreeBasicBlockList(blocks, count);
}
}
}

public LowLevelILFunction? GetForeignFunctionLiftedIL(Function function)
{
if (null == function)
{
throw new ArgumentNullException(nameof(function));
}

BNFunctionLifterContext native = this.Native;
ulong[] inlinedCalls = this.InlinedCalls;
using (ScopedAllocator allocator = new ScopedAllocator())
{
IntPtr result = NativeMethods.BNGetForeignFunctionLiftedIL(
function.DangerousGetHandle(),
native.logger,
new UIntPtr((ulong)inlinedCalls.Length),
allocator.AllocStructArray(inlinedCalls));
return LowLevelILFunction.TakeHandle(
result,
false,
function.Architecture);
}
}

private ArchitectureAndAddress[] ReadLocations(IntPtr locations, ulong count)
{
return UnsafeUtils.ReadStructArray<
BNArchitectureAndAddress,
ArchitectureAndAddress>(
locations,
count,
ArchitectureAndAddress.FromNative);
}
}
}
19 changes: 19 additions & 0 deletions Struct/BNCustomArchitecture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,25 @@ public virtual void AnalyzeBasicBlocks(
function.DangerousGetHandle(),
context.DangerousGetHandle());
}

/// <summary>
/// Lifts a function using the core-owned function-level lifting context.
/// </summary>
public virtual bool LiftFunction(
LowLevelILFunction function,
FunctionLifterContext context)
{
return NativeMethods.BNArchitectureDefaultLiftFunction(
function.DangerousGetHandle(),
context.DangerousGetHandle());
}

/// <summary>
/// Releases architecture-specific context created during basic-block analysis.
/// </summary>
public virtual void FreeFunctionArchContext(IntPtr context)
{
}

public virtual string GetRegisterName(
RegisterIndex reg
Expand Down
28 changes: 28 additions & 0 deletions Struct/BNFunctionLifterContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Runtime.InteropServices;

namespace BinaryNinja
{
[StructLayout(LayoutKind.Sequential)]
internal struct BNFunctionLifterContext
{
internal IntPtr platform;
internal IntPtr logger;
internal ulong basicBlockCount;
internal IntPtr basicBlocks;
internal ulong inlinedRemappingEntryCount;
internal IntPtr inlinedRemappingKeys;
internal IntPtr inlinedRemappingValues;
internal ulong indirectBranchesCount;
internal IntPtr indirectBranches;
internal ulong noReturnCallsCount;
internal IntPtr noReturnCalls;
internal ulong contextualFunctionReturnCount;
internal IntPtr contextualFunctionReturnLocations;
internal IntPtr contextualFunctionReturnValues;
internal ulong inlinedCallsCount;
internal IntPtr inlinedCalls;
internal IntPtr functionArchContext;
internal IntPtr containsInlinedFunctions;
}
}
Loading