From 6c96e51b249e8c3efd321b075140473dc43ceb8c Mon Sep 17 00:00:00 2001 From: zyb Date: Tue, 18 Jun 2024 16:21:07 +0800 Subject: [PATCH] modified: .gitignore modified: README.md modified: npk.py modified: patch.py --- .gitignore | 3 ++- README.md | 9 +++++++ npk.py | 7 ------ patch.py | 72 ++++++++++++++++++++++++++++-------------------------- 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore index 0540009..bfefc43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ __pycache__/ -venv/ \ No newline at end of file +venv/ +patch_*.py \ No newline at end of file diff --git a/README.md b/README.md index 97d5523..775d045 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,15 @@ ### Uses keygen to generate license key (keygen in iso or img). ![](keygen.png) + +### npk.py + Sign,Verify,Create, Extract npk file. +### patch.py + Patch public key and sign NPK files +### netinstall.py + Modify netinstallexe to enable network installation of NPK files that have been resigned in ISO +### upgrade.py + By adding static domain name resolution in RouterOS, the NPK file that has been resigned in ISO can be installed during the upgrade process. ### all patches are applied automatically with [github workflow](https://github.com/elseif/MikroTikPatch/blob/main/.github/workflows/mikrotik_patch.yml). diff --git a/npk.py b/npk.py index 77f8626..5e0430b 100644 --- a/npk.py +++ b/npk.py @@ -239,14 +239,7 @@ class NovaPackage: assert int.from_bytes(data[4:8],'little') == len(data) - 8, 'Invalid Nova Package Size' return NovaPackage(data[8:]) -def get_latest_version(channel:str) -> str: - import requests - response = requests.get(f'https://upgrade.mikrotik.com/routeros/NEWESTa7.{channel}') - return response.text.split(' ')[0] -def create_option_npk(npk_file:str,squashfs_file:str)->NovaPackage: - - return option_npk if __name__=='__main__': import argparse,os diff --git a/patch.py b/patch.py index 1d4861d..3b98f8e 100644 --- a/patch.py +++ b/patch.py @@ -64,36 +64,40 @@ def patch_squashfs(path,key_dict): data = data.replace(old_public_key,new_public_key) open(file,'wb').write(data) -def patch_system_npk(key_dict,input_file,output_file=None): - npk = NovaPackage.load(input_file) - file_container = NpkFileContainer.unserialize_from(npk[NpkPartID.FILE_CONTAINER].data) - for item in file_container: - if item.name == b'boot/EFI/BOOT/BOOTX64.EFI': - print(f'patch {item.name} ...') - item.data = patch_bzimage(item.data,key_dict) - open('linux','wb').write(item.data) - break - npk[NpkPartID.FILE_CONTAINER].data = file_container.serialize() - try: - squashfs_file = 'squashfs.sfs' - extract_dir = 'squashfs-root' - open(squashfs_file,'wb').write(npk[NpkPartID.SQUASHFS].data) - print(f"extract {squashfs_file} ...") - _, stderr = run_shell_command(f"unsquashfs -d {extract_dir} {squashfs_file}") - print(stderr.decode()) - patch_squashfs(extract_dir,key_dict) - print(f"pack {extract_dir} ...") +def patch_npk_file(key_dict,kcdsa_private_key,eddsa_private_key,input_file,output_file=None): + npk = NovaPackage.load(input_file) + if npk[NpkPartID.NAME_INFO].data.name == 'system': + file_container = NpkFileContainer.unserialize_from(npk[NpkPartID.FILE_CONTAINER].data) + for item in file_container: + if item.name == b'boot/EFI/BOOT/BOOTX64.EFI': + print(f'patch {item.name} ...') + item.data = patch_bzimage(item.data,key_dict) + open('linux','wb').write(item.data) + elif item.name == b'boot/kernel': + from netinstall import patch_elf + print(f'patch {item.name} ...') + item.data = patch_elf(item.data,key_dict) + open('linux','wb').write(item.data) + npk[NpkPartID.FILE_CONTAINER].data = file_container.serialize() + try: + squashfs_file = 'squashfs.sfs' + extract_dir = 'squashfs-root' + open(squashfs_file,'wb').write(npk[NpkPartID.SQUASHFS].data) + print(f"extract {squashfs_file} ...") + _, stderr = run_shell_command(f"unsquashfs -d {extract_dir} {squashfs_file}") + print(stderr.decode()) + patch_squashfs(extract_dir,key_dict) + print(f"pack {extract_dir} ...") + run_shell_command(f"rm -f {squashfs_file}") + _, stderr = run_shell_command(f"mksquashfs {extract_dir} {squashfs_file} -quiet -comp xz -no-xattrs -b 256k") + print(stderr.decode()) + except Exception as e: + print(e) + print(f"clean ...") + run_shell_command(f"rm -rf {extract_dir}") + npk[NpkPartID.SQUASHFS].data = open(squashfs_file,'rb').read() run_shell_command(f"rm -f {squashfs_file}") - _, stderr = run_shell_command(f"mksquashfs {extract_dir} {squashfs_file} -quiet -comp xz -no-xattrs -b 256k") - print(stderr.decode()) - except Exception as e: - print(e) - print(f"clean ...") - run_shell_command(f"rm -rf {extract_dir}") - npk[NpkPartID.SQUASHFS].data = open(squashfs_file,'rb').read() - run_shell_command(f"rm -f {squashfs_file}") - kcdsa_private_key = bytes.fromhex(os.environ['CUSTOM_LICENSE_PRIVATE_KEY']) - eddsa_private_key = bytes.fromhex(os.environ['CUSTOM_NPK_SIGN_PRIVATE_KEY']) + npk.sign(kcdsa_private_key,eddsa_private_key) npk.save(output_file or input_file) @@ -101,26 +105,26 @@ if __name__ == '__main__': import argparse,os parser = argparse.ArgumentParser(description='MikroTik patcher') subparsers = parser.add_subparsers(dest="command") - npk_parser = subparsers.add_parser('npk',help='patch routeros.npk file') + npk_parser = subparsers.add_parser('npk',help='patch and sign npk file') npk_parser.add_argument('input',type=str, help='Input file') npk_parser.add_argument('-o','--output',type=str,help='Output file') - netinstall_parser = subparsers.add_parser('netinstall',help='patch netinstall file') netinstall_parser.add_argument('input',type=str, help='Input file') netinstall_parser.add_argument('-o','--output',type=str,help='Output file') args = parser.parse_args() - key_dict = { bytes.fromhex(os.environ['MIKRO_LICENSE_PUBLIC_KEY']):bytes.fromhex(os.environ['CUSTOM_LICENSE_PUBLIC_KEY']), bytes.fromhex(os.environ['MIKRO_NPK_SIGN_PUBLIC_LKEY']):bytes.fromhex(os.environ['CUSTOM_NPK_SIGN_PUBLIC_KEY']) } + kcdsa_private_key = bytes.fromhex(os.environ['CUSTOM_LICENSE_PRIVATE_KEY']) + eddsa_private_key = bytes.fromhex(os.environ['CUSTOM_NPK_SIGN_PRIVATE_KEY']) if args.command =='npk': print(f'patching {args.input} ...') - patch_system_npk(key_dict,args.input) + patch_npk_file(key_dict,kcdsa_private_key,eddsa_private_key,args.input,args.output) elif args.command == 'netinstall': from netinstall import patch_netinstall print(f'patching {args.input} ...') - patch_netinstall(key_dict,args.input) + patch_netinstall(key_dict,args.input,args.output) else: parser.print_help()