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
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` will ~~target python v3.12 (finally!)~~, be pep8-compliant (hopefully..), and be type-hinted!
cyan supports **linux, macOS, WSL, and jailbroken iOS!** all either x86_64 or arm64/aarch64 !!
## features
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
- 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
@@ -23,8 +22,6 @@ more coming soon! i'm trying to copy pyzule in order to deprecate it in favor of
## 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
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`
## 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
@@ -51,5 +53,7 @@ then finally, to install or update cyan, just `pip install --force-reinstall git
[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",
help="if unspecified, overwrites input"
)
parser.add_argument(
"-z", "--cyan", metavar="cyan",
help="the .cyan file to use"
)
parser.add_argument(
"-f", metavar="file", nargs="+",

View File

@@ -38,6 +38,10 @@ def main(parser: ArgumentParser) -> None:
else:
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,
# since user might inject their own extensions
if args.remove_extensions:

View File

@@ -1,13 +1,14 @@
import os
import sys
import json
import shutil
import zipfile
import platform
import subprocess
from uuid import uuid4
from typing import Optional
from glob import glob, iglob
from argparse import Namespace
from typing import Optional, Any
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):
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:
payload = f"{tmpdir}/Payload"
@@ -179,3 +183,29 @@ def make_ipa(tmpdir: str, output: str, level: int) -> None:
if weird != 0:
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.