mirror of
https://github.com/eaglerforge/EaglerForgeInjector
synced 2025-07-23 06:01:38 -09:00
wip server
This commit is contained in:
parent
b84dfa61ad
commit
5a6628a617
4
efserver.js
Normal file
4
efserver.js
Normal file
@ -0,0 +1,4 @@
|
||||
function EFServer() {
|
||||
//Todo: write mod that disables rendering engine, autodisplays gui, and makes run server button.
|
||||
console.log("hello world");
|
||||
}
|
265
index.html
265
index.html
@ -89,18 +89,27 @@
|
||||
>
|
||||
<br /><br />
|
||||
<button class="btn btn-primary" id="giveme">Make modded client</button>
|
||||
<button class="btn btn-primary" disabled>Make modded server(node.js)</button>
|
||||
<button class="btn btn-primary" id="givemeserver" disabled>
|
||||
Make modded server (coming soonish maybe)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<br /><br /><br />
|
||||
<span>Info:</span>
|
||||
<div id="#info">
|
||||
<details>
|
||||
<summary>Where can I download an unobfuscated unsigned Eaglercraft build?</summary>
|
||||
<a href="https://github.com/Eaglercraft-Archive/unminified-eaglercraft-builds/releases/latest">https://github.com/Eaglercraft-Archive/unminified-eaglercraft-builds/releases/latest</a>
|
||||
<summary>
|
||||
Where can I download an unobfuscated unsigned Eaglercraft build?
|
||||
</summary>
|
||||
<a
|
||||
href="https://github.com/Eaglercraft-Archive/unminified-eaglercraft-builds/releases/latest"
|
||||
>https://github.com/Eaglercraft-Archive/unminified-eaglercraft-builds/releases/latest</a
|
||||
>
|
||||
</details>
|
||||
<details>
|
||||
<summary>How do I compile my own unobfuscated unsigned Eaglercraft build?</summary>
|
||||
<summary>
|
||||
How do I compile my own unobfuscated unsigned Eaglercraft build?
|
||||
</summary>
|
||||
Once you have a local EaglercraftX workspace setup, in
|
||||
<code>build.gradle</code>, set the <code>obfuscate</code> property to
|
||||
<code>false</code>. Then, run <code>CompileJS.bat</code> (or .sh if on
|
||||
@ -133,57 +142,10 @@
|
||||
<script>
|
||||
document.querySelector("#htmlFile").addEventListener("input", (e) => {
|
||||
if (e.target.files[0]) {
|
||||
document.querySelector(".custom-file-label").innerText = e.target.files[0].name;
|
||||
document.querySelector(".custom-file-label").innerText =
|
||||
e.target.files[0].name;
|
||||
}
|
||||
});
|
||||
function entriesToStaticVariableProxy(entries, prefix) {
|
||||
var getComponents = "";
|
||||
entries.forEach((entry) => {
|
||||
getComponents += `
|
||||
case \`${entry.name}\`:
|
||||
return ${entry.variable};
|
||||
break;`;
|
||||
});
|
||||
|
||||
var setComponents = "";
|
||||
entries.forEach((entry) => {
|
||||
setComponents += `
|
||||
case \`${entry.name}\`:
|
||||
${entry.variable} = c;
|
||||
break;`;
|
||||
});
|
||||
var proxy = `
|
||||
ModAPI.hooks._rippedStaticIndexer[\`${prefix.replace(
|
||||
"var ",
|
||||
""
|
||||
)}\`] = [${entries
|
||||
.flatMap((x) => {
|
||||
return '"' + x.name + '"';
|
||||
})
|
||||
.join(",")}];
|
||||
ModAPI.hooks._rippedStaticProperties[\`${prefix.replace(
|
||||
"var ",
|
||||
""
|
||||
)}\`] = new Proxy({${
|
||||
entries
|
||||
.flatMap((x) => {
|
||||
return '"' + x.name + '"';
|
||||
})
|
||||
.join(":null,") + (entries.length > 0 ? ":null" : "")
|
||||
}}, {
|
||||
get: function (a,b,c) {
|
||||
switch (b) {
|
||||
${getComponents}
|
||||
}
|
||||
},
|
||||
set: function (a,b,c) {
|
||||
switch (b) {
|
||||
${setComponents}
|
||||
}
|
||||
}
|
||||
});`;
|
||||
return proxy;
|
||||
}
|
||||
var modapi_preinit = `globalThis.ModAPI ||= {};
|
||||
ModAPI.hooks ||= {};
|
||||
ModAPI.hooks.freezeCallstack = false;
|
||||
@ -197,206 +159,13 @@ ModAPI.hooks._rippedStaticProperties ||= {};
|
||||
ModAPI.hooks._rippedStaticIndexer ||= {};
|
||||
`;
|
||||
var freezeCallstack = `if(ModAPI.hooks.freezeCallstack){return false};`;
|
||||
document.querySelector("#giveme").addEventListener("click", () => {
|
||||
if (
|
||||
!document.querySelector("input").files ||
|
||||
!document.querySelector("input").files[0]
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @type File
|
||||
var file = document.querySelector("input").files[0];
|
||||
var fileType = file.name.split(".");
|
||||
fileType = fileType[fileType.length - 1];
|
||||
|
||||
file.text().then((string) => {
|
||||
var patchedFile = string;
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`(function(root, module) {`,
|
||||
`${modapi_preinit}
|
||||
(function(root, module) {`
|
||||
);
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`var main;(function(){`,
|
||||
`${modapi_preinit}
|
||||
var main;(function(){`
|
||||
);
|
||||
patchedFile = patchedFile
|
||||
.replace("\r", "")
|
||||
.replace(
|
||||
"var main;\n(function() {",
|
||||
modapi_preinit + "var main;\n(function() {"
|
||||
);
|
||||
patchedFile = patchedFile.replace(
|
||||
/function \$rt_metadata\(data\)( ?){/gm,
|
||||
`function $rt_metadata(data) {
|
||||
/*/EaglerForge Client Patch/*/
|
||||
ModAPI.hooks._rippedData.push(data);
|
||||
/*/EaglerForge Client Patch/*/`
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`return thread != null && thread.isResuming()`,
|
||||
(match) => {
|
||||
return freezeCallstack + match;
|
||||
}
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`return thread != null && thread.isSuspending();`,
|
||||
(match) => {
|
||||
return freezeCallstack + match;
|
||||
}
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`return $rt_currentNativeThread;`,
|
||||
(match) => {
|
||||
return (
|
||||
`if(ModAPI.hooks.freezeCallstack){return {isResuming: ()=>{false}, isSuspending: ()=>{false}, push: (a)=>{}, pop: ()=>{console.warn("Frozen stack was popped, context is now unstable.")}}};` +
|
||||
match
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replace(
|
||||
` id="game_frame">`,
|
||||
` id="game_frame">
|
||||
\<script id="modapi_postinit"\>${globalThis.modapi_postinit}\<\/script\>
|
||||
\<script id="modapi_modloader"\>${globalThis.modapi_modloader}\<\/script\>
|
||||
\<script id="modapi_guikit"\>${globalThis.modapi_guikit}\<\/script\>
|
||||
\<script id="modapi_postinit_data"\>globalThis.modapi_postinit = \`${globalThis.modapi_postinit}\`;\<\/script\>`
|
||||
);
|
||||
|
||||
const extractConstructorRegex =
|
||||
/^\s*function (\S*?)__init_\d*?\((?!\$)/gm;
|
||||
const extractConstructorFullNameRegex =
|
||||
/function (\S*?)__init_[0-9]*/gm;
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
extractConstructorRegex,
|
||||
(match) => {
|
||||
var fullName = match.match(extractConstructorFullNameRegex);
|
||||
fullName = fullName[0].replace("function ", "");
|
||||
return (
|
||||
`ModAPI.hooks._rippedConstructors[\`${fullName}\`] = ${fullName};
|
||||
` + match
|
||||
);
|
||||
}
|
||||
);
|
||||
const extractInstanceMethodRegex =
|
||||
/^[\t ]*function \S+?_\S+?_\S+?\((\$this)?/gm; // /^[\t ]*function \S+?_\S+?_\S+?\(\$this/gm
|
||||
const extractInstanceMethodFullNameRegex = /function (\S*?)\(/gm; // /function (\S*?)\(\$this/gm
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
extractInstanceMethodRegex,
|
||||
(match) => {
|
||||
if (
|
||||
match.includes("__init_") ||
|
||||
match.includes("__clinit_") ||
|
||||
match.includes("_$callClinit")
|
||||
) {
|
||||
return match;
|
||||
}
|
||||
var fullName = match.match(extractInstanceMethodFullNameRegex);
|
||||
fullName = fullName[0].replace("function ", "").replace("(", "");
|
||||
return (
|
||||
`function ${fullName}(...args) {
|
||||
return ModAPI.hooks.methods[\`${fullName}\`].apply(this, args);
|
||||
}
|
||||
ModAPI.hooks._rippedMethodTypeMap[\`${fullName}\`] = \`${
|
||||
match.endsWith("($this") ? "instance" : "static"
|
||||
}\`;
|
||||
ModAPI.hooks.methods[\`${fullName}\`]=` +
|
||||
match.replace(fullName + "(", "(")
|
||||
);
|
||||
return match;
|
||||
}
|
||||
);
|
||||
var staticVariables = [
|
||||
...patchedFile.matchAll(/var \S+?_\S+?_\S+? = null;/gm),
|
||||
].flatMap((x) => {
|
||||
return x[0];
|
||||
});
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
/var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm,
|
||||
function (match) {
|
||||
var prefix = match.replaceAll(
|
||||
/ = \$rt_classWithoutFields\(\S*?\);/gm,
|
||||
""
|
||||
);
|
||||
var entries = [];
|
||||
staticVariables.forEach((entry) => {
|
||||
if (entry.startsWith(prefix)) {
|
||||
var variableName = entry
|
||||
.replace("var ", "")
|
||||
.replace(" = null;", "");
|
||||
var segments = variableName.split("_");
|
||||
segments.splice(0, 2);
|
||||
var name = segments.join("_");
|
||||
entries.push({
|
||||
name: name,
|
||||
variable: variableName,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var proxy = entriesToStaticVariableProxy(entries, prefix);
|
||||
|
||||
return match + proxy;
|
||||
}
|
||||
);
|
||||
//Edge cases. sigh
|
||||
//Done: add support for static properties on classes with constructors like this: function nmcg_GuiMainMenu() {
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
/function [a-z]+?_([a-zA-Z\$]+?)\(\) \{/gm,
|
||||
(match) => {
|
||||
var prefix = "var " + match.replace("function ", "").replace("() {", "");
|
||||
var entries = [];
|
||||
|
||||
staticVariables.forEach((entry) => {
|
||||
if (entry.startsWith(prefix)) {
|
||||
var variableName = entry
|
||||
.replace("var ", "")
|
||||
.replace(" = null;", "");
|
||||
var segments = variableName.split("_");
|
||||
segments.splice(0, 2);
|
||||
var name = segments.join("_");
|
||||
entries.push({
|
||||
name: name,
|
||||
variable: variableName,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var proxy = entriesToStaticVariableProxy(entries, prefix);
|
||||
|
||||
return proxy + "\n" + match;
|
||||
}
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
/function \$rt_\S+?\(/gm,
|
||||
(match) => {
|
||||
var name = match.replace("function ", "");
|
||||
name = name.substring(0, name.length - 1);
|
||||
return (
|
||||
`ModAPI.hooks._teavm[\`${name}\`]=${name};
|
||||
` + match
|
||||
);
|
||||
}
|
||||
);
|
||||
patchedFile = patchedFile.replaceAll(/main\(\);\s*?}/gm, (match) => {
|
||||
return match.replace("main();", "main();ModAPI.hooks._postInit();");
|
||||
});
|
||||
var blob = new Blob([patchedFile], { type: file.type });
|
||||
saveAs(blob, "processed." + fileType);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script src="injector.js"></script>
|
||||
|
||||
<!-- Code assets -->
|
||||
<script src="postinit.injector.js"></script>
|
||||
<script src="modloader.injector.js"></script>
|
||||
<script src="modgui.injector.js"></script>
|
||||
<script src="efserver.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
269
injector.js
Normal file
269
injector.js
Normal file
@ -0,0 +1,269 @@
|
||||
function entriesToStaticVariableProxy(entries, prefix) {
|
||||
var getComponents = "";
|
||||
entries.forEach((entry) => {
|
||||
getComponents += `
|
||||
case \`${entry.name}\`:
|
||||
return ${entry.variable};
|
||||
break;`;
|
||||
});
|
||||
|
||||
var setComponents = "";
|
||||
entries.forEach((entry) => {
|
||||
setComponents += `
|
||||
case \`${entry.name}\`:
|
||||
${entry.variable} = c;
|
||||
break;`;
|
||||
});
|
||||
var proxy = `
|
||||
ModAPI.hooks._rippedStaticIndexer[\`${prefix.replace(
|
||||
"var ",
|
||||
""
|
||||
)}\`] = [${entries
|
||||
.flatMap((x) => {
|
||||
return '"' + x.name + '"';
|
||||
})
|
||||
.join(",")}];
|
||||
ModAPI.hooks._rippedStaticProperties[\`${prefix.replace(
|
||||
"var ",
|
||||
""
|
||||
)}\`] = new Proxy({${entries
|
||||
.flatMap((x) => {
|
||||
return '"' + x.name + '"';
|
||||
})
|
||||
.join(":null,") + (entries.length > 0 ? ":null" : "")
|
||||
}}, {
|
||||
get: function (a,b,c) {
|
||||
switch (b) {
|
||||
${getComponents}
|
||||
}
|
||||
},
|
||||
set: function (a,b,c) {
|
||||
switch (b) {
|
||||
${setComponents}
|
||||
}
|
||||
}
|
||||
});`;
|
||||
return proxy;
|
||||
}
|
||||
function processClasses(string) {
|
||||
var patchedFile = string;
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`(function(root, module) {`,
|
||||
`${modapi_preinit}
|
||||
(function(root, module) {`
|
||||
);
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`var main;(function(){`,
|
||||
`${modapi_preinit}
|
||||
var main;(function(){`
|
||||
);
|
||||
patchedFile = patchedFile
|
||||
.replace("\r", "")
|
||||
.replace(
|
||||
"var main;\n(function() {",
|
||||
modapi_preinit + "var main;\n(function() {"
|
||||
);
|
||||
patchedFile = patchedFile.replace(
|
||||
/function \$rt_metadata\(data\)( ?){/gm,
|
||||
`function $rt_metadata(data) {
|
||||
/*/EaglerForge Client Patch/*/
|
||||
ModAPI.hooks._rippedData.push(data);
|
||||
/*/EaglerForge Client Patch/*/`
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`return thread != null && thread.isResuming()`,
|
||||
(match) => {
|
||||
return freezeCallstack + match;
|
||||
}
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`return thread != null && thread.isSuspending();`,
|
||||
(match) => {
|
||||
return freezeCallstack + match;
|
||||
}
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
`return $rt_currentNativeThread;`,
|
||||
(match) => {
|
||||
return (
|
||||
`if(ModAPI.hooks.freezeCallstack){return {isResuming: ()=>{false}, isSuspending: ()=>{false}, push: (a)=>{}, pop: ()=>{console.warn("Frozen stack was popped, context is now unstable.")}}};` +
|
||||
match
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replace(
|
||||
` id="game_frame">`,
|
||||
` id="game_frame">
|
||||
\<script id="modapi_postinit"\>${globalThis.modapi_postinit}\<\/script\>
|
||||
\<script id="modapi_modloader"\>${globalThis.modapi_modloader}\<\/script\>
|
||||
\<script id="modapi_guikit"\>${globalThis.modapi_guikit}\<\/script\>
|
||||
\<script id="modapi_postinit_data"\>globalThis.modapi_postinit = \`${globalThis.modapi_postinit}\`;\<\/script\>
|
||||
\<script id="libserverside"\>{"._|_libserverside_|_."}\<\>`
|
||||
);
|
||||
|
||||
const extractConstructorRegex =
|
||||
/^\s*function (\S*?)__init_\d*?\((?!\$)/gm;
|
||||
const extractConstructorFullNameRegex =
|
||||
/function (\S*?)__init_[0-9]*/gm;
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
extractConstructorRegex,
|
||||
(match) => {
|
||||
var fullName = match.match(extractConstructorFullNameRegex);
|
||||
fullName = fullName[0].replace("function ", "");
|
||||
return (
|
||||
`ModAPI.hooks._rippedConstructors[\`${fullName}\`] = ${fullName};
|
||||
` + match
|
||||
);
|
||||
}
|
||||
);
|
||||
const extractInstanceMethodRegex =
|
||||
/^[\t ]*function \S+?_\S+?_\S+?\((\$this)?/gm; // /^[\t ]*function \S+?_\S+?_\S+?\(\$this/gm
|
||||
const extractInstanceMethodFullNameRegex = /function (\S*?)\(/gm; // /function (\S*?)\(\$this/gm
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
extractInstanceMethodRegex,
|
||||
(match) => {
|
||||
if (
|
||||
match.includes("__init_") ||
|
||||
match.includes("__clinit_") ||
|
||||
match.includes("_$callClinit")
|
||||
) {
|
||||
return match;
|
||||
}
|
||||
var fullName = match.match(extractInstanceMethodFullNameRegex);
|
||||
fullName = fullName[0].replace("function ", "").replace("(", "");
|
||||
return (
|
||||
`function ${fullName}(...args) {
|
||||
return ModAPI.hooks.methods[\`${fullName}\`].apply(this, args);
|
||||
}
|
||||
ModAPI.hooks._rippedMethodTypeMap[\`${fullName}\`] = \`${match.endsWith("($this") ? "instance" : "static"
|
||||
}\`;
|
||||
ModAPI.hooks.methods[\`${fullName}\`]=` +
|
||||
match.replace(fullName + "(", "(")
|
||||
);
|
||||
return match;
|
||||
}
|
||||
);
|
||||
var staticVariables = [
|
||||
...patchedFile.matchAll(/var \S+?_\S+?_\S+? = null;/gm),
|
||||
].flatMap((x) => {
|
||||
return x[0];
|
||||
});
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
/var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm,
|
||||
function (match) {
|
||||
var prefix = match.replaceAll(
|
||||
/ = \$rt_classWithoutFields\(\S*?\);/gm,
|
||||
""
|
||||
);
|
||||
var entries = [];
|
||||
staticVariables.forEach((entry) => {
|
||||
if (entry.startsWith(prefix)) {
|
||||
var variableName = entry
|
||||
.replace("var ", "")
|
||||
.replace(" = null;", "");
|
||||
var segments = variableName.split("_");
|
||||
segments.splice(0, 2);
|
||||
var name = segments.join("_");
|
||||
entries.push({
|
||||
name: name,
|
||||
variable: variableName,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var proxy = entriesToStaticVariableProxy(entries, prefix);
|
||||
|
||||
return match + proxy;
|
||||
}
|
||||
);
|
||||
//Edge cases. sigh
|
||||
//Done: add support for static properties on classes with constructors like this: function nmcg_GuiMainMenu() {
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
/function [a-z]+?_([a-zA-Z\$]+?)\(\) \{/gm,
|
||||
(match) => {
|
||||
var prefix = "var " + match.replace("function ", "").replace("() {", "");
|
||||
var entries = [];
|
||||
|
||||
staticVariables.forEach((entry) => {
|
||||
if (entry.startsWith(prefix)) {
|
||||
var variableName = entry
|
||||
.replace("var ", "")
|
||||
.replace(" = null;", "");
|
||||
var segments = variableName.split("_");
|
||||
segments.splice(0, 2);
|
||||
var name = segments.join("_");
|
||||
entries.push({
|
||||
name: name,
|
||||
variable: variableName,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var proxy = entriesToStaticVariableProxy(entries, prefix);
|
||||
|
||||
return proxy + "\n" + match;
|
||||
}
|
||||
);
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
/function \$rt_\S+?\(/gm,
|
||||
(match) => {
|
||||
var name = match.replace("function ", "");
|
||||
name = name.substring(0, name.length - 1);
|
||||
return (
|
||||
`ModAPI.hooks._teavm[\`${name}\`]=${name};
|
||||
` + match
|
||||
);
|
||||
}
|
||||
);
|
||||
patchedFile = patchedFile.replaceAll(/main\(\);\s*?}/gm, (match) => {
|
||||
return match.replace("main();", "main();ModAPI.hooks._postInit();");
|
||||
});
|
||||
return patchedFile;
|
||||
}
|
||||
|
||||
document.querySelector("#giveme").addEventListener("click", () => {
|
||||
if (
|
||||
!document.querySelector("input").files ||
|
||||
!document.querySelector("input").files[0]
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @type File
|
||||
var file = document.querySelector("input").files[0];
|
||||
var fileType = file.name.split(".");
|
||||
fileType = fileType[fileType.length - 1];
|
||||
|
||||
file.text().then((string) => {
|
||||
var patchedFile = processClasses(string);
|
||||
patchedFile.replace(`{"._|_libserverside_|_."}`)
|
||||
var blob = new Blob([patchedFile], { type: file.type });
|
||||
saveAs(blob, "processed." + fileType);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector("#givemeserver").addEventListener("click", () => {
|
||||
if (
|
||||
!document.querySelector("input").files ||
|
||||
!document.querySelector("input").files[0]
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @type File
|
||||
var file = document.querySelector("input").files[0];
|
||||
var fileType = file.name.split(".");
|
||||
fileType = fileType[fileType.length - 1];
|
||||
|
||||
file.text().then((string) => {
|
||||
var patchedFile = processClasses(string);
|
||||
patchedFile.replace(`{"._|_libserverside_|_."}`, `(${EFServer.toString()})()`);
|
||||
var blob = new Blob([patchedFile], { type: file.type });
|
||||
saveAs(blob, "efserver." + fileType);
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user