-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobfuscator.py
108 lines (82 loc) · 4.07 KB
/
obfuscator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import random
import string
import ast
import argparse
import tokenize
from io import StringIO
NO_OBFUSCATE = set([ #this is here because I couldn't fix these
'os', 'sys', 'random', 'string', 'ast', 're', 'open', 'print', 'exit', #you could probably get rid of some of them
'getattr', 'setattr', 'delattr', 'hasattr', 'int', 'str', 'list', 'dict',
'tuple', 'range', 'len', 'type', 'isinstance', 'dir', 'id', 'input',
'sum', 'min', 'max', 'map', 'filter', 'sorted', 'enumerate', 'zip', '_',
'path', '__init__', '__main__'
])
def add_module_functions(module_name, no_obfuscate):
try:
module = __import__(module_name)
for name in dir(module):
no_obfuscate.add(name)
if '.' in name:
submodule = name.split('.')[0]
no_obfuscate.add(submodule)
except ImportError:
pass
def collect_imported_modules(filename):
with open(filename, 'r') as f:
source_code = f.read()
tree = ast.parse(source_code)
imported_modules = set()
for node in ast.walk(tree):
if isinstance(node, (ast.Import, ast.ImportFrom)):
for alias in node.names:
imported_modules.add(alias.name if isinstance(node, ast.Import) else node.module)
if isinstance(node, ast.ImportFrom):
imported_modules.add(alias.name)
return imported_modules
def generate_random_name(length):
return ''.join(random.choices(string.ascii_lowercase, k=length))
def collect_names(node, name_map, imported_modules, imported_functions_classes, no_obfuscate, length):
builtins = dir(__builtins__)
if isinstance(node, ast.FunctionDef):
if node.name not in builtins and node.name not in imported_functions_classes and node.name not in no_obfuscate:
name_map[node.name] = generate_random_name(length)
elif isinstance(node, ast.Name):
if node.id not in builtins and node.id not in imported_modules and node.id not in imported_functions_classes and node.id not in no_obfuscate:
if node.id not in name_map:
name_map[node.id] = generate_random_name(length)
for child in ast.iter_child_nodes(node):
collect_names(child, name_map, imported_modules, imported_functions_classes, no_obfuscate, length)
def obfuscate_and_replace(file_path, length, output_file):
name_map = {}
imported_modules = collect_imported_modules(file_path)
for module in imported_modules:
add_module_functions(module, NO_OBFUSCATE)
with open(file_path, 'r') as f:
source_code = f.read()
tree = ast.parse(source_code)
imported_functions_classes = {alias.name for node in ast.walk(tree) if isinstance(node, ast.ImportFrom) for alias in node.names}
collect_names(tree, name_map, imported_modules, imported_functions_classes, NO_OBFUSCATE, length)
result = []
tokens = list(tokenize.generate_tokens(StringIO(source_code).readline))
for tok in tokens:
toknum, tokval, start, end, line = tok
if toknum == tokenize.NAME and tokval in name_map:
result.append((toknum, name_map[tokval], start, end, line))
else:
result.append(tok)
updated_code = tokenize.untokenize(result)
with open(output_file, 'w') as file:
file.write(updated_code)
print("File has been obfuscated successfully")
def main():
parser = argparse.ArgumentParser(description="Python Code Obfuscator", epilog="by stigsec")
parser.add_argument('-i', '--input', required=True, help="Input Python code")
parser.add_argument('-l', '--length', type=int, default=16, help="Length of obfuscated names")
parser.add_argument('-o', '--output', required=True, help="Output file")
args = parser.parse_args()
if args.length <= 3: #if less than 3, weird problems occur
print("Error: Length must be greater than 3.")
return
obfuscate_and_replace(args.input, args.length, args.output)
if __name__ == "__main__":
main()