-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchk_pass.py
More file actions
143 lines (112 loc) · 4.77 KB
/
Copy pathchk_pass.py
File metadata and controls
143 lines (112 loc) · 4.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import sys
import hashlib
import base64
import argparse
from pathlib import Path
def extract_pwd_info(project_dir: Path) -> tuple[bytes, bytes, str]:
"""Извлекает соль и хеш из STATION.CTX в папке проекта."""
ctx = project_dir / "STATION.CTX"
if not ctx.exists():
raise FileNotFoundError(f"STATION.CTX не найден: {ctx}")
data = ctx.read_bytes()
# Ищем PWD в UTF-16LE
needle = "PWD".encode("utf-16-le")
idx = data.find(needle)
if idx == -1:
raise ValueError("Строка PWD не найдена в STATION.CTX")
# Декодируем окрестность в текст для поиска Base64-строк
chunk = data[idx:idx + 200]
text_chunk = chunk.decode("utf-16-le", errors="ignore")
# Ищем все токены, похожие на Base64 (A-Za-z0-9+/=, длина >= 4)
import re
b64_lines = re.findall(r"[A-Za-z0-9+/=]{4,}", text_chunk)
if len(b64_lines) < 2:
raise ValueError(
f"Не удалось найти две Base64-строки рядом с PWD. Найдено: {b64_lines}"
)
salt_b64 = b64_lines[0]
hash_b64 = b64_lines[1]
try:
salt = base64.b64decode(salt_b64)
target = base64.b64decode(hash_b64)
except Exception as e:
raise ValueError(f"Ошибка декодирования Base64 (соль={salt_b64!r}, хеш={hash_b64!r}): {e}")
if len(salt) != 8:
raise ValueError(f"Соль ожидалась 8 байт, получено {len(salt)}")
if len(target) != 32:
raise ValueError(f"Хеш ожидался 32 байта, получено {len(target)}")
return salt, target, ctx.name
def check_password(salt: bytes, candidate: str) -> bytes:
"""SHA-256(соль || кандидат в UTF-16LE)."""
return hashlib.sha256(salt + candidate.encode("utf-16-le")).digest()
def load_candidates(args: argparse.Namespace) -> list[str]:
"""Собирает список кандидатов из аргументов."""
candidates = []
if args.try_passwords:
candidates.extend(args.try_passwords)
if args.file:
path = Path(args.file)
if not path.exists():
print(f"[!] Файл не найден: {path}", file=sys.stderr)
else:
with open(path, "r", encoding="utf-8") as f:
for line in f:
candidate = line.strip()
if candidate:
candidates.append(candidate)
if not candidates:
raise ValueError("Не указаны кандидаты. Используйте --try или --file.")
return candidates
def main():
parser = argparse.ArgumentParser(
description="Проверка пароля проекта Unity Pro / Control Expert по списку кандидатов",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Примеры:
chk_pass.py X:\\Analiz\\Project\\ --try Admin123
chk_pass.py project_folder --file passwords.txt
""",
)
parser.add_argument(
"project", type=str, help="Путь к папке проекта (содержащей STATION.CTX)"
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--try", dest="try_passwords", nargs="+", metavar="PWD", help="Пароли для проверки")
group.add_argument("--file", dest="file", metavar="PATH", help="Файл со списком паролей (по одному на строку)")
args = parser.parse_args()
project_dir = Path(args.project)
if not project_dir.is_dir():
print(f"[!] Папка не найдена: {project_dir}", file=sys.stderr)
sys.exit(1)
# 1. Извлечение соли и хеша
try:
salt, target, ctx_name = extract_pwd_info(project_dir)
except Exception as e:
print(f"[!] Ошибка извлечения из STATION.CTX: {e}", file=sys.stderr)
sys.exit(1)
print(f"[*] STATION.CTX: {ctx_name}")
print(f"[*] Соль: {salt.hex().upper()}")
print(f"[*] Хеш: {target.hex().upper()}")
# 2. Загрузка кандидатов
try:
candidates = load_candidates(args)
except ValueError as e:
print(f"[!] {e}", file=sys.stderr)
sys.exit(1)
# 3. Проверка
found = None
checked = 0
for pwd in candidates:
checked += 1
h = check_password(salt, pwd)
if h == target:
found = pwd
break
if found:
print(f"\n[+] НАЙДЕН: {found}")
sys.exit(0)
else:
print(f"\n[-] {checked} проверено — совпадений нет")
sys.exit(1)
if __name__ == "__main__":
main()