diff --git a/deploy/services/drhider.py b/deploy/services/drhider.py index f9955c4..50d3ef5 100644 --- a/deploy/services/drhider.py +++ b/deploy/services/drhider.py @@ -189,6 +189,7 @@ class TwoPassObfuscator: def __init__(self, llm_client=None): self._mapping: Dict[str, str] = {} # оригинал → замена (только для точных текстовых совпадений) self._regex_replacements: List[Tuple[str, str, Callable]] = [] # (pattern, type, generator) + self._sorted_keys: List[str] = [] # ключи mapping, отсортированные по длине (убывание) self._llm_client = llm_client def obfuscate(self, files: List[Tuple[str, bytes, str]]) -> Tuple[bytes, str]: @@ -220,6 +221,9 @@ class TwoPassObfuscator: if self._llm_client: self._scan_llm_ner(all_texts) + # Предсортировать ключи один раз для _apply_replacements + self._sorted_keys = sorted(self._mapping.keys(), key=len, reverse=True) + # --- Проход 2: замена --- results = [] for fname, content, ctype in files: @@ -244,6 +248,7 @@ class TwoPassObfuscator: finally: self._mapping.clear() self._regex_replacements.clear() + self._sorted_keys.clear() def _expand_zips(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]: """Распаковать ZIP-файлы, заменив их содержимым. Остальные файлы — как есть.""" @@ -432,13 +437,15 @@ class TwoPassObfuscator: def _apply_replacements(self, text: str) -> str: """Применить все замены из словаря mapping к строке. Сначала длинные, потом короткие.""" - # Сортируем по длине оригинала (убывание) чтобы избежать частичных замен - sorted_keys = sorted(self._mapping.keys(), key=len, reverse=True) result = text - for original in sorted_keys: + for original in self._sorted_keys: replacement = self._mapping[original] - # Только точное совпадение (не подстрока) - result = re.sub(re.escape(original), replacement, result) + # Границы слова — если сущность начинается и заканчивается на \w + if original and original[0].isalnum() and original[-1].isalnum(): + pattern = r'(? Tuple[bytes, str]: @@ -220,6 +221,9 @@ class TwoPassObfuscator: if self._llm_client: self._scan_llm_ner(all_texts) + # Предсортировать ключи один раз для _apply_replacements + self._sorted_keys = sorted(self._mapping.keys(), key=len, reverse=True) + # --- Проход 2: замена --- results = [] for fname, content, ctype in files: @@ -244,6 +248,7 @@ class TwoPassObfuscator: finally: self._mapping.clear() self._regex_replacements.clear() + self._sorted_keys.clear() def _expand_zips(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]: """Распаковать ZIP-файлы, заменив их содержимым. Остальные файлы — как есть.""" @@ -432,13 +437,15 @@ class TwoPassObfuscator: def _apply_replacements(self, text: str) -> str: """Применить все замены из словаря mapping к строке. Сначала длинные, потом короткие.""" - # Сортируем по длине оригинала (убывание) чтобы избежать частичных замен - sorted_keys = sorted(self._mapping.keys(), key=len, reverse=True) result = text - for original in sorted_keys: + for original in self._sorted_keys: replacement = self._mapping[original] - # Только точное совпадение (не подстрока) - result = re.sub(re.escape(original), replacement, result) + # Границы слова — если сущность начинается и заканчивается на \w + if original and original[0].isalnum() and original[-1].isalnum(): + pattern = r'(?