rust_native_obf/
lib.rs

1pub mod rng;
2pub mod hash;
3pub mod string;
4pub mod flow;
5pub mod encoding;
6pub mod pointer;
7pub mod wide;
8
9pub use rng::{xxhash_mix, siphash_seed, gen_entropy, GLOBAL_SEED};
10pub use hash::{xxhash32, sdbm_hash};
11
12pub fn opaque_true() -> bool {
13    let t = std::time::SystemTime::now()
14        .duration_since(std::time::UNIX_EPOCH)
15        .unwrap()
16        .as_nanos();
17    (t | 1) != 0
18}
19
20pub fn opaque_identity<T>(val: T) -> T {
21    if opaque_true() { val } else { unreachable!() }
22}
23
24pub fn stack_trash() {
25    let mut buf = [0u8; 512];
26    for i in 0..512 {
27        buf[i] = ((i * 73) ^ 0xaa) as u8;
28    }
29    std::hint::black_box(&buf);
30}
31
32#[macro_export]
33macro_rules! hidden_call {
34    ($expr:expr) => {{
35        if $crate::opaque_true() {
36            $crate::stack_trash();
37            $expr
38        } else {
39            unreachable!()
40        }
41    }};
42}
43
44pub fn noise_loop(count: usize) -> u64 {
45    let mut acc = 0u64;
46    for i in 0..count {
47        acc = acc.wrapping_add(i as u64);
48        acc ^= 0xdeadbeef;
49        acc = acc.rotate_left(7);
50    }
51    acc
52}
53
54pub fn fake_compute(input: u64) -> u64 {
55    let mut val = input;
56    val ^= 0xa5a5a5a5a5a5a5a5;
57    val = val.wrapping_mul(0x517cc1b727220a95);
58    val = val.rotate_left(23);
59    val ^= val >> 17;
60    val
61}
62
63#[macro_export]
64macro_rules! obf_if {
65    ($cond:expr, $then:block, $else:block) => {{
66        let c = $cond;
67        $crate::stack_trash();
68        if c { $then } else { $else }
69    }};
70    ($cond:expr, $then:block) => {{
71        let c = $cond;
72        $crate::stack_trash();
73        if c { $then }
74    }};
75}
76
77pub fn xor_stream(data: &mut [u8], key: &[u8]) {
78    for (i, byte) in data.iter_mut().enumerate() {
79        *byte ^= key[i % key.len()];
80    }
81}
82
83pub fn cascade_encrypt(data: &[u8], rounds: usize) -> Vec<u8> {
84    let mut result = data.to_vec();
85    for round in 0..rounds {
86        let mut key = (0xb7u8).wrapping_add(round as u8);
87        for byte in result.iter_mut() {
88            *byte = byte.wrapping_add(key);
89            *byte ^= key;
90            key = key.wrapping_mul(17).wrapping_add(83);
91        }
92    }
93    result
94}
95
96pub fn cascade_decrypt(data: &[u8], rounds: usize) -> Vec<u8> {
97    let mut result = data.to_vec();
98    for round in (0..rounds).rev() {
99        let mut key = (0xb7u8).wrapping_add(round as u8);
100        for byte in result.iter_mut() {
101            *byte ^= key;
102            *byte = byte.wrapping_sub(key);
103            key = key.wrapping_mul(17).wrapping_add(83);
104        }
105    }
106    result
107}
108
109pub struct ObfuscatedValue<T> {
110    data: Vec<u8>,
111    key: u64,
112    _marker: std::marker::PhantomData<T>,
113}
114
115impl<T: Sized> ObfuscatedValue<T> {
116    pub fn new(val: T) -> Self {
117        let bytes = unsafe {
118            std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::<T>())
119        };
120        let key = noise_loop(100);
121        let data = bytes.iter().enumerate()
122            .map(|(i, &b)| b ^ ((key >> (i % 8 * 8)) as u8))
123            .collect();
124        std::mem::forget(val);
125        Self { data, key, _marker: std::marker::PhantomData }
126    }
127
128    pub fn get(&self) -> T {
129        let mut bytes = vec![0u8; self.data.len()];
130        for (i, &b) in self.data.iter().enumerate() {
131            bytes[i] = b ^ ((self.key >> (i % 8 * 8)) as u8);
132        }
133        unsafe { std::ptr::read(bytes.as_ptr() as *const T) }
134    }
135}
136
137pub fn tamper_check(expected: u32) -> bool {
138    let actual = ct_xxhash!(b"tamper_check");
139    actual == expected
140}
141
142pub fn anti_debug() -> bool {
143    #[cfg(target_os = "windows")]
144    {
145        unsafe {
146            extern "system" {
147                fn IsDebuggerPresent() -> i32;
148            }
149            IsDebuggerPresent() == 0
150        }
151    }
152    #[cfg(not(target_os = "windows"))]
153    {
154        true
155    }
156}
157
158#[macro_export]
159macro_rules! debug_trap {
160    () => {
161        if !$crate::anti_debug() {
162            panic!("debugger detected");
163        }
164    };
165}