From 5c68e4fcec0c90c48180ddfc8d3dccafe1e1fab2 Mon Sep 17 00:00:00 2001 From: Kavish Devar Date: Fri, 10 Jan 2025 23:37:07 +0530 Subject: [PATCH] add support for qualcomm libraries and a README --- root-module-manual/.gitignore | 3 +++ root-module-manual/README.md | 19 ++++++++++++++ root-module-manual/main.py | 19 +++++++------- root-module-manual/server.py | 49 ++++++++++++++++++++++++++++++++--- 4 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 root-module-manual/.gitignore create mode 100644 root-module-manual/README.md diff --git a/root-module-manual/.gitignore b/root-module-manual/.gitignore new file mode 100644 index 0000000..4bed222 --- /dev/null +++ b/root-module-manual/.gitignore @@ -0,0 +1,3 @@ +uploads +*.zip +*.json diff --git a/root-module-manual/README.md b/root-module-manual/README.md new file mode 100644 index 0000000..51e1f1f --- /dev/null +++ b/root-module-manual/README.md @@ -0,0 +1,19 @@ +# Root Module Generator + +Use it by visiting [https://aln.kavishdevar.me](https://aln.kavishdevar.me) + +## Instructions – Website +- Open the website +- Upload the file +- Click on the patch button +- Wait for the patch to complete +- Download the module +- Install it in your root manager (e.g. KernelSU, Magisk, APatch, etc.) + +## Instructions – CLI +- Install `radare2`. Make sure you have it in your PATH. Check by running `radare2 -v`. +- Run `python3 main.py `. The module will be generated in the same directory as the input file. + +# License + +Same as project license. Check [/LICENSE](/LICENSE) for more information. \ No newline at end of file diff --git a/root-module-manual/main.py b/root-module-manual/main.py index f7400e3..da411ba 100644 --- a/root-module-manual/main.py +++ b/root-module-manual/main.py @@ -94,18 +94,20 @@ def patch_address(file_path, address, patch_bytes): run_command(f"radare2 -q -e bin.cache=true -w -c 's {address}; wx {patch_bytes}; wci' {file_path}") logging.info(f"Successfully patched address {address}") -def copy_file_to_src(file_path): +def copy_file_to_src(file_path, library_name): """ - Copies a file to the 'src/' directory. + Copies a file to the 'src/' directory with the specified library name. Args: file_path (str): The path to the file to copy. + library_name (str): The name to use for the copied library. """ src_dir = 'src/' if not os.path.exists(src_dir): os.makedirs(src_dir) - shutil.copy(file_path, src_dir) - logging.info(f"Copied {file_path} to {src_dir}") + dest_path = os.path.join(src_dir, library_name) + shutil.copy(file_path, dest_path) + logging.info(f"Copied {file_path} to {dest_path}") def zip_src_files(): """ @@ -115,8 +117,6 @@ def zip_src_files(): for root, dirs, files in os.walk('src/'): for file in files: file_path = os.path.join(root, file) - if file_path == os.path.join('src', os.path.basename(file_path)): - continue # Skip the original uploaded file if os.path.islink(file_path): link_target = os.readlink(file_path) zip_info = zipfile.ZipInfo(os.path.relpath(file_path, 'src/')) @@ -140,11 +140,12 @@ def main(): handler = logger.handlers[0] handler.setFormatter(ColoredFormatter('%(asctime)s - %(levelname)s - %(message)s')) - if len(sys.argv) != 2: - logging.error("Usage: python main.py ") + if len(sys.argv) != 3: + logging.error("Usage: python main.py ") sys.exit(1) file_path = sys.argv[1] + library_name = sys.argv[2] # Patch l2c_fcr_chk_chan_modes l2c_fcr_chk_chan_modes_address = get_symbol_address(file_path, "l2c_fcr_chk_chan_modes") @@ -155,7 +156,7 @@ def main(): patch_address(file_path, l2cu_send_peer_info_req_address, "c0035fd6") # Copy file to src/ - copy_file_to_src(file_path) + copy_file_to_src(file_path, library_name) # Zip files under src/ zip_src_files() diff --git a/root-module-manual/server.py b/root-module-manual/server.py index 530dd13..3eeaf2d 100644 --- a/root-module-manual/server.py +++ b/root-module-manual/server.py @@ -13,8 +13,34 @@ PERMALINK_EXPIRY = 600 # 10 minutes PATCHES_JSON = 'patches.json' # Configure logging +class LogColors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + +class ColoredFormatter(logging.Formatter): + def format(self, record): + log_colors = { + 'DEBUG': LogColors.OKCYAN, + 'INFO': LogColors.OKGREEN, + 'WARNING': LogColors.WARNING, + 'ERROR': LogColors.FAIL, + 'CRITICAL': LogColors.FAIL + LogColors.BOLD + } + log_color = log_colors.get(record.levelname, LogColors.ENDC) + record.msg = f"{log_color}{record.msg}{LogColors.ENDC}" + return super().format(record) + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger() +handler = logger.handlers[0] +handler.setFormatter(ColoredFormatter('%(asctime)s - %(levelname)s - %(message)s')) def save_patch_info(permalink_id, file_path): patch_info = { @@ -154,6 +180,9 @@ def index(): Click to upload a file +
@@ -218,9 +247,15 @@ def patch(): return jsonify({"error": "No selected file"}), 400 if not file.filename.endswith('.so'): return jsonify({"error": "Invalid file type. Only .so files are allowed."}), 400 - file_path = os.path.join('uploads', file.filename) + + # Generate a unique file path + file_uuid = str(uuid.uuid4()) + file_path = os.path.join('uploads', f"{file_uuid}_{file.filename}") file.save(file_path) + # Determine the library name based on the checkbox + library_name = "libbluetooth_qti.so" if 'qti' in request.form else "libbluetooth_jni.so" + # Patch the file try: l2c_fcr_chk_chan_modes_address = get_symbol_address(file_path, "l2c_fcr_chk_chan_modes") @@ -235,6 +270,7 @@ def patch(): permalink_id = str(uuid.uuid4()) PATCHED_LIBRARIES[permalink_id] = { 'file_path': file_path, + 'library_name': library_name, 'timestamp': time.time() } @@ -243,6 +279,7 @@ def patch(): # Schedule deletion threading.Timer(PERMALINK_EXPIRY, delete_expired_permalink, args=[permalink_id]).start() + logger.info(f"Permalink {permalink_id} created, will expire in {PERMALINK_EXPIRY} seconds") return jsonify({'permalink': f'/download/{permalink_id}'}) @@ -252,11 +289,12 @@ def download(permalink_id): return "Permalink expired or invalid", 404 file_path = PATCHED_LIBRARIES[permalink_id]['file_path'] + library_name = PATCHED_LIBRARIES[permalink_id]['library_name'] if not os.path.exists(file_path): return "File not found", 404 try: - copy_file_to_src(file_path) + copy_file_to_src(file_path, library_name) zip_src_files() except Exception as e: logger.error(f"Error preparing download: {str(e)}") @@ -268,9 +306,12 @@ def download(permalink_id): def delete_expired_permalink(permalink_id): if permalink_id in PATCHED_LIBRARIES: - if os.path.exists(PATCHED_LIBRARIES[permalink_id]['file_path']): - os.remove(PATCHED_LIBRARIES[permalink_id]['file_path']) + file_path = PATCHED_LIBRARIES[permalink_id]['file_path'] + if os.path.exists(file_path): + os.remove(file_path) + logger.info(f"Deleted file: {file_path}") del PATCHED_LIBRARIES[permalink_id] + logger.info(f"Permalink {permalink_id} expired and removed from PATCHED_LIBRARIES") if not os.path.exists('uploads'): os.makedirs('uploads')