mirror of
https://github.com/NohamR/pyzule-rw.git
synced 2026-10-10 18:39:41 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ae265b413 | ||
|
|
740d3716dc | ||
|
|
5ce7a0cb43 | ||
|
|
04a40f2aa6 | ||
|
|
6845281446 | ||
|
|
54da4485a5 | ||
|
|
f7b0169ee9 | ||
|
|
ffbff5c78d |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,3 +6,6 @@ build/
|
||||
*.cyan
|
||||
.DS_Store
|
||||
|
||||
*.ipa
|
||||
*.app/
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
a rewrite of [pyzule](https://github.com/asdfzxcvbn/pyzule) that doesn't (completely) suck !!
|
||||
|
||||
wouldn't a go rewrite be really cool? (or in rust or something, adding features to this makes me realize PYTHONM FUCKING SUCKS SOMEONE PLEASE REWRITE IN LIKE ANY COMPILED AND STATICALLY TYPED LANGUAGE PLEASE!!!!!!!
|
||||
|
||||
## features
|
||||
|
||||
you can open an issue to request a feature :D !! also see my [recommended flags](https://github.com/asdfzxcvbn/pyzule-rw/wiki/recommended-flags)
|
||||
|
||||
@@ -21,15 +21,16 @@ def main() -> None:
|
||||
"-o", "--output", metavar="output",
|
||||
help="if unspecified, overwrites input"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-z", "--cyan", metavar="cyan",
|
||||
help="the .cyan file to use"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-z", "--cyan", metavar="cyan", nargs="+",
|
||||
help="the .cyan file(s) to use"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f", metavar="file", nargs="+",
|
||||
help="a tweak to inject/item to be added to the bundle"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-n", metavar="name",
|
||||
help="modify the app's name"
|
||||
@@ -101,9 +102,13 @@ def main() -> None:
|
||||
"--overwrite", action="store_true",
|
||||
help="overwrite existing files without confirming"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tv", action="store_true",
|
||||
help="inject tvOS-compatible CydiaSubstrate instead of iOS"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--version", action="version", version="cyan v1.4.2"
|
||||
"--version", action="version", version="cyan v1.4.5"
|
||||
)
|
||||
|
||||
from cyan import logic
|
||||
|
||||
BIN
cyan/extras/CydiaSubstrate_tvos.framework/CydiaSubstrate
Normal file
BIN
cyan/extras/CydiaSubstrate_tvos.framework/CydiaSubstrate
Normal file
Binary file not shown.
25
cyan/extras/CydiaSubstrate_tvos.framework/Info.plist
Normal file
25
cyan/extras/CydiaSubstrate_tvos.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
cyan/extras/CydiaSubstrate_tvos.framework/LICENSE
Normal file
27
cyan/extras/CydiaSubstrate_tvos.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.
|
||||
BIN
cyan/extras/zero.requirements
Normal file
BIN
cyan/extras/zero.requirements
Normal file
Binary file not shown.
@@ -45,7 +45,7 @@ def main(parser: ArgumentParser) -> None:
|
||||
|
||||
if args.cyan is not None:
|
||||
changing = vars(args)
|
||||
tbhutils.parse_cyan(changing, tmpdir)
|
||||
tbhutils.parse_cyans(changing, tmpdir)
|
||||
|
||||
# this goes before injection,
|
||||
# since user might inject their own extensions
|
||||
@@ -55,7 +55,7 @@ def main(parser: ArgumentParser) -> None:
|
||||
app.remove_encrypted_extensions()
|
||||
|
||||
if args.f is not None:
|
||||
app.executable.inject(args.f, tmpdir)
|
||||
app.executable.inject(args.f, tmpdir, tvos=args.tv)
|
||||
if args.n is not None:
|
||||
app.plist.change_name(args.n)
|
||||
if args.v is not None:
|
||||
|
||||
@@ -13,7 +13,10 @@ class Executable:
|
||||
otool = f"{specific}/otool"
|
||||
idylib = f"{specific}/insert_dylib"
|
||||
|
||||
starters = ("\t/Library/", "\t@rpath", "\t@executable_path")
|
||||
# adding /usr/lib/ now, idk why i didnt before. lets hope nothing breaks
|
||||
## LITERALLY 2 DAYS LATER. WHAT THE FUCK IS @LOADER_PATH HELP
|
||||
## i will cry if only checking for '@' will break this.
|
||||
starters = ("\t/Library/", "\t/usr/lib/", "\t@")
|
||||
|
||||
# substrate could show up as
|
||||
# CydiaSubstrate.framework, libsubstrate.dylib, EVEN CydiaSubstrate.dylib
|
||||
|
||||
@@ -24,7 +24,7 @@ class MainExecutable(Executable):
|
||||
else:
|
||||
self.inj_func = self.lief_inject
|
||||
|
||||
def inject(self, tweaks: dict[str, str], tmpdir: str) -> None:
|
||||
def inject(self, tweaks: dict[str, str], tmpdir: str, tvos: bool = False) -> None:
|
||||
ENT_PATH = f"{self.bundle_path}/cyan.entitlements"
|
||||
PLUGINS_DIR = f"{self.bundle_path}/PlugIns"
|
||||
FRAMEWORKS_DIR = f"{self.bundle_path}/Frameworks"
|
||||
@@ -61,6 +61,9 @@ class MainExecutable(Executable):
|
||||
|
||||
# inject/fix user things
|
||||
for bn, path in tweaks.items():
|
||||
if os.path.islink(path):
|
||||
continue # symlinks can potentially have some security implications
|
||||
|
||||
if bn.endswith(".appex"):
|
||||
fpath = f"{PLUGINS_DIR}/{bn}"
|
||||
existed = tbhutils.delete_if_exists(fpath, bn)
|
||||
@@ -94,6 +97,8 @@ class MainExecutable(Executable):
|
||||
|
||||
# orion has a *weak* dependency to substrate,
|
||||
# but will still crash without it. nice !!!!!!!!!!!
|
||||
## edit: actually, maybe this is in case someone uses Internal backend?
|
||||
## someone test it pls!!!
|
||||
if "orion." in needed:
|
||||
needed.add("substrate.")
|
||||
|
||||
@@ -101,10 +106,19 @@ class MainExecutable(Executable):
|
||||
real = self.common[missing]["name"] # e.g. "Orion.framework"
|
||||
ip = f"{FRAMEWORKS_DIR}/{real}"
|
||||
existed = tbhutils.delete_if_exists(ip, real)
|
||||
shutil.copytree(f"{self.install_dir}/extras/{real}", ip)
|
||||
|
||||
if tvos and missing == "substrate.":
|
||||
src = f"{self.install_dir}/extras/CydiaSubstrate_tvos.framework"
|
||||
else:
|
||||
src = f"{self.install_dir}/extras/{real}"
|
||||
|
||||
shutil.copytree(src, ip)
|
||||
|
||||
if not existed:
|
||||
if not tvos:
|
||||
print(f"[*] auto-injected {real}")
|
||||
else:
|
||||
print(f"[*] auto-injected {real} (tvos)")
|
||||
|
||||
# FINALLY !!
|
||||
if self.inj is not None: # type: ignore
|
||||
@@ -132,9 +146,12 @@ class MainExecutable(Executable):
|
||||
print("[!] failed to merge new entitlements, are they valid?")
|
||||
|
||||
def sign_with_entitlements(self, entitlements: str) -> bool:
|
||||
return subprocess.run(
|
||||
[self.ldid, f"-S{entitlements}", "-M", "-Cadhoc", self.path]
|
||||
).returncode == 0
|
||||
return subprocess.run([
|
||||
self.ldid,
|
||||
f"-S{entitlements}", "-M", "-Cadhoc",
|
||||
f"-Q{self.install_dir}/extras/zero.requirements",
|
||||
self.path
|
||||
]).returncode == 0
|
||||
|
||||
def lief_inject(self, cmd: str) -> None:
|
||||
if self.inj is None: # type: ignore
|
||||
|
||||
@@ -70,8 +70,10 @@ def validate_inputs(args: Namespace) -> Optional[str]:
|
||||
if args.l is not None and not os.path.isfile(args.l):
|
||||
sys.exit(f"[!] {args.l} does not exist")
|
||||
|
||||
if args.cyan is not None and not os.path.isfile(args.cyan):
|
||||
sys.exit(f"[!] {args.cyan} does not exist")
|
||||
if args.cyan is not None:
|
||||
for cyan in args.cyan:
|
||||
if not os.path.isfile(cyan):
|
||||
sys.exit(f"[!] {cyan} does not exist")
|
||||
|
||||
if args.x is not None:
|
||||
if not os.path.isfile(args.x):
|
||||
@@ -189,7 +191,7 @@ def extract_deb(deb: str, tweaks: dict[str, str], tmpdir: str) -> None:
|
||||
glob(f"{t2}/**/*.framework", recursive=True)
|
||||
), []): # type: ignore
|
||||
if (
|
||||
os.path.islink(hi) # symlinks are broken iirc
|
||||
os.path.islink(hi) # symlinks are broken iirc, also for security
|
||||
or hi.count(".bundle") > 1 # prevent sub-bundle detection (rip)
|
||||
or hi.count(".framework") > 1
|
||||
):
|
||||
@@ -232,10 +234,12 @@ def make_ipa(tmpdir: str, output: str, level: int) -> None:
|
||||
print(f"[?] was unable to zip {weird} file(s) due to timestamps")
|
||||
|
||||
|
||||
def parse_cyan(args: dict[str, Any], tmpdir: str) -> None:
|
||||
print("[*] parsing .cyan file..")
|
||||
with zipfile.ZipFile(args["cyan"]) as zf:
|
||||
DOT_PATH = f"{tmpdir}/cyan"
|
||||
def parse_cyans(args: dict[str, Any], tmpdir: str) -> None:
|
||||
for ind, cyan in enumerate(args["cyan"]):
|
||||
print(f"[*] parsing {os.path.basename(cyan)} ..")
|
||||
|
||||
with zipfile.ZipFile(cyan) as zf:
|
||||
DOT_PATH = f"{tmpdir}/cyan-{ind}"
|
||||
os.mkdir(DOT_PATH)
|
||||
|
||||
with zf.open("config.json") as f:
|
||||
@@ -260,6 +264,7 @@ def parse_cyan(args: dict[str, Any], tmpdir: str) -> None:
|
||||
args["x"] = zf.extract("new.entitlements", DOT_PATH)
|
||||
del config["x"]
|
||||
|
||||
# the rest of the config (not the ones above, we `del` them)
|
||||
for k, v in config.items():
|
||||
args[k] = v
|
||||
|
||||
|
||||
4
setup.py
4
setup.py
@@ -4,10 +4,10 @@ from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="cyan",
|
||||
version="1.4.2",
|
||||
version="1.4.5",
|
||||
description="finally, pyzule doesn't suck",
|
||||
author="zx",
|
||||
author_email="zx@hrzn.email",
|
||||
author_email="z@zxcvbn.fyi",
|
||||
packages=["cyan", "cyan.tbhtypes", "cgen"],
|
||||
python_requires=">=3.9",
|
||||
include_package_data=True,
|
||||
|
||||
Reference in New Issue
Block a user