Skip to content

Commit 0b41680

Browse files
Cleanup
1 parent 818134b commit 0b41680

File tree

2 files changed

+78
-42
lines changed

2 files changed

+78
-42
lines changed

README.md

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
# Python Code Obfuscator
2-
I was browsing /r/dailyprogrammer on Reddit one day, and attempted one of the [daily challenges](https://www.reddit.com/r/dailyprogrammer/comments/2ao99p/7142014_challenge_171_easy_hex_to_8x8_bitmap/). After doing the challenge, I read through the comments and found a [ very interesting submission](https://www.reddit.com/r/dailyprogrammer/comments/2ao99p/7142014_challenge_171_easy_hex_to_8x8_bitmap/cixkjuu/).
2+
I was browsing /r/dailyprogrammer on Reddit one day, and attempted one of the daily challenges. After doing the challenge, I read through the comments and found a [very interesting submission](https://www.reddit.com/r/dailyprogrammer/comments/2ao99p/7142014_challenge_171_easy_hex_to_8x8_bitmap/cixkjuu/).
33

44
Seeing that baffled me at first sight, but after reading [/u/ntxhhf's breakdown](https://www.reddit.com/r/dailyprogrammer/comments/2ao99p/7142014_challenge_171_easy_hex_to_8x8_bitmap/ciza4c9/) of his code, I was inspired to make my own code obfuscator for Python using the ideas in his post.
55

6-
*So what exactly does this script do?*
7-
It takes your regular-looking Python code, and makes it unreadable!
6+
*What exactly does this script do?*
7+
It takes your regular-looking Python code, and obfuscates it! It takes any specified Python script, and will attempt to create an equivalent script that has the *same exact* functionality as the original, but is incredibly difficult for humans to read regularly.
8+
9+
*"So... how is this useful?"*
10+
According to [Wikipedia](https://en.wikipedia.org/wiki/Obfuscation_(software))...
11+
> Programmers may deliberately obfuscate code to conceal its purpose (security through obscurity) or its logic or implicit values embedded in it, primarily, in order to prevent tampering, deter reverse engineering, or even as a puzzle or recreational challenge for someone reading the source code.
812
913
## Usage
10-
`$ python obfuscator.py inputfile outputfile`
14+
> usage: obfuscator.py [-h] [--debug] inputfile outputfile
15+
>
16+
> positional arguments:
17+
> inputfile Name of the input file
18+
> outputfile Name of the output file
19+
>
20+
> optional arguments:
21+
> -h, --help show this help message and exit
22+
> --debug Show debug info
1123
1224
## Examples
1325

@@ -61,6 +73,22 @@ _=str(''.join(chr(__RSV) for __RSV in [0x62,0x75,0x69,0x6c,0x74,0x69,0x6e,0x73])
6173
getattr(__import__(_), __)(getattr(__import__(_), ___)(((____**____)+(__________<<(____**____)))))
6274
```
6375

76+
## Mini-FAQ
77+
* **Should I use this for distributing my source code?**
78+
As of the time I'm writing this, I highly recommend against that idea. There are some instances of code in that the parser cannot handle (multi-line strings, for instance). Also, the output really won't do much to prevent reverse-engineering.
79+
* **The output is too big! How do I reduce the output size?**
80+
As of right now, the biggest impact is the inefficiency of encoding strings. For the smallest output, make sure to set the following constants in the script:
81+
```
82+
USE_HEXSTRINGS = True
83+
OBFUSCATE_BUILTINS = False
84+
REMOVE_COMMENTS = True
85+
```
86+
* **It's still too big!**
87+
That wasn't a question. But yes, I will be doing periodic optimizations to this project when I have time. After all, it is just a side-project for me! :)
88+
* **Is there a license?**
89+
Yes, it is currently distributed under the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/).
90+
6491
## Credits
65-
* Brandon Asuncion (me@brandonasuncion.tech) - Code
92+
* Brandon Asuncion - Code
93+
Questions/Comments? Feel free to contact me at: **me@brandonasuncion.tech**
6694
* [/u/ntxhhf](https://www.reddit.com/r/dailyprogrammer/comments/2ao99p/7142014_challenge_171_easy_hex_to_8x8_bitmap/ciza4c9/) - For the idea, and his breakdown of using lists/sets to create boolean values and integers

obfuscator.py

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
1-
#!/usr/bin/python
2-
'''
3-
Python Code Obfuscator
4-
by Brandon Asuncion
5-
me@brandonasuncion.tech
6-
'''
1+
#!/usr/bin/env python3
2+
3+
4+
# Python Code Obfuscator
5+
# by Brandon Asuncion
6+
#
7+
# Questions/Comments? me@brandonasuncion.tech
8+
79

810
import string
911
import sys
12+
import argparse
1013

1114
# How strings are encoded
1215
# Turning off will remove all numbers in the code,
1316
# but will increase output size by a lot!
1417
USE_HEXSTRINGS = True
1518

16-
# Remove comments from code
17-
REMOVE_COMMENTS = True
18-
1919
# Obfuscate Python's built-in function calls
20-
# Note: Code output will be large!
2120
OBFUSCATE_BUILTINS = False
2221

22+
# Remove comments from code
23+
REMOVE_COMMENTS = True
24+
2325
# Special code replacements
2426
REPLACEMENTS = {
2527
'True': '(()==())',
2628
'False': '(()==[])',
2729
}
2830

29-
# Name of variable for internal actions (such as string decryption)
30-
RESERVED_VAR = "__RSV"
31-
32-
BUILTINS_CONST = "__B"
31+
# Ignore the following two constants if you don't know what they mean
32+
RESERVED_VAR = "__RSV" # Name of variable for internal actions (such as string decryption)
33+
BUILTINS_CONST = "__B" # name used in the header for storing the "builtins" string
3334

3435
_RESERVED = [
3536
# Python reserved keywords
@@ -59,7 +60,7 @@
5960
]
6061

6162
# Might not be a complete list...
62-
PREPAD = [';', ':', '=', '+', '-', '*', '%', '^', '<<', '>>', '|', '^', '/', ',', '{', '}', '[', ']']
63+
_PREPAD = [';', ':', '=', '+', '-', '*', '%', '^', '<<', '>>', '|', '^', '/', ',', '{', '}', '[', ']']
6364

6465
class Obfuscator(object):
6566

@@ -174,7 +175,7 @@ def obfuscate(self, code, append_header = True):
174175

175176
# Pad certain characters so they can be parsed properly
176177
prepadded = code
177-
for p in PREPAD:
178+
for p in _PREPAD:
178179
prepadded = prepadded.replace(p, " {} ".format(p))
179180
prepadded = prepadded.replace('(', "( ").replace(')', ' )')
180181

@@ -217,7 +218,7 @@ def obfuscate(self, code, append_header = True):
217218

218219

219220
# arithmetic and similar symbols are passed along as well
220-
if symbol in PREPAD:
221+
if symbol in _PREPAD:
221222
result += symbol
222223
continue
223224

@@ -310,33 +311,40 @@ def obfuscate_lines(self, code):
310311

311312
result += self.obfuscate(line, False) + "\n"
312313
return self.getHeader() + result
314+
315+
class MyArgParser(argparse.ArgumentParser):
316+
def error(self, message):
317+
sys.stderr.write('Error: {}\n'.format(message))
318+
self.print_help()
319+
sys.exit(2)
313320

314321
def main():
315-
if len(sys.argv) < 3:
316-
print('Usage: obfuscator.py inputfile outputfile')
317-
else:
318-
with open(sys.argv[1], 'r') as fh:
319-
lines = fh.read()
320-
321-
obf = Obfuscator()
322-
output = obf.obfuscate_lines(lines)
323-
print(output)
324-
325-
with open(sys.argv[2], 'w') as fh:
326-
fh.write(output)
322+
parser = MyArgParser(description='Python Code Obfuscator by Brandon Asuncion (me@brandonasuncion.tech)')
323+
parser.add_argument('inputfile', help="Name of the input file")
324+
parser.add_argument('outputfile', help="Name of the output file")
325+
parser.add_argument('--debug', help="Show debug info", action="store_true")
326+
args = vars(parser.parse_args())
327+
328+
print('Opening {} for obfuscation'.format(args['inputfile']))
329+
with open(args['inputfile'], 'r') as fh:
330+
lines = fh.read()
331+
332+
obf = Obfuscator()
333+
output = obf.obfuscate_lines(lines)
334+
335+
with open(args['outputfile'], 'w') as fh:
336+
fh.write(output)
337+
print('Written to {}\n'.format(args['outputfile']))
327338

328-
'''
329-
print('VARIABLES')
339+
if args['debug']:
340+
print('CONVERTED VARIABLES')
330341
for v in obf.variables:
331342
print("{}\t=> {}".format(v, obf.variables[v]))
332-
343+
333344
print('\nVARIABLES IN HEADER')
334-
for n in sorted(obf.header_variables, key = lambda x: int(x)):
345+
for n in sorted(obf.header_variables, key=len):
335346
print("{}\t=> {}".format(n, obf.header_variables[n]))
336-
print()
337-
'''
338-
print('Written to {}'.format(sys.argv[2]))
339-
347+
print()
340348

341349
if __name__ == "__main__":
342350
main()

0 commit comments

Comments
 (0)