Skip to content

Commit 2cdf24b

Browse files
authored
Add custom architecture assembly callbacks (#149)
1 parent ea07380 commit 2cdf24b

2 files changed

Lines changed: 307 additions & 0 deletions

File tree

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace BinaryNinja
5+
{
6+
public abstract partial class CustomArchitecture
7+
{
8+
private delegate bool ManagedPatchCallback(byte[] data, ulong address);
9+
10+
[UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
11+
[return: MarshalAs(UnmanagedType.I1)]
12+
private delegate bool CanAssembleCallback(IntPtr context);
13+
14+
[UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
15+
[return: MarshalAs(UnmanagedType.I1)]
16+
private delegate bool AssembleCallback(
17+
IntPtr context,
18+
[MarshalAs(UnmanagedType.LPUTF8Str)] string code,
19+
ulong address,
20+
IntPtr result,
21+
IntPtr errors);
22+
23+
[UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
24+
[return: MarshalAs(UnmanagedType.I1)]
25+
private delegate bool PatchCallback(
26+
IntPtr context,
27+
IntPtr data,
28+
ulong address,
29+
ulong length);
30+
31+
[UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
32+
[return: MarshalAs(UnmanagedType.I1)]
33+
private delegate bool SkipAndReturnValueCallback(
34+
IntPtr context,
35+
IntPtr data,
36+
ulong address,
37+
ulong length,
38+
ulong value);
39+
40+
private void AddAssemblyAndPatchCallbacks(ref BNCustomArchitecture callbacks)
41+
{
42+
callbacks.canAssemble = UnsafeUtils.PinCallback<CanAssembleCallback>(
43+
this.CanAssembleAdapter);
44+
callbacks.assemble = UnsafeUtils.PinCallback<AssembleCallback>(this.AssembleAdapter);
45+
callbacks.isNeverBranchPatchAvailable = UnsafeUtils.PinCallback<PatchCallback>(
46+
this.IsNeverBranchPatchAvailableAdapter);
47+
callbacks.isAlwaysBranchPatchAvailable = UnsafeUtils.PinCallback<PatchCallback>(
48+
this.IsAlwaysBranchPatchAvailableAdapter);
49+
callbacks.isInvertBranchPatchAvailable = UnsafeUtils.PinCallback<PatchCallback>(
50+
this.IsInvertBranchPatchAvailableAdapter);
51+
callbacks.isSkipAndReturnZeroPatchAvailable = UnsafeUtils.PinCallback<PatchCallback>(
52+
this.IsSkipAndReturnZeroPatchAvailableAdapter);
53+
callbacks.isSkipAndReturnValuePatchAvailable = UnsafeUtils.PinCallback<PatchCallback>(
54+
this.IsSkipAndReturnValuePatchAvailableAdapter);
55+
callbacks.convertToNop = UnsafeUtils.PinCallback<PatchCallback>(
56+
this.ConvertToNopAdapter);
57+
callbacks.alwaysBranch = UnsafeUtils.PinCallback<PatchCallback>(
58+
this.AlwaysBranchAdapter);
59+
callbacks.invertBranch = UnsafeUtils.PinCallback<PatchCallback>(
60+
this.InvertBranchAdapter);
61+
callbacks.skipAndReturnValue = UnsafeUtils.PinCallback<SkipAndReturnValueCallback>(
62+
this.SkipAndReturnValueAdapter);
63+
}
64+
65+
private bool CanAssembleAdapter(IntPtr context)
66+
{
67+
try
68+
{
69+
return this.CanAssemble();
70+
}
71+
catch (Exception exception)
72+
{
73+
Core.LogError("Unhandled exception in CustomArchitecture.CanAssemble: {0}", exception);
74+
75+
return false;
76+
}
77+
}
78+
79+
private bool AssembleAdapter(
80+
IntPtr context,
81+
string code,
82+
ulong address,
83+
IntPtr result,
84+
IntPtr errors)
85+
{
86+
try
87+
{
88+
byte[] data = this.Assemble(code, address) ?? Array.Empty<byte>();
89+
NativeMethods.BNSetDataBufferContents(result, data, (ulong)data.Length);
90+
Marshal.WriteIntPtr(errors, NativeMethods.BNAllocString(string.Empty));
91+
92+
return true;
93+
}
94+
catch (Exception exception)
95+
{
96+
Core.LogError("Unhandled exception in CustomArchitecture.Assemble: {0}", exception);
97+
NativeMethods.BNSetDataBufferContents(result, Array.Empty<byte>(), 0);
98+
Marshal.WriteIntPtr(errors, NativeMethods.BNAllocString(exception.Message));
99+
100+
return false;
101+
}
102+
}
103+
104+
private bool IsNeverBranchPatchAvailableAdapter(
105+
IntPtr context,
106+
IntPtr data,
107+
ulong address,
108+
ulong length)
109+
{
110+
return this.InvokePatchAvailability(
111+
data,
112+
address,
113+
length,
114+
this.IsNeverBranchPatchAvailable,
115+
"IsNeverBranchPatchAvailable");
116+
}
117+
118+
private bool IsAlwaysBranchPatchAvailableAdapter(
119+
IntPtr context,
120+
IntPtr data,
121+
ulong address,
122+
ulong length)
123+
{
124+
return this.InvokePatchAvailability(
125+
data,
126+
address,
127+
length,
128+
this.IsAlwaysBranchPatchAvailable,
129+
"IsAlwaysBranchPatchAvailable");
130+
}
131+
132+
private bool IsInvertBranchPatchAvailableAdapter(
133+
IntPtr context,
134+
IntPtr data,
135+
ulong address,
136+
ulong length)
137+
{
138+
return this.InvokePatchAvailability(
139+
data,
140+
address,
141+
length,
142+
this.IsInvertBranchPatchAvailable,
143+
"IsInvertBranchPatchAvailable");
144+
}
145+
146+
private bool IsSkipAndReturnZeroPatchAvailableAdapter(
147+
IntPtr context,
148+
IntPtr data,
149+
ulong address,
150+
ulong length)
151+
{
152+
return this.InvokePatchAvailability(
153+
data,
154+
address,
155+
length,
156+
this.IsSkipAndReturnZeroPatchAvailable,
157+
"IsSkipAndReturnZeroPatchAvailable");
158+
}
159+
160+
private bool IsSkipAndReturnValuePatchAvailableAdapter(
161+
IntPtr context,
162+
IntPtr data,
163+
ulong address,
164+
ulong length)
165+
{
166+
return this.InvokePatchAvailability(
167+
data,
168+
address,
169+
length,
170+
this.IsSkipAndReturnValuePatchAvailable,
171+
"IsSkipAndReturnValuePatchAvailable");
172+
}
173+
174+
private bool InvokePatchAvailability(
175+
IntPtr data,
176+
ulong address,
177+
ulong length,
178+
ManagedPatchCallback callback,
179+
string callbackName)
180+
{
181+
try
182+
{
183+
return callback(this.ReadPatchData(data, length), address);
184+
}
185+
catch (Exception exception)
186+
{
187+
Core.LogError(
188+
"Unhandled exception in CustomArchitecture.{0}: {1}",
189+
callbackName,
190+
exception);
191+
192+
return false;
193+
}
194+
}
195+
196+
private bool ConvertToNopAdapter(
197+
IntPtr context,
198+
IntPtr data,
199+
ulong address,
200+
ulong length)
201+
{
202+
return this.InvokePatch(
203+
data,
204+
address,
205+
length,
206+
this.ConvertToNop,
207+
"ConvertToNop");
208+
}
209+
210+
private bool AlwaysBranchAdapter(
211+
IntPtr context,
212+
IntPtr data,
213+
ulong address,
214+
ulong length)
215+
{
216+
return this.InvokePatch(
217+
data,
218+
address,
219+
length,
220+
this.AlwaysBranch,
221+
"AlwaysBranch");
222+
}
223+
224+
private bool InvertBranchAdapter(
225+
IntPtr context,
226+
IntPtr data,
227+
ulong address,
228+
ulong length)
229+
{
230+
return this.InvokePatch(
231+
data,
232+
address,
233+
length,
234+
this.InvertBranch,
235+
"InvertBranch");
236+
}
237+
238+
private bool InvokePatch(
239+
IntPtr data,
240+
ulong address,
241+
ulong length,
242+
ManagedPatchCallback callback,
243+
string callbackName)
244+
{
245+
try
246+
{
247+
byte[] managedData = this.ReadPatchData(data, length);
248+
bool result = callback(managedData, address);
249+
if (result && 0 != managedData.Length)
250+
{
251+
Marshal.Copy(managedData, 0, data, managedData.Length);
252+
}
253+
254+
return result;
255+
}
256+
catch (Exception exception)
257+
{
258+
Core.LogError(
259+
"Unhandled exception in CustomArchitecture.{0}: {1}",
260+
callbackName,
261+
exception);
262+
263+
return false;
264+
}
265+
}
266+
267+
private bool SkipAndReturnValueAdapter(
268+
IntPtr context,
269+
IntPtr data,
270+
ulong address,
271+
ulong length,
272+
ulong value)
273+
{
274+
try
275+
{
276+
byte[] managedData = this.ReadPatchData(data, length);
277+
bool result = this.SkipAndReturnValue(managedData, address, value);
278+
if (result && 0 != managedData.Length)
279+
{
280+
Marshal.Copy(managedData, 0, data, managedData.Length);
281+
}
282+
283+
return result;
284+
}
285+
catch (Exception exception)
286+
{
287+
Core.LogError(
288+
"Unhandled exception in CustomArchitecture.SkipAndReturnValue: {0}",
289+
exception);
290+
291+
return false;
292+
}
293+
}
294+
295+
private byte[] ReadPatchData(IntPtr data, ulong length)
296+
{
297+
byte[] result = new byte[checked((int)length)];
298+
if (0 != result.Length)
299+
{
300+
Marshal.Copy(data, result, 0, result.Length);
301+
}
302+
303+
return result;
304+
}
305+
}
306+
}

Architecture/CustomArchitectureRegistration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public Architecture Register(string name)
6262
this.AddRegisterCallbacks(ref callbacks);
6363
this.AddFlagCallbacks(ref callbacks);
6464
this.AddInstructionCallbacks(ref callbacks);
65+
this.AddAssemblyAndPatchCallbacks(ref callbacks);
6566

6667
using (ScopedAllocator allocator = new ScopedAllocator())
6768
{

0 commit comments

Comments
 (0)