Scratch In-Editor Obfuscator

Scratchのエディタ上で直接、変数・リスト・定義名をランダム化する

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Userscripts installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey installieren.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

(Ich habe bereits einen Benutzerstil Verwaltung, ich möchte ihn installieren!)

// ==UserScript==
// @name         Scratch In-Editor Obfuscator
// @namespace    https://scratch.mit.edu/
// @version      1.0
// @description  Scratchのエディタ上で直接、変数・リスト・定義名をランダム化する
// @author       You
// @match        https://scratch.mit.edu/projects/*
// @grant        none
// ==/UserScript==

(() => {
    'use strict';

    const makeRandomName = () => '_0x' + Math.random().toString(36).substring(2, 8);

    const obfuscateCurrentProject = () => {
        // ScratchのVM(Virtual Machine)を取得
        const vm = window.vm || (document.querySelector('canvas') && document.querySelector('canvas').__reactInternalInstance$?.return?.stateNode?.props?.vm);
        if (!vm) {
            alert('Scratchのエディタデータが見つかりませんでした。');
            return;
        }

        const nameMap = new Map();
        const getNewName = (oldName) => {
            if (oldName.startsWith('☁')) return oldName; // クラウド変数は維持
            if (!nameMap.has(oldName)) {
                nameMap.set(oldName, makeRandomName());
            }
            return nameMap.get(oldName);
        };

        // 1. 変数・リスト・メッセージの書き換え
        vm.runtime.targets.forEach(target => {
            // 変数名
            for (const id in target.variables) {
                target.variables[id].name = getNewName(target.variables[id].name);
            }
            // リスト名
            for (const id in target.lists) {
                target.lists[id].name = getNewName(target.lists[id].name);
            }
            // メッセージ名
            for (const id in target.broadcasts) {
                target.broadcasts[id] = getNewName(target.broadcasts[id]);
            }
        });

        // 2. カスタムブロック(定義)の書き換え
        vm.runtime.targets.forEach(target => {
            for (const blockId in target.blocks._blocks) {
                const block = target.blocks._blocks[blockId];
                if (block.mutation && block.mutation.proccode) {
                    const parts = block.mutation.proccode.split(/(%[sbnb])/);
                    parts[0] = getNewName(parts[0]);
                    block.mutation.proccode = parts.join('');
                }
            }
        });

        // 3. 画面(ワークスペース)を再描画して表示を更新
        vm.emitWorkspaceUpdate();
        alert('画面上の変数名や定義名をランダム化しました!');
    };

    // UIボタンの作成
    const addButton = () => {
        if (document.getElementById('direct-obfuscate-btn')) return;

        const btn = document.createElement('button');
        btn.id = 'direct-obfuscate-btn';
        btn.innerText = '⚡ 画面上の名前を難読化';
        btn.style.cssText = `
            position: fixed;
            top: 10px;
            right: 180px;
            z-index: 99999;
            padding: 6px 12px;
            background: #e91e63;
            color: white;
            border: none;
            border-radius: 4px;
            font-weight: bold;
            cursor: pointer;
            box-shadow: 0 2px 5px rgba(0,0,0,0.3);
        `;

        btn.addEventListener('click', obfuscateCurrentProject);
        document.body.appendChild(btn);
    };

    const timer = setInterval(() => {
        if (document.querySelector('.gui_menu-bar_2300M') || document.querySelector('canvas')) {
            addButton();
        }
    }, 1000);
})();