1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use core::ptr;

/// Obfuscates the xref to static data.
///
/// ```
/// static FOO: i32 = 42;
/// let foo = obfstr::xref!(&FOO);
///
/// // When looking at the disassembly the reference to `FOO` has been obfuscated.
/// assert_eq!(foo as *const _, &FOO as *const _);
/// ```
#[macro_export]
macro_rules! xref {
	($e:expr) => { $crate::xref($e, $crate::random!(usize) & 0xffff) };
}

/// Obfuscates the xref to static data.
///
/// The offset can be initialized with [`random!`] for a compiletime random value.
///
/// ```
/// static FOO: i32 = 42;
/// let foo = obfstr::xref(&FOO, 0x123);
///
/// // When looking at the disassembly the reference to `FOO` has been obfuscated.
/// assert_eq!(foo as *const _, &FOO as *const _);
/// ```
#[inline(always)]
pub fn xref<T: ?Sized>(p: &'static T, offset: usize) -> &'static T {
	unsafe {
		let mut p: *const T = p;
		// To avoid LLMV optimizing away the obfuscation, launder it through read_volatile
		let val = ptr::read_volatile(&(p as *const u8).wrapping_sub(offset)).wrapping_add(offset);
		// set_ptr_value
		*(&mut p as *mut *const T as *mut *const u8) = val;
		&*p
	}
}

/// Obfuscates the xref to static data.
///
/// ```
/// static mut FOO: i32 = 42;
/// let foo = obfstr::xref_mut!(unsafe { &mut FOO });
///
/// // When looking at the disassembly the reference to `FOO` has been obfuscated.
/// assert_eq!(foo as *mut _, unsafe { &mut FOO } as *mut _);
/// ```
#[macro_export]
macro_rules! xref_mut {
	($e:expr) => { $crate::xref_mut($e, $crate::random!(usize) & 0xffff) };
}

/// Obfuscates the xref to static data.
///
/// The offset can be initialized with [`random!`] for a compiletime random value.
///
/// ```
/// static mut FOO: i32 = 42;
/// let foo = obfstr::xref_mut(unsafe { &mut FOO }, 0x321);
///
/// // When looking at the disassembly the reference to `FOO` has been obfuscated.
/// assert_eq!(foo as *mut _, unsafe { &mut FOO } as *mut _);
/// ```
#[inline(always)]
pub fn xref_mut<T: ?Sized>(p: &'static mut T, offset: usize) -> &'static mut T {
	unsafe {
		let mut p: *mut T = p;
		// To avoid LLMV optimizing away the obfuscation, launder it through read_volatile
		let val = ptr::read_volatile(&(p as *mut u8).wrapping_sub(offset)).wrapping_add(offset);
		// set_ptr_value
		*(&mut p as *mut *mut T as *mut *mut u8) = val;
		&mut *p
	}
}

#[test]
fn test_xref_slice() {
	static FOO: [i32; 42] = [13; 42];
	let foo = xref::<[i32]>(&FOO[..], 0x1000);
	assert_eq!(foo as *const _, &FOO as *const _);
}