diff --git a/README.md b/README.md index 0a49f9e..7e7987f 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,4 @@ how to run: 3. finally run `node index.js` 4. done -to run the apk you need to execute this command first (adb): `adb shell pm grant tech.rabbit.r1launcher.r1 android.permission.WRITE_SECURE_SETTINGS` or in termux `pm grant tech.rabbit.r1launcher.r1 android.permission.WRITE_SECURE_SETTINGS` - -the patcher won't work (atleast for now) with the newest apk version because of the activity where you need to choose cellular or wifi. This can be worked around if you install an older apk first, do the setup, and then update to the latest version. \ No newline at end of file +to run the apk you need to execute this command first (adb): `adb shell pm grant tech.rabbit.r1launcher.r1 android.permission.WRITE_SECURE_SETTINGS` or in termux `pm grant tech.rabbit.r1launcher.r1 android.permission.WRITE_SECURE_SETTINGS` \ No newline at end of file diff --git a/functions.js b/functions.js new file mode 100644 index 0000000..86adba2 --- /dev/null +++ b/functions.js @@ -0,0 +1,97 @@ +const {generateIMEI} = require("./utils"); + +const imei = generateIMEI(); + +const getOSVersion = { + location: "smali/classes/tech/rabbit/r1launcher/RLApp.smali", + code: [ + `.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 = { + location: "smali/classes/tech/rabbit/r1launcher/settings/utils/SystemControllerUtil.smali", + code: [ + `.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 = { + location: "smali/classes/AppConfig.smali", + code: [ + `.method public final getDeviceId()Ljava/lang/String;`, + `.locals 0`, + `.line 34`, + `const-string p0, "${imei}"`, + `return-object p0`, + `.end method`, +]}; + +const onKeyUp = { + location: "smali/classes/tech/rabbit/r1launcher/rabbit/KeyEventHandler.smali", + code: [ + ".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 = { + location: "smali/classes/tech/rabbit/r1launcher/rabbit/KeyEventHandler.smali", + code: [ + ".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", +]}; + +const gotoConnectNetwork = { + location: "smali/classes/tech/rabbit/r1launcher/initstep/InitStepActivity.smali", + code: [ + ".method public final gotoConnectNetwork(Ltech/rabbit/r1launcher/initstep/process/ConnectNetworkFragment$ShowType;)V", + ".locals 2", + `const-string v0, "rabbit explode"`, + "invoke-virtual {p0, v0}, Ltech/rabbit/r1launcher/initstep/InitStepActivity;->connectWifiSuccess(Ljava/lang/String;)V", + "return-void", + ".end method", +]}; + +const functions = { + functions: [getOSVersion, getImei, getDeviceId, onKeyUp, onKeyDown, gotoConnectNetwork] +} +module.exports = {functions} \ No newline at end of file diff --git a/index.js b/index.js index 387c7d8..6d2b183 100644 --- a/index.js +++ b/index.js @@ -1,127 +1,49 @@ const fs = require("fs"); -const { execSync } = require("child_process"); -const { Litterbox } = require("node-catbox"); +const {functions} = require("./functions"); +const {decomp, modifyFunc, replaceLib, build} = require("./utils"); +const settings = require("./settings.json"); -const litterbox = new Litterbox(); +const decompName = settings.apkFileName; -//CHANGE THESE -let decompName = "RabbitLauncher0517"; //.apk file name without .apk -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", -]; +const base = `${decompName}_decompile_xml`; decomp(); -modifyFunc( - `./${base}/smali/classes/tech/rabbit/r1launcher/RLApp.smali`, - getOSVersion -); +functions.functions.forEach(func => { + modifyFunc(`./${base}/`+func.location, func.code) +}) -modifyFunc( - `./${base}/smali/classes/tech/rabbit/r1launcher/settings/utils/SystemControllerUtil.smali`, - getImei -); +// modifyFunc( +// `./${base}/smali/classes/tech/rabbit/r1launcher/RLApp.smali`, +// getOSVersion +// ); -modifyFunc(`./${base}/smali/classes/AppConfig.smali`, getDeviceId); +// modifyFunc( +// `./${base}/smali/classes/tech/rabbit/r1launcher/settings/utils/SystemControllerUtil.smali`, +// getImei +// ); -modifyFunc( - `./${base}/smali/classes/tech/rabbit/r1launcher/rabbit/KeyEventHandler.smali`, - onKeyUp -); -modifyFunc( - `./${base}/smali/classes/tech/rabbit/r1launcher/rabbit/KeyEventHandler.smali`, - onKeyDown -); +// 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 +// ); + +// modifyFunc( +// `./${base}/smali/classes/tech/rabbit/r1launcher/initstep/InitStepActivity.smali`, +// gotoConnectNetwork +// ); replaceLib("./libbase.so", "libbase.so"); +if(fs.existsSync(`./${decompName}_out.apk`)) fs.rmSync(`./${decompName}_out.apk`); +if(fs.existsSync(`./${decompName}_Patched.apk`)) fs.rmSync(`./${decompName}_Patched.apk`); + build(); fs.renameSync( @@ -130,113 +52,4 @@ fs.renameSync( ); fs.rmdirSync(`./${base}`, { recursive: true, force: true }); -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) - ); -} - -//these next 2 functions are taken from -//https://annabelsandford.github.io/rabbit-r1-imeigen/imei_check_v1.html - -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; - 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); - } - if (start > 0 && end < 0) { - if (element.includes(modifyWith[modifyWith.length - 1])) { - end = iter; - - 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}`); - - execSync( - `java -jar uber-apk-signer-1.2.1.jar -a ${decompName}_decompile_xml_out.apk` - ); -} +fs.rmSync(`${base}_out.apk`); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ff4eae3..719f631 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,18 +7,7 @@ "": { "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" - } + "license": "ISC" } } } diff --git a/package.json b/package.json index b8bca68..9a51652 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,5 @@ }, "author": "meowster", "license": "ISC", - "description": "", - "dependencies": { - "node-catbox": "^3.1.0" - } + "description": "" } diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..6bf9b1d --- /dev/null +++ b/settings.json @@ -0,0 +1,3 @@ +{ + "apkFileName": "RabbitLauncher0517" +} \ No newline at end of file diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..55b5445 --- /dev/null +++ b/utils.js @@ -0,0 +1,103 @@ +const { execSync } = require("child_process"); +const fs = require("fs"); +const settings = require("./settings.json"); +const decompName = settings.apkFileName; + +//these next 2 functions are taken from +//https://annabelsandford.github.io/rabbit-r1-imeigen/imei_check_v1.html + +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; + 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); + } + if (start > 0 && end < 0) { + if (element.includes(modifyWith[modifyWith.length - 1])) { + end = iter; + + 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, + `./${decompName}_decompile_xml/root/lib/arm64-v8a/${oldLib}` + ); +} + +function build() { + execSync(`java -jar APKEditor.jar b -i ${decompName}_decompile_xml`); + + execSync( + `java -jar uber-apk-signer-1.2.1.jar -a ${decompName}_decompile_xml_out.apk` + ); +} + +module.exports = {generateIMEI, decomp, modifyFunc, replaceLib, build} \ No newline at end of file