Harden BitTorrent and DHT malware, mount-trap, and archive-trap detection
Browse files- armiger_dht_rsi.py +3 -1
- armiger_inference.py +36 -10
armiger_dht_rsi.py
CHANGED
|
@@ -3226,7 +3226,9 @@ def generate_golden_canary_suite(seed: int = 20261018) -> List[CanaryItem]:
|
|
| 3226 |
"Big.Buck.Bunny.2024.CAM.1080p.download_tool.bat",
|
| 3227 |
]
|
| 3228 |
for i in range(25):
|
| 3229 |
-
|
|
|
|
|
|
|
| 3230 |
items.append(CanaryItem(
|
| 3231 |
item_id=f"canary_jnk_{i:03d}",
|
| 3232 |
title=name,
|
|
|
|
| 3226 |
"Big.Buck.Bunny.2024.CAM.1080p.download_tool.bat",
|
| 3227 |
]
|
| 3228 |
for i in range(25):
|
| 3229 |
+
_base = malware_names[i % len(malware_names)]
|
| 3230 |
+
_dot = _base.rfind(".")
|
| 3231 |
+
name = f"{_base[:_dot]}_sample{i}{_base[_dot:]}" if _dot != -1 else f"{_base}_sample{i}"
|
| 3232 |
items.append(CanaryItem(
|
| 3233 |
item_id=f"canary_jnk_{i:03d}",
|
| 3234 |
title=name,
|
armiger_inference.py
CHANGED
|
@@ -13,12 +13,16 @@ from __future__ import annotations
|
|
| 13 |
import hashlib
|
| 14 |
import json
|
| 15 |
import math
|
|
|
|
| 16 |
from pathlib import Path
|
| 17 |
import re
|
| 18 |
from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple
|
| 19 |
import zlib
|
| 20 |
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
NEURAL_HEAD_CLASSES: Dict[str, List[str]] = {
|
| 24 |
"category": [
|
|
@@ -94,7 +98,7 @@ _SIDE_EP_ZIP_RE = re.compile(
|
|
| 94 |
r"\bS\d{1,2}E\d{1,3}\b.*?\b(?:1080p|720p|2160p|WEB-DL|WEBRip|BluRay|HDTV)\b)"
|
| 95 |
)
|
| 96 |
_SIDE_BENIGN_ZIP_RE = re.compile(
|
| 97 |
-
r"(?i)\b(?:batch|complete|season[ ._-]*\d+|s\d{1,2}[ ._-]*complete|\d{1,3}[ ._-]*-[ ._-]*\d{1,3}|"
|
| 98 |
r"ost|soundtrack|artbook|scans?|wallpapers?|fonts?|subs?|subtitles?)\b"
|
| 99 |
)
|
| 100 |
|
|
@@ -116,6 +120,8 @@ def _get_vocab_ext_map() -> Dict[str, int]:
|
|
| 116 |
if _VOCAB_EXT_MAP is not None:
|
| 117 |
return _VOCAB_EXT_MAP
|
| 118 |
vpath = Path(__file__).resolve().with_name("vocab.json")
|
|
|
|
|
|
|
| 119 |
if vpath.exists():
|
| 120 |
data = json.loads(vpath.read_text(encoding="utf-8"))
|
| 121 |
_VOCAB_EXT_MAP = {e: i + 1 for i, e in enumerate(data.get("exts", []))}
|
|
@@ -259,7 +265,7 @@ def encode_torrent_features(
|
|
| 259 |
htm_set = {"html", "htm", "url", "mht", "torrent"}
|
| 260 |
scr_set = {"scr", "lnk", "vbs", "hta", "pif", "ps1", "wsf", "reg"}
|
| 261 |
vid_set = {"mkv", "mp4", "avi", "ts", "m2ts", "wmv", "mov", "webm", "flv", "mpg", "mpeg", "m4v", "vob", "ogv", "rmvb", "3gp", "asf", "divx"}
|
| 262 |
-
bd_game_benign = {"vcdiff", "apk", "bdmv", "clpi", "mpls", "ifo", "bup", "vob", "npa", "vpk", "pck", "umd", "pak", "xp3", "rgss3a", "wolf", "nsp", "xci", "wbfs"}
|
| 263 |
|
| 264 |
side[0] = sum(1 for e in f_exts_str if e in ebk_set) / n_f
|
| 265 |
side[1] = sum(1 for e in f_exts_str if e in pdf_set) / n_f
|
|
@@ -268,15 +274,32 @@ def encode_torrent_features(
|
|
| 268 |
side[4] = sum(1 for e in f_exts_str if e in con_set) / n_f
|
| 269 |
side[5] = sum(1 for e in f_exts_str if e in app_set) / n_f
|
| 270 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
n_real_exec_dll = 0
|
| 272 |
has_real_exe = False
|
| 273 |
has_dll = False
|
| 274 |
has_scr_trap = False
|
| 275 |
has_oversized_lnk = False
|
| 276 |
has_root_launcher = False
|
|
|
|
|
|
|
| 277 |
vid_depths: List[int] = []
|
| 278 |
|
| 279 |
for (p_i, _), e_str, s_b, d_i, w_i in zip(items, f_exts_str, sizes, depths, words_list):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 280 |
p_tok_h = _extract_token_hashes(p_i)
|
| 281 |
is_benign_stub = (e_str == "exe") and (s_b < 15 or 16570 in w_i or bool(p_tok_h & _BENIGN_README_EXE_H))
|
| 282 |
if e_str in exe_dll_set and not is_benign_stub:
|
|
@@ -300,29 +323,32 @@ def encode_torrent_features(
|
|
| 300 |
side[7] = sum(1 for e in f_exts_str if e in iso_set) / n_f
|
| 301 |
side[8] = sum(1 for e in f_exts_str if e in arc_set) / n_f
|
| 302 |
side[9] = sum(1 for e in f_exts_str if e in htm_set) / n_f
|
| 303 |
-
side[10] = 1.0 if
|
| 304 |
|
| 305 |
-
vc = bool(_SIDE_VID_CLAIM_RE.search(name) or _SIDE_ANIME_KW_RE.search(name) or has_sub_grp or has_dub_grp)
|
| 306 |
is_sw_or_game = bool(
|
| 307 |
has_game_grp
|
| 308 |
or has_sw_grp
|
| 309 |
-
or _SIDE_SW_APP_TITLE_RE.search(name)
|
| 310 |
or any(e in bd_game_benign for e in f_exts_str)
|
| 311 |
)
|
| 312 |
vid_share = base_stats[2]
|
| 313 |
-
flagged =
|
| 314 |
-
if not is_sw_or_game
|
| 315 |
if vc and has_real_exe and has_dll:
|
| 316 |
flagged = True
|
| 317 |
-
elif vc and
|
| 318 |
flagged = True
|
| 319 |
elif (vc or len(vid_depths) > 0) and has_oversized_lnk:
|
| 320 |
flagged = True
|
| 321 |
elif vc and vid_share == 0.0 and (has_real_exe or has_scr_trap):
|
| 322 |
flagged = True
|
| 323 |
-
elif len(items) =
|
| 324 |
if _SIDE_EP_ZIP_RE.search(name) and not _SIDE_BENIGN_ZIP_RE.search(name):
|
| 325 |
flagged = True
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
|
| 327 |
if flagged or _SIDE_VPN_TRAP_RE.search(name) or (vc and vid_share == 0.0 and (side[6] > 0 or side[9] > 0 or side[10] > 0)):
|
| 328 |
side[11] = 1.0
|
|
|
|
| 13 |
import hashlib
|
| 14 |
import json
|
| 15 |
import math
|
| 16 |
+
import os
|
| 17 |
from pathlib import Path
|
| 18 |
import re
|
| 19 |
from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple
|
| 20 |
import zlib
|
| 21 |
|
| 22 |
+
try:
|
| 23 |
+
import numpy as np
|
| 24 |
+
except ImportError:
|
| 25 |
+
np = None # type: ignore[assignment]
|
| 26 |
|
| 27 |
NEURAL_HEAD_CLASSES: Dict[str, List[str]] = {
|
| 28 |
"category": [
|
|
|
|
| 98 |
r"\bS\d{1,2}E\d{1,3}\b.*?\b(?:1080p|720p|2160p|WEB-DL|WEBRip|BluRay|HDTV)\b)"
|
| 99 |
)
|
| 100 |
_SIDE_BENIGN_ZIP_RE = re.compile(
|
| 101 |
+
r"(?i)\b(?:batch|complete|season[ ._-]*\d+|s\d{1,2}[ ._-]*complete|e?\d{1,3}[ ._-]*[~-][ ._-]*e?\d{1,3}|시즌\s*\d+|완결|全集|合集|"
|
| 102 |
r"ost|soundtrack|artbook|scans?|wallpapers?|fonts?|subs?|subtitles?)\b"
|
| 103 |
)
|
| 104 |
|
|
|
|
| 120 |
if _VOCAB_EXT_MAP is not None:
|
| 121 |
return _VOCAB_EXT_MAP
|
| 122 |
vpath = Path(__file__).resolve().with_name("vocab.json")
|
| 123 |
+
if not vpath.exists() and os.environ.get("ARMIGER_MODEL_DIR"):
|
| 124 |
+
vpath = Path(os.environ["ARMIGER_MODEL_DIR"]) / "vocab.json"
|
| 125 |
if vpath.exists():
|
| 126 |
data = json.loads(vpath.read_text(encoding="utf-8"))
|
| 127 |
_VOCAB_EXT_MAP = {e: i + 1 for i, e in enumerate(data.get("exts", []))}
|
|
|
|
| 265 |
htm_set = {"html", "htm", "url", "mht", "torrent"}
|
| 266 |
scr_set = {"scr", "lnk", "vbs", "hta", "pif", "ps1", "wsf", "reg"}
|
| 267 |
vid_set = {"mkv", "mp4", "avi", "ts", "m2ts", "wmv", "mov", "webm", "flv", "mpg", "mpeg", "m4v", "vob", "ogv", "rmvb", "3gp", "asf", "divx"}
|
| 268 |
+
bd_game_benign = {"vcdiff", "apk", "bdmv", "clpi", "mpls", "ifo", "bup", "vob", "npa", "vpk", "pck", "umd", "pak", "xp3", "rgss3a", "wolf", "nsp", "xci", "wbfs", "rpa", "rpy", "rpyb"}
|
| 269 |
|
| 270 |
side[0] = sum(1 for e in f_exts_str if e in ebk_set) / n_f
|
| 271 |
side[1] = sum(1 for e in f_exts_str if e in pdf_set) / n_f
|
|
|
|
| 274 |
side[4] = sum(1 for e in f_exts_str if e in con_set) / n_f
|
| 275 |
side[5] = sum(1 for e in f_exts_str if e in app_set) / n_f
|
| 276 |
|
| 277 |
+
vc = bool(_SIDE_VID_CLAIM_RE.search(name) or _SIDE_ANIME_KW_RE.search(name) or has_sub_grp or has_dub_grp)
|
| 278 |
+
has_renpy_structure = not vc and any(
|
| 279 |
+
p_i.replace("\\", "/").lower().endswith((".rpa", ".rpy", ".rpyb"))
|
| 280 |
+
or "/renpy/" in "/" + p_i.replace("\\", "/").lower()
|
| 281 |
+
for p_i, _ in items
|
| 282 |
+
)
|
| 283 |
+
renpy_say_re = re.compile(r"(?i)(?:^|/)lib/(?:py\d+-)?windows-[^/]+/say\.vbs$")
|
| 284 |
+
|
| 285 |
n_real_exec_dll = 0
|
| 286 |
has_real_exe = False
|
| 287 |
has_dll = False
|
| 288 |
has_scr_trap = False
|
| 289 |
has_oversized_lnk = False
|
| 290 |
has_root_launcher = False
|
| 291 |
+
has_unconditional_trap_ext = False
|
| 292 |
+
has_any_scr_ext = False
|
| 293 |
vid_depths: List[int] = []
|
| 294 |
|
| 295 |
for (p_i, _), e_str, s_b, d_i, w_i in zip(items, f_exts_str, sizes, depths, words_list):
|
| 296 |
+
p_posix = p_i.replace("\\", "/")
|
| 297 |
+
if has_renpy_structure and renpy_say_re.search(p_posix):
|
| 298 |
+
continue
|
| 299 |
+
if e_str in scr_set:
|
| 300 |
+
has_any_scr_ext = True
|
| 301 |
+
if e_str in {"scr", "vbs", "vbe", "hta", "pif", "wsf", "wsh", "cpl", "one"}:
|
| 302 |
+
has_unconditional_trap_ext = True
|
| 303 |
p_tok_h = _extract_token_hashes(p_i)
|
| 304 |
is_benign_stub = (e_str == "exe") and (s_b < 15 or 16570 in w_i or bool(p_tok_h & _BENIGN_README_EXE_H))
|
| 305 |
if e_str in exe_dll_set and not is_benign_stub:
|
|
|
|
| 323 |
side[7] = sum(1 for e in f_exts_str if e in iso_set) / n_f
|
| 324 |
side[8] = sum(1 for e in f_exts_str if e in arc_set) / n_f
|
| 325 |
side[9] = sum(1 for e in f_exts_str if e in htm_set) / n_f
|
| 326 |
+
side[10] = 1.0 if has_any_scr_ext else 0.0
|
| 327 |
|
|
|
|
| 328 |
is_sw_or_game = bool(
|
| 329 |
has_game_grp
|
| 330 |
or has_sw_grp
|
| 331 |
+
or (not vc and _SIDE_SW_APP_TITLE_RE.search(name))
|
| 332 |
or any(e in bd_game_benign for e in f_exts_str)
|
| 333 |
)
|
| 334 |
vid_share = base_stats[2]
|
| 335 |
+
flagged = has_unconditional_trap_ext
|
| 336 |
+
if not is_sw_or_game:
|
| 337 |
if vc and has_real_exe and has_dll:
|
| 338 |
flagged = True
|
| 339 |
+
elif vc and len(vid_depths) >= 1 and (has_real_exe or has_root_launcher or has_scr_trap):
|
| 340 |
flagged = True
|
| 341 |
elif (vc or len(vid_depths) > 0) and has_oversized_lnk:
|
| 342 |
flagged = True
|
| 343 |
elif vc and vid_share == 0.0 and (has_real_exe or has_scr_trap):
|
| 344 |
flagged = True
|
| 345 |
+
elif len(items) <= 2 and any(e in ("zip", "zipx", "rar", "7z") for e in f_exts_str) and vid_share == 0.0:
|
| 346 |
if _SIDE_EP_ZIP_RE.search(name) and not _SIDE_BENIGN_ZIP_RE.search(name):
|
| 347 |
flagged = True
|
| 348 |
+
elif len(items) <= 2 and any(e in ("iso", "img", "vhd", "vhdx", "udf") for e in f_exts_str) and vid_share == 0.0:
|
| 349 |
+
name_stem = re.sub(r"\.(?:iso|img|vhd|vhdx|udf|dmg)$", "", name.strip(), flags=re.IGNORECASE)
|
| 350 |
+
if _SIDE_EP_ZIP_RE.search(name_stem) and not re.search(r"(?i)\b(?:dvd|bd25|bd50|remux|untouched|pal|ntsc|iso)\b", name_stem):
|
| 351 |
+
flagged = True
|
| 352 |
|
| 353 |
if flagged or _SIDE_VPN_TRAP_RE.search(name) or (vc and vid_share == 0.0 and (side[6] > 0 or side[9] > 0 or side[10] > 0)):
|
| 354 |
side[11] = 1.0
|