fix: ios 16

This commit is contained in:
hashbro
2026-08-09 21:57:08 +08:00
parent 6bf33e2761
commit 6bc172c570
179 changed files with 6246 additions and 400 deletions
+1
View File
@@ -0,0 +1 @@
"""Vendored offline helpers (no network)."""
File diff suppressed because it is too large Load Diff
+142
View File
@@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""Offline reproducer for the Coruna PLServerPool domain generator.
This script performs no DNS lookups and makes no network requests. It is
intended for IOC generation and static-analysis verification only.
"""
from __future__ import annotations
import argparse
MASK32 = 0xFFFFFFFF
HASH_SEED = 0x9E3779B1
MURMUR_M = 0x5BD1E995
ALNUM = "abcdefghijklmnopqrstuvwxyz0123456789"
ALNUM_HYPHEN = "abcdefghijklmnopqrstuvwxyz0123456789-"
TLDS = (
".com",
".net",
".org",
".cc",
".so",
".online",
".cfd",
".site",
".lol",
".net", # Deliberately duplicated in the sample's 15-entry table.
".live",
".store",
".app",
".icu",
".info",
)
KNOWN_SEEDS = {
"deployment": "09d0b8d58a71653cd1c89c64c866f2e6",
"reporting": "2d2aebba0bf3d7d694194a7ab93b0a96",
"placeholder-deployment": "UNDEFINED_DEPLOYMENT_SEED",
"placeholder-reporting": "UNDEFINED_REPORTING_SEED",
}
def murmur_hash2(value: str, seed: int = HASH_SEED) -> int:
data = value.encode("utf-8")
result = (seed ^ len(data)) & MASK32
offset = 0
while offset + 4 <= len(data):
block = int.from_bytes(data[offset : offset + 4], "little")
block = (block * MURMUR_M) & MASK32
block ^= block >> 24
block = (block * MURMUR_M) & MASK32
result = (result * MURMUR_M) & MASK32
result ^= block
offset += 4
tail = data[offset:]
if len(tail) == 3:
result ^= tail[2] << 16
if len(tail) >= 2:
result ^= tail[1] << 8
if len(tail) >= 1:
result ^= tail[0]
result = (result * MURMUR_M) & MASK32
result ^= result >> 13
result = (result * MURMUR_M) & MASK32
result ^= result >> 15
return result & MASK32
def xorshift32(state: int) -> int:
state ^= (state << 13) & MASK32
state ^= state >> 17
state ^= (state << 5) & MASK32
return state & MASK32
def generate_domains(seed: str, count: int = 5) -> list[str]:
"""Generate the sample's externally used candidate slice.
The native helper builds 512 strings internally, while PLServerPool asks
for and retains the first five. ``count`` is therefore capped at 512 for
analysis, although five is the operational pool size in this build.
"""
if not 1 <= count <= 512:
raise ValueError("count must be between 1 and 512")
base_hash = murmur_hash2(seed)
domains: list[str] = []
for index in range(512):
state = murmur_hash2(f"{seed}{index}") ^ base_hash
if state == 0:
state = 1
state = xorshift32(state)
label_length = 16 + state % 9
state = xorshift32(state)
label = ALNUM[state % len(ALNUM)]
for _ in range(1, label_length - 1):
state = xorshift32(state)
alphabet = ALNUM if label[-1] == "-" else ALNUM_HYPHEN
label += alphabet[state % len(alphabet)]
state = xorshift32(state)
label += ALNUM[state % len(ALNUM)]
state = xorshift32(state)
domains.append(f"www.{label}{TLDS[state % len(TLDS)]}")
return domains[:count]
def main() -> None:
parser = argparse.ArgumentParser(
description="Reproduce Coruna DGA candidates offline (no network access)."
)
parser.add_argument(
"seed",
nargs="?",
default="deployment",
help=(
"deployment, reporting, placeholder-deployment, "
"placeholder-reporting, or a literal seed"
),
)
parser.add_argument("-n", "--count", type=int, default=5)
args = parser.parse_args()
seed = KNOWN_SEEDS.get(args.seed, args.seed)
print(f"seed={seed}")
for index, domain in enumerate(generate_domains(seed, args.count), 1):
print(f"{index:03d} {domain}")
if __name__ == "__main__":
main()