diff --git a/.gitignore b/.gitignore index f056d4c..f52d357 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,7 @@ __pycache__/* python-*.exe build/* dist/* +Encoded/* +Decoded/* decoder*.spec encoder*.spec \ No newline at end of file diff --git a/calc.html b/Examples/calc.html similarity index 100% rename from calc.html rename to Examples/calc.html diff --git a/example.html b/Examples/example.html similarity index 100% rename from example.html rename to Examples/example.html diff --git a/exampleCoffeeHouse.html b/Examples/exampleCoffeeHouse.html similarity index 99% rename from exampleCoffeeHouse.html rename to Examples/exampleCoffeeHouse.html index ad30cd7..1d95ab7 100644 --- a/exampleCoffeeHouse.html +++ b/Examples/exampleCoffeeHouse.html @@ -1,58 +1,58 @@ - - - - The Coffee House - - - - -
- -
-
-
-

About Us

-

We are a cozy coffee shop located in the heart of the city. Our mission is to provide our customers with high-quality coffee, baked goods, and a welcoming atmosphere.

- The Coffee House -
- -
-

Contact Us

-
- -
- -
- -
- -
-
-
- - + + + + The Coffee House + + + + +
+ +
+
+
+

About Us

+

We are a cozy coffee shop located in the heart of the city. Our mission is to provide our customers with high-quality coffee, baked goods, and a welcoming atmosphere.

+ The Coffee House +
+ +
+

Contact Us

+
+ +
+ +
+ +
+ +
+
+
+ + \ No newline at end of file diff --git a/decoder.py b/decoder.py index 8a0356d..0510fe8 100644 --- a/decoder.py +++ b/decoder.py @@ -6,6 +6,7 @@ import gzip import io from urllib.parse import unquote +from readchar import readkey, key import magic @@ -22,7 +23,9 @@ def read_file(input_file, mode='rb', encoding=None): return content def write_file(output_file, content, mode='w', encoding=None): - with open(output_file, mode, encoding=encoding) as f: + decoded_dir = "Decoded" + decoded_file_path = f"{decoded_dir}/{output_file}" + with open(decoded_file_path, mode, encoding=encoding) as f: f.write(content) class CustomHTMLParser(HTMLParser): @@ -38,6 +41,7 @@ def parse_decoding_arguments(): parser.add_argument('input_html_file', type=str, help='Input HTML file') parser.add_argument('output_file', type=str, help='Output file') parser.add_argument('--cyberchef', action='store_true', help='Save CyberChef output to a file') + parser.add_argument('--step_mode', action='store_true', help='Decoder will do one step at a time and show what happens at each step') return parser.parse_args() def decode_base64(encoded_content): @@ -85,10 +89,19 @@ def create_cyberchef_ops_json(encoding_steps): return json.dumps(cyberchef_ops, indent=2) -def decode_random_encoding(script_content): +def step_mode(decoded_content_snippet, current_encoding_step, next_encoding_step): + print(f"\nCurrent encoding step: {current_encoding_step} -> {next_encoding_step}") + print(f"Decoded content snippet (first 500 characters): \n{decoded_content_snippet[:500]}") + print("Press ENTER key to proceed to the next decoding step...") + while True: + k = readkey() + if k == key.ENTER: + break + +def decode_random_encoding(script_content, step_mode_flag): decoded_content = script_content counters = {"base64": 0, "unicode": 0, "uri": 0, "gzip": 0} - encoding_steps = [] + encoding_steps = ["Encoded content"] while True: updated = False @@ -99,6 +112,8 @@ def decode_random_encoding(script_content): decoded_str = decode_base64(b64_match.group(2)).decode('utf-8') decoded_content = decoded_content.replace(b64_match.group(0), decoded_str) counters["base64"] += 1 + if step_mode_flag: + step_mode(decoded_str, ''.join(encoding_steps[-1:]), "base64") encoding_steps.append("base64") updated = True @@ -110,6 +125,8 @@ def decode_random_encoding(script_content): if decoded_str != encoded_str: decoded_content = decoded_content.replace(unicode_match.group(0), decoded_str) counters["unicode"] += 1 + if step_mode_flag: + step_mode(decoded_str, ''.join(encoding_steps[-1:]), "uricode") encoding_steps.append("unicode") updated = True else: @@ -118,6 +135,8 @@ def decode_random_encoding(script_content): if decoded_uri_str != encoded_str: decoded_content = decoded_content.replace(unicode_match.group(0), decoded_uri_str) counters["uri"] += 1 + if step_mode_flag: + step_mode(decoded_str, ''.join(encoding_steps[-1:]), "uri") encoding_steps.append("uri") updated = True except Exception as e: @@ -129,10 +148,14 @@ def decode_random_encoding(script_content): decoded_str = decode_and_unzip_base64(gzip_match.group(1)) decoded_content = decoded_content.replace(gzip_match.group(0), decoded_str) counters["gzip"] += 1 + if step_mode_flag: + step_mode(decoded_str, ''.join(encoding_steps[-1:]), "gzip") encoding_steps.append("gzip") updated = True if not updated: + print("decoded_content snippet:", decoded_content[:200]) # Print the first 200 characters of the decoded content + print("\nNo more encodings detected. Decoding complete.") break for key, value in counters.items(): @@ -144,7 +167,9 @@ def decode_random_encoding(script_content): def scan_for_mime_types(output_file): mime = magic.Magic(mime=True) - with open(output_file, "rb") as f: + decoded_dir = "Decoded" + decoded_file_path = f"{decoded_dir}/{output_file}" + with open(decoded_file_path, "rb") as f: content = f.read() mime_type = mime.from_buffer(content) print(f"MIME Type: {mime_type}") @@ -186,7 +211,9 @@ def scan_for_mime_types(output_file): def scan_for_script_tags(output_file): mime = magic.Magic(mime=True) - with open(output_file, "rb") as f: + decoded_dir = "Decoded" + decoded_file_path = f"{decoded_dir}/{output_file}" + with open(decoded_file_path, "rb") as f: content = f.read() mime_type = mime.from_buffer(content) @@ -214,7 +241,7 @@ def scan_for_script_tags(output_file): def decode_main(args): script_content = extract_script_content(args.input_html_file) - decoded_content, encoding_steps = decode_random_encoding(script_content) + decoded_content, encoding_steps = decode_random_encoding(script_content, args.step_mode) write_file(args.output_file, decoded_content, mode='w', encoding='utf-8') scan_for_mime_types(args.output_file) scan_for_script_tags(args.output_file) diff --git a/encoder.py b/encoder.py index d452dde..068c258 100644 --- a/encoder.py +++ b/encoder.py @@ -17,9 +17,13 @@ def read_file(input_file, mode='rb', encoding=None): content = f.read() return content -def write_file(output_file, content, mode='w', encoding=None): - with open(output_file, mode, encoding=encoding) as f: +def write_file(output_file, content, mode='w', encoding=None): + encoded_dir = "Encoded" + output_file_path = f"{encoded_dir}/{output_file}" + with open(output_file_path, mode, encoding=encoding) as f: f.write(content) + print(f"Encoded content written to: {output_file_path}") + f.close() def gzip_content(content): compressed = gzip.compress(content) @@ -83,18 +87,21 @@ def gzip_wrap_in_html(encoded_content): def random_encoding(content): html_content = content.decode('utf-8') encoding_steps = random.randint(1, 10) + encoding_patterns = { + 'None': ('base64', 'unicode', 'uri'), + 'base64': ('unicode', 'uri'), + 'unicode': ('base64', 'uri'), + 'uri': ('base64', 'unicode') + } prev_encoding = None - prev_prev_encoding = None - + encoding_flow = [] + for _ in range(encoding_steps): - encoding_types = ['base64', 'unicode', 'uri'] - if prev_encoding == 'unicode' and prev_prev_encoding != 'uri': - encoding_type = random.choice(['base64', 'unicode']) - elif prev_encoding == 'uri' and prev_prev_encoding != 'unicode': - encoding_type = random.choice(['base64', 'uri']) + if prev_encoding is None: + encoding_type = random.choice(encoding_patterns.get('None')) else: - encoding_type = random.choice(encoding_types) - + encoding_type = random.choice(encoding_patterns.get(prev_encoding)) + if encoding_type == 'base64': content = encode_base64(content) html_content = base64_wrap_in_html(content) @@ -108,8 +115,11 @@ def random_encoding(content): html_content = unicode_wrap_in_html(content) content = html_content.encode('utf-8') - prev_prev_encoding = prev_encoding prev_encoding = encoding_type + encoding_flow.append(encoding_type) + + print(f"Total encoding steps: {encoding_steps}") + print(f"Random encoding flow: original -> {' -> '.join(encoding_flow)}") return html_content def main(args): @@ -140,3 +150,4 @@ def main(args): if __name__ == '__main__': main(parse_arguments()) + \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index bc3665e..8b0d76a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ argparse -python-magic \ No newline at end of file +python-magic +readchar \ No newline at end of file