Slide 1

Slide 1 text

Numbers obfuscation in Python Dmitry Alimov 2017

Slide 2

Slide 2 text

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.

Slide 3

Slide 3 text

Fixed in Python 3 >>> {} > [] Traceback (most recent call last): File "", line 1, in TypeError: '>' not supported between instances of 'dict' and 'list' Let's use the following approach in Python 3: >>> [] < [] False

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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)

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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 = (((((-~(-~([]<[]))<<-~-~(-~([]<[])))-~(-~([]<[])))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~(-~-~( -~([]<[]))<<-~(-~([]<[]))))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~-~-~-~-~(-~([]<[])))*(-~(-~([ ]<[]))<<-~-~(-~([]<[])))-~-~-~-~-~-~-~(-~([]<[])))*(-~(-~([]<[]))<<-~-~(-~([]<[])))-~-~-~-~ -~-~(-~([]<[]))

Slide 12

Slide 12 text

Other examples Negative numbers: change the sign in front of the parentheses Possible errors for huge numbers :( Traceback (most recent call last): File "", line 1, in File "", line 8, in get_number ... File "", 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

Slide 13

Slide 13 text

Questions https://t.me/spbpython https://t.me/piterpy_meetup

Slide 14

Slide 14 text

Links http://delimitry.blogspot.com/2015/01/python-numbers-obfuscation.html https://docs.python.org/2/library/stdtypes.html#comparisons