├── .gitignore ├── FLEXall.plist ├── Makefile ├── README.md ├── Tweak.xm └── control /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .theos 3 | packages 4 | FLEX 5 | -------------------------------------------------------------------------------- /FLEXall.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.UIKit" ); }; } 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(THEOS_PACKAGE_SCHEME),rootless) 2 | export ARCHS = arm64 arm64e 3 | export TARGET = iphone:clang:13.0:15.0 4 | else 5 | export ARCHS = armv7 armv7s arm64 arm64e 6 | export TARGET = iphone:clang:13.0:9.0 7 | endif 8 | 9 | include $(THEOS)/makefiles/common.mk 10 | 11 | TWEAK_NAME = FLEXall 12 | FLEXall_FRAMEWORKS = UIKit 13 | FLEXall_FILES = Tweak.xm 14 | FLEXall_CFLAGS += -fobjc-arc -w 15 | 16 | include $(THEOS_MAKE_PATH)/tweak.mk 17 | 18 | before-stage:: 19 | find . -name ".DS_Store" -delete 20 | 21 | after-install:: 22 | install.exec "killall -9 SpringBoard" 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FLEXall 2 | Another FLEX loader that can be activated using long press on status bar or long three finger press anywhere. 3 | 4 | ## Blacklist Processes 5 | FLEXall has the ability to not be loaded in specific processes, which can be specified by adding the following in `/var/mobile/Library/Preferences/com.dgh0st.flexall.blacklist.plist`: 6 | ```xml 7 | 8 | 9 | 10 | 11 | blacklist 12 | 13 | process.bundle.identifier 14 | 15 | 16 | ``` 17 | By default Snapchat is blacklisted to reduce the chances of getting banned. 18 | -------------------------------------------------------------------------------- /Tweak.xm: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | @interface SpringBoard : UIApplication // iOS 3 - 13 6 | -(BOOL)isLocked; // iOS 4 - 13 7 | // -(id)_accessibilityTopDisplay; // iOS 5 - 13 8 | @end 9 | 10 | @interface SBBacklightController : NSObject // iOS 7 - 13 11 | +(id)sharedInstance; // iOS 7 - 13 12 | // -(NSTimeInterval)defaultLockScreenDimInterval; // iOS 7 - 13 13 | // -(void)preventIdleSleepForNumberOfSeconds:(NSTimeInterval)arg1; // iOS 7 - 13 14 | -(void)resetLockScreenIdleTimer; // iOS 7 - 10 15 | @end 16 | 17 | @interface SBDashBoardIdleTimerProvider : NSObject // iOS 11 - 13 18 | -(void)addDisabledIdleTimerAssertionReason:(id)arg1; // iOS 11 - 13 19 | -(void)removeDisabledIdleTimerAssertionReason:(id)arg1; // iOS 11 - 13 20 | // -(BOOL)isDisabledAssertionActiveForReason:(id)arg1; // iOS 11 - 13 21 | // -(void)resetIdleTimer; // iOS 11 - 13 22 | @end 23 | 24 | @interface SBDashBoardViewController : UIViewController { // iOS 10 - 12 25 | SBDashBoardIdleTimerProvider *_idleTimerProvider; // iOS 11 - 12 26 | } 27 | @end 28 | 29 | @interface SBDashBoardIdleTimerController : NSObject { // iOS 13 30 | SBDashBoardIdleTimerProvider *_dashBoardIdleTimerProvider; // iOS 13 31 | } 32 | @end 33 | 34 | @interface CSCoverSheetViewController : UIViewController // iOS 13 35 | -(id)idleTimerController; // iOS 13 36 | @end 37 | 38 | @interface SBCoverSheetPresentationManager : NSObject // iOS 11 - 13 39 | +(id)sharedInstance; // iOS 11 - 13 40 | -(id)dashBoardViewController; // iOS 11 - 12 41 | -(id)coverSheetViewController; // iOS 13 42 | @end 43 | 44 | @interface UIStatusBarWindow : UIWindow // iOS 4 - 13 45 | @end 46 | 47 | @interface UIStatusBarTapAction : NSObject // iOS 13 48 | @property (nonatomic, readonly) NSInteger type; // iOS 13 49 | @end 50 | 51 | @interface UIStatusBar : UIView // iOS 4 - 13 52 | @end 53 | 54 | @interface SBMainDisplaySceneLayoutStatusBarView : UIView // iOS 13 55 | -(void)_statusBarTapped:(id)arg1 type:(NSInteger)arg2; // iOS 13 56 | @end 57 | 58 | @interface FLEXExplorerViewController : UIViewController 59 | -(void)resignKeyAndDismissViewControllerAnimated:(BOOL)arg1 completion:(id)arg2; // Pre-FLEX 4 60 | @end 61 | 62 | @interface FLEXManager : NSObject 63 | @property (nonatomic) FLEXExplorerViewController *explorerViewController; 64 | +(FLEXManager *)sharedManager; 65 | // -(void)showExplorer; 66 | @end 67 | 68 | @interface FLEXWindow : UIWindow 69 | @end 70 | 71 | typedef NS_ENUM(NSUInteger, FLEXObjectExplorerSection) { // Pre-FLEX 4 72 | FLEXObjectExplorerSectionDescription, 73 | FLEXObjectExplorerSectionCustom, 74 | FLEXObjectExplorerSectionProperties, 75 | FLEXObjectExplorerSectionIvars, 76 | FLEXObjectExplorerSectionMethods, 77 | FLEXObjectExplorerSectionClassMethods, 78 | FLEXObjectExplorerSectionSuperclasses, 79 | FLEXObjectExplorerSectionReferencingInstances 80 | }; 81 | 82 | @interface FLEXTableViewSection : NSObject // FLEX 4+ 83 | @property (nonatomic, readonly, nullable) NSString *title; 84 | @end 85 | 86 | @interface FLEXSingleRowSection : FLEXTableViewSection // FLEX 4+ 87 | @end 88 | 89 | @interface FLEXObjectExplorerViewController : UITableViewController 90 | @property (nonatomic, readonly) FLEXTableViewSection *customSection; // FLEX 4 - 5 91 | @end 92 | 93 | @interface NSObject (PrivateFLEXall) 94 | -(id)safeValueForKey:(id)arg1; 95 | @end 96 | 97 | @interface UIWindow (PrivateFLEXall) 98 | @property (nonatomic, strong) UILongPressGestureRecognizer *flexAllLongPress; 99 | @end 100 | 101 | @interface FLEXallGestureManager : NSObject 102 | @property (nonatomic, assign) void *flexHandle; 103 | @property (nonatomic, assign) void *reflexHandle; 104 | +(instancetype)sharedManager; 105 | -(void)show; 106 | @end 107 | 108 | // libflex symbols 109 | static id (*GetFLXManager)(); 110 | static SEL (*GetFLXRevealSEL)(); 111 | static Class (*GetFLXWindowClass)(); 112 | 113 | #define kFLEXallWindowLevel 2050 114 | #define kFLEXallLongPressType 1337 115 | #define kFLEXallBlacklistPath ROOT_PATH_NS(@"/var/mobile/Library/Preferences/com.dgh0st.flexall.blacklist.plist") 116 | #define kFLEXallObjectGraphSectionTitle @"Object Graph" 117 | #define kFLEXallDisableIdleTimerReason @"FLEXallDisableIdle" 118 | #define kFLEXallFlexPath ROOT_PATH("/Library/MobileSubstrate/DynamicLibraries/libFLEX.dylib") 119 | #define kFLEXallReflexPath ROOT_PATH("/Library/MobileSubstrate/DynamicLibraries/libreflex.dylib") 120 | 121 | static UILongPressGestureRecognizer *RegisterLongPressGesture(UIWindow *window, NSUInteger fingers) { 122 | UILongPressGestureRecognizer *longPress = nil; 123 | Class flexWindowClass = GetFLXWindowClass(); 124 | if (flexWindowClass == nil || ![window isKindOfClass:flexWindowClass]) { 125 | longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:[FLEXallGestureManager sharedManager] action:@selector(show)]; 126 | longPress.numberOfTouchesRequired = fingers; 127 | [window addGestureRecognizer:longPress]; 128 | } 129 | return longPress; 130 | } 131 | 132 | %hook UIWindow 133 | %property (nonatomic, strong) UILongPressGestureRecognizer *flexAllLongPress; 134 | 135 | -(void)becomeKeyWindow { 136 | %orig(); 137 | 138 | if (self.flexAllLongPress == nil) { 139 | self.flexAllLongPress = RegisterLongPressGesture(self, 3); 140 | } 141 | } 142 | 143 | -(void)resignKeyWindow { 144 | if (self.flexAllLongPress != nil) { 145 | [self removeGestureRecognizer:self.flexAllLongPress]; 146 | self.flexAllLongPress = nil; 147 | } 148 | 149 | %orig(); 150 | } 151 | %end 152 | 153 | %hook UIStatusBarWindow 154 | -(id)initWithFrame:(CGRect)arg1 { 155 | self = %orig(arg1); 156 | if (self != nil) { 157 | RegisterLongPressGesture(self, 1); 158 | } 159 | return self; 160 | } 161 | %end 162 | 163 | %group iOS13plusStatusBar 164 | // runs in SpringBoard 165 | %hook SBMainDisplaySceneLayoutStatusBarView 166 | -(void)_addStatusBarIfNeeded { 167 | %orig(); 168 | 169 | UIStatusBar *_statusBar = [self valueForKey:@"_statusBar"]; 170 | UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_statusBarLongPressed:)]; 171 | [_statusBar addGestureRecognizer:longPress]; 172 | } 173 | 174 | %new 175 | -(void)_statusBarLongPressed:(UILongPressGestureRecognizer *)recognizer { 176 | if (recognizer.state == UIGestureRecognizerStateBegan) { 177 | [self _statusBarTapped:recognizer type:kFLEXallLongPressType]; 178 | } 179 | } 180 | %end 181 | 182 | %hook UIStatusBarManager 183 | // handled in applications 184 | -(void)handleTapAction:(UIStatusBarTapAction *)arg1 { 185 | if (arg1.type == kFLEXallLongPressType) { 186 | [[FLEXallGestureManager sharedManager] show]; 187 | } else { 188 | %orig(arg1); 189 | } 190 | } 191 | %end 192 | %end 193 | 194 | %group commonFLEXHooks 195 | %hook UIViewController 196 | -(BOOL)_canShowWhileLocked { 197 | UIViewController *currentViewController = self; 198 | while (currentViewController != nil) { 199 | if ([currentViewController isKindOfClass:%c(FLEXExplorerViewController)] || [currentViewController isKindOfClass:%c(FLEXNavigationController)]) { 200 | return YES; 201 | } 202 | 203 | if (currentViewController.presentingViewController != nil) { 204 | currentViewController = currentViewController.presentingViewController; 205 | } else { 206 | currentViewController = currentViewController.parentViewController; 207 | } 208 | } 209 | 210 | return %orig(); 211 | } 212 | %end 213 | 214 | %hook FLEXWindow 215 | -(BOOL)_shouldCreateContextAsSecure { 216 | return YES; 217 | } 218 | 219 | -(id)initWithFrame:(CGRect)arg1 { 220 | self = %orig(arg1); 221 | if (self != nil) { 222 | [self setWindowLevel:kFLEXallWindowLevel]; // above springboard alert window but below flash window (and callout bar stuff) 223 | } 224 | return self; 225 | } 226 | %end 227 | 228 | %hook FLEXObjectExplorerViewController 229 | -(void)viewDidLoad { 230 | %orig(); 231 | 232 | FLEXManager *manager = GetFLXManager(); 233 | if (self.navigationItem.rightBarButtonItems.count == 0 && [manager.explorerViewController respondsToSelector:@selector(resignKeyAndDismissViewControllerAnimated:completion:)]) { 234 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(handleDonePressed:)]; 235 | } 236 | } 237 | 238 | -(NSArray *)possibleExplorerSections { // Pre-FLEX 4 239 | static NSArray *possibleSections = %orig(); 240 | static dispatch_once_t onceToken; 241 | dispatch_once(&onceToken, ^{ 242 | NSNumber *referencingInstancesSection = @(FLEXObjectExplorerSectionReferencingInstances); 243 | NSMutableArray *newSections = [possibleSections mutableCopy]; 244 | [newSections removeObject:referencingInstancesSection]; 245 | NSUInteger newIndex = [newSections indexOfObject:@(FLEXObjectExplorerSectionCustom)]; 246 | [newSections insertObject:referencingInstancesSection atIndex:newIndex + 1]; 247 | possibleSections = [newSections copy]; 248 | }); 249 | return possibleSections; 250 | } 251 | 252 | -(NSArray *)makeSections { // FLEX 4+ 253 | NSArray *sections = %orig(); 254 | 255 | if ([self respondsToSelector:@selector(customSection)]) { 256 | // FLEX should never add another one of thse but this should work even if it does 257 | NSArray *singleRowSections = [sections filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^(FLEXTableViewSection *evaluatedObject, NSDictionary *bindings) { 258 | if ([evaluatedObject isKindOfClass:%c(FLEXSingleRowSection)] && [evaluatedObject.title isEqualToString:kFLEXallObjectGraphSectionTitle]) { 259 | return YES; 260 | } 261 | return NO; 262 | }]]; 263 | 264 | NSUInteger customSectionIndex = [sections indexOfObject:self.customSection]; 265 | if (customSectionIndex != NSNotFound && singleRowSections.count > 0) { 266 | NSMutableArray *newSections = [sections mutableCopy]; 267 | [newSections removeObjectsInArray:singleRowSections]; 268 | [newSections insertObjects:singleRowSections atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(customSectionIndex + 1, singleRowSections.count)]]; 269 | sections = [newSections copy]; 270 | } 271 | } 272 | 273 | return sections; 274 | } 275 | 276 | %new 277 | -(void)handleDonePressed:(id)arg1 { 278 | FLEXManager *manager = GetFLXManager(); 279 | if ([manager.explorerViewController respondsToSelector:@selector(resignKeyAndDismissViewControllerAnimated:completion:)]) { // Pre-FLEX 4 280 | [manager.explorerViewController resignKeyAndDismissViewControllerAnimated:YES completion:nil]; 281 | } 282 | } 283 | %end 284 | %end 285 | 286 | %group iOS11plusDisableIdleTimer 287 | static SBDashBoardIdleTimerProvider *GetDashBoardIdleTimerProvider() { 288 | SBCoverSheetPresentationManager *presentationManager = [%c(SBCoverSheetPresentationManager) sharedInstance]; 289 | SBDashBoardIdleTimerProvider *_idleTimerProvider = nil; 290 | if ([presentationManager respondsToSelector:@selector(dashBoardViewController)]) { 291 | SBDashBoardViewController *dashBoardViewController = [presentationManager dashBoardViewController]; 292 | _idleTimerProvider = [dashBoardViewController safeValueForKey:@"_idleTimerProvider"]; 293 | } else if ([presentationManager respondsToSelector:@selector(coverSheetViewController)]) { 294 | SBDashBoardIdleTimerController *dashboardIdleTimerController = [[presentationManager coverSheetViewController] idleTimerController]; 295 | _idleTimerProvider = [dashboardIdleTimerController safeValueForKey:@"_dashBoardIdleTimerProvider"]; 296 | } 297 | return _idleTimerProvider; 298 | } 299 | 300 | %hook FLEXManager 301 | -(void)showExplorer { 302 | %orig(); 303 | 304 | [GetDashBoardIdleTimerProvider() addDisabledIdleTimerAssertionReason:kFLEXallDisableIdleTimerReason]; 305 | } 306 | 307 | -(void)hideExplorer { 308 | %orig(); 309 | 310 | [GetDashBoardIdleTimerProvider() removeDisabledIdleTimerAssertionReason:kFLEXallDisableIdleTimerReason]; 311 | } 312 | %end 313 | %end 314 | 315 | %group preiOS11ResetIdleTimer 316 | %hook FLEXWindow 317 | -(id)hitTest:(CGPoint)arg1 withEvent:(id)arg2 { 318 | id result = %orig(); 319 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) { 320 | SBBacklightController *backlightController = [%c(SBBacklightController) sharedInstance]; 321 | [backlightController resetLockScreenIdleTimer]; 322 | } 323 | return result; 324 | } 325 | %end 326 | %end 327 | 328 | static id FallbackFLXGetManager() { 329 | return [%c(FLEXManager) sharedManager]; 330 | } 331 | 332 | static SEL FallbackFLXRevealSEL() { 333 | return @selector(showExplorer); 334 | } 335 | 336 | static Class FallbackFLXWindowClass() { 337 | return %c(FLEXWindow); 338 | } 339 | 340 | @implementation FLEXallGestureManager 341 | +(instancetype)sharedManager { 342 | static FLEXallGestureManager *_sharedManager = nil; 343 | static dispatch_once_t onceToken; 344 | dispatch_once(&onceToken, ^{ 345 | _sharedManager = [[self alloc] init]; 346 | }); 347 | return _sharedManager; 348 | } 349 | 350 | -(instancetype)init { 351 | self = [super init]; 352 | self.flexHandle = NULL; 353 | self.reflexHandle = NULL; 354 | return self; 355 | } 356 | 357 | -(void)_loadFLEXIfNeeded { 358 | @synchronized(self) { 359 | if (self.flexHandle == NULL && [[NSFileManager defaultManager] fileExistsAtPath:@(kFLEXallFlexPath)]) { 360 | self.flexHandle = dlopen(kFLEXallFlexPath, RTLD_LAZY); 361 | if (self.flexHandle != NULL) { 362 | GetFLXManager = (id(*)())dlsym(self.flexHandle, "FLXGetManager") ?: &FallbackFLXGetManager; 363 | GetFLXRevealSEL = (SEL(*)())dlsym(self.flexHandle, "FLXRevealSEL") ?: &FallbackFLXRevealSEL; 364 | GetFLXWindowClass = (Class(*)())dlsym(self.flexHandle, "FLXWindowClass") ?: &FallbackFLXWindowClass; 365 | 366 | if (%c(SBBacklightController) && [%c(SBBacklightController) instancesRespondToSelector:@selector(resetLockScreenIdleTimer)]) { 367 | %init(preiOS11ResetIdleTimer, FLEXWindow=GetFLXWindowClass()); 368 | } else if (%c(SBCoverSheetPresentationManager)) { 369 | %init(iOS11plusDisableIdleTimer, FLEXManager=[GetFLXManager() class]); 370 | } 371 | 372 | %init(commonFLEXHooks, FLEXWindow=GetFLXWindowClass()); 373 | } else { 374 | // TODO: potentially add alert with dlerror 375 | } 376 | } 377 | 378 | if (self.reflexHandle == NULL && [[NSFileManager defaultManager] fileExistsAtPath:@(kFLEXallReflexPath)]) { 379 | self.reflexHandle = dlopen(kFLEXallReflexPath, RTLD_LAZY); 380 | } 381 | } 382 | } 383 | 384 | -(void)show { 385 | [self _loadFLEXIfNeeded]; 386 | 387 | FLEXManager *manager = GetFLXManager(); 388 | SEL showSelector = GetFLXRevealSEL(); 389 | if (manager != nil && showSelector != NULL) 390 | [manager performSelector:showSelector]; 391 | } 392 | 393 | -(void)dealloc { 394 | if (self.flexHandle != NULL) 395 | dlclose(self.flexHandle); 396 | self.flexHandle = NULL; 397 | 398 | if (self.reflexHandle != NULL) 399 | dlclose(self.reflexHandle); 400 | self.reflexHandle = NULL; 401 | } 402 | @end 403 | 404 | %ctor { 405 | NSArray *args = [[NSProcessInfo processInfo] arguments]; 406 | if (args != nil && args.count != 0) { 407 | NSString *execPath = args[0]; 408 | BOOL isSpringBoard = [[execPath lastPathComponent] isEqualToString:@"SpringBoard"]; 409 | BOOL isApplication = [execPath rangeOfString:@"/Application"].location != NSNotFound; 410 | 411 | // get blacklisted processes 412 | NSArray *blacklistedProcesses = nil; 413 | if ([[NSFileManager defaultManager] fileExistsAtPath:kFLEXallBlacklistPath]) { 414 | /* 415 | Looks for the following format in blacklist plist: 416 | 417 | 418 | blacklist 419 | 420 | process.bundle.identifier 421 | 422 | 423 | */ 424 | NSMutableDictionary *blacklistDict = [NSMutableDictionary dictionaryWithContentsOfFile:kFLEXallBlacklistPath]; 425 | blacklistedProcesses = [blacklistDict objectForKey:@"blacklist"]; 426 | } else { 427 | blacklistedProcesses = @[ 428 | @"com.toyopagroup.picaboo" // snapchat 429 | ]; 430 | } 431 | 432 | NSString *processBundleIdentifier = [NSBundle mainBundle].bundleIdentifier; 433 | BOOL isBlacklisted = [blacklistedProcesses containsObject:processBundleIdentifier]; 434 | if (!isBlacklisted) { 435 | if ((isSpringBoard || isApplication)) { 436 | GetFLXManager = &FallbackFLXGetManager; 437 | GetFLXRevealSEL = &FallbackFLXRevealSEL; 438 | GetFLXWindowClass = &FallbackFLXWindowClass; 439 | 440 | if (%c(UIStatusBarManager)) { 441 | %init(iOS13plusStatusBar); 442 | } 443 | 444 | %init(); 445 | } 446 | } 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.dgh0st.flexall 2 | Name: FLEXall 3 | Depends: mobilesubstrate, libflex 4 | Version: 0.0.1 5 | Architecture: iphoneos-arm 6 | Description: Load FLEX loader dynamically. 7 | Maintainer: DGh0st 8 | Author: DGh0st 9 | Section: Tweaks 10 | --------------------------------------------------------------------------------