diff --git a/.gitignore b/.gitignore index ceaea36..8b4ec9f 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,6 @@ dist .yarn/install-state.gz .pnp.* +*_decompile +*_Patched +*_decompile* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..5a938ce --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 4, + "useTabs": false +} diff --git a/APKEditor.jar b/APKEditor.jar new file mode 100644 index 0000000..22bca3f Binary files /dev/null and b/APKEditor.jar differ diff --git a/RabbitLauncher0517.apk b/RabbitLauncher0517.apk new file mode 100644 index 0000000..2673711 Binary files /dev/null and b/RabbitLauncher0517.apk differ diff --git a/RabbitLauncher0517_Patched.apk b/RabbitLauncher0517_Patched.apk new file mode 100644 index 0000000..5b35912 Binary files /dev/null and b/RabbitLauncher0517_Patched.apk differ diff --git a/index.js b/index.js new file mode 100644 index 0000000..134e603 --- /dev/null +++ b/index.js @@ -0,0 +1,251 @@ +const fs = require("fs"); +const { execSync } = require("child_process"); +const { Litterbox } = require("node-catbox"); + +const litterbox = new Litterbox(); + +//CHANGE THESE +let decompName = "RabbitLauncher0517"; +let uploadToLitterBox = false; +//CHANGE THESE ^^^^^^^^^^ + +let base = `${decompName}_decompile_xml`; + +let imei = generateIMEI(); + +const getOSVersion = [ + `.method private final getOSVersion()Ljava/lang/String;`, + `.locals 0`, + `.line 49`, + `const-string p0, "rabbit_OS_v0.8.86_20240523151103"`, + `return-object p0`, + `.end method`, +]; + +const getImei = [ + `.method public final getImei(Landroid/content/Context;)Ljava/lang/String;`, + `.locals 0`, + + `.line 49`, + `const-string p0, "${imei}"`, + + `return-object p0`, + `.end method`, +]; + +const getDeviceId = [ + `.method public final getDeviceId()Ljava/lang/String;`, + `.locals 0`, + + `.line 34`, + `const-string p0, "${imei}"`, + + `return-object p0`, + `.end method`, +]; + +const onKeyUp = [ + ".method public final onKeyUp(ILandroid/view/KeyEvent;)Z", + ".locals 3", + + "const/4 p0, -0x1", + + "sput p0, Ltech/rabbit/r1launcher/rabbit/KeyEventHandler;->lastKey:I", + + "sput p1, Ltech/rabbit/r1launcher/rabbit/KeyEventHandler;->lastUpKey:I", + + "const/16 p0, 0x18", + "if-eq p1, p0, :setter", + + "const/16 p0, 0x19", + "if-eq p1, p0, :setter", + + "const/16 p0, 0x13", + + "if-eq p1, p0, :cond_0", + + "const/16 p0, 0x14", + + "if-eq p1, p0, :cond_0", + + "packed-switch p1, :pswitch_data_0", + + "goto :goto_0", + + ":setter", + "const/16 p1, 0x1A", + ":cond_0", + ":pswitch_0", +]; + +const onKeyDown = [ + ".method public final onKeyDown(ILandroid/view/KeyEvent;)Z", + ".locals 3", + "const/16 p0, 0x18", + "if-eq p1, p0, :setter", + "const/16 p0, 0x19", + "if-eq p1, p0, :setter", + "const/16 p0, 0x13", + "if-eq p1, p0, :cond_0", + "const/16 p0, 0x14", + "if-eq p1, p0, :cond_0", + "packed-switch p1, :pswitch_data_0", + "goto :goto_0", + ":setter", + "const/16 p1, 0x1A", + ":cond_0", + ":pswitch_0", +]; + +decomp(); + +modifyFunc( + `.\\${base}\\smali\\classes\\tech\\rabbit\\r1launcher\\RLApp.smali`, + getOSVersion +); + +modifyFunc( + `.\\${base}\\smali\\classes\\tech\\rabbit\\r1launcher\\settings\\utils\\SystemControllerUtil.smali`, + getImei +); + +modifyFunc(`.\\${base}\\smali\\classes\\AppConfig.smali`, getDeviceId); + +modifyFunc( + `.\\${base}\\smali\\classes\\tech\\rabbit\\r1launcher\\rabbit\\KeyEventHandler.smali`, + onKeyUp +); +modifyFunc( + `.\\${base}\\smali\\classes\\tech\\rabbit\\r1launcher\\rabbit\\KeyEventHandler.smali`, + onKeyDown +); + +replaceLib(".\\libbase.so", "libbase.so") + +build(); + +fs.renameSync( + `${base}_out-aligned-debugSigned.apk`, + `${decompName}_Patched.apk` +); + +fs.rmdirSync(`.\\${base}`) +fs.rmSync(`${base}_out.apk`) + +if (uploadToLitterBox) { + console.log("Uploading to LitterBox"); + litterbox + .upload({ + path: `${decompName}_Patched.apk`, + duration: "24h", // or omit to default to 1h + }) + .then((response) => + console.log("Output uploaded to LitterBox! Link: " + response) + ); +} + +function calculateChecksum(imeiWithoutChecksum) { + let imeiArray = imeiWithoutChecksum.split("").map(Number); + let sum = 0; + let double = false; + for (let i = 0; i < imeiArray.length; i++) { + let digit = imeiArray[i]; + if (double) { + digit *= 2; + if (digit > 9) { + digit -= 9; + } + } + sum += digit; + double = !double; + } + let checksum = (10 - (sum % 10)) % 10; + return String(checksum); +} + +function generateIMEI() { + const TAC = "35847631"; + const serialNumberPrefix = "00"; + let serialNumber = serialNumberPrefix; + for (let i = 0; i < 4; i++) { + serialNumber += Math.floor(Math.random() * 10); + } + let imeiWithoutChecksum = TAC + serialNumber; + let checksum = calculateChecksum(imeiWithoutChecksum); + let generatedIMEI = imeiWithoutChecksum + checksum; + return generatedIMEI; +} + +function decomp() { + execSync( + `java -jar APKEditor.jar d -i ${decompName}.apk`, + (err, stdout, stderr) => { + if (err) { + console.error(err); + return; + } + console.log("decompiled"); + } + ); +} + +function modifyFunc(path, modifyWith) { + let start = -1; //so we know what part to modify + let end = -1; + try { + let data = fs.readFileSync(path, "utf8"); + let lineArr = data.split("\n"); + let iter = 0; + + lineArr.forEach((element) => { + if (element.includes(modifyWith[0])) { + start = lineArr.indexOf(element); + //console.log("start ", start); + } + if (start > 0 && end < 0) { + if (element.includes(modifyWith[modifyWith.length - 1])) { + end = iter; + //console.log("end ", end); + + for (let i = start; i <= end; i++) { + if (modifyWith[i - start] !== undefined) + lineArr[i] = modifyWith[i - start]; + else lineArr[i] = ""; + } + } + } + element.replace(" ", "\n"); + iter++; + }); + + fs.writeFileSync(path, lineArr.join("\n"), "utf-8"); + console.log("File modified successfully"); + } catch (err) { + console.error("Error reading or writing file", err); + } +} + +function replaceLib(newLibLocation, oldLib) { + fs.copyFileSync(newLibLocation, `.\\${base}\\root\\lib\\arm64-v8a\\${oldLib}`) +} + +function build() { + execSync(`java -jar APKEditor.jar b -i ${base}`, (err, stdout, stderr) => { + if (err) { + console.error(err); + return; + } + console.log(`stdout: ${stdout}`); + }); + + execSync( + `java -jar uber-apk-signer-1.2.1.jar -a ${decompName}_decompile_xml_out.apk`, + (err, stdout, stderr) => { + if (err) { + console.error(err); + return; + } + console.log(`stdout: ${stdout}`); + } + ); +} diff --git a/libbase.so b/libbase.so new file mode 100644 index 0000000..e5d6ec7 Binary files /dev/null and b/libbase.so differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ff4eae3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "rabbitlauncher-builder", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "rabbitlauncher-builder", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "node-catbox": "^3.1.0" + } + }, + "node_modules/node-catbox": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/node-catbox/-/node-catbox-3.1.0.tgz", + "integrity": "sha512-bgTKwgResdwPiTLnkOevBwv+uKMaYrNUN9s0++VyFFxoENeutnUVt9McULRagOun6PXusmIevpqBYwfcXxciwg==", + "engines": { + "node": ">=19" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b8bca68 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "rabbitlauncher-builder", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "meowster", + "license": "ISC", + "description": "", + "dependencies": { + "node-catbox": "^3.1.0" + } +} diff --git a/uber-apk-signer-1.2.1.jar b/uber-apk-signer-1.2.1.jar new file mode 100644 index 0000000..a7a4d6c Binary files /dev/null and b/uber-apk-signer-1.2.1.jar differ