1
1
// See https://github.com/tsarpaul/llvm-string-obfuscator
2
2
// for a more detailed explanation.
3
3
4
+ use inkwell:: values:: { ArrayValue , AsValueRef } ;
4
5
use llvm_plugin:: inkwell:: basic_block:: BasicBlock ;
5
6
use llvm_plugin:: inkwell:: module:: { Linkage , Module } ;
6
7
use llvm_plugin:: inkwell:: values:: { BasicValueEnum , FunctionValue , GlobalValue } ;
@@ -9,6 +10,29 @@ use llvm_plugin::{
9
10
LlvmModulePass , ModuleAnalysisManager , PassBuilder , PipelineParsing , PreservedAnalyses ,
10
11
} ;
11
12
13
+ #[ cfg( not( any(
14
+ feature = "llvm15-0" ,
15
+ feature = "llvm16-0" ,
16
+ feature = "llvm17-0" ,
17
+ feature = "llvm18-1" ,
18
+ ) ) ) ]
19
+ macro_rules! ptr_type {
20
+ ( $cx: ident, $ty: ident) => {
21
+ $cx. $ty( ) . ptr_type( AddressSpace :: default ( ) )
22
+ } ;
23
+ }
24
+ #[ cfg( any(
25
+ feature = "llvm15-0" ,
26
+ feature = "llvm16-0" ,
27
+ feature = "llvm17-0" ,
28
+ feature = "llvm18-1" ,
29
+ ) ) ]
30
+ macro_rules! ptr_type {
31
+ ( $cx: ident, $ty: ident) => {
32
+ $cx. ptr_type( AddressSpace :: default ( ) )
33
+ } ;
34
+ }
35
+
12
36
#[ llvm_plugin:: plugin( name = "StringObfuscatorPass" , version = "v0.1" ) ]
13
37
fn plugin_registrar ( builder : & mut PassBuilder ) {
14
38
builder. add_module_pipeline_parsing_callback ( |name, pass_manager| {
@@ -71,12 +95,12 @@ fn encode_global_strings<'a>(module: &mut Module<'a>) -> Vec<GlobalString<'a>> {
71
95
_ => None ,
72
96
} )
73
97
. filter ( |( _, _, arr) | {
74
- // needs to be called before `get_string_constant `, otherwise it may crash
98
+ // needs to be called before `array_as_const_string `, otherwise it may crash
75
99
arr. is_const_string ( )
76
100
} )
77
101
. filter_map ( |( global, stru, arr) | {
78
102
// we ignore non-UTF8 strings, since they are probably not human-readable
79
- let s = arr . get_string_constant ( ) . and_then ( |s| s . to_str ( ) . ok ( ) ) ?;
103
+ let s = array_as_const_string ( & arr ) . and_then ( |s| str :: from_utf8 ( s ) . ok ( ) ) ?;
80
104
let encoded_str = s. bytes ( ) . map ( |c| c + 1 ) . collect :: < Vec < _ > > ( ) ;
81
105
Some ( ( global, stru, encoded_str) )
82
106
} )
@@ -101,11 +125,22 @@ fn encode_global_strings<'a>(module: &mut Module<'a>) -> Vec<GlobalString<'a>> {
101
125
. collect ( )
102
126
}
103
127
128
+ pub fn array_as_const_string < ' a > ( arr : & ' a ArrayValue ) -> Option < & ' a [ u8 ] > {
129
+ let mut len = 0 ;
130
+ let ptr = unsafe { inkwell:: llvm_sys:: core:: LLVMGetAsString ( arr. as_value_ref ( ) , & mut len) } ;
131
+
132
+ if ptr. is_null ( ) {
133
+ None
134
+ } else {
135
+ unsafe { Some ( std:: slice:: from_raw_parts ( ptr. cast ( ) , len) ) }
136
+ }
137
+ }
138
+
104
139
fn create_decode_fn < ' a > ( module : & mut Module < ' a > ) -> FunctionValue < ' a > {
105
140
let cx = module. get_context ( ) ;
106
141
107
142
// create type `void decode(int8*, int32)`
108
- let arg1_ty = cx . i8_type ( ) . ptr_type ( AddressSpace :: default ( ) ) ;
143
+ let arg1_ty = ptr_type ! ( cx , i8_type ) ;
109
144
let arg2_ty = cx. i32_type ( ) ;
110
145
let fn_ty = cx
111
146
. void_type ( )
@@ -140,9 +175,7 @@ fn create_decode_fn<'a>(module: &mut Module<'a>) -> FunctionValue<'a> {
140
175
. unwrap ( ) ;
141
176
142
177
builder. position_at_end ( loop_body_bb) ;
143
- let phi1 = builder
144
- . build_phi ( cx. i8_type ( ) . ptr_type ( AddressSpace :: default ( ) ) , "" )
145
- . unwrap ( ) ;
178
+ let phi1 = builder. build_phi ( ptr_type ! ( cx, i8_type) , "" ) . unwrap ( ) ;
146
179
let phi2 = builder. build_phi ( cx. i32_type ( ) , "" ) . unwrap ( ) ;
147
180
let var9 = builder
148
181
. build_int_nsw_add (
@@ -186,7 +219,9 @@ fn create_decode_fn<'a>(module: &mut Module<'a>) -> FunctionValue<'a> {
186
219
feature = "llvm17-0" ,
187
220
feature = "llvm18-1" ,
188
221
) ) ) ]
189
- let var11 = builder. build_load ( phi1. as_basic_value ( ) . into_pointer_value ( ) , "" ) ;
222
+ let var11 = builder
223
+ . build_load ( phi1. as_basic_value ( ) . into_pointer_value ( ) , "" )
224
+ . unwrap ( ) ;
190
225
#[ cfg( any(
191
226
feature = "llvm15-0" ,
192
227
feature = "llvm16-0" ,
@@ -240,11 +275,7 @@ fn create_decode_stub<'a>(
240
275
let ( s, len) = match globstr {
241
276
GlobalString :: Array ( gs, len) => {
242
277
let s = builder
243
- . build_pointer_cast (
244
- gs. as_pointer_value ( ) ,
245
- cx. i8_type ( ) . ptr_type ( AddressSpace :: default ( ) ) ,
246
- "" ,
247
- )
278
+ . build_pointer_cast ( gs. as_pointer_value ( ) , ptr_type ! ( cx, i8_type) , "" )
248
279
. unwrap ( ) ;
249
280
( s, len)
250
281
}
@@ -265,14 +296,14 @@ fn create_decode_stub<'a>(
265
296
feature = "llvm18-1" ,
266
297
) ) ]
267
298
let s = {
268
- let i8_ty_ptr = cx . i8_type ( ) . ptr_type ( AddressSpace :: default ( ) ) ;
299
+ let i8_ty_ptr = ptr_type ! ( cx , i8_type ) ;
269
300
let struct_ty = cx. struct_type ( & [ i8_ty_ptr. into ( ) ] , false ) ;
270
301
builder
271
302
. build_struct_gep ( struct_ty, gs. as_pointer_value ( ) , id, "" )
272
303
. unwrap ( )
273
304
} ;
274
305
let s = builder
275
- . build_pointer_cast ( s, cx . i8_type ( ) . ptr_type ( AddressSpace :: default ( ) ) , "" )
306
+ . build_pointer_cast ( s, ptr_type ! ( cx , i8_type ) , "" )
276
307
. unwrap ( ) ;
277
308
( s, len)
278
309
}
0 commit comments