Init. commit

This commit is contained in:
Caplag
2026-03-02 21:44:22 +03:00
committed by Ivan Z
commit 9511b38280
38 changed files with 4397 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
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(),
)