KEMBAR78
Numbers obfuscation in Python | PDF
Numbers obfuscation
in Python
Dmitry Alimov
2017
Types comparison
>>> {} > [] # i.e. 'd' > 'l' ([d]ict > [l]ist)
False
>>> [] > {} # i.e. 'l' > 'd' ([l]ist > [d]ict)
True
Python 2 only!
CPython implementation detail: Objects of different types except numbers
are ordered by their type names; objects of the same types that don’t
support proper comparison are ordered by their address.
Fixed in Python 3
>>> {} > []
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'dict' and 'list'
Let's use the following approach in Python 3:
>>> [] < []
False
True and False
As bool type inherits from int, bool values explicitly considered as integer, it's
possible to get 0 and 1 from False and True.
>>> False == 0
True
>>> True == 1
True
NB:
In Python 2 it is possible to reassign True and False.
In Python 3 True and False are keywords and always equal to 1 and 0.
Numbers
Other numbers can be obtained by applying logical operations
E.g. "~" = bitwise NOT, or "<<" bitwise left shift.
For example 2:
2 = -(-2) = -(~1)
>>> 2 == -(-2) == -(~1)
True
Numbers (Python 2)
nums = [
'([]<{})', # 0
'([]>{})', # 1
'-~([]>{})', # 2
'-~-~([]>{})', # 3
'-~-~-~([]>{})', # 4
'-~-~-~-~([]>{})', # 5
'-~-~-~-~-~([]>{})', # 6
'-~-~-~-~-~-~([]>{})', # 7
'-~-~-~-~-~-~-~([]>{})', # 8
'~-~([]>{})*~-~([]>{})', # 9
'~-~-~-~([]>{})*~([]>{})', # 10
'-~-~(~-~([]>{})*~-~([]>{}))', # 11
'(-~-~([]>{})<<-~([]>{}))', # 12
'-~(-~-~([]>{})<<-~([]>{}))', # 13
'-~-~-~-~-~-~([]>{})*-~([]>{})', # 14
'~-~([]>{})*~-~-~-~([]>{})', # 15
'(-~([]>{})<<-~-~([]>{}))', # 16
]
numbers_count = len(nums) - 1
Numbers (Python 3)
nums = [
'([]<[])', # 0
'(-~([]<[]))', # 1
'-~(-~([]<[]))', # 2
'-~-~(-~([]<[]))', # 3
'-~-~-~(-~([]<[]))', # 4
'-~-~-~-~(-~([]<[]))', # 5
'-~-~-~-~-~(-~([]<[]))', # 6
'-~-~-~-~-~-~(-~([]<[]))', # 7
'-~-~-~-~-~-~-~(-~([]<[]))', # 8
'~-~(-~([]<[]))*~-~(-~([]<[]))', # 9
'~-~-~-~(-~([]<[]))*~(-~([]<[]))', # 10
'-~-~(~-~(-~([]<[]))*~-~(-~([]<[])))', # 11
'(-~-~(-~([]<[]))<<-~(-~([]<[])))', # 12
'-~(-~-~(-~([]<[]))<<-~(-~([]<[])))', # 13
'-~-~-~-~-~-~(-~([]<[]))*-~(-~([]<[]))', # 14
'~-~(-~([]<[]))*~-~-~-~(-~([]<[]))', # 15
'(-~(-~([]<[]))<<-~-~(-~([]<[])))', # 16
]
numbers_count = len(nums) - 1
Converting numbers
Let’s take 16 as a base (i.e. hexadecimal numeral system)
therefore each decimal number can be obtained by sum of multiplications of each
decimal digit of a number by 16.
Example:
17 = (16+1)
42 = (2*16+10)
123 = (7*16+11)
1000 = ((3*16+14)*16+8)
Converting numbers
def get_number(num):
r = ''
if num > numbers_count:
if num // numbers_count > 1:
if num % numbers_count == 0:
r += '(%s*%s)' % (get_number(num // numbers_count), numbers_count)
else:
r += '(%s*%s+%s)' % (get_number(num // numbers_count), numbers_count, num % numbers_count)
else:
r += '(%s+%s)' % (numbers_count, get_number(num - numbers_count))
else:
r = '%s' % num
return r
def convert_nums(s):
res = s
for n in range(numbers_count, -1, -1):
res = res.replace(str(n), nums[n])
res = res.replace('+-', '-')
return res
Examples
num = 1234567
num_str = get_number(num)
num_str = num_str[1:-1] if num_str[0] == '(' and num_str[-1] == ')' else num_str
print(num_str)
# ((((16+2)*16+13)*16+6)*16+8)*16+7
obfuscated = convert_nums(num_str)
print(obfuscated)
#(((((-~([]>{})<<-~-~([]>{}))-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~(-~-~([]>{})<<-~([]>{})))
*(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~-~([]>{}))*
(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~([]>{})
print(eval(obfuscated))
# 1234567
Examples
Python 2:
1234567 = ((((16+2)*16+13)*16+6)*16+8)*16+7 =
(((((-~([]>{})<<-~-~([]>{}))-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~(-~-~([]>{})<<-~([]>{})))*
(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~-~([]>{}))*(
-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~([]>{})
Python 3:
1234567 = ((((16+2)*16+13)*16+6)*16+8)*16+7 =
(((((-~(-~([]<[]))<<-~-~(-~([]<[])))-~(-~([]<[])))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~(-~-~(
-~([]<[]))<<-~(-~([]<[]))))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~-~-~-~-~(-~([]<[])))*(-~(-~([
]<[]))<<-~-~(-~([]<[])))-~-~-~-~-~-~-~(-~([]<[])))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~-~-~-~
-~-~(-~([]<[]))
Other examples
Negative numbers: change the sign in front of the parentheses
Possible errors for huge numbers :(
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in get_number
...
File "<stdin>", line 3, in get_number
RecursionError: maximum recursion depth exceeded in comparison
_push: parser stack overflow
Traceback (most recent call last):
File "obfuscation.py", line 51, in
print(eval(obfuscated))
MemoryError
Questions
https://t.me/spbpython
https://t.me/piterpy_meetup
Links
http://delimitry.blogspot.com/2015/01/python-numbers-obfuscation.html
https://docs.python.org/2/library/stdtypes.html#comparisons

Numbers obfuscation in Python

  • 1.
  • 2.
    Types comparison >>> {}> [] # i.e. 'd' > 'l' ([d]ict > [l]ist) False >>> [] > {} # i.e. 'l' > 'd' ([l]ist > [d]ict) True Python 2 only! CPython implementation detail: Objects of different types except numbers are ordered by their type names; objects of the same types that don’t support proper comparison are ordered by their address.
  • 3.
    Fixed in Python3 >>> {} > [] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: '>' not supported between instances of 'dict' and 'list' Let's use the following approach in Python 3: >>> [] < [] False
  • 4.
    True and False Asbool type inherits from int, bool values explicitly considered as integer, it's possible to get 0 and 1 from False and True. >>> False == 0 True >>> True == 1 True NB: In Python 2 it is possible to reassign True and False. In Python 3 True and False are keywords and always equal to 1 and 0.
  • 5.
    Numbers Other numbers canbe obtained by applying logical operations E.g. "~" = bitwise NOT, or "<<" bitwise left shift. For example 2: 2 = -(-2) = -(~1) >>> 2 == -(-2) == -(~1) True
  • 6.
    Numbers (Python 2) nums= [ '([]<{})', # 0 '([]>{})', # 1 '-~([]>{})', # 2 '-~-~([]>{})', # 3 '-~-~-~([]>{})', # 4 '-~-~-~-~([]>{})', # 5 '-~-~-~-~-~([]>{})', # 6 '-~-~-~-~-~-~([]>{})', # 7 '-~-~-~-~-~-~-~([]>{})', # 8 '~-~([]>{})*~-~([]>{})', # 9 '~-~-~-~([]>{})*~([]>{})', # 10 '-~-~(~-~([]>{})*~-~([]>{}))', # 11 '(-~-~([]>{})<<-~([]>{}))', # 12 '-~(-~-~([]>{})<<-~([]>{}))', # 13 '-~-~-~-~-~-~([]>{})*-~([]>{})', # 14 '~-~([]>{})*~-~-~-~([]>{})', # 15 '(-~([]>{})<<-~-~([]>{}))', # 16 ] numbers_count = len(nums) - 1
  • 7.
    Numbers (Python 3) nums= [ '([]<[])', # 0 '(-~([]<[]))', # 1 '-~(-~([]<[]))', # 2 '-~-~(-~([]<[]))', # 3 '-~-~-~(-~([]<[]))', # 4 '-~-~-~-~(-~([]<[]))', # 5 '-~-~-~-~-~(-~([]<[]))', # 6 '-~-~-~-~-~-~(-~([]<[]))', # 7 '-~-~-~-~-~-~-~(-~([]<[]))', # 8 '~-~(-~([]<[]))*~-~(-~([]<[]))', # 9 '~-~-~-~(-~([]<[]))*~(-~([]<[]))', # 10 '-~-~(~-~(-~([]<[]))*~-~(-~([]<[])))', # 11 '(-~-~(-~([]<[]))<<-~(-~([]<[])))', # 12 '-~(-~-~(-~([]<[]))<<-~(-~([]<[])))', # 13 '-~-~-~-~-~-~(-~([]<[]))*-~(-~([]<[]))', # 14 '~-~(-~([]<[]))*~-~-~-~(-~([]<[]))', # 15 '(-~(-~([]<[]))<<-~-~(-~([]<[])))', # 16 ] numbers_count = len(nums) - 1
  • 8.
    Converting numbers Let’s take16 as a base (i.e. hexadecimal numeral system) therefore each decimal number can be obtained by sum of multiplications of each decimal digit of a number by 16. Example: 17 = (16+1) 42 = (2*16+10) 123 = (7*16+11) 1000 = ((3*16+14)*16+8)
  • 9.
    Converting numbers def get_number(num): r= '' if num > numbers_count: if num // numbers_count > 1: if num % numbers_count == 0: r += '(%s*%s)' % (get_number(num // numbers_count), numbers_count) else: r += '(%s*%s+%s)' % (get_number(num // numbers_count), numbers_count, num % numbers_count) else: r += '(%s+%s)' % (numbers_count, get_number(num - numbers_count)) else: r = '%s' % num return r def convert_nums(s): res = s for n in range(numbers_count, -1, -1): res = res.replace(str(n), nums[n]) res = res.replace('+-', '-') return res
  • 10.
    Examples num = 1234567 num_str= get_number(num) num_str = num_str[1:-1] if num_str[0] == '(' and num_str[-1] == ')' else num_str print(num_str) # ((((16+2)*16+13)*16+6)*16+8)*16+7 obfuscated = convert_nums(num_str) print(obfuscated) #(((((-~([]>{})<<-~-~([]>{}))-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~(-~-~([]>{})<<-~([]>{}))) *(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~-~([]>{}))* (-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~([]>{}) print(eval(obfuscated)) # 1234567
  • 11.
    Examples Python 2: 1234567 =((((16+2)*16+13)*16+6)*16+8)*16+7 = (((((-~([]>{})<<-~-~([]>{}))-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~(-~-~([]>{})<<-~([]>{})))* (-~([]>{})<<-~-~([]>{}))-~-~-~-~-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~-~([]>{}))*( -~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~([]>{}) Python 3: 1234567 = ((((16+2)*16+13)*16+6)*16+8)*16+7 = (((((-~(-~([]<[]))<<-~-~(-~([]<[])))-~(-~([]<[])))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~(-~-~( -~([]<[]))<<-~(-~([]<[]))))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~-~-~-~-~(-~([]<[])))*(-~(-~([ ]<[]))<<-~-~(-~([]<[])))-~-~-~-~-~-~-~(-~([]<[])))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~-~-~-~ -~-~(-~([]<[]))
  • 12.
    Other examples Negative numbers:change the sign in front of the parentheses Possible errors for huge numbers :( Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in get_number ... File "<stdin>", line 3, in get_number RecursionError: maximum recursion depth exceeded in comparison _push: parser stack overflow Traceback (most recent call last): File "obfuscation.py", line 51, in print(eval(obfuscated)) MemoryError
  • 13.
  • 14.