## Monday, January 12, 2015

### Python numbers obfuscation

Python numbers obfuscation can be done the next way:

>>> {} > [] # i.e. 'd' > 'l' ([d]ict > [l]ist)
False
>>> [] > {} # i.e. 'l' > 'd' ([l]ist > [d]ict)
True

And it's possible to get values 0 and 1 from False and True, by implicit converting bool to int.

>>> False == 0
True
>>> True == 1
True

Other numbers could be received by applying logical operations (like "~" = bitwise NOT, or "<<" bitwise left shift).
For example 2:
2 = -(-2) =  -(~1)

Let's take 16 or more first numbers, and all other numbers could be obtained by sum and/or multiplication of these first numbers.
```nums = [
'([]<{})',  # 0
'([]>{})',  # 1
'-~([]>{})',  # 2
'-~-~([]>{})',  # 3
'-~-~-~([]>{})',  # 4
'-~-~-~-~([]>{})',  # 5
'-~-~-~-~-~([]>{})',  # 6
'-~-~-~-~-~-~([]>{})',  # 7
'-~-~-~-~-~-~-~([]>{})',  # 8
'~-~([]>{})*~-~([]>{})',  # 9
'~-~-~-~([]>{})*~([]>{})',  # 10
'-~-~(~-~([]>{})*~-~([]>{}))',  # 11
'(-~-~([]>{})<<-~([]>{}))',  # 12
'-~(-~-~([]>{})<<-~([]>{}))',  # 13
'-~-~-~-~-~-~([]>{})*-~([]>{})',  # 14
'~-~([]>{})*~-~-~-~([]>{})',  # 15
'(-~([]>{})<<-~-~([]>{}))',  # 16
]
numbers_count = len(nums) - 1

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 xrange(numbers_count, -1, -1):
res = res.replace(str(n), nums[n])
res = res.replace('+-', '-')
return res
```
Example:
```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 ```
So here the number 1234567 was successfully obfuscated and restored using eval function.
1234567 = ((((16+2)*16+13)*16+6)*16+8)*16+7 = (((((-~([]>{})<<-~-~([]>{}))-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~(-~-~([]>{})<<-~([]>{})))*(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~-~([]>{}))*(-~([]>{})<<-~-~([]>{}))-~-~-~-~-~-~([]>{})

For negative numbers you only need to change the sign in front of the parentheses.

But for huge numbers like 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789, will be an error:
```_push: parser stack overflow
Traceback (most recent call last):
File "obfuscation.py", line 51, in
print eval(obfuscated)
MemoryError
```
So be careful and use nested parentheses carefully :)

The presentation with updated version of obfuscator (added Python 3 support):
http://speakerdeck.com/delimitry/numbers-obfuscation-in-python