(已解决)忍娘24图片解密求助

import argparse
from pathlib import Path
from typing import Iterable


KEY = b"quantaninjagirl24"
HEADER = bytes([0xEF, 0xFE, 0x80])
CHUNK_DECRYPT = 128

def rc4_init(key: bytes) -> list[int]:
    s = list(range(256))
    j = 0
    for i in range(256):
        j = (j + s[i] + key[i % len(key)]) & 0xFF
        s[i], s[j] = s[j], s[i]
    return s


def rc4_crypt(key_state: list[int], data: bytes) -> bytes:
    s = key_state.copy()
    i = j = 0
    out = bytearray()
    for byte in data:
        i = (i + 1) & 0xFF
        j = (j + s[i]) & 0xFF
        s[i], s[j] = s[j], s[i]
        k = s[(s[i] + s[j]) & 0xFF]
        out.append(byte ^ k)
    return bytes(out)

def decrypt_texture(buf: bytes) -> bytes | None:
    if not buf.startswith(HEADER):
        return None

    payload = buf[3:]
    to_dec  = payload[:CHUNK_DECRYPT]
    rest    = payload[len(to_dec):]

    state = rc4_init(KEY)
    dec_first = rc4_crypt(state, to_dec)
    return dec_first + rest


def process_file(path: Path, out_dir: Path | None):
    raw = path.read_bytes()
    dec = decrypt_texture(raw)
    if dec is None:
        return False

    out_path = (
        out_dir / path.name if out_dir
        else path.with_suffix(".dec.png")
    )
    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_bytes(dec)
    return True


def walk_inputs(targets: Iterable[Path]):
    for p in targets:
        if p.is_dir():
            yield from p.rglob("*.png")
        elif p.is_file():
            yield p


def main():
    ap = argparse.ArgumentParser(
        description="decrypt")
    ap.add_argument("input")
    ap.add_argument("-o", type=Path)
    args = ap.parse_args()

    hits = 0
    for f in walk_inputs(Path(i) for i in args.input):
        if process_file(f, args.o):
            hits += 1

if __name__ == "__main__":
    main()
1 个赞