84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
from functools import lru_cache
|
|
from pathlib import Path
|
|
from typing import Dict, List, Optional
|
|
|
|
import omvll
|
|
|
|
_CONFIG_PATH = Path(__file__).with_name("obfuscation.yml")
|
|
|
|
|
|
def _parse_settings() -> Dict[str, List[str] | Optional[int]]:
|
|
settings: Dict[str, List[str] | Optional[int]] = {
|
|
"seed": None,
|
|
"functions": [],
|
|
"passes": [],
|
|
}
|
|
current: Optional[str] = None
|
|
if not _CONFIG_PATH.exists():
|
|
return settings
|
|
|
|
for raw_line in _CONFIG_PATH.read_text(encoding="utf-8").splitlines():
|
|
line = raw_line.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
if line.startswith("seed:"):
|
|
value = line.split(":", 1)[1].strip()
|
|
try:
|
|
settings["seed"] = int(value, 0)
|
|
except ValueError:
|
|
settings["seed"] = None
|
|
continue
|
|
if line.startswith("functions"):
|
|
current = "functions"
|
|
continue
|
|
if line.startswith("passes"):
|
|
current = "passes"
|
|
continue
|
|
if line.startswith("-") and current in ("functions", "passes"):
|
|
entry = line[1:].strip().strip('"').strip("'")
|
|
if entry:
|
|
settings[current].append(entry)
|
|
return settings
|
|
|
|
|
|
class PurrfectSnapConfig(omvll.ObfuscationConfig):
|
|
def __init__(self, settings: Dict[str, List[str] | Optional[int]]):
|
|
super().__init__()
|
|
self._targets = set(settings.get("functions") or [])
|
|
self._passes = set(settings.get("passes") or [])
|
|
|
|
def _should_obfuscate(self, func: omvll.Function) -> bool:
|
|
if not self._targets:
|
|
return True
|
|
return func.demangled_name in self._targets or func.name in self._targets
|
|
|
|
def _pass_enabled(self, name: str) -> bool:
|
|
return not self._passes or name in self._passes
|
|
|
|
def obfuscate_arithmetic(self, mod: omvll.Module, func: omvll.Function) -> bool:
|
|
return self._should_obfuscate(func) and self._pass_enabled("InstructionsSubstitution")
|
|
|
|
def flatten_cfg(self, mod: omvll.Module, func: omvll.Function) -> bool:
|
|
return self._should_obfuscate(func) and self._pass_enabled("ControlFlowFlattening")
|
|
|
|
def bogus_control_flow(self, mod: omvll.Module, func: omvll.Function) -> bool:
|
|
return self._should_obfuscate(func) and self._pass_enabled("BogusControlFlow")
|
|
|
|
def obfuscate_string(
|
|
self,
|
|
mod: omvll.Module,
|
|
func: omvll.Function,
|
|
string: bytes,
|
|
):
|
|
if self._should_obfuscate(func) and self._pass_enabled("StringsEncryption"):
|
|
return omvll.StringEncOptGlobal()
|
|
return False
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def omvll_get_config() -> omvll.ObfuscationConfig:
|
|
"""Return an instance of the obfuscation configuration used by O-MVLL."""
|
|
return PurrfectSnapConfig(_parse_settings())
|