From 2248e6062721e26df4284225f117dbc73fc4e5cd Mon Sep 17 00:00:00 2001 From: khanhduytran0 Date: Sun, 28 Dec 2025 10:10:30 +0700 Subject: [PATCH] BypassMarketplace: hook os_eligibility_get_domain_answer --- BypassMarketplace.x | 103 ++++++++++++++++++++++++++++++----------- Makefile | 2 +- filter.plist | 1 + layout/DEBIAN/postinst | 4 +- layout/DEBIAN/postrm | 4 +- 5 files changed, 82 insertions(+), 32 deletions(-) diff --git a/BypassMarketplace.x b/BypassMarketplace.x index a6237be..2557aa7 100644 --- a/BypassMarketplace.x +++ b/BypassMarketplace.x @@ -1,32 +1,81 @@ @import Foundation; -%group Hook_managedappdistributiond -// "Not bypassing eligibility for com.apple.mobilesafari:personal (isProfileValidated: false isUPPValidated:false isBeta:false" -// Used in managedappdistributiond. Pseudocode of a validate function in OSEligbility.framework: -#if 0 -LSBundleRecord *bundleRecord = ...; -BOOL isProfileValidated = bundleRecord.isProfileValidated; -BOOL isUPPValidated = bundleRecord.isUPPValidated; -BOOL isBeta = bundleRecord.isBeta; -if ( (isProfileValidated == NO) || (isUPPValidated == YES) || (isBeta == YES) ) { - log("Not bypassing eligibility for %s:%s (isProfileValidated: %{bool}d isUPPValidated:%{bool}d isBeta:%{bool}d", bundleRecord.bundleIdentifier.UTF8String, somethingThatSaysPersonal, isProfileValidated, isUPPValidated, isBeta); - return 0; -} -#endif +typedef CF_ENUM(uint64_t, EligibilityDomainType) { + /// Install marketplace-distributed apps + EligibilityDomainTypeHydrogen = 2, + /// Update/restore marketplace-distributed apps + EligibilityDomainTypeHelium = 3, + /// Update/restore web browser engine host apps + EligibilityDomainTypeLithium = 4, + /// Install web browser engine host apps + EligibilityDomainTypeCarbon = 7, + /// Install apps distributed via the web + EligibilityDomainTypeArgon = 19, + /// Update/restore apps distributed via the web + EligibilityDomainTypePotassium = 20, +}; +typedef CF_ENUM(uint64_t, EligibilityAnswer) { + EligibilityAnswerEligible = 4, +}; +typedef CF_ENUM(uint64_t, EligibilityAnswerSource) { + EligibilityAnswerSourceInvalid = 0, + EligibilityAnswerSourceComputed = 1, + EligibilityAnswerSourceForced = 2, +}; +//@interface EligibilityOverride : NSObject +//- (NSMutableDictionary *)overrideMap; +//@end +//@interface EligibilityOverrideData : NSObject +//- (instancetype)initWithAnswer:(EligibilityAnswer)answer context:(id)context; +//@end -// So we just hook these to return values that will bypass eligibility -// for managedappdistributiond -%hook LSBundleRecord -- (BOOL)isProfileValidated { - return YES; +//%group Hook_eligibilityd +// seems to already be YES +//%hook GlobalConfiguration +//- (BOOL)supportsForcedAnswers { +// return YES; +//} +//%end +//%hook EligibilityEngine +//- (EligibilityOverride *)_loadOverridesWithError:(NSError **)error { +// EligibilityOverride *result = %orig; +// if (!result) { +// result = [NSClassFromString(@"EligibilityOverride") new]; +// } +// EligibilityOverrideData *overrideData = [[NSClassFromString(@"EligibilityOverrideData") alloc] initWithAnswer:EligibilityAnswerEligible context:nil]; +// NSMutableDictionary *overrideMap = result.overrideMap; +// overrideMap[@(EligibilityDomainTypeHydrogen)] = overrideData; +// overrideMap[@(EligibilityDomainTypeHelium)] = overrideData; +// overrideMap[@(EligibilityDomainTypeLithium)] = overrideData; +// overrideMap[@(EligibilityDomainTypeCarbon)] = overrideData; +// overrideMap[@(EligibilityDomainTypeArgon)] = overrideData; +// overrideMap[@(EligibilityDomainTypePotassium)] = overrideData; +// return result; +//} +//%end +//%end + +%group Hook_os_eligibility_get_domain_answer +int os_eligibility_get_domain_answer(EligibilityDomainType domain, EligibilityAnswer *answer_ptr, EligibilityAnswerSource *answer_source_ptr, xpc_object_t *status_ptr, xpc_object_t *context_ptr); +%hookf(int, os_eligibility_get_domain_answer, EligibilityDomainType domain, EligibilityAnswer *answer_ptr, EligibilityAnswerSource *answer_source_ptr, xpc_object_t *status_ptr, xpc_object_t *context_ptr) { + switch (domain) { + case EligibilityDomainTypeHydrogen: + case EligibilityDomainTypeHelium: + case EligibilityDomainTypeLithium: + case EligibilityDomainTypeCarbon: + case EligibilityDomainTypeArgon: + case EligibilityDomainTypePotassium: + if (answer_ptr) { + *answer_ptr = EligibilityAnswerEligible; + } + if (answer_source_ptr) { + *answer_source_ptr = EligibilityAnswerSourceForced; + } + return 0; + default: + return %orig(domain, answer_ptr, answer_source_ptr, status_ptr, context_ptr); + } } -- (BOOL)isUPPValidated { - return NO; -} -- (BOOL)isBeta { - return NO; -} -%end %end // for appstorecomponentsd, we hook URL method to replace region code @@ -52,8 +101,8 @@ if ( (isProfileValidated == NO) || (isUPPValidated == YES) || (isBeta == YES) ) %ctor { NSString *processName = NSProcessInfo.processInfo.processName; - if ([processName isEqualToString:@"managedappdistributiond"]) { - %init(Hook_managedappdistributiond); + if ([processName isEqualToString:@"managedappdistributiond"] || [processName isEqualToString:@"installd"]) { + %init(Hook_os_eligibility_get_domain_answer); } else if ([processName isEqualToString:@"appstorecomponentsd"]) { %init(Hook_appstorecomponentsd); } diff --git a/Makefile b/Makefile index 6d8a736..fe7d9bc 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ TARGET := iphone:clang:latest:15.0 -INSTALL_TARGET_PROCESSES = appstorecomponentsd managedappdistributiond MobileStorageMounter +INSTALL_TARGET_PROCESSES = appstorecomponentsd installd managedappdistributiond MobileStorageMounter THEOS_PACKAGE_SCHEME := rootless include $(THEOS)/makefiles/common.mk diff --git a/filter.plist b/filter.plist index ebc1839..74422d8 100644 --- a/filter.plist +++ b/filter.plist @@ -2,6 +2,7 @@ Filter = { Executables = ( appstorecomponentsd, + installd, "managedappdistributiond", MobileStorageMounter, ); diff --git a/layout/DEBIAN/postinst b/layout/DEBIAN/postinst index e38a721..1757cc9 100755 --- a/layout/DEBIAN/postinst +++ b/layout/DEBIAN/postinst @@ -1,3 +1,3 @@ #!/bin/sh -# managedappdistributiond does not honor SIGTERM -killall -KILL managedappdistributiond || true +# some daemons do not honor SIGTERM +killall -KILL appstorecomponentsd installd managedappdistributiond || true diff --git a/layout/DEBIAN/postrm b/layout/DEBIAN/postrm index e38a721..1757cc9 100755 --- a/layout/DEBIAN/postrm +++ b/layout/DEBIAN/postrm @@ -1,3 +1,3 @@ #!/bin/sh -# managedappdistributiond does not honor SIGTERM -killall -KILL managedappdistributiond || true +# some daemons do not honor SIGTERM +killall -KILL appstorecomponentsd installd managedappdistributiond || true