1#![allow(bare_trait_objects, ellipsis_inclusive_range_patterns)]
2
3extern crate proc_macro;
4use proc_macro::*;
5
6fn ignore_groups(mut input: TokenStream) -> TokenStream {
15 let mut tokens = input.clone().into_iter();
16 loop {
17 if let Some(TokenTree::Group(group)) = tokens.next() {
18 if group.delimiter() == Delimiter::None {
19 input = group.stream();
20 continue;
21 }
22 }
23 return input;
24 }
25}
26
27#[cfg(feature = "rand")]
28#[proc_macro_attribute]
29pub fn obfstr_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
30 drop(args);
31 replace_macro(replace_macro(input, "_obfstr_", obfstr_impl), "_strlen_", strlen_impl)
32}
33
34#[cfg(feature = "rand")]
35fn strlen_impl(mut input: TokenStream) -> TokenStream {
36 input = ignore_groups(input);
37 if let Some(TokenTree::Literal(literal)) = input.into_iter().next() {
38 let s = string_parse(literal);
39 TokenStream::from(TokenTree::Literal(Literal::usize_suffixed(s.len())))
40 }
41 else {
42 panic!("expected a string literal")
43 }
44}
45#[cfg(feature = "rand")]
46fn obfstr_impl(mut input: TokenStream) -> TokenStream {
47 input = ignore_groups(input);
48 let mut tt = input.into_iter();
49 let mut token = tt.next();
50
51 let mut wide = false;
53 if let Some(TokenTree::Ident(ident)) = &token {
54 if ident.to_string() == "L" {
55 wide = true;
56 token = tt.next();
57 }
58 }
59
60 let string = match token {
62 Some(TokenTree::Literal(lit)) => string_parse(lit),
63 Some(tt) => panic!("expected a string literal: `{}`", tt),
64 None => panic!("expected a string literal"),
65 };
66
67 token = tt.next();
69 if let Some(tt) = token {
70 panic!("unexpected token: `{}`", tt);
71 }
72
73 let key = rand::random::<u32>();
75 let array = if wide {
77 let mut words = {string}.encode_utf16().collect::<Vec<u16>>();
78 wencrypt(&mut words, key)
79 }
80 else {
81 let mut bytes = string.into_bytes();
82 encrypt(&mut bytes, key)
83 }.into_iter().collect();
84
85 vec![
87 TokenTree::Literal(Literal::u32_suffixed(key)),
88 TokenTree::Punct(Punct::new(',', Spacing::Alone)),
89 TokenTree::Group(Group::new(Delimiter::Bracket, array)),
90 ].into_iter().collect()
91}
92
93#[cfg(feature = "rand")]
94fn next_round(mut x: u32) -> u32 {
95 x ^= x << 13;
96 x ^= x >> 17;
97 x ^= x << 5;
98 x
99}
100
101#[cfg(feature = "rand")]
102fn encrypt(bytes: &mut [u8], mut key: u32) -> Vec<TokenTree> {
103 for byte in bytes.iter_mut() {
104 key = next_round(key);
105 *byte = (*byte).wrapping_sub(key as u8);
106 }
107 let mut array = Vec::new();
108 for &byte in bytes.iter() {
109 array.push(TokenTree::Literal(Literal::u8_suffixed(byte)));
110 array.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
111 }
112 array
113}
114
115#[cfg(feature = "rand")]
116fn wencrypt(words: &mut [u16], mut key: u32) -> Vec<TokenTree> {
117 for word in words.iter_mut() {
118 key = next_round(key);
119 *word = (*word).wrapping_sub(key as u16);
120 }
121 let mut array = Vec::new();
122 for &word in words.iter() {
123 array.push(TokenTree::Literal(Literal::u16_suffixed(word)));
124 array.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
125 }
126 array
127}
128
129fn string_parse(input: Literal) -> String {
132 let string = input.to_string();
133 let mut bytes = string.as_bytes();
134
135 if bytes.len() < 2 || bytes[0] != b'"' || bytes[bytes.len() - 1] != b'"' {
137 panic!("expected a string literal: `{}`", input);
138 }
139 bytes = &bytes[1..bytes.len() - 1];
140 let string: &str = unsafe { &*(bytes as *const _ as *const str) };
141
142 let mut unescaped = String::new();
144 let mut chars = string.chars();
145 while let Some(mut chr) = chars.next() {
146 if chr == '\\' {
147 chr = match chars.next() {
148 Some('t') => '\t',
149 Some('n') => '\n',
150 Some('r') => '\r',
151 Some('0') => '\0',
152 Some('\\') => '\\',
153 Some('\'') => '\'',
154 Some('\"') => '\"',
155 Some('u') => {
156 match chars.next() {
157 Some('{') => (),
158 Some(chr) => panic!("invalid unicode escape character: `{}`", chr),
159 None => panic!("invalid unicode escape at end of string"),
160 }
161 let mut u = 0;
162 loop {
163 match chars.next() {
164 Some(chr @ '0'...'9') => {
165 u = u * 16 + (chr as u32 - '0' as u32);
166 },
167 Some(chr @ 'a'...'f') => {
168 u = u * 16 + (chr as u32 - 'a' as u32) + 10;
169 },
170 Some(chr @ 'A'...'F') => {
171 u = u * 16 + (chr as u32 - 'A' as u32) + 10;
172 },
173 Some('}') => break,
174 Some(chr) => panic!("invalid unicode escape character: `{}`", chr),
175 None => panic!("invalid unicode escape at end of string"),
176 };
177 }
178 match std::char::from_u32(u) {
179 Some(chr) => chr,
180 None => panic!("invalid unicode escape character: `\\u{{{}}}`", u),
181 }
182 },
183 Some(chr) => panic!("invalid escape character: `{}`", chr),
184 None => panic!("invalid escape at end of string"),
185 }
186 }
187 unescaped.push(chr);
188 }
189 unescaped
190}
191
192#[proc_macro_attribute]
195pub fn wide_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
196 drop(args);
197 replace_macro(input, "_wide_", wide_impl)
198}
199
200fn wide_impl(mut input: TokenStream) -> TokenStream {
201 input = ignore_groups(input);
202 let mut iter = input.into_iter();
204 let string = match iter.next() {
205 Some(TokenTree::Literal(lit)) => string_parse(lit),
206 Some(tt) => panic!("expected a string literal: `{}`", tt),
207 None => panic!("expected a string literal"),
208 };
209 if let Some(tt) = iter.next() {
210 panic!("unexpected token: `{}`", tt);
211 }
212 let mut array = Vec::new();
214 for word in string.encode_utf16() {
215 array.push(TokenTree::Literal(Literal::u16_suffixed(word)));
216 array.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
217 }
218 let elements = array.into_iter().collect();
219 vec![
221 TokenTree::Punct(Punct::new('&', Spacing::Alone)),
222 TokenTree::Group(Group::new(Delimiter::Bracket, elements)),
223 ].into_iter().collect()
224}
225
226#[cfg(feature = "rand")]
229#[proc_macro_attribute]
230pub fn random_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
231 drop(args);
232 replace_macro(input, "_random_", random_impl)
233}
234
235#[cfg(feature = "rand")]
236fn random_impl(mut input: TokenStream) -> TokenStream {
237 input = ignore_groups(input);
238 let mut tt = input.into_iter();
239 match tt.next() {
240 Some(TokenTree::Ident(ident)) => {
241 if let Some(tt) = tt.next() {
242 panic!("unexpected token: `{}`", tt);
243 }
244 random_parse(ident).into()
245 },
246 Some(tt) => panic!("expected a primitive name: `{}`", tt),
247 None => panic!("expected a primitive name"),
248 }
249}
250
251#[cfg(feature = "rand")]
252fn random_parse(input: Ident) -> TokenTree {
253 match &*input.to_string() {
254 "u8" => Literal::u8_suffixed(rand::random::<u8>()),
255 "u16" => Literal::u16_suffixed(rand::random::<u16>()),
256 "u32" => Literal::u32_suffixed(rand::random::<u32>()),
257 "u64" => Literal::u64_suffixed(rand::random::<u64>()),
258 "usize" => Literal::usize_suffixed(rand::random::<usize>()),
259 "i8" => Literal::i8_suffixed(rand::random::<i8>()),
260 "i16" => Literal::i16_suffixed(rand::random::<i16>()),
261 "i32" => Literal::i32_suffixed(rand::random::<i32>()),
262 "i64" => Literal::i64_suffixed(rand::random::<i64>()),
263 "isize" => Literal::isize_suffixed(rand::random::<isize>()),
264 "f32" => Literal::f32_suffixed(rand::random::<f32>()),
265 "f64" => Literal::f64_suffixed(rand::random::<f64>()),
266 s => panic!("unsupported type: `{}`", s),
267 }.into()
268}
269
270fn replace<F>(input: TokenStream, mut f: F) -> TokenStream
274 where F: FnMut(&[TokenTree]) -> Option<(usize, TokenStream)>
275{
276 let input: Vec<TokenTree> = input.into_iter().collect();
277 let mut output = Vec::new();
278 replace_rec(input, &mut output, &mut f);
279 output.into_iter().collect()
280}
281fn replace_rec(input: Vec<TokenTree>, output: &mut Vec<TokenTree>, f: &mut FnMut(&[TokenTree]) -> Option<(usize, TokenStream)>) {
282 let mut into_iter = input.into_iter();
283 loop {
284 if let Some((mut skip, replace)) = f(into_iter.as_slice()) {
286 output.extend(replace);
287 while skip > 0 {
288 let _ = into_iter.next();
289 skip -= 1;
290 }
291 }
292 match into_iter.next() {
293 Some(TokenTree::Group(group)) => {
295 let group_input = group.stream().into_iter().collect();
296 let mut group_output = Vec::new();
297 replace_rec(group_input, &mut group_output, f);
298 let group_stream = group_output.into_iter().collect();
299 output.push(TokenTree::Group(Group::new(group.delimiter(), group_stream)));
300 },
301 Some(tt) => output.push(tt),
302 None => break,
303 }
304 }
305}
306fn replace_macro(input: TokenStream, name: &str, f: fn(TokenStream) -> TokenStream) -> TokenStream {
308 replace(input, |tokens| {
309 if tokens.len() >= 3 {
310 if let (
311 TokenTree::Ident(ident),
312 TokenTree::Punct(punct),
313 TokenTree::Group(group),
314 ) = (
315 &tokens[0],
316 &tokens[1],
317 &tokens[2],
318 ) {
319 if punct.as_char() == '!' && ident.to_string() == name {
320 return Some((3, f(group.stream())));
321 }
322 }
323 }
324 None
325 })
326}