@@ -43,18 +43,21 @@ class NStrats(Enum):
4343 HEX = 3
4444 BOOLEAN = 4
4545 LEN = 5
46+ BITWISE = 6
4647
4748 INT_STRATS = ( # positive int obfuscation strategies
4849 NStrats .STRING ,
4950 NStrats .ADDITION ,
5051 NStrats .HEX ,
5152 NStrats .LEN ,
53+ NStrats .BITWISE ,
5254 )
5355 NEG_INT_STRATS = ( # negative int obfuscation strategies
5456 NStrats .STRING ,
5557 NStrats .ADDITION ,
5658 NStrats .HEX ,
5759 NStrats .LEN ,
60+ NStrats .BITWISE ,
5861 )
5962 FLOAT_STRATS = ( # positive float obfuscation strategies
6063 NStrats .STRING ,
@@ -203,6 +206,133 @@ def obf_len_random(tokval):
203206 )
204207 return t
205208
209+ @staticmethod
210+ def obf_bitwise (tokval ): # noqa: C901, PLR0912
211+ """Obfuscate integer using bitwise operations."""
212+ n = int (tokval )
213+
214+ # choose a sub-strategy randomly
215+ strategies = ["xor" , "shift" , "not" ]
216+ if n != 0 :
217+ strategies .append ("or_compose" )
218+ strategy = random .choice (strategies )
219+
220+ if strategy == "xor" :
221+ # n = a ^ b where a is random, b = n ^ a
222+ mask = random .randint (1 , max (abs (n ) + 100 , 255 ))
223+ other = n ^ mask
224+ tokens = [
225+ (NUMBER , str (mask )),
226+ (OP , "^" ),
227+ ]
228+ if other < 0 :
229+ tokens .extend (
230+ [
231+ (LPAR , "(" ),
232+ (NUMBER , str (other )),
233+ (RPAR , ")" ),
234+ ],
235+ )
236+ else :
237+ tokens .append ((NUMBER , str (other )))
238+
239+ elif strategy == "shift" :
240+ if n == 0 :
241+ # 1 >> 1 = 0
242+ tokens = [
243+ (NUMBER , "1" ),
244+ (OP , ">>" ),
245+ (NUMBER , "1" ),
246+ ]
247+ elif n > 0 :
248+ # find a valid shift amount
249+ k = random .randint (1 , 3 )
250+ shifted = n >> k
251+ remainder = n - (shifted << k )
252+ if remainder == 0 :
253+ tokens = [
254+ (NUMBER , str (shifted )),
255+ (OP , "<<" ),
256+ (NUMBER , str (k )),
257+ ]
258+ else :
259+ tokens = [
260+ (LPAR , "(" ),
261+ (NUMBER , str (shifted )),
262+ (OP , "<<" ),
263+ (NUMBER , str (k )),
264+ (RPAR , ")" ),
265+ (OP , "|" ),
266+ (NUMBER , str (remainder )),
267+ ]
268+ else :
269+ # for negatives, use ~(~n)
270+ complement = ~ n
271+ tokens = [
272+ (OP , "~" ),
273+ (NUMBER , str (complement )),
274+ ]
275+
276+ elif strategy == "not" :
277+ # ~(~n) = n, but render as ~m where m = ~n
278+ complement = ~ n
279+ if complement >= 0 :
280+ tokens = [
281+ (OP , "~" ),
282+ (NUMBER , str (complement )),
283+ ]
284+ else :
285+ tokens = [
286+ (OP , "~" ),
287+ (LPAR , "(" ),
288+ (NUMBER , str (complement )),
289+ (RPAR , ")" ),
290+ ]
291+
292+ else :
293+ # or_compose: split n into disjoint bit groups
294+ # a | b where a & b == 0 and a | b == n
295+ if n > 0 :
296+ bit_len = n .bit_length ()
297+ split = random .randint (1 , max (bit_len - 1 , 1 ))
298+ mask = (1 << split ) - 1
299+ a = n & mask
300+ b = n & ~ mask
301+ else :
302+ # for negatives, use XOR as fallback
303+ mask = random .randint (1 , 255 )
304+ other = n ^ mask
305+ tokens = [
306+ (NUMBER , str (mask )),
307+ (OP , "^" ),
308+ ]
309+ if other < 0 :
310+ tokens .extend (
311+ [
312+ (LPAR , "(" ),
313+ (NUMBER , str (other )),
314+ (RPAR , ")" ),
315+ ],
316+ )
317+ else :
318+ tokens .append ((NUMBER , str (other )))
319+ return [
320+ (LPAR , "(" ),
321+ * tokens ,
322+ (RPAR , ")" ),
323+ ]
324+ tokens = [
325+ (NUMBER , str (a )),
326+ (OP , "|" ),
327+ (NUMBER , str (b )),
328+ ]
329+
330+ return [
331+ (LPAR , "(" ),
332+ * tokens ,
333+ (RPAR , ")" ),
334+ ]
335+
206336 @staticmethod
207337 def verify_number_obfuscation (tokval , tokens ):
208338 # if only one token then it's the same
@@ -217,7 +347,7 @@ def verify_number_obfuscation(tokval, tokens):
217347 logger .error (msg )
218348 return False
219349
220- def obfuscate_number (self , toknum , tokval ): # noqa: C901 PLR0912
350+ def obfuscate_number (self , toknum , tokval ): # noqa: C901, PLR0912, PLR0915
221351 unobfuscated = [(toknum , tokval )]
222352
223353 # get token type
@@ -268,6 +398,8 @@ def obfuscate_number(self, toknum, tokval): # noqa: C901 PLR0912
268398 tokens = self .obf_boolean_conversion (tokval )
269399 elif strategy == self .NStrats .LEN :
270400 tokens = self .obf_len_random (tokval )
401+ elif strategy == self .NStrats .BITWISE :
402+ tokens = self .obf_bitwise (tokval )
271403 else :
272404 msg = f"Strategy { strategy } not found"
273405 raise PofError (msg ) # noqa: TRY301
0 commit comments