はじめに
venoroa1358です。
NScripter のシナリオファイル nscript.dat は暗号化されたファイルですが、XOR暗号によって暗号化されているため容易に復号できます。すでにYet Another nsdecという使いやすい復号化ツールが公開されていますが、ここではPythonによる復号化方法を紹介します。
実行にはPython3環境が必要です。復号化したファイルの取り扱いには注意してください。
原理
オープンソース版NScripter 実行環境である、ONscripter のシナリオ復号化処理を見ると、キー「0x84」を用いたXOR暗号であることが分かります。include文を除くと、たったの一行で実現されています。
XOR暗号は、あるキーで暗号化したファイルに対して、同じキーでもう一度暗号化すると元の状態に戻るという性質があります。したがって、0x84をキーとしたXOR暗号化プログラムを作成することで、nscript.datを復号化できます。
最小限のコードによる復号化
nscripter_bin = bytearray()
with open("nscript.dat", "rb") as f:
    # nscript.dat バイト列として読み込む
    nscript_dat = f.read()
    for b in nscript_dat:
        # 復号化
        nscripter_bin.append(b ^ 0x84)
# バイト列を Shift-JISでデコードしたものを文字列として保存
result = bytes(nscripter_bin).decode("shift_jis")
with open("00.txt", "w+", encoding="utf-8") as f:
    # utf-8 として書き出し
    f.write(result)
文字コードに関する厄介な問題を避けるため、復号化後のデータをShift-JISとみなし、それをutf-8に変換して保存しています。
上記の内容をテキストエディタ等にコピーし、拡張子を.pyにして保存し、nscript.datがあるディレクトリで実行すると復号化できます。次の例はWindowsでのものです。
> python.exe ファイル名.py動作しない場合はPython3が正しくインストールされているか、nscript.datの場所を間違っていないかご確認ください。
おまけ:例外処理を加えて変換元や保存先のファイル名を指定する
おまけとして、例外処理をある程度頑張って、変換元と保存先のファイル名を指定できるようにしたコードを紹介します。
もし復号化対象のnscript.datの文字コードがShift-JISではなくutf-8だった場合も結果を正しく保存できるようにしたつもりです。Shift-JISでないnscript.datが存在するかは不明。
ファイル名はコマンドライン引数で取っています。実行時は、変換元のファイル名 保存先のファイル名 の順で指定してください。
> python.exe .\nsdec.py nscript.dat story.txtコードはこんな感じです。
import sys
def decode_nscript(input="nscript.dat", output="00.txt"):
    NSCRIPTER_XOR_KEY = 0x84
    nscripter_bin = bytearray()
    try:
        print(f"{input} の変換を開始します。")
        with open(input, "rb") as f:
            nscript_dat = f.read()
            for b in nscript_dat:
                nscripter_bin.append(b ^ NSCRIPTER_XOR_KEY)
        print("復号化に成功しました。")
    except FileNotFoundError:
        sys.exit(f"{input} が見つかりません。中断します。")
    except ValueError:
        sys.exit(f"{input} をオープンできません。中断します。")
    except PermissionError:
        sys.exit(f"{input} へのアクセスが拒否されました。中断します。")
    result = bytes(nscripter_bin)
    try:
        result = result.decode("shift_jis")
        save_result(output, result, "w+", "utf-8")
    except UnicodeDecodeError:
        print("Shift-JISからutf-8への変換に失敗しました。")
        save_result(output, result, "wb+", None)
def save_result(output, result, mode, enctype):
    try:
        with open(output, mode, encoding=enctype) as f:
            f.write(result)
            print(f"復号したデータの保存に成功しました。 {output} を確認してください。")
    except ValueError:
        sys.exit(f"{output} をオープンできません。中断します。")
    except PermissionError:
        sys.exit(f"{output} へのアクセスが拒否されました。中断します。")
if __name__ == "__main__":
    args = sys.argv
    if len(args) >= 2:
        input = args[1]
        output = args[2]
        decode_nscript(input, output)
    else:
        decode_nscript()
余談
XOR暗号の性質上、NScripter 公式の暗号化ツール(nscmake.exe)をnscript.datに適用すると復号化できそうな気がするのですが、どうなんでしょうね。