1extern crate proc_macro;
25use proc_macro::TokenStream;
26use quote::quote;
27use rand::Rng;
28use syn::{parse_macro_input, ItemFn};
29
30#[proc_macro_attribute]
43pub fn obfuscate(_: TokenStream, input: TokenStream) -> TokenStream {
44 let func = parse_macro_input!(input as ItemFn);
45 let func_sig = &func.sig;
46 let func_attrs = &func.attrs;
47 let func_vis = &func.vis;
48 let block = &func.block;
49 let stmts = &block.stmts;
50 let mut new_stmts = proc_macro2::TokenStream::new();
51
52 for stmt in stmts {
53 let junk = generate_junk_block();
54 new_stmts.extend(junk);
55 new_stmts.extend(quote! { #stmt });
56 }
57
58 let output = quote! {
59 #(#func_attrs)*
60 #func_vis #func_sig {
61 #new_stmts
62 }
63 };
64
65 output.into()
68}
69
70#[derive(Clone, Copy)]
71enum JunkType {
72 Number,
73 Boolean,
74 String,
75}
76
77impl JunkType {
78 fn random(rng: &mut impl Rng) -> Self {
79 match rng.random_range(0..3) {
80 0 => JunkType::Number,
81 1 => JunkType::Boolean,
82 _ => JunkType::String,
83 }
84 }
85}
86
87fn generate_junk_block() -> proc_macro2::TokenStream {
88 let mut rng = rand::rng();
89 let junk_type = JunkType::random(&mut rng);
90 let var_count = rng.random_range(100..201);
91
92 let (ty, init_value) = match junk_type {
93 JunkType::Number => (quote!(u32), quote!(42u32)),
94 JunkType::Boolean => (quote!(bool), quote!(true)),
95 JunkType::String => (quote!(String), quote!(String::from("initial"))),
96 };
97
98 let base_var = syn::Ident::new("_x", proc_macro2::Span::call_site());
99 let mut var_statements = proc_macro2::TokenStream::new();
100
101 for i in 0..var_count {
102 let var_name = format!("_v{}", i);
103 let var_ident = syn::Ident::new(&var_name, proc_macro2::Span::call_site());
104
105 let expr = match junk_type {
106 JunkType::Number => {
107 let num = rng.random::<u32>();
108 match rng.random_range(0..6) {
109 0 => quote! { #base_var.wrapping_add(#num) },
110 1 => quote! { #base_var.wrapping_sub(#num) },
111 2 => quote! { #base_var.wrapping_shl(1) },
112 3 => quote! { #base_var.wrapping_shr(1) },
113 4 => quote! { #base_var.wrapping_mul(#num) },
114 _ => quote! { #base_var.wrapping_rem(#num.wrapping_add(1)) },
115 }
116 }
117 JunkType::Boolean => match rng.random_range(0..3) {
118 0 => quote! { !#base_var },
119 1 => quote! { #base_var && true },
120 _ => quote! { #base_var || false },
121 },
122 JunkType::String => match rng.random_range(0..3) {
123 0 => quote! { format!("{}", #base_var) },
124 1 => quote! { #base_var.clone() + "" },
125 _ => quote! { String::from(#base_var) },
126 },
127 };
128
129 var_statements.extend(quote! {
130 let #var_ident: #ty = #expr;
131 #base_var = #var_ident;
132 });
133 }
134
135 quote! {{
136 let mut #base_var: #ty = #init_value;
137 #var_statements
138 let _ = &#base_var;
139 }}
140}