Files
Geroi-Kodeksa/HumanAI-Forensic-Hard/scripts/veracrypt.py
2026-03-02 21:44:22 +03:00

186 lines
6.2 KiB
Python

import logging
from typing import Generator, Iterable, List, Tuple
from volatility3.framework import constants, interfaces, objects, renderers
from volatility3.framework.configuration import requirements
from volatility3.framework.interfaces import configuration
from volatility3.framework.objects.utility import array_to_string
from volatility3.framework.renderers import format_hints
from volatility3.framework.symbols import intermed
from volatility3.framework.symbols.windows.extensions import pe
from volatility3.plugins.windows import modules
vollog = logging.getLogger(__name__)
class Passphrase(interfaces.plugins.PluginInterface):
"""VeraCrypt/TrueCrypt cached passphrase finder (driver .data scan)."""
_version = (0, 1, 0)
_required_framework_version = (2, 5, 2)
@classmethod
def get_requirements(cls) -> List[configuration.RequirementInterface]:
return [
requirements.ModuleRequirement(
"kernel",
description="Windows kernel",
architectures=["Intel32", "Intel64"],
),
requirements.VersionRequirement(
name="modules", component=modules.Modules, version=(3, 0, 0)
),
requirements.IntRequirement(
name="min-length",
description="Minimum length of passphrases to identify",
default=5,
optional=True,
),
requirements.StringRequirement(
name="driver",
description=(
"Driver name substring to scan (case-insensitive), "
"e.g. 'veracrypt', 'veracrypt-x64.sys', 'truecrypt.sys'"
),
default="veracrypt",
optional=True,
),
]
def scan_module(
self, module_base: int, layer_name: str
) -> Generator[Tuple[int, str], None, None]:
pe_table_name = intermed.IntermediateSymbolTable.create(
self.context, self.config_path, "windows", "pe", class_types=pe.class_types
)
dos_header: pe.IMAGE_DOS_HEADER = self.context.object(
pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
layer_name,
module_base,
)
data_section: objects.StructType = next(
sec
for sec in dos_header.get_nt_header().get_sections()
if array_to_string(sec.Name) == ".data"
)
base: int = data_section.VirtualAddress + module_base
size: int = data_section.Misc.VirtualSize
# Looking at `Length` in TrueCrypt/Common/Password.h::Password struct
DWORD_SIZE_BYTES: int = 4
fmt = objects.DataFormatInfo(
length=DWORD_SIZE_BYTES, byteorder="little", signed=True
)
int32 = objects.templates.ObjectTemplate(
objects.Integer, pe_table_name + constants.BANG + "int", data_format=fmt
)
count, not_aligned = divmod(size, DWORD_SIZE_BYTES)
if not_aligned:
raise ValueError("PE data section not DWORD-aligned!")
lengths = self.context.object(
pe_table_name + constants.BANG + "array",
layer_name,
base,
count=count,
subtype=int32,
)
min_length = self.config.get("min-length")
for length in lengths:
if not min_length <= length <= 64:
continue
offset = length.vol["offset"] + DWORD_SIZE_BYTES
passphrase: objects.Bytes = self.context.object(
pe_table_name + constants.BANG + "bytes",
layer_name,
offset,
length=length,
)
if not all(0x20 <= c < 0x7F for c in passphrase):
continue
buf: objects.Bytes = self.context.object(
pe_table_name + constants.BANG + "bytes",
layer_name,
offset + length + 1,
length=3,
)
if any(buf):
continue
yield offset, passphrase.decode(encoding="ascii")
def _find_driver_bases(
self, mods: Iterable[interfaces.objects.ObjectInterface]
) -> List[int]:
driver_substr = (self.config.get("driver") or "").lower().strip()
def matches(mod_name: str, needle: str) -> bool:
return needle and needle in mod_name
def bases_for(needle: str) -> List[int]:
out: List[int] = []
for mod in mods:
try:
name = mod.BaseDllName.get_string().lower()
except Exception:
continue
if matches(name, needle):
out.append(int(mod.DllBase))
return out
if driver_substr:
bases = bases_for(driver_substr)
if bases:
return bases
for needle in ("veracrypt", "truecrypt"):
bases = bases_for(needle)
if bases:
return bases
return []
def _generator(self):
kernel = self.context.modules[self.config["kernel"]]
mods: Iterable[interfaces.objects.ObjectInterface] = modules.Modules.list_modules(
self.context, self.config["kernel"]
)
driver_bases = self._find_driver_bases(mods)
if not driver_bases:
vollog.warning(
"No VeraCrypt driver module found in the modules list. Unable to proceed."
)
return
seen = set()
for module_base in driver_bases:
try:
for offset, password in self.scan_module(module_base, kernel.layer_name):
key = (offset, password)
if key in seen:
continue
seen.add(key)
yield (0, (format_hints.Hex(offset), len(password), password))
except Exception as exc:
vollog.debug("Failed scanning module at 0x%x: %s", module_base, exc)
def run(self) -> renderers.TreeGrid:
return renderers.TreeGrid(
[
("Offset", format_hints.Hex),
("Length", int),
("Password", str),
],
self._generator(),
)