100 lines
2.2 KiB
TypeScript
100 lines
2.2 KiB
TypeScript
import { promises as fs } from "fs";
|
|
import * as path from "path";
|
|
import * as os from "os";
|
|
import { setConsoleTitle } from "@ocbwoy3/libocbwoy3";
|
|
|
|
setConsoleTitle("Roblox Studio patcher");
|
|
|
|
const SIGNATURE = Buffer.from([
|
|
0x48, 0x81, 0xec, 0x40, 0x03, 0x00, 0x00, 0x84, 0xd2, 0x74, 0x05, 0xe8,
|
|
]);
|
|
|
|
const PATCH = Buffer.from([
|
|
0x48, 0x81, 0xec, 0x40, 0x03, 0x00, 0x00, 0x84, 0xd2, 0x90, 0x90, 0xe8,
|
|
]);
|
|
|
|
const baseDir = path.join(
|
|
os.homedir(),
|
|
".var/app/org.vinegarhq.Vinegar/data/vinegar/versions",
|
|
);
|
|
|
|
function findSignature(buffer: Buffer, signature: Buffer): number {
|
|
const sigLen = signature.length;
|
|
for (let i = 0; i <= buffer.length - sigLen; i++) {
|
|
let match = true;
|
|
for (let j = 0; j < sigLen; j++) {
|
|
if (buffer[i + j] !== signature[j]) {
|
|
match = false;
|
|
break;
|
|
}
|
|
}
|
|
if (match) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
async function patchFile(folder: string) {
|
|
const exePath = path.join(folder, "RobloxStudioBeta.exe");
|
|
|
|
let binary: Buffer;
|
|
try {
|
|
binary = await fs.readFile(exePath);
|
|
} catch (err) {
|
|
console.error(
|
|
`[ERROR] Could not read ${exePath}/RobloxStudioBeta.exe:`,
|
|
err,
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (findSignature(binary, PATCH)) {
|
|
console.log(
|
|
`[SKIP] ${folder}/RobloxStudioBeta.exe has already been patched`,
|
|
);
|
|
return;
|
|
}
|
|
|
|
const offset = findSignature(binary, SIGNATURE);
|
|
if (offset === -1) {
|
|
console.error(
|
|
`[FAIL] Signature not found in ${exePath}/RobloxStudioBeta.exe`,
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Apply patch
|
|
PATCH.copy(binary, offset);
|
|
try {
|
|
await fs.writeFile(exePath, binary);
|
|
console.log(`[PATCHED] Patched ${exePath}/RobloxStudioBeta.exe`);
|
|
} catch (err) {
|
|
console.error(`[ERROR] Failed to write patched file:`, err);
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
const folders: string[] = [];
|
|
|
|
try {
|
|
const entries = await fs.readdir(baseDir, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
if (entry.isDirectory()) {
|
|
folders.push(path.join(baseDir, entry.name));
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error(`[ERROR] Failed to list folders in ${baseDir}:`, err);
|
|
return;
|
|
}
|
|
|
|
console.log(`[INFO] Found ${folders.length} version folders.`);
|
|
|
|
const start = Date.now();
|
|
await Promise.all(folders.map(patchFile));
|
|
console.log(
|
|
`[DONE] Patched internal Roblox Studio in ${Date.now() - start}ms`,
|
|
);
|
|
}
|
|
|
|
main();
|