feat: .cyan files

This commit is contained in:
zx
2024-09-08 22:31:26 -04:00
parent 1e9607d9e1
commit c8197a8c47
5 changed files with 51 additions and 9 deletions

View File

@@ -1,15 +1,14 @@
# pyzule-rw / cyan # pyzule-rw / cyan
rewriting [pyzule](https://github.com/asdfzxcvbn/pyzule), but actually good this time! btw.. cyan/pyzule looks best with a monospace font !! :D a rewrite of [pyzule](https://github.com/asdfzxcvbn/pyzule) that doesn't (completely) suck !!
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.. cyan supports **linux, macOS, WSL, and jailbroken iOS!** all either x86_64 or arm64/aarch64 !!
`cyan` will ~~target python v3.12 (finally!)~~, be pep8-compliant (hopefully..), and be type-hinted!
## features ## features
more coming soon! i'm trying to copy pyzule in order to deprecate it in favor of cyan, which is 1000x better more coming soon! i'm trying to copy pyzule in order to deprecate it in favor of cyan, which is 1000x better
- generate and use [shareable .cyan files](https://github.com/asdfzxcvbn/cyan-gen) to configure IPAs!
- inject deb, dylib, framework, bundle, and appex files/folders - inject deb, dylib, framework, bundle, and appex files/folders
- automatically fix dependencies on CydiaSubstrate **(cyan uses [ElleKit](https://github.com/evelyneee/ellekit/)!)**, Cephei*, and Orion - automatically fix dependencies on CydiaSubstrate **(cyan uses [ElleKit](https://github.com/evelyneee/ellekit/)!)**, Cephei*, and Orion
- copy any unknown file/folder types to app root - copy any unknown file/folder types to app root
@@ -23,8 +22,6 @@ more coming soon! i'm trying to copy pyzule in order to deprecate it in favor of
## install instructions ## install instructions
cyan works on linux, macOS, WSL, and jailbroken iOS!
first, make sure you have [ar](https://command-not-found.com/ar) and [tar](https://command-not-found.com/tar) installed first, make sure you have [ar](https://command-not-found.com/ar) and [tar](https://command-not-found.com/tar) installed
also obviously install python, version 3.9 or greater is required (the version available on the procursus repo for iOS) also obviously install python, version 3.9 or greater is required (the version available on the procursus repo for iOS)
@@ -35,7 +32,12 @@ also obviously install python, version 3.9 or greater is required (the version a
then finally, to install or update cyan, just `pip install --force-reinstall git+https://github.com/asdfzxcvbn/pyzule-rw.git#egg=cyan` then finally, to install or update cyan, just `pip install --force-reinstall git+https://github.com/asdfzxcvbn/pyzule-rw.git#egg=cyan`
## todo ## acknowledgements
- [Al4ise](https://github.com/Al4ise) for the original [Azule](https://github.com/Al4ise/Azule)
- [lief-project](https://github.com/lief-project) for [LIEF](https://github.com/lief-project/LIEF)
### todo
[x] refactor: dont prepare, just copy and fix as you go [x] refactor: dont prepare, just copy and fix as you go
@@ -51,5 +53,7 @@ then finally, to install or update cyan, just `pip install --force-reinstall git
[x] feat: change app icon [x] feat: change app icon
[] feat: .cyan files (lol rip .pyzule files) [x] feat: .cyan files (lol rip .pyzule files)
:D

View File

@@ -21,6 +21,10 @@ def main() -> None:
"-o", "--output", metavar="output", "-o", "--output", metavar="output",
help="if unspecified, overwrites input" help="if unspecified, overwrites input"
) )
parser.add_argument(
"-z", "--cyan", metavar="cyan",
help="the .cyan file to use"
)
parser.add_argument( parser.add_argument(
"-f", metavar="file", nargs="+", "-f", metavar="file", nargs="+",

View File

@@ -38,6 +38,10 @@ def main(parser: ArgumentParser) -> None:
else: else:
sys.exit("[!] main binary is encrypted; exiting") sys.exit("[!] main binary is encrypted; exiting")
if args.cyan is not None:
changing = vars(args)
tbhutils.parse_cyan(changing, tmpdir)
# this goes before injection, # this goes before injection,
# since user might inject their own extensions # since user might inject their own extensions
if args.remove_extensions: if args.remove_extensions:

View File

@@ -1,13 +1,14 @@
import os import os
import sys import sys
import json
import shutil import shutil
import zipfile import zipfile
import platform import platform
import subprocess import subprocess
from uuid import uuid4 from uuid import uuid4
from typing import Optional
from glob import glob, iglob from glob import glob, iglob
from argparse import Namespace from argparse import Namespace
from typing import Optional, Any
def validate_inputs(args: Namespace) -> Optional[str]: def validate_inputs(args: Namespace) -> Optional[str]:
@@ -57,6 +58,9 @@ def validate_inputs(args: Namespace) -> Optional[str]:
if args.k is not None and not os.path.isfile(args.k): if args.k is not None and not os.path.isfile(args.k):
sys.exit(f"[!] {args.k} does not exist") sys.exit(f"[!] {args.k} does not exist")
if args.cyan is not None and not os.path.isfile(args.cyan):
sys.exit(f"[!] {args.cyan} does not exist")
def get_app(path: str, tmpdir: str, is_ipa: bool) -> str: def get_app(path: str, tmpdir: str, is_ipa: bool) -> str:
payload = f"{tmpdir}/Payload" payload = f"{tmpdir}/Payload"
@@ -179,3 +183,29 @@ def make_ipa(tmpdir: str, output: str, level: int) -> None:
if weird != 0: if weird != 0:
print(f"[?] was unable to zip {weird} file(s) due to timestamps") 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"
os.mkdir(DOT_PATH)
with zf.open("config.json") as f:
config = json.load(f)
if "f" in config:
NAMES = [n for n in zf.namelist() if n.startswith("inject/")]
zf.extractall(DOT_PATH, NAMES)
# ensure not None
args["f"] = args["f"] if args["f"] is not None else {}
for e in os.scandir(f"{DOT_PATH}/inject"):
args["f"][e.name] = e.path
del config["f"]
if "k" in config:
args["k"] = zf.extract("icon.idk", DOT_PATH)
del config["k"]
for k, v in config.items():
args[k] = v

BIN
test.cyan Normal file

Binary file not shown.