Skip to content

Commit a468194

Browse files
committed
Initial commit
0 parents commit a468194

File tree

5 files changed

+230
-0
lines changed

5 files changed

+230
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2023 Martin Nestorov
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Whitespace-only changes.

config.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Configure colors for printing messages
2+
YELLOW = '\033[93m'
3+
BLUE = '\033[94m'
4+
GREEN = '\033[92m'
5+
RED = '\033[91m'
6+
RESET = '\033[0m'
7+
8+
# Log filename
9+
log_filename = 'app.log'

main.py

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import sys
2+
import base64
3+
import os
4+
import re
5+
import logging
6+
import shutil
7+
from zlib import compress
8+
from concurrent.futures import ThreadPoolExecutor
9+
from tqdm import tqdm
10+
from config import (log_filename, YELLOW, BLUE, GREEN, RED, RESET)
11+
12+
# Configure logging
13+
logging.basicConfig(filename=log_filename, level=logging.DEBUG, format='%(asctime)s %(levelname)s:%(message)s', datefmt='%Y-%m-%d %H:%M:%S')
14+
15+
def obfuscate_php(input_file, obfuscation_level, create_backup, output_directory):
16+
if create_backup:
17+
backup_file = f"{os.path.splitext(input_file)[0]}_backup.php"
18+
shutil.copy2(input_file, backup_file)
19+
logging.info(f"Created backup: {backup_file}")
20+
21+
try:
22+
logging.info(f"Obfuscating {input_file} with level: {obfuscation_level}")
23+
24+
with open(input_file, "r") as f:
25+
php_code = f.read()
26+
27+
if obfuscation_level == 'low':
28+
encoded_php_code = base64.b64encode(php_code.encode()).decode()
29+
obfuscated_code = f"<?php eval(base64_decode('{encoded_php_code}')); ?>"
30+
elif obfuscation_level == 'medium':
31+
compressed_php_code = compress(php_code.encode())
32+
encoded_php_code = base64.b64encode(compressed_php_code).decode()
33+
obfuscated_code = f"<?php eval(gzinflate(base64_decode('{encoded_php_code}'))); ?>"
34+
elif obfuscation_level == 'high':
35+
compressed_php_code = compress(php_code.encode())
36+
encoded_php_code = base64.b64encode(compressed_php_code).decode()
37+
obfuscated_code = f"<?php eval(gzinflate(base64_decode('{encoded_php_code}'))); ?>"
38+
39+
var_pattern = re.compile(r'\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*')
40+
var_names = set(var_pattern.findall(obfuscated_code))
41+
for var_name in var_names:
42+
new_var_name = f"${obfuscation_level}_{var_name[1:]}"
43+
obfuscated_code = obfuscated_code.replace(var_name, new_var_name)
44+
45+
# Save the obfuscated code to the output directory
46+
output_file = os.path.join(output_directory, f"obfuscated_{os.path.basename(input_file)}")
47+
with open(output_file, "w") as f:
48+
f.write(obfuscated_code)
49+
50+
print(f"{GREEN}Obfuscated file saved as {output_file}{RESET}")
51+
logging.info(f"Obfuscated {input_file} successfully")
52+
53+
except Exception as e:
54+
logging.error(f"Error while obfuscating {input_file}: {e}")
55+
print(f"{RED}Error while obfuscating {input_file}: {e}{RESET}")
56+
57+
def obfuscate_file(args):
58+
input_file, obfuscation_level, create_backup, output_directory = args
59+
obfuscate_php(input_file, obfuscation_level, create_backup, output_directory)
60+
61+
def process_directory(directory, obfuscation_level, exclude_list, create_backup, output_directory, max_workers=4):
62+
total_files = 0
63+
for root, _, files in os.walk(directory):
64+
for file in files:
65+
if file.lower().endswith(".php"):
66+
total_files += 1
67+
68+
progress_bar = tqdm(total=total_files, desc="Obfuscating", unit="file")
69+
70+
file_list = []
71+
for root, _, files in os.walk(directory):
72+
for file in files:
73+
if file.lower().endswith(".php"):
74+
input_file = os.path.join(root, file)
75+
76+
if any(os.path.commonpath([input_file, exclude]) == os.path.abspath(exclude) for exclude in exclude_list):
77+
logging.info(f"Skipping {input_file}: excluded")
78+
continue
79+
80+
file_list.append((input_file, obfuscation_level, create_backup, output_directory))
81+
82+
progress_bar = tqdm(total=len(file_list), desc="Obfuscating", unit="file")
83+
84+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
85+
for _ in executor.map(obfuscate_file, file_list):
86+
progress_bar.update()
87+
88+
progress_bar.close()
89+
90+
def interactive_mode():
91+
print(f"{GREEN}Welcome to the PHP Obfuscator Interactive Mode!{RESET}")
92+
print(f"{GREEN}Follow the prompts to obfuscate your PHP files.\n{RESET}")
93+
94+
print(f"{GREEN}Choose the mode for obfuscating your PHP files:{RESET}")
95+
print(f"{BLUE}1: Single file{RESET}")
96+
print(f"{BLUE}2: Multiple files{RESET}")
97+
print(f"{BLUE}3: Entire project directory{RESET}")
98+
mode = input(f"{GREEN}Enter the mode number (1/2/3): {RESET}")
99+
100+
print(f"{GREEN}\nChoose the obfuscation level:{RESET}")
101+
print(f"{BLUE}1: Low (Base64 encoding){RESET}")
102+
print(f"{BLUE}2: Medium (zlib compression + Base64 encoding){RESET}")
103+
print(f"{BLUE}3: High (zlib compression + Base64 encoding + simple variable renaming){RESET}")
104+
obfuscation_level = input(f"{GREEN}Enter the obfuscation level number (1/2/3): {RESET}")
105+
106+
exclude_input = input(f"{GREEN}\nEnter a comma-separated list of files or directories to exclude (leave empty if none): {RESET}")
107+
exclude_list = [path.strip() for path in exclude_input.split(',') if path.strip()]
108+
109+
backup_input = input(f"{GREEN}\nCreate backups of original PHP files? (y/n): {RESET}")
110+
create_backup = backup_input.lower() == 'y'
111+
112+
output_directory = input(f"{GREEN}\nEnter the output directory path: {RESET}")
113+
if not os.path.exists(output_directory):
114+
os.makedirs(output_directory)
115+
116+
if mode == '1':
117+
input_file = input(f"{GREEN}\nEnter the PHP file path: {RESET}")
118+
obfuscate_php(input_file, obfuscation_level, create_backup, output_directory)
119+
elif mode == '2':
120+
input_files = input(f"{GREEN}\nEnter a comma-separated list of PHP files to obfuscate: {RESET}")
121+
files = [file.strip() for file in input_files.split(',') if file.strip()]
122+
for file in files:
123+
obfuscate_php(file, obfuscation_level, create_backup, output_directory)
124+
elif mode == '3':
125+
input_directory = input(f"{GREEN}\nEnter the directory path containing PHP files: {RESET}")
126+
process_directory(input_directory, obfuscation_level, exclude_list, create_backup, output_directory)
127+
else:
128+
print(f"{RED}Invalid mode. Exiting...{RESET}")
129+
sys.exit(1)
130+
131+
def main():
132+
interactive = input(f"{YELLOW}Do you want to run the script in interactive mode? (y/n): {RESET}").lower()
133+
if interactive == 'y':
134+
interactive_mode()
135+
else:
136+
print(f"{GREEN}Choose the mode for obfuscating your PHP files: {RESET}")
137+
print(f"{BLUE}1: Single file{RESET}")
138+
print(f"{BLUE}2: Multiple files{RESET}")
139+
print(f"{BLUE}3: Entire project directory{RESET}")
140+
mode = input(f"{GREEN}Enter the mode number (1/2/3): {RESET}")
141+
142+
print(f"{GREEN}\nSelect obfuscation level: {RESET}")
143+
print(f"{BLUE}1: Low (Base64 encoding){RESET}")
144+
print(f"{BLUE}2: Medium (zlib compression + Base64 encoding){RESET}")
145+
print(f"{BLUE}3: High (zlib compression + Base64 encoding + simple variable renaming){RESET}")
146+
obfuscation_level = input(f"{GREEN}Enter the obfuscation level number (1/2/3): {RESET}")
147+
148+
output_directory = input(f"{GREEN}Enter the output directory path: {RESET}")
149+
if not os.path.exists(output_directory):
150+
os.makedirs(output_directory)
151+
152+
level_mapping = {'1': 'low', '2': 'medium', '3': 'high'}
153+
if obfuscation_level not in level_mapping:
154+
logging.warning("Invalid obfuscation level. Choose from: 1, 2, or 3")
155+
print(f"{RED}Invalid obfuscation level. Choose from: 1, 2, or 3{RESET}")
156+
sys.exit(1)
157+
obfuscation_level = level_mapping[obfuscation_level]
158+
159+
exclude_input = input(f"{GREEN}Enter file or directory paths to exclude (separated by a space): {RESET}")
160+
exclude_list = [os.path.abspath(exclude.strip()) for exclude in exclude_input.split()]
161+
162+
backup_input = input(f"{GREEN}Create backups of original PHP files? (y/n): {RESET}").lower()
163+
create_backup = backup_input == 'y'
164+
165+
if mode == '1':
166+
input_file = input(f"{GREEN}Enter the PHP file path: {RESET}")
167+
if not input_file.lower().endswith(".php") or not os.path.isfile(input_file):
168+
logging.warning("Invalid PHP file path")
169+
print(f"{RED}Invalid PHP file path{RESET}")
170+
sys.exit(1)
171+
if any(os.path.commonpath([input_file, exclude]) == os.path.abspath(exclude) for exclude in exclude_list):
172+
logging.info(f"Skipping {input_file}: excluded")
173+
else:
174+
obfuscate_php(input_file, obfuscation_level, create_backup)
175+
elif mode == '2':
176+
file_paths = input(f"{GREEN}Enter the PHP file paths separated by a space: {RESET}")
177+
files = file_paths.split()
178+
179+
for input_file in files:
180+
if not input_file.lower().endswith(".php") or not os.path.isfile(input_file):
181+
logging.warning(f"Skipping {input_file}: not a valid PHP file")
182+
print(f"{RED}Skipping {input_file}: not a valid PHP file{RESET}")
183+
continue
184+
obfuscate_php(input_file, obfuscation_level, create_backup)
185+
elif mode == '3':
186+
input_directory = input(f"{GREEN}Enter the project directory path: {RESET}")
187+
if not os.path.isdir(input_directory):
188+
logging.warning("Invalid directory path")
189+
print(f"{RED}Invalid directory path{RESET}")
190+
sys.exit(1)
191+
process_directory(input_directory, obfuscation_level, exclude_list, create_backup)
192+
else:
193+
logging.warning("Invalid mode. Choose from: 1, 2, or 3")
194+
print(f"{RED}Invalid mode. Choose from: 1, 2, or 3{RESET}")
195+
sys.exit(1)
196+
197+
if __name__ == "__main__":
198+
main()

start.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
python3 /home/YOUR_USERNAME/path/to/your/script/main.py

0 commit comments

Comments
 (0)