Skip to content

Commit

Permalink
Update xref obfuscation (#48)
Browse files Browse the repository at this point in the history
Also eliminates bound checks in murmur3.

Closes #46
  • Loading branch information
CasualX authored Mar 2, 2023
1 parent cf45dbb commit 697d9ad
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 25 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "obfstr"
version = "0.4.1"
version = "0.4.2"
edition = "2021"
license = "MIT"

Expand Down
26 changes: 15 additions & 11 deletions src/murmur3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Expose MurmurHash3, a keyed hash function. Not ready for public API.
*/

use core::slice;

/// MurmurHash3 (32-bit variant) keyed hash function.
#[doc(hidden)]
#[macro_export]
Expand All @@ -13,14 +15,14 @@ macro_rules! murmur3 {
/// MurmurHash3 (32-bit variant) keyed hash function.
#[doc(hidden)]
#[inline]
pub const fn murmur3(s: &[u8], seed: u32) -> u32 {
pub const fn murmur3(string: &[u8], seed: u32) -> u32 {
let mut h = seed;
const C1: u32 = 0xcc9e2d51;
const C2: u32 = 0x1b873593;

let mut i = 0;
while i < s.len() & !3 {
let mut k = u32::from_le_bytes([s[i + 0], s[i + 1], s[i + 2], s[i + 3]]);
let mut s = string;
while s.len() >= 4 {
let mut k = u32::from_le_bytes([s[0], s[1], s[2], s[3]]);
k = k.wrapping_mul(C1);
k = k.rotate_left(15);
k = k.wrapping_mul(C2);
Expand All @@ -29,20 +31,22 @@ pub const fn murmur3(s: &[u8], seed: u32) -> u32 {
h = h.rotate_left(13);
h = h.wrapping_mul(5).wrapping_add(0xe6546b64);

i += 4;
// The slicing operator isn't stable in const fn
// s = &s[4..];
s = unsafe { slice::from_raw_parts(s.as_ptr().add(4), s.len() - 4)};
}

if s.len() % 4 != 0 {
let k = match s.len() % 4 {
3 => u32::from_le_bytes([s[i + 0], s[i + 1], s[i + 2], 0]),
2 => u32::from_le_bytes([s[i + 0], s[i + 1], 0, 0]),
1 => u32::from_le_bytes([s[i + 0], 0, 0, 0]),
if s.len() > 0 {
let k = match s.len() {
3 => u32::from_le_bytes([s[0], s[1], s[2], 0]),
2 => u32::from_le_bytes([s[0], s[1], 0, 0]),
1 => u32::from_le_bytes([s[0], 0, 0, 0]),
_ => 0/*unreachable!()*/,
};
h ^= k.wrapping_mul(C1).rotate_left(15).wrapping_mul(C2);
}

fmix32(h ^ s.len() as u32)
fmix32(h ^ string.len() as u32)
}

#[inline]
Expand Down
25 changes: 12 additions & 13 deletions src/xref.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::{hint, ptr};
use core::hint;

/// Obfuscates the xref to static data.
///
Expand All @@ -20,8 +20,7 @@ macro_rules! xref {
macro_rules! __xref {
($offset:expr, $seed:expr, $e:expr) => {{
const _XREF_OFFSET: usize = $offset;
static mut _XREF_STATIC_MUT_OFFSET: usize = _XREF_OFFSET;
$crate::xref::xref::<_, _XREF_OFFSET, {$seed}>($e, unsafe { &mut _XREF_STATIC_MUT_OFFSET })
$crate::xref::xref::<_, _XREF_OFFSET, {$seed}>(::core::hint::black_box($e), ::core::hint::black_box(_XREF_OFFSET))
}};
}

Expand All @@ -46,7 +45,8 @@ const fn obfchoice(v: usize, seed: u64) -> usize {
}
}
#[inline(always)]
const fn obfuscate(mut v: usize, mut seed: u64) -> usize {
const fn obfuscate<const SEED: u64>(mut v: usize) -> usize {
let mut seed = SEED;
use crate::splitmix;
seed = splitmix(seed);
v = obfchoice(v, seed);
Expand All @@ -61,12 +61,12 @@ const fn obfuscate(mut v: usize, mut seed: u64) -> usize {
}

/// Obfuscates the xref to static data.
#[inline(always)]
pub fn xref<T: ?Sized, const OFFSET: usize, const SEED: u64>(p: &'static T, offset: &'static usize) -> &'static T {
#[inline(never)]
pub fn xref<T: ?Sized, const OFFSET: usize, const SEED: u64>(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(obfuscate(OFFSET, SEED))).wrapping_add(obfuscate(ptr::read_volatile(offset), SEED));
let val = (p as *const u8).wrapping_sub(obfuscate::<SEED>(OFFSET)).wrapping_add(obfuscate::<SEED>(offset));
// set_ptr_value
*(&mut p as *mut *const T as *mut *const u8) = val;
&*p
Expand All @@ -91,18 +91,17 @@ macro_rules! xref_mut {
macro_rules! __xref_mut {
($offset:expr, $seed:expr, $e:expr) => {{
const _XREF_OFFSET: usize = $offset;
static mut _XREF_STATIC_MUT_OFFSET: usize = _XREF_OFFSET;
$crate::xref::xref_mut::<_, _XREF_OFFSET, {$seed}>($e, unsafe { &mut _XREF_STATIC_MUT_OFFSET })
$crate::xref::xref_mut::<_, _XREF_OFFSET, {$seed}>(::core::hint::black_box($e), ::core::hint::black_box(_XREF_OFFSET))
}};
}

/// Obfuscates the xref to static data.
#[inline(always)]
pub fn xref_mut<T: ?Sized, const OFFSET: usize, const SEED: u64>(p: &'static mut T, offset: &'static usize) -> &'static mut T {
#[inline(never)]
pub fn xref_mut<T: ?Sized, const OFFSET: usize, const SEED: u64>(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(obfuscate(OFFSET, SEED))).wrapping_add(obfuscate(ptr::read_volatile(offset), SEED));
let val = (p as *mut u8).wrapping_sub(obfuscate::<SEED>(OFFSET)).wrapping_add(obfuscate::<SEED>(offset));
// set_ptr_value
*(&mut p as *mut *mut T as *mut *mut u8) = val;
&mut *p
Expand All @@ -119,6 +118,6 @@ fn test_xref_slice() {
#[test]
fn regression1() {
// Caused by `v = v ^ (v >> RNG)` when RNG is zero to always be zero
let v = obfuscate(4898264233338431333usize, (-4272872662024917058i64) as u64);
let v = obfuscate::<{(-4272872662024917058i64) as u64}>(4898264233338431333usize);
assert_ne!(v, 0);
}

0 comments on commit 697d9ad

Please sign in to comment.