binaryninja/
relocation.rs

1use crate::low_level_il::LowLevelILRegularFunction;
2use crate::rc::Guard;
3use crate::string::IntoCStr;
4use crate::{
5    architecture::CoreArchitecture,
6    binary_view::BinaryView,
7    rc::{CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable},
8    symbol::Symbol,
9};
10use binaryninjacore_sys::*;
11use std::borrow::Borrow;
12use std::mem::MaybeUninit;
13use std::os::raw::c_void;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16pub enum RelocationType {
17    ELFGlobalRelocationType,
18    ELFCopyRelocationType,
19    ELFJumpSlotRelocationType,
20    StandardRelocationType,
21    IgnoredRelocation,
22    UnhandledRelocation,
23}
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
26pub enum RelocationOperand {
27    Operand(usize),
28    AutocoerceExternPtr,
29    NocoerceExternPtr,
30    Invalid,
31}
32
33impl From<BNRelocationType> for RelocationType {
34    fn from(t: BNRelocationType) -> Self {
35        match t {
36            BNRelocationType::ELFGlobalRelocationType => RelocationType::ELFGlobalRelocationType,
37            BNRelocationType::ELFCopyRelocationType => RelocationType::ELFCopyRelocationType,
38            BNRelocationType::ELFJumpSlotRelocationType => {
39                RelocationType::ELFJumpSlotRelocationType
40            }
41            BNRelocationType::StandardRelocationType => RelocationType::StandardRelocationType,
42            BNRelocationType::IgnoredRelocation => RelocationType::IgnoredRelocation,
43            BNRelocationType::UnhandledRelocation => RelocationType::UnhandledRelocation,
44        }
45    }
46}
47
48impl From<RelocationType> for BNRelocationType {
49    fn from(t: RelocationType) -> Self {
50        match t {
51            RelocationType::ELFGlobalRelocationType => BNRelocationType::ELFGlobalRelocationType,
52            RelocationType::ELFCopyRelocationType => BNRelocationType::ELFCopyRelocationType,
53            RelocationType::ELFJumpSlotRelocationType => {
54                BNRelocationType::ELFJumpSlotRelocationType
55            }
56            RelocationType::StandardRelocationType => BNRelocationType::StandardRelocationType,
57            RelocationType::IgnoredRelocation => BNRelocationType::IgnoredRelocation,
58            RelocationType::UnhandledRelocation => BNRelocationType::UnhandledRelocation,
59        }
60    }
61}
62
63impl From<usize> for RelocationOperand {
64    fn from(operand: usize) -> Self {
65        match operand {
66            0xfffffffd => RelocationOperand::AutocoerceExternPtr,
67            0xfffffffe => RelocationOperand::NocoerceExternPtr,
68            0xffffffff => RelocationOperand::Invalid,
69            _ => RelocationOperand::Operand(operand),
70        }
71    }
72}
73
74impl From<RelocationOperand> for usize {
75    fn from(operand: RelocationOperand) -> Self {
76        match operand {
77            RelocationOperand::Operand(operand) => operand,
78            RelocationOperand::AutocoerceExternPtr => 0xfffffffd,
79            RelocationOperand::NocoerceExternPtr => 0xfffffffe,
80            RelocationOperand::Invalid => 0xffffffff,
81        }
82    }
83}
84
85// TODO: How to handle related relocation linked lists?
86#[derive(Clone, Debug)]
87pub struct RelocationInfo {
88    pub type_: RelocationType,
89    pub pc_relative: bool,
90    pub base_relative: bool,
91    pub base: u64,
92    pub size: usize,
93    pub truncate_size: usize,
94    pub native_type: u64,
95    pub addend: usize,
96    pub has_sign: bool,
97    pub implicit_addend: bool,
98    pub external: bool,
99    pub symbol_index: usize,
100    pub section_index: usize,
101    pub address: u64,
102    pub target: u64,
103    pub data_relocation: bool,
104    relocation_data_cache: [u8; MAX_RELOCATION_SIZE as usize],
105}
106
107impl RelocationInfo {
108    pub fn new() -> Self {
109        RelocationInfo {
110            type_: RelocationType::UnhandledRelocation,
111            pc_relative: false,
112            base_relative: false,
113            base: 0,
114            size: 0,
115            truncate_size: 0,
116            native_type: 0,
117            addend: 0,
118            has_sign: false,
119            implicit_addend: false,
120            external: false,
121            symbol_index: 0,
122            section_index: 0,
123            address: 0,
124            target: 0,
125            data_relocation: false,
126            relocation_data_cache: [0; MAX_RELOCATION_SIZE as usize],
127        }
128    }
129
130    pub(crate) fn from_raw(reloc: &BNRelocationInfo) -> Self {
131        RelocationInfo {
132            type_: reloc.type_.into(),
133            pc_relative: reloc.pcRelative,
134            base_relative: reloc.baseRelative,
135            base: reloc.base,
136            size: reloc.size,
137            truncate_size: reloc.truncateSize,
138            native_type: reloc.nativeType,
139            addend: reloc.addend,
140            has_sign: reloc.hasSign,
141            implicit_addend: reloc.implicitAddend,
142            external: reloc.external,
143            symbol_index: reloc.symbolIndex,
144            section_index: reloc.sectionIndex,
145            address: reloc.address,
146            target: reloc.target,
147            data_relocation: reloc.dataRelocation,
148            relocation_data_cache: reloc.relocationDataCache,
149        }
150    }
151
152    pub(crate) fn as_raw(&self) -> BNRelocationInfo {
153        BNRelocationInfo {
154            type_: self.type_.into(),
155            pcRelative: self.pc_relative,
156            baseRelative: self.base_relative,
157            base: self.base,
158            size: self.size,
159            truncateSize: self.truncate_size,
160            nativeType: self.native_type,
161            addend: self.addend,
162            hasSign: self.has_sign,
163            implicitAddend: self.implicit_addend,
164            external: self.external,
165            symbolIndex: self.symbol_index,
166            sectionIndex: self.section_index,
167            address: self.address,
168            target: self.target,
169            dataRelocation: self.data_relocation,
170            relocationDataCache: self.relocation_data_cache,
171            // TODO: How to handle this?
172            prev: core::ptr::null_mut(),
173            next: core::ptr::null_mut(),
174        }
175    }
176}
177
178impl Default for RelocationInfo {
179    fn default() -> Self {
180        Self::new()
181    }
182}
183
184// TODO: There is NO freeing of the relocation
185// TODO: A quick look it seem that the relocation ptr is always not owned so this is _fine_
186// TODO: REALLY need to come back to this at some point.
187pub struct Relocation(*mut BNRelocation);
188
189impl Relocation {
190    pub(crate) unsafe fn from_raw(reloc: *mut BNRelocation) -> Self {
191        Relocation(reloc)
192    }
193
194    pub fn info(&self) -> RelocationInfo {
195        RelocationInfo::from_raw(unsafe { &BNRelocationGetInfo(self.0) })
196    }
197
198    pub fn architecture(&self) -> Option<CoreArchitecture> {
199        let raw = unsafe { BNRelocationGetArchitecture(self.0) };
200        if raw.is_null() {
201            return None;
202        }
203
204        Some(unsafe { CoreArchitecture::from_raw(raw) })
205    }
206
207    pub fn target(&self) -> u64 {
208        unsafe { BNRelocationGetTarget(self.0) }
209    }
210
211    pub fn address(&self) -> u64 {
212        unsafe { BNRelocationGetReloc(self.0) }
213    }
214
215    pub fn symbol(&self) -> Option<Ref<Symbol>> {
216        let raw = unsafe { BNRelocationGetSymbol(self.0) };
217        if raw.is_null() {
218            return None;
219        }
220
221        Some(unsafe { Symbol::ref_from_raw(raw) })
222    }
223}
224
225impl CoreArrayProvider for Relocation {
226    type Raw = *mut BNRelocation;
227    type Context = ();
228    type Wrapped<'a> = Guard<'a, Relocation>;
229}
230
231unsafe impl CoreArrayProviderInner for Relocation {
232    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
233        BNFreeRelocationList(raw, count);
234    }
235
236    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
237        Guard::new(Relocation(*raw), &())
238    }
239}
240
241pub trait RelocationHandler: 'static + Sized + AsRef<CoreRelocationHandler> {
242    type Handle: Borrow<Self>;
243
244    fn get_relocation_info(
245        &self,
246        _bv: &BinaryView,
247        _arch: &CoreArchitecture,
248        _info: &mut [RelocationInfo],
249    ) -> bool {
250        false
251    }
252
253    fn apply_relocation(
254        &self,
255        bv: &BinaryView,
256        arch: &CoreArchitecture,
257        reloc: &Relocation,
258        dest: &mut [u8],
259    ) -> bool {
260        self.default_apply_relocation(bv, arch, reloc, dest)
261    }
262
263    fn get_operand_for_external_relocation(
264        &self,
265        _data: &[u8],
266        _addr: u64,
267        // TODO: Are we sure this is not a liftedilfunction?
268        _il: &LowLevelILRegularFunction,
269        _reloc: &Relocation,
270    ) -> RelocationOperand {
271        RelocationOperand::AutocoerceExternPtr
272    }
273
274    fn handle(&self) -> Self::Handle;
275}
276
277pub trait RelocationHandlerExt: RelocationHandler {
278    fn default_apply_relocation(
279        &self,
280        bv: &BinaryView,
281        arch: &CoreArchitecture,
282        reloc: &Relocation,
283        dest: &mut [u8],
284    ) -> bool {
285        unsafe {
286            BNRelocationHandlerDefaultApplyRelocation(
287                self.as_ref().0,
288                bv.handle,
289                arch.handle,
290                reloc.0,
291                dest.as_mut_ptr(),
292                dest.len(),
293            )
294        }
295    }
296}
297
298impl<T: RelocationHandler> RelocationHandlerExt for T {}
299
300#[derive(Eq, PartialEq, Hash, Debug)]
301pub struct CoreRelocationHandler(*mut BNRelocationHandler);
302
303unsafe impl Send for CoreRelocationHandler {}
304unsafe impl Sync for CoreRelocationHandler {}
305
306impl CoreRelocationHandler {
307    pub(crate) unsafe fn ref_from_raw(raw: *mut BNRelocationHandler) -> Ref<Self> {
308        unsafe { Ref::new(CoreRelocationHandler(raw)) }
309    }
310}
311
312impl AsRef<CoreRelocationHandler> for CoreRelocationHandler {
313    fn as_ref(&self) -> &Self {
314        self
315    }
316}
317
318impl RelocationHandler for CoreRelocationHandler {
319    type Handle = Self;
320
321    fn get_relocation_info(
322        &self,
323        bv: &BinaryView,
324        arch: &CoreArchitecture,
325        info: &mut [RelocationInfo],
326    ) -> bool {
327        let mut raw_info = info.iter().map(|i| i.as_raw()).collect::<Vec<_>>();
328        let res = unsafe {
329            BNRelocationHandlerGetRelocationInfo(
330                self.0,
331                bv.handle,
332                arch.handle,
333                raw_info.as_mut_ptr(),
334                raw_info.len(),
335            )
336        };
337        for (info, raw) in info.iter_mut().zip(raw_info.iter()) {
338            *info = RelocationInfo::from_raw(raw);
339        }
340        res
341    }
342
343    fn apply_relocation(
344        &self,
345        bv: &BinaryView,
346        arch: &CoreArchitecture,
347        reloc: &Relocation,
348        dest: &mut [u8],
349    ) -> bool {
350        unsafe {
351            BNRelocationHandlerApplyRelocation(
352                self.0,
353                bv.handle,
354                arch.handle,
355                reloc.0,
356                dest.as_mut_ptr(),
357                dest.len(),
358            )
359        }
360    }
361
362    fn get_operand_for_external_relocation(
363        &self,
364        data: &[u8],
365        addr: u64,
366        il: &LowLevelILRegularFunction,
367        reloc: &Relocation,
368    ) -> RelocationOperand {
369        unsafe {
370            BNRelocationHandlerGetOperandForExternalRelocation(
371                self.0,
372                data.as_ptr(),
373                addr,
374                data.len(),
375                il.handle,
376                reloc.0,
377            )
378            .into()
379        }
380    }
381
382    fn handle(&self) -> CoreRelocationHandler {
383        CoreRelocationHandler(self.0)
384    }
385}
386
387impl ToOwned for CoreRelocationHandler {
388    type Owned = Ref<Self>;
389
390    fn to_owned(&self) -> Self::Owned {
391        unsafe { RefCountable::inc_ref(self) }
392    }
393}
394
395unsafe impl RefCountable for CoreRelocationHandler {
396    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
397        Ref::new(Self(BNNewRelocationHandlerReference(handle.0)))
398    }
399
400    unsafe fn dec_ref(handle: &Self) {
401        BNFreeRelocationHandler(handle.0);
402    }
403}
404
405pub(crate) fn register_relocation_handler<R, F>(arch: &CoreArchitecture, name: &str, func: F)
406where
407    R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync + Sized,
408    F: FnOnce(CustomRelocationHandlerHandle<R>, CoreRelocationHandler) -> R,
409{
410    #[repr(C)]
411    struct RelocationHandlerBuilder<R>
412    where
413        R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
414    {
415        handler: R,
416    }
417
418    extern "C" fn cb_free<R>(ctxt: *mut c_void)
419    where
420        R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
421    {
422        unsafe {
423            let _handler = Box::from_raw(ctxt as *mut RelocationHandlerBuilder<R>);
424        }
425    }
426
427    extern "C" fn cb_get_relocation_info<R>(
428        ctxt: *mut c_void,
429        bv: *mut BNBinaryView,
430        arch: *mut BNArchitecture,
431        result: *mut BNRelocationInfo,
432        count: usize,
433    ) -> bool
434    where
435        R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
436    {
437        let custom_handler = unsafe { &*(ctxt as *mut R) };
438        let bv = unsafe { BinaryView::ref_from_raw(BNNewViewReference(bv)) };
439        let arch = unsafe { CoreArchitecture::from_raw(arch) };
440        let result = unsafe { core::slice::from_raw_parts_mut(result, count) };
441        let mut info = result
442            .iter()
443            .map(RelocationInfo::from_raw)
444            .collect::<Vec<_>>();
445        let ok =
446            custom_handler.get_relocation_info(bv.as_ref(), arch.as_ref(), info.as_mut_slice());
447        for (result, info) in result.iter_mut().zip(info.iter()) {
448            *result = info.as_raw();
449        }
450        ok
451    }
452
453    extern "C" fn cb_apply_relocation<R>(
454        ctxt: *mut c_void,
455        bv: *mut BNBinaryView,
456        arch: *mut BNArchitecture,
457        reloc: *mut BNRelocation,
458        dest: *mut u8,
459        len: usize,
460    ) -> bool
461    where
462        R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
463    {
464        let custom_handler = unsafe { &*(ctxt as *mut R) };
465        let bv = unsafe { BinaryView::ref_from_raw(BNNewViewReference(bv)) };
466        let arch = unsafe { CoreArchitecture::from_raw(arch) };
467        let reloc = unsafe { Relocation::from_raw(reloc) };
468        let dest = unsafe { core::slice::from_raw_parts_mut(dest, len) };
469        custom_handler.apply_relocation(bv.as_ref(), arch.as_ref(), &reloc, dest)
470    }
471
472    extern "C" fn cb_get_operand_for_external_relocation<R>(
473        ctxt: *mut c_void,
474        data: *const u8,
475        addr: u64,
476        len: usize,
477        il: *mut BNLowLevelILFunction,
478        reloc: *mut BNRelocation,
479    ) -> usize
480    where
481        R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
482    {
483        let custom_handler = unsafe { &*(ctxt as *mut R) };
484        let data = unsafe { core::slice::from_raw_parts(data, len) };
485        let reloc = unsafe { Relocation::from_raw(reloc) };
486
487        let func = unsafe { BNGetLowLevelILOwnerFunction(il) };
488        if func.is_null() {
489            return RelocationOperand::Invalid.into();
490        }
491
492        let arch = unsafe { BNGetFunctionArchitecture(func) };
493        unsafe { BNFreeFunction(func) };
494        if arch.is_null() {
495            return RelocationOperand::Invalid.into();
496        }
497        let arch = unsafe { CoreArchitecture::from_raw(arch) };
498        let il = unsafe { LowLevelILRegularFunction::from_raw_with_arch(il, Some(arch)) };
499
500        custom_handler
501            .get_operand_for_external_relocation(data, addr, &il, &reloc)
502            .into()
503    }
504
505    let name = name.to_cstr();
506
507    let raw = Box::leak(Box::new(
508        MaybeUninit::<RelocationHandlerBuilder<_>>::zeroed(),
509    ));
510    let mut custom_handler = BNCustomRelocationHandler {
511        context: raw.as_mut_ptr() as *mut _,
512        freeObject: Some(cb_free::<R>),
513        getRelocationInfo: Some(cb_get_relocation_info::<R>),
514        applyRelocation: Some(cb_apply_relocation::<R>),
515        getOperandForExternalRelocation: Some(cb_get_operand_for_external_relocation::<R>),
516    };
517
518    let handle_raw = unsafe { BNCreateRelocationHandler(&mut custom_handler) };
519    assert!(!handle_raw.is_null());
520    let handle = CoreRelocationHandler(handle_raw);
521    let custom_handle = CustomRelocationHandlerHandle {
522        handle: raw.as_mut_ptr() as *mut R,
523    };
524    unsafe {
525        raw.write(RelocationHandlerBuilder {
526            handler: func(custom_handle, CoreRelocationHandler(handle.0)),
527        });
528
529        BNArchitectureRegisterRelocationHandler(
530            arch.handle,
531            name.as_ref().as_ptr() as *const _,
532            handle.handle().as_ref().0,
533        );
534    }
535}
536
537pub struct CustomRelocationHandlerHandle<R>
538where
539    R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
540{
541    handle: *mut R,
542}
543
544unsafe impl<R> Send for CustomRelocationHandlerHandle<R> where
545    R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync
546{
547}
548
549unsafe impl<R> Sync for CustomRelocationHandlerHandle<R> where
550    R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync
551{
552}
553
554impl<R> Clone for CustomRelocationHandlerHandle<R>
555where
556    R: 'static + RelocationHandler<Handle = Self> + Send + Sync,
557{
558    fn clone(&self) -> Self {
559        *self
560    }
561}
562
563impl<R> Copy for CustomRelocationHandlerHandle<R> where
564    R: 'static + RelocationHandler<Handle = Self> + Send + Sync
565{
566}
567
568impl<R> Borrow<R> for CustomRelocationHandlerHandle<R>
569where
570    R: 'static + RelocationHandler<Handle = Self> + Send + Sync,
571{
572    fn borrow(&self) -> &R {
573        unsafe { &*self.handle }
574    }
575}