mirror of
https://github.com/NohamR/pyzule-rw.git
synced 2026-10-10 18:39:41 +00:00
chore: making progress
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# pyzule-rw / cyan
|
||||
|
||||
rewriting [pyzule](https://github.com/asdfzxcvbn/pyzule), but actually good this time!
|
||||
rewriting [pyzule](https://github.com/asdfzxcvbn/pyzule), but actually good this time! btw.. cyan/pyzule looks best with a monospace font !! :D
|
||||
|
||||
this is pretty much just a hobby project that i'll work on when i'm bored. pyzule in its current state is kinda ugly, but it works and i haven't really had the motivation to work on it. there really isn't any need for improvements, anyway..
|
||||
|
||||
|
||||
BIN
extras/CydiaSubstrate.framework/CydiaSubstrate
Normal file
BIN
extras/CydiaSubstrate.framework/CydiaSubstrate
Normal file
Binary file not shown.
25
extras/CydiaSubstrate.framework/Info.plist
Normal file
25
extras/CydiaSubstrate.framework/Info.plist
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>CydiaSubstrate</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>ellekit</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>ElleKit</string>
|
||||
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.3</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.1.3</string>
|
||||
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
27
extras/CydiaSubstrate.framework/LICENSE
Normal file
27
extras/CydiaSubstrate.framework/LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2022 Évelyne Bélanger All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither ElleKit nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,12 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
# cyan, aka pyzule-rw; by zx, 2024
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
import cyan
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if sys.version_info < (3, 12):
|
||||
sys.exit("[!] please upgrade to python 3.12 or higher")
|
||||
elif sys.platform == "win32":
|
||||
sys.exit("[!] windows is not supported")
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="cyan, an azule \"clone\" for modifying iOS apps"
|
||||
)
|
||||
@@ -29,21 +35,14 @@ def main() -> None:
|
||||
"--overwrite", action="store_true",
|
||||
help="skip overwrite confirmation"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ignore-encrypted", action="store_true",
|
||||
help="skip main binary encryption check"
|
||||
)
|
||||
|
||||
cyan.main(parser)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
# INPUT = os.path.realpath(args.input)
|
||||
# WORKING_DIR = os.getcwd()
|
||||
# PZ_DIR = os.path.expanduser("~/.config/cyan")
|
||||
# changed = False
|
||||
|
||||
# if not (INPUT.endswith(".ipa") or INPUT.endswith(".app")):
|
||||
# sys.exit("[!] input must be a .ipa/.app")
|
||||
# elif not os.path.exists(INPUT):
|
||||
# sys.exit("[!] input does not exist")
|
||||
# elif not args.o and (input("[<] override your input file? [y/N] ").strip()
|
||||
# .lower() not in ("y", "yes")):
|
||||
# sys.exit("[!] not overriding input, missing -o")
|
||||
|
||||
17
src/cyan.py
17
src/cyan.py
@@ -1,7 +1,10 @@
|
||||
import os
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
import tbhutils
|
||||
import tbhtypes
|
||||
|
||||
|
||||
def main(parser: ArgumentParser) -> None:
|
||||
@@ -20,6 +23,16 @@ def main(parser: ArgumentParser) -> None:
|
||||
if arg_err is not None:
|
||||
parser.error(arg_err)
|
||||
|
||||
# verbose notices
|
||||
if args.o
|
||||
INPUT_IS_IPA = True if args.i.endswith(".ipa") else False
|
||||
# OUTPUT_IS_IPA = True if args.o.endswith(".ipa") else False
|
||||
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
app_path, plist_path = tbhutils.get_app(args.i, tmpdir, INPUT_IS_IPA)
|
||||
app = tbhtypes.AppBundle(app_path, plist_path)
|
||||
|
||||
if app.executable.is_encrypted():
|
||||
if args.ignore_encrypted:
|
||||
print("[?] main binary is encrypted, ignoring")
|
||||
else:
|
||||
sys.exit("[!] main binary is encrypted; exiting")
|
||||
|
||||
|
||||
31
src/tbhtypes.py
Normal file
31
src/tbhtypes.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
import sys
|
||||
from subprocess import run
|
||||
|
||||
import tbhutils
|
||||
|
||||
|
||||
class AppBundle:
|
||||
def __init__(self, path: str, plist_path: str):
|
||||
self.path = path
|
||||
self.plist = tbhutils.get_plist(plist_path)
|
||||
self.executable = Executable(
|
||||
f"{path}/{self.plist["CFBundleExecutable"]}"
|
||||
)
|
||||
|
||||
|
||||
class Executable:
|
||||
td = tbhutils.get_tools_dir()
|
||||
otool = f"{td}/otool"
|
||||
|
||||
def __init__(self, path: str):
|
||||
if not os.path.isfile(path):
|
||||
sys.exit(f"[!] {path} does not exist (executable)")
|
||||
|
||||
self.path = path
|
||||
|
||||
def is_encrypted(self) -> bool:
|
||||
proc = run([self.otool, "-l", self.path])
|
||||
return b"cryptid 1" in proc.stdout
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import os
|
||||
from typing import Optional
|
||||
import sys
|
||||
import shutil
|
||||
import zipfile
|
||||
import platform
|
||||
import plistlib
|
||||
from glob import glob
|
||||
from argparse import Namespace
|
||||
from typing import Optional, Any
|
||||
|
||||
|
||||
def validate_inputs(args: Namespace) -> Optional[str]:
|
||||
@@ -13,5 +19,85 @@ def validate_inputs(args: Namespace) -> Optional[str]:
|
||||
if not os.path.exists(args.i):
|
||||
return f"{args.i} does not exist"
|
||||
|
||||
if os.path.exists(args.o):
|
||||
if args.overwrite:
|
||||
return print("[*] output already exists; will overwrite !")
|
||||
|
||||
try:
|
||||
overwrite = input(
|
||||
f"[<] {args.o} already exists, overwrite it? [Y/n] "
|
||||
if args.output is not None
|
||||
else "[<] no output was specified. overwrite the input? [Y/n] "
|
||||
).strip().lower()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit("[>] bye!")
|
||||
|
||||
if overwrite not in ("y", "yes", ""):
|
||||
print("[>] quitting.")
|
||||
sys.exit(0)
|
||||
|
||||
if args.f is not None:
|
||||
args.f = {os.path.normpath(f) for f in args.f}
|
||||
nonexistent = [f for f in args.f if not os.path.exists(f)]
|
||||
|
||||
if len(nonexistent) != 0:
|
||||
print("[!] please ensure the following file(s) exist:")
|
||||
for ne in nonexistent:
|
||||
print(f"[?] - {ne}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_app(path: str, tmpdir: str, is_ipa: bool) -> tuple[str, str]:
|
||||
payload = f"{tmpdir}/Payload"
|
||||
|
||||
if is_ipa:
|
||||
print("[*] extracting ipa..")
|
||||
|
||||
try:
|
||||
with zipfile.ZipFile(path) as ipa:
|
||||
names = ipa.namelist()
|
||||
|
||||
if not any(name.startswith("Payload/") for name in names):
|
||||
raise KeyError
|
||||
elif not any(name.endswith(".app/Info.plist") for name in names):
|
||||
sys.exit("[!] no Info.plist, invalid app")
|
||||
|
||||
ipa.extractall(tmpdir)
|
||||
app = glob(f"{payload}/*.app")[0]
|
||||
plist = f"{app}/Info.plist"
|
||||
except (KeyError, IndexError):
|
||||
sys.exit("[!] couldn't find either Payload or app folder, invalid ipa")
|
||||
except zipfile.BadZipFile:
|
||||
sys.exit(f"[!] {path} is not a zipfile (ipa)")
|
||||
|
||||
print("[*] extracted ipa")
|
||||
else:
|
||||
if not os.path.isfile((plist := f"{path}/Info.plist")):
|
||||
sys.exit("[!] no Info.plist, invalid app")
|
||||
|
||||
print("[*] copying app..")
|
||||
shutil.copytree(path, (app := f"{payload}/{os.path.basename(path)}"))
|
||||
print("[*] copied app")
|
||||
|
||||
return app, plist
|
||||
|
||||
|
||||
def get_tools_dir() -> str:
|
||||
mach = platform.machine()
|
||||
system = platform.system()
|
||||
prefix = ""
|
||||
|
||||
if "iPhone" in mach or "iPad" in mach:
|
||||
mach = "arm64"
|
||||
prefix = "/var/jb" # sorry, rootless only !!
|
||||
|
||||
return f"{prefix}/opt/cyan/tools/{system}/{mach}"
|
||||
|
||||
|
||||
def get_plist(path: str) -> dict[str, Any]:
|
||||
try:
|
||||
with open(path, "rb") as f:
|
||||
return plistlib.load(f)
|
||||
except Exception:
|
||||
sys.exit(f"[!] couldn't read {path}")
|
||||
|
||||
|
||||
BIN
tools/Darwin/arm64/install_name_tool
Normal file
BIN
tools/Darwin/arm64/install_name_tool
Normal file
Binary file not shown.
BIN
tools/Darwin/arm64/ldid
Normal file
BIN
tools/Darwin/arm64/ldid
Normal file
Binary file not shown.
BIN
tools/Darwin/arm64/otool
Normal file
BIN
tools/Darwin/arm64/otool
Normal file
Binary file not shown.
BIN
tools/Darwin/x86_64/install_name_tool
Normal file
BIN
tools/Darwin/x86_64/install_name_tool
Normal file
Binary file not shown.
BIN
tools/Darwin/x86_64/ldid
Normal file
BIN
tools/Darwin/x86_64/ldid
Normal file
Binary file not shown.
BIN
tools/Darwin/x86_64/otool
Normal file
BIN
tools/Darwin/x86_64/otool
Normal file
Binary file not shown.
BIN
tools/Linux/aarch64/install_name_tool
Executable file
BIN
tools/Linux/aarch64/install_name_tool
Executable file
Binary file not shown.
BIN
tools/Linux/aarch64/ldid
Executable file
BIN
tools/Linux/aarch64/ldid
Executable file
Binary file not shown.
BIN
tools/Linux/aarch64/otool
Executable file
BIN
tools/Linux/aarch64/otool
Executable file
Binary file not shown.
BIN
tools/Linux/x86_64/install_name_tool
Executable file
BIN
tools/Linux/x86_64/install_name_tool
Executable file
Binary file not shown.
BIN
tools/Linux/x86_64/ldid
Executable file
BIN
tools/Linux/x86_64/ldid
Executable file
Binary file not shown.
BIN
tools/Linux/x86_64/otool
Executable file
BIN
tools/Linux/x86_64/otool
Executable file
Binary file not shown.
Reference in New Issue
Block a user