├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── control ├── entitlements.xml ├── layout └── usr │ └── bin │ └── cyrun ├── main.mm └── packages └── net.tateu.cyrun_1.0.5_iphoneos-arm.deb /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .theos 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2018 Josh Harris (tateu) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export GO_EASY_ON_ME = 1 2 | 3 | export ARCHS = arm64 4 | export SDKVERSION = 8.4 5 | export TARGET = iphone:clang:8.4 6 | 7 | # export DEBUG = 1 8 | ifeq ($(DEBUG),1) 9 | PACKAGE_VERSION = $(THEOS_PACKAGE_BASE_VERSION)+debug 10 | else 11 | PACKAGE_VERSION = $(THEOS_PACKAGE_BASE_VERSION) 12 | endif 13 | 14 | include $(THEOS)/makefiles/common.mk 15 | 16 | TOOL_NAME = cyrun2 17 | cyrun2_FILES = main.mm 18 | cyrun2_FRAMEWORKS = MobileCoreServices 19 | cyrun2_PRIVATE_FRAMEWORKS = BackBoardServices SoftwareUpdateServices 20 | cyrun2_CODESIGN_FLAGS = -Sentitlements.xml 21 | 22 | include $(THEOS_MAKE_PATH)/tool.mk 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cyrun 2 | For the Electra iOS 11 Jailbreaks. 3 | 4 | cyrun is comprised of an executable and bash script. It will 5 | 6 | * Enable/disable the cycriptListenerTweak dylib file (which loads Cyript and runs a CYListenServer on port 8556) 7 | * Write the App bundleIdentifier or Process Executable Name to the tweak filter plist 8 | * Kill the App/Process and, if it is an App, they will be relaunched automatically by Cyrun. Other, non App processes, may need to be manually launched if iOS does not handle that on it's own like it does for SpringBoard and backboardd. 9 | * If enabled successfully, the bash script will then run `cycript -r 127.0.0.1:8556` 10 | 11 | It is meant to be used alongside [cycriptListenerTweak](https://github.com/tateu/cycriptListenerTweak). 12 | 13 | # INSTALLATION 14 | 15 | # From SSH or terminal as root 16 | cd ~ 17 | # download https://electrarepo64.coolstar.org/debs/ncurses_6.1_iphoneos-arm.deb 18 | # download http://apt.saurik.com/debs/readline_6.0-8_iphoneos-arm.deb 19 | # download http://apt.saurik.com/debs/cycript_0.9.594_iphoneos-arm.deb 20 | # download https://electrarepo64.coolstar.org/debs/ldid_2_1.2.2-coolstar_iphoneos-arm.deb 21 | # download http://www.tateu.net/repo/files/net.tateu.cycriptlistenertweak_1.0.0_iphoneos-arm.deb 22 | # download http://www.tateu.net/repo/files/net.tateu.cyrun_1.0.4_iphoneos-arm.deb 23 | dpkg -i ncurses_6.1_iphoneos-arm.deb 24 | dpkg -i readline_6.0-8_iphoneos-arm.deb 25 | dpkg -i cycript_0.9.594_iphoneos-arm.deb 26 | dpkg -i ldid_2_1.2.2-coolstar_iphoneos-arm.deb 27 | dpkg -i net.tateu.cycriptlistenertweak_1.0.0_iphoneos-arm.deb 28 | dpkg -i net.tateu.cyrun_1.0.4_iphoneos-arm.deb 29 | 30 | The newest versions of cyrun and cycriptListenerTweak can be found on [my repo in Cydia](http://www.tateu.net/repo/). 31 | 32 | And then you can use the bash script to sign the Cycript binaries with the correct Electra entitlements 33 | 34 | cyrun -s 35 | 36 | Then you can load Cycript into SpringBoard. SpringBoard will be terminated and auto restart 37 | 38 | cyrun -n SpringBoard -e 39 | 40 | Or you can unload Cycript from SpringBoard. SpringBoard will be terminated and auto restart 41 | 42 | cyrun -n SpringBoard -d 43 | 44 | Or you can load and auto unloaded Cycript from the iOS Mail App. Mail will be terminated and auto restart. When you ?exit Cycript, it will be killed and unloaded. 45 | 46 | cyrun -n Mail -e -d 47 | 48 | Or you can load and auto unloaded Cycript from backboardd. backboardd will be terminated and auto restart. When you ?exit Cycript, it will be killed and unloaded. 49 | 50 | cyrun -x backboardd -e -d 51 | 52 | The '-n' command takes an AppName, ExecutableName, IconName or LocalizedName. 53 | 54 | You can use a bundleIdentifier instead of an App name with `'-b com.apple.springboard'` 55 | 56 | You can also turn off the 'ask to continue' prompts with '-f' 57 | 58 | cyrun -b com.apple.mobilemail -e -d -f 59 | 60 | You can also load a Cycript scipt file 61 | 62 | cyrun -b com.apple.mobilemail -e -d -f -c /path/to/script.cy 63 | 64 | If you try to enable Cycript for an App that is not SpringBoard while your device is passcode locked, you will see a warning message, since it will most likely fail for most Apps. 65 | 66 | Unfortunately, some things still do not work correctly, possibly (most likely) due to the fact we are using Substitute on iOS 11 and not Substrate. 67 | 68 | @import com.saurik.substrate.MS; 69 | // the above succeeds without error but trying to use any of the functions it imports results in errors such as 70 | // throw new Error("*** _require(class_getInstanceMethod(_class, sel)):../ObjectiveC/Library.mm(2711):Selector_callAsFunction_type") /* type@[native code] hookMessage */ 71 | @import net.limneos.classdumpdyld; 72 | // the above succeeds without error but trying to use any of the functions it imports results in errors such as 73 | // throw #"-[NSBundle isKindOfClass:]: unrecognized selector sent to instance 0x10110c1a0" 74 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: net.tateu.cyrun 2 | Name: cyrun 3 | Depends: firmware (>=11.0), mobilesubstrate, net.tateu.cycriptlistenertweak, Cycript, ldid 4 | Version: 1.0.5 5 | Architecture: iphoneos-arm 6 | Description: Cycript Loader for iOS 11. 7 | Maintainer: tateu (Josh Harris) 8 | Author: tateu (Josh Harris) 9 | Depiction: http://www.tateu.net/repo/html/?p=cyrun 10 | Section: System 11 | Tag: role::developer 12 | -------------------------------------------------------------------------------- /entitlements.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | platform-application 5 | 6 | com.apple.private.skip-library-validation 7 | 8 | run-unsigned-code 9 | 10 | get-task-allow 11 | 12 | com.apple.frontboard.launchapplications 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /layout/usr/bin/cyrun: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | POSITIONAL=() 4 | while [[ $# -gt 0 ]] 5 | do 6 | key="$1" 7 | case $key in 8 | -b|--bundle) 9 | bundleIdentifier="$2" 10 | shift # past argument 11 | shift # past value 12 | ;; 13 | -n|--name) 14 | applicationName="$2" 15 | shift 16 | shift 17 | ;; 18 | -x|--exec) 19 | executableName="$2" 20 | shift 21 | shift 22 | ;; 23 | -e|--enable) 24 | enable=YES 25 | shift # past argument 26 | ;; 27 | -d|--disable) 28 | disable=YES 29 | shift 30 | ;; 31 | -f|--force) 32 | force=YES 33 | shift 34 | ;; 35 | -p|--path) 36 | tweakFolderPath="$2" 37 | shift 38 | shift 39 | ;; 40 | -i|--inject) 41 | inject=YES 42 | shift 43 | ;; 44 | -h|--help) 45 | help=YES 46 | shift 47 | ;; 48 | -s|--sign) 49 | sign=YES 50 | shift 51 | ;; 52 | -c|--cyscript) 53 | cyscript="$2" 54 | shift 55 | shift 56 | ;; 57 | *) # unknown option 58 | POSITIONAL+=("$1") # save it in an array for later 59 | shift # past argument 60 | ;; 61 | esac 62 | done 63 | 64 | set -- "${POSITIONAL[@]}" # restore positional parameters 65 | 66 | if [ "$help" == "YES" ]; then 67 | echo "Usage:" 68 | echo " -b - Bundle Identifier of the Application" 69 | echo " 'com.apple.MobileSMS'" 70 | echo " -n - Application Name, ExecutableName, IconName or LocalizedName" 71 | echo " 'Messages'" 72 | echo " -x - Executable Name" 73 | echo " 'backboardd'" 74 | echo " -e - Enable Cycript for the given Process" 75 | echo " If running in Tweak Mode, kill the Process" 76 | echo " Then, if it is an App, restart it" 77 | echo " If running in Inject Mode (Experimental)," 78 | echo " directly inject cycriptListener.dylib" 79 | echo " -d - Disable Cycript for the given Process by killing the Process" 80 | echo " and disabling cycriptListener.dylib" 81 | echo " If both enable and disable are set," 82 | echo " Cycript will be enabled and then disabled after exiting" 83 | echo " -f - Run without asking for confirmation" 84 | echo " -p - Full path to the MobileSubstrate tweak folder" 85 | echo " default value is '/Library/MobileSubstrate/DynamicLibraries'" 86 | echo " -i - Use inject_criticald to load Cycript, instead of the default TweakMode" 87 | echo " This will inject Cycript without having to kill the Process first." 88 | echo " However, this is experimental and seems to fail often and crash the Process" 89 | echo " -c - Load an external Cycript script" 90 | echo " -s - Sign the Cycript binaries with entitlements for Electra iOS 11" 91 | echo " -h - This help file" 92 | echo " You must choose an option to Sign or an (AppBundleID or AppName or ExecutableName) and options for (enable and/or disable Cycript)" 93 | exit 0 94 | fi 95 | 96 | if [ "$sign" == "YES" ]; then 97 | `cycript -h` 98 | retVal=$? 99 | 100 | if [ "$retVal" == "127" ] ; then 101 | echo "ERROR - The Cycript binary does not appear to be installed" 102 | exit 1 103 | fi 104 | 105 | if [ "$retVal" != "137" ] && [ "$force" != "YES" ]; then 106 | echo "The Cycript binary appears to have already been signed correctly" 107 | echo "If you would like to force it to be resigned, run this again with" 108 | echo " cyrun -s -f" 109 | exit 0 110 | fi 111 | 112 | read -p "Would you like to sign the Cycript binaries for the Electra JB (y or n)? " -n 1 -r 113 | echo 114 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then 115 | echo "Ok, cancelled" 116 | exit 0 117 | fi 118 | 119 | cat > /tmp/cyrun_ent.xml << EOF 120 | 121 | 122 | 123 | platform-application 124 | 125 | com.apple.private.skip-library-validation 126 | 127 | run-unsigned-code 128 | 129 | get-task-allow 130 | 131 | 132 | 133 | EOF 134 | 135 | # cp -a /usr/bin/cycript /usr/bin/cycript.bak 136 | # cp -a /usr/lib/libcycript.dylib /usr/lib/libcycript.dylib.bak 137 | 138 | cp -a /usr/bin/cycript /tmp/ 139 | cp -a /usr/lib/libcycript.dylib /tmp/ 140 | rm -rf /usr/bin/cycript 141 | rm -rf /usr/lib/libcycript.dylib 142 | ldid -S/tmp/cyrun_ent.xml /tmp/cycript 143 | ldid -S /tmp/libcycript.dylib 144 | cp -a /tmp/cycript /usr/bin/ 145 | cp -a /tmp/libcycript.dylib /usr/lib/ 146 | 147 | exit 0 148 | fi 149 | 150 | if [ "$sign" == "YES" ]; then 151 | netstat -na | grep LISTEN 152 | fi 153 | 154 | cmd="cyrun2" 155 | if [ "$help" == "YES" ]; then 156 | enable=N 157 | disable=N 158 | bundleIdentifier="" 159 | applicationName="" 160 | cmd="$cmd -h" 161 | fi 162 | 163 | if [ "$bundleIdentifier" != "" ]; then 164 | cmd="$cmd -b $bundleIdentifier" 165 | fi 166 | 167 | if [ "$applicationName" != "" ]; then 168 | cmd="$cmd -n $applicationName" 169 | fi 170 | 171 | if [ "$executableName" != "" ]; then 172 | cmd="$cmd -x $executableName" 173 | fi 174 | 175 | if [ "$enable" == "YES" ]; then 176 | cmd="$cmd -e" 177 | fi 178 | 179 | if [ "$disable" == "YES" ]; then 180 | cmd="$cmd -d" 181 | fi 182 | 183 | if [ "$force" == "YES" ]; then 184 | cmd="$cmd -f" 185 | fi 186 | 187 | if [ "$tweakFolderPath" != "" ]; then 188 | cmd="$cmd -p $tweakFolderPath" 189 | fi 190 | 191 | if [ "$inject" == "YES" ]; then 192 | cmd="$cmd -i" 193 | fi 194 | 195 | `$cmd` 196 | retVal=$? 197 | 198 | if [ "$retVal" == "0" ] && [ "$enable" == "YES" ]; then 199 | if [ "$cyscript" != "" ]; then 200 | cycript -r 127.0.0.1:8556 "$cyscript" 201 | fi 202 | cycript -r 127.0.0.1:8556 203 | 204 | if [ "$disable" == "YES" ]; then 205 | cmd="cyrun2 -d" 206 | 207 | if [ "$bundleIdentifier" != "" ]; then 208 | cmd="$cmd -b $bundleIdentifier" 209 | fi 210 | 211 | if [ "$applicationName" != "" ]; then 212 | cmd="$cmd -n $applicationName" 213 | fi 214 | 215 | if [ "$executableName" != "" ]; then 216 | cmd="$cmd -x $executableName" 217 | fi 218 | 219 | if [ "$force" == "YES" ]; then 220 | cmd="$cmd -f" 221 | fi 222 | 223 | if [ "$tweakFolderPath" != "" ]; then 224 | cmd="$cmd -p $tweakFolderPath" 225 | fi 226 | 227 | if [ "$inject" == "YES" ]; then 228 | cmd="$cmd -i" 229 | fi 230 | 231 | `$cmd` 232 | fi 233 | fi 234 | -------------------------------------------------------------------------------- /main.mm: -------------------------------------------------------------------------------- 1 | #include 2 | #import 3 | #import 4 | #import 5 | #import 6 | 7 | enum { 8 | filterTypeBundle = 0, 9 | filterTypeExecutable 10 | }; 11 | 12 | typedef long BKSOpenApplicationErrorCode; 13 | enum { 14 | BKSOpenApplicationErrorCodeNone = 0, 15 | }; 16 | 17 | extern NSString *BKSActivateForEventOptionTypeBackgroundContentFetching; 18 | extern NSString *BKSDebugOptionKeyArguments; 19 | extern NSString *BKSDebugOptionKeyEnvironment; 20 | extern NSString *BKSDebugOptionKeyStandardOutPath; 21 | extern NSString *BKSDebugOptionKeyStandardErrorPath; 22 | extern NSString *BKSDebugOptionKeyWaitForDebugger; 23 | extern NSString *BKSDebugOptionKeyDisableASLR; 24 | extern NSString *BKSOpenApplicationOptionKeyDebuggingOptions; 25 | extern NSString *BKSOpenApplicationOptionKeyUnlockDevice; 26 | extern NSString *BKSOpenApplicationOptionKeyActivateForEvent; 27 | extern NSString *BKSDebugOptionKeyDebugOnNextLaunch; 28 | extern NSString *BKSDebugOptionKeyCancelDebugOnNextLaunch; 29 | 30 | @interface BKSSystemService : NSObject { 31 | // FBSSystemService* _fbsSystemService; 32 | } 33 | -(void)cleanupClientPort:(unsigned)arg1 ; 34 | -(void)openApplication:(id)arg1 options:(id)arg2 clientPort:(unsigned)arg3 withResult:(/*^block*/id)arg4 ; 35 | -(void)terminateApplication:(id)arg1 forReason:(int)arg2 andReport:(BOOL)arg3 withDescription:(id)arg4 ; 36 | -(void)terminateApplicationGroup:(int)arg1 forReason:(int)arg2 andReport:(BOOL)arg3 withDescription:(id)arg4 ; 37 | -(id)init; 38 | -(void)dealloc; 39 | -(void)openApplication:(id)arg1 options:(id)arg2 withResult:(/*^block*/id)arg3 ; 40 | -(id)systemApplicationBundleIdentifier; 41 | -(int)pidForApplication:(id)arg1 ; 42 | -(unsigned)createClientPort; 43 | -(void)openURL:(id)arg1 application:(id)arg2 options:(id)arg3 clientPort:(unsigned)arg4 withResult:(/*^block*/id)arg5 ; 44 | -(BOOL)canOpenApplication:(id)arg1 reason:(int*)arg2 ; 45 | @end 46 | 47 | @interface LSResourceProxy : NSObject // _LSQueryResult -> NSObject 48 | @property (nonatomic,readonly) NSString *primaryIconName; 49 | @end 50 | 51 | @interface LSBundleProxy : LSResourceProxy 52 | @property (nonatomic,readonly) NSString *localizedShortName; 53 | @property (nonatomic,readonly) NSString *bundleExecutable; 54 | @property (nonatomic,readonly) NSString *bundleIdentifier; 55 | -(id)localizedName; 56 | @end 57 | 58 | @interface LSApplicationProxy : LSBundleProxy 59 | @property (nonatomic,readonly) NSString *itemName; 60 | @property (nonatomic,readonly) NSString *applicationType; // User, System 61 | @property (nonatomic,readonly) NSUInteger installType; 62 | @end 63 | 64 | @interface LSApplicationWorkspace : NSObject 65 | + (id)defaultWorkspace; 66 | - (id)allApplications; 67 | @end 68 | 69 | @interface SUKeybagInterface : NSObject 70 | + (id)sharedInstance; 71 | @property (nonatomic,readonly) BOOL isPasscodeLocked; 72 | @end 73 | 74 | static inline BOOL isLocalPortOpen(short port) 75 | { 76 | struct sockaddr_in addr; 77 | int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 78 | 79 | memset(&addr, 0, sizeof(addr)); 80 | addr.sin_family = AF_INET; 81 | addr.sin_port = htons(port); 82 | 83 | if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr)) { 84 | int result = connect(sock, (struct sockaddr *)&addr, sizeof(addr)); 85 | if (result == 0) { 86 | close(sock); 87 | return YES; 88 | } 89 | } 90 | 91 | return NO; 92 | } 93 | 94 | // https://stackoverflow.com/questions/6610705/how-to-get-process-id-in-iphone-or-ipad 95 | static inline int getPID(NSString *processNameSearch) 96 | { 97 | int pid = -1; 98 | int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL ,0}; 99 | 100 | size_t miblen = 4; 101 | size_t size; 102 | int st = sysctl(mib, miblen, NULL, &size, NULL, 0); 103 | struct kinfo_proc * process = NULL; 104 | struct kinfo_proc * newprocess = NULL; 105 | 106 | do { 107 | size += size / 10; 108 | newprocess = (kinfo_proc *)realloc(process, size); 109 | 110 | if (!newprocess) { 111 | if (process) { 112 | free(process); 113 | process = NULL; 114 | } 115 | 116 | return pid; 117 | } 118 | 119 | process = newprocess; 120 | st = sysctl(mib, miblen, process, &size, NULL, 0); 121 | } while (st == -1 && errno == ENOMEM); 122 | 123 | if (st == 0) { 124 | if (size % sizeof(struct kinfo_proc) == 0) { 125 | int nprocess = size / sizeof(struct kinfo_proc); 126 | if (nprocess) { 127 | // char line[10]; 128 | for (int i = nprocess - 1; i >= 0; i--) { 129 | NSString *processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm]; 130 | 131 | if ([processName isEqualToString:processNameSearch]) { 132 | pid = process[i].kp_proc.p_pid; 133 | [processName release]; 134 | break; 135 | } 136 | 137 | [processName release]; 138 | } 139 | } 140 | } 141 | 142 | free(process); 143 | process = NULL; 144 | } 145 | 146 | return pid; 147 | } 148 | 149 | static inline BOOL killProcessByName(NSString *executableName, pid_t *pid) 150 | { 151 | pid_t p; 152 | int lastpid = *pid; 153 | char *argv[] = {"killall", "-9", (char *)[executableName UTF8String], NULL}; 154 | posix_spawn(&p, "/usr/bin/killall", NULL, NULL, argv, NULL); 155 | 156 | fprintf(stderr, "Waiting for Process to close...\n"); 157 | [NSThread sleepForTimeInterval:2.0f]; 158 | *pid = getPID(executableName); 159 | if (lastpid == *pid) { 160 | fprintf(stderr, "ERROR - could not kill Process (%d == %d)\n", lastpid, *pid); 161 | return NO; 162 | } 163 | 164 | return YES; 165 | } 166 | 167 | static void showHelp() 168 | { 169 | fprintf(stderr, "Usage:\n"); 170 | fprintf(stderr, " -b - Bundle Identifier of the Application\n"); 171 | fprintf(stderr, " 'com.apple.MobileSMS'\n"); 172 | fprintf(stderr, " -n - Application Name, ExecutableName, IconName or LocalizedName\n"); 173 | fprintf(stderr, " 'Messages'\n"); 174 | fprintf(stderr, " -x - Executable Name\n"); 175 | fprintf(stderr, " 'backboardd'\n"); 176 | fprintf(stderr, " -e - Enable Cycript for the given Process\n"); 177 | fprintf(stderr, " If running in Tweak Mode, kill the Process\n"); 178 | fprintf(stderr, " Then, if it is an App, restart it\n"); 179 | fprintf(stderr, " If running in Inject Mode (Experimental),\n"); 180 | fprintf(stderr, " directly inject cycriptListener.dylib\n"); 181 | fprintf(stderr, " -d - Disable Cycript for the given Process by killing the Process\n"); 182 | fprintf(stderr, " and disabling cycriptListener.dylib\n"); 183 | fprintf(stderr, " -f - Run without asking for confirmation\n"); 184 | fprintf(stderr, " -p - Full path to the MobileSubstrate tweak folder\n"); 185 | fprintf(stderr, " default value is '/Library/MobileSubstrate/DynamicLibraries'\n"); 186 | fprintf(stderr, " -i - Use inject_criticald to load Cycript, instead of the default TweakMode\n"); 187 | fprintf(stderr, " This will inject Cycript without having to kill the Process first.\n"); 188 | fprintf(stderr, " However, this is experimental and seems to fail often and crash the Process\n"); 189 | fprintf(stderr, " -h - This help file\n"); 190 | fprintf(stderr, " You must choose an (AppBundleID or AppName or ExecutableName) and options for (enable and/or disable Cycript)\n"); 191 | } 192 | 193 | int main(int argc, char **argv, char **envp) 194 | { 195 | BOOL enable = NO; 196 | BOOL disable = NO; 197 | BOOL force = NO; 198 | BOOL executable = NO; 199 | BOOL tweakMode = YES; 200 | NSString *tweakFolderPath = @"/Library/MobileSubstrate/DynamicLibraries"; 201 | NSString *bundleIdentifier = nil; 202 | NSString *applicationName = nil; 203 | NSString *executableName = nil; 204 | 205 | for (int i = 0; i < argc; i++) { 206 | if (strcmp(argv[i], "--bundle") == 0 || strcmp(argv[i], "-b") == 0) { 207 | bundleIdentifier = [NSString stringWithUTF8String:argv[++i]]; 208 | } else if (strcmp(argv[i], "--name") == 0 || strcmp(argv[i], "-n") == 0) { 209 | applicationName = [NSString stringWithUTF8String:argv[++i]]; 210 | } else if (strcmp(argv[i], "--exec") == 0 || strcmp(argv[i], "-x") == 0) { 211 | executableName = [NSString stringWithUTF8String:argv[++i]]; 212 | executable = YES; 213 | bundleIdentifier = @""; 214 | applicationName = executableName; 215 | } else if (strcmp(argv[i], "--enable") == 0 || strcmp(argv[i], "-e") == 0) { 216 | enable = YES; 217 | } else if (strcmp(argv[i], "--disable") == 0 || strcmp(argv[i], "-d") == 0) { 218 | disable = YES; 219 | } else if (strcmp(argv[i], "--force") == 0 || strcmp(argv[i], "-f") == 0) { 220 | force = YES; 221 | } else if (strcmp(argv[i], "--path") == 0 || strcmp(argv[i], "-p") == 0) { 222 | tweakFolderPath = [NSString stringWithUTF8String:argv[++i]]; 223 | } else if (strcmp(argv[i], "--inject") == 0 || strcmp(argv[i], "-i") == 0) { 224 | tweakMode = NO; 225 | } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { 226 | showHelp(); 227 | return 1; 228 | } 229 | } 230 | 231 | if ((!bundleIdentifier && !applicationName && !executableName) || (!enable && !disable)) { 232 | showHelp(); 233 | return 1; 234 | } 235 | 236 | if ([bundleIdentifier isEqualToString:@"com.apple.springboard"]) { 237 | applicationName = @"SpringBoard"; 238 | executableName = @"SpringBoard"; 239 | } else if (applicationName && [[applicationName lowercaseString] isEqualToString:@"springboard"]) { 240 | applicationName = @"SpringBoard"; 241 | executableName = @"SpringBoard"; 242 | bundleIdentifier = @"com.apple.springboard"; 243 | } else { 244 | LSApplicationWorkspace *applicationWorkspace = [LSApplicationWorkspace defaultWorkspace]; 245 | NSArray *proxies = [applicationWorkspace allApplications]; 246 | 247 | for (LSApplicationProxy *proxy in proxies) { 248 | if (bundleIdentifier && [bundleIdentifier isEqualToString:proxy.bundleIdentifier]) { 249 | executableName = proxy.bundleExecutable; 250 | applicationName = proxy.localizedName; 251 | break; 252 | } else if (executableName) { 253 | if ([executableName isEqualToString:proxy.bundleExecutable]) { 254 | executable = NO; 255 | bundleIdentifier = proxy.bundleIdentifier; 256 | applicationName = proxy.localizedName; 257 | break; 258 | } 259 | } else if (applicationName) { 260 | BOOL found = NO; 261 | if ([applicationName isEqualToString:proxy.bundleExecutable]) { 262 | found = YES; 263 | executableName = proxy.bundleExecutable; 264 | bundleIdentifier = proxy.bundleIdentifier; 265 | } else if ([applicationName isEqualToString:proxy.localizedName]) { 266 | found = YES; 267 | executableName = proxy.bundleExecutable; 268 | bundleIdentifier = proxy.bundleIdentifier; 269 | } else if ([applicationName isEqualToString:proxy.itemName]) { 270 | found = YES; 271 | executableName = proxy.bundleExecutable; 272 | bundleIdentifier = proxy.bundleIdentifier; 273 | } else if ([applicationName isEqualToString:proxy.primaryIconName]) { 274 | found = YES; 275 | executableName = proxy.bundleExecutable; 276 | bundleIdentifier = proxy.bundleIdentifier; 277 | } 278 | 279 | if (found) { 280 | break; 281 | } 282 | } 283 | } 284 | } 285 | 286 | if (!bundleIdentifier) { 287 | fprintf(stderr, "ERROR - could not find bundleIdentifier for %s\n", [applicationName UTF8String]); 288 | if (!tweakMode) { 289 | fprintf(stderr, " Maybe you meant to run with '-x' instead of '-n' or '-b'?\n"); 290 | } 291 | return 1; 292 | } 293 | 294 | if (!executableName) { 295 | fprintf(stderr, "ERROR - could not find executableName for %s\n", [bundleIdentifier UTF8String]); 296 | return 1; 297 | } 298 | 299 | NSString *plistPath = [NSString stringWithFormat:@"%@/cycriptListener.plist", tweakFolderPath]; 300 | if (![NSFileManager.defaultManager fileExistsAtPath:plistPath]) { 301 | fprintf(stderr, "ERROR - could not find plist at %s\n Please specify the correct path using the '-p /path/to/tweakFolder' option\n", [plistPath UTF8String]); 302 | return 1; 303 | } 304 | 305 | if (!tweakMode && ![NSFileManager.defaultManager fileExistsAtPath:@"/electra/inject_criticald"]) { 306 | fprintf(stderr, "ERROR - could not find /electra/inject_criticald\n"); 307 | return 1; 308 | } 309 | 310 | NSString *enabledPath = [NSString stringWithFormat:@"%@/cycriptListener.dylib", tweakFolderPath]; 311 | NSString *disabledPath = [NSString stringWithFormat:@"%@/cycriptListener.disabled", tweakFolderPath]; 312 | 313 | BOOL isPasscodeLocked = [[objc_getClass("SUKeybagInterface") sharedInstance] isPasscodeLocked]; 314 | 315 | int filterType = -1; 316 | NSArray *filterFileObjectList = nil; 317 | int pid = getPID(executableName); 318 | BOOL isCycriptRunning = isLocalPortOpen(8556); 319 | if (isCycriptRunning) { 320 | NSDictionary *filterFile = [NSDictionary dictionaryWithContentsOfFile:plistPath]; 321 | NSDictionary *filter = [filterFile objectForKey:@"Filter"]; 322 | if ([filter objectForKey:@"Bundles"]) { 323 | filterFileObjectList = [filter objectForKey:@"Bundles"]; 324 | filterType = filterTypeBundle; 325 | } else { 326 | filterFileObjectList = [filter objectForKey:@"Executables"]; 327 | filterType = filterTypeExecutable; 328 | } 329 | [filterFile release]; 330 | } 331 | 332 | fprintf(stderr, "applicationName: %s is %s (%d)\n executableName: %s\n bundleIdentifier: %s\n Cycript is %s: %s\n Device is%s passcode locked\n %s\n", [applicationName UTF8String], pid == -1 ? "not running" : "running", pid, [executableName UTF8String], [bundleIdentifier UTF8String], isCycriptRunning ? "active" : "inactive", filterFileObjectList ? [[filterFileObjectList objectAtIndex:0] UTF8String] : "", isPasscodeLocked ? "" : " not", tweakMode ? "Tweak Mode" : "Inject Mode (Experimental)"); 333 | 334 | if (isPasscodeLocked && enable && ![executableName isEqualToString:@"SpringBoard"] && (!executable && tweakMode)) { 335 | fprintf(stderr, "WARNING - Since your device is passcode locked and you are trying to enable Cycript for an App, there is a good chance this will fail!\n"); 336 | } 337 | 338 | if (isCycriptRunning && !enable && disable) { 339 | if (executable || !tweakMode) { 340 | if (filterFileObjectList && ![executableName isEqualToString:[filterFileObjectList objectAtIndex:0]]) { 341 | fprintf(stderr, "WARNING - Cycript is active but it looks like the executableName you are trying to disable it for does not match!\n"); 342 | } 343 | } else { 344 | if (filterFileObjectList) { 345 | if (filterType == filterTypeBundle && ![bundleIdentifier isEqualToString:[filterFileObjectList objectAtIndex:0]]) { 346 | fprintf(stderr, "WARNING - Cycript is active but it looks like the bundleIdentifier you are trying to disable it for does not match!\n"); 347 | } else if (filterType == filterTypeExecutable && ![executableName isEqualToString:[filterFileObjectList objectAtIndex:0]]) { 348 | fprintf(stderr, "WARNING - Cycript is active but it looks like the executableName you are trying to disable it for does not match!\n"); 349 | } 350 | } 351 | } 352 | } else if (enable && isCycriptRunning) { 353 | BOOL match = YES; 354 | if (executable || !tweakMode) { 355 | if (filterFileObjectList && ![executableName isEqualToString:[filterFileObjectList objectAtIndex:0]]) { 356 | fprintf(stderr, "WARNING - Cycript is active but it looks like the executableName you are trying to enable it for does not match!\n"); 357 | match = NO; 358 | } 359 | } else { 360 | if (filterFileObjectList) { 361 | if (filterType == filterTypeBundle && ![bundleIdentifier isEqualToString:[filterFileObjectList objectAtIndex:0]]) { 362 | fprintf(stderr, "WARNING - Cycript is active but it looks like the bundleIdentifier you are trying to enable it for does not match!\n"); 363 | match = NO; 364 | } else if (filterType == filterTypeExecutable && ![executableName isEqualToString:[filterFileObjectList objectAtIndex:0]]) { 365 | fprintf(stderr, "WARNING - Cycript is active but it looks like the executableName you are trying to enable it for does not match!\n"); 366 | match = NO; 367 | } 368 | } 369 | } 370 | if (match) { 371 | fprintf(stderr, "Success, Cycript was already active for the Process. You may now run\n cycript -r 127.0.0.1:8556\n"); 372 | return 0; 373 | } else { 374 | fprintf(stderr, " You cannot enable Cycript in a new Process while it is still running in old one\n"); 375 | fprintf(stderr, "Do you want to connect to the current Process (y or n)? "); 376 | 377 | char line[10]; 378 | if (fgets(line, sizeof(line), stdin) == NULL) { 379 | printf("ERROR - Input.\n"); 380 | return 1; 381 | } 382 | 383 | if (line[0] != 'y' && line[0] != 'Y') { 384 | fprintf(stderr, "Ok, cancelled\n"); 385 | fprintf(stderr, " You can probably disable Cycript with\n cyrun -%s %s -d\n", filterType == filterTypeBundle ? "b" : "x", [[filterFileObjectList objectAtIndex:0] UTF8String]); 386 | return 1; 387 | } else { 388 | fprintf(stderr, "Success, You may now run\n cycript -r 127.0.0.1:8556\n"); 389 | return 0; 390 | } 391 | } 392 | } 393 | 394 | if (!tweakMode && pid == -1 && enable) { 395 | fprintf(stderr, "ERROR - You are trying to enable Cycript using inject mode for an executable that is not running.\n"); 396 | return 1; 397 | } else if (executable && pid == -1 && enable) { 398 | fprintf(stderr, "WARNING - You are trying to enable Cycript for an executable that is not running. Cyrun cannot confirm whether or not this is valid!\n"); 399 | } 400 | 401 | if (!force) { 402 | fprintf(stderr, "Do you want to continue %s Cycript (y or n)? ", enable ? "enabling" : "disabling"); 403 | 404 | char line[10]; 405 | if (fgets(line, sizeof(line), stdin) == NULL) { 406 | printf("ERROR - Input.\n"); 407 | return 1; 408 | } 409 | 410 | if (line[0] != 'y' && line[0] != 'Y') { 411 | fprintf(stderr, "Ok, cancelled\n"); 412 | return 1; 413 | } 414 | } 415 | 416 | if (enable) { 417 | NSDictionary *filter = nil; 418 | if (executable || !tweakMode) { 419 | filter = [NSDictionary dictionaryWithObjectsAndKeys: 420 | @[executableName], @"Executables", 421 | nil 422 | ]; 423 | } else { 424 | filter = [NSDictionary dictionaryWithObjectsAndKeys: 425 | @[bundleIdentifier], @"Bundles", 426 | nil 427 | ]; 428 | } 429 | 430 | NSDictionary *filterFile = [NSDictionary dictionaryWithObjectsAndKeys: 431 | filter, @"Filter", 432 | nil 433 | ]; 434 | 435 | [filterFile writeToFile:plistPath atomically:YES]; 436 | [filter release]; 437 | [filterFile release]; 438 | 439 | if (tweakMode) { 440 | if ([NSFileManager.defaultManager fileExistsAtPath:disabledPath]) { 441 | NSError *error = NULL; 442 | BOOL result = YES; 443 | if ([NSFileManager.defaultManager fileExistsAtPath:enabledPath]) { 444 | // this might happen right after reinstalling the tweak 445 | result = [NSFileManager.defaultManager removeItemAtPath:disabledPath error:&error]; 446 | } else { 447 | result = [NSFileManager.defaultManager moveItemAtPath:disabledPath toPath:enabledPath error:&error]; 448 | if (!result) { 449 | fprintf(stderr, "ERROR - enabling dylib file\n (%ld) %s\n", error.code, [error.localizedDescription UTF8String]); 450 | return 1; 451 | } 452 | } 453 | } 454 | 455 | if (pid != -1) { 456 | // [systemService terminateApplication:bundleIdentifier forReason:0 andReport:NO withDescription:@"cyrun"]; 457 | BOOL success = killProcessByName(executableName, &pid); 458 | if (!success) { 459 | return 1; 460 | } 461 | } 462 | 463 | if (!executable && ![bundleIdentifier isEqualToString:@"com.apple.springboard"]) { 464 | BKSSystemService *systemService = [[BKSSystemService alloc] init]; 465 | NSMutableDictionary *options = [NSMutableDictionary dictionary]; 466 | 467 | if (isPasscodeLocked) { 468 | [options setObject:[NSNumber numberWithBool:NO] forKey:BKSOpenApplicationOptionKeyUnlockDevice]; 469 | [options setObject:[NSNumber numberWithBool:YES] forKey:@"__ActivateSuspended"]; 470 | } else { 471 | [options setObject:[NSNumber numberWithBool:YES] forKey:BKSOpenApplicationOptionKeyUnlockDevice]; 472 | } 473 | 474 | __block BKSOpenApplicationErrorCode openApplicationErrorCode = BKSOpenApplicationErrorCodeNone; 475 | __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 476 | [systemService openApplication:bundleIdentifier options:options withResult:^(NSError *error) { 477 | if (error) { 478 | fprintf(stderr, "ERROR - openApplication failed for %s\n (%ld) %s\n", [bundleIdentifier UTF8String], error.code, [error.localizedDescription UTF8String]); 479 | openApplicationErrorCode = (BKSOpenApplicationErrorCode)[error code]; 480 | } 481 | 482 | dispatch_semaphore_signal(semaphore); 483 | } 484 | ]; 485 | 486 | const uint32_t timeoutDuration = 10; 487 | dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timeoutDuration * NSEC_PER_SEC); 488 | long success = dispatch_semaphore_wait(semaphore, timeout) == 0; 489 | 490 | if (!success) { 491 | fprintf(stderr, "ERROR - openApplication timeout for %s\n", [bundleIdentifier UTF8String]); 492 | return 1; 493 | } else if (openApplicationErrorCode != BKSOpenApplicationErrorCodeNone) { 494 | return 1; 495 | } else { 496 | pid = getPID(executableName); 497 | if (pid == -1) { 498 | fprintf(stderr, "ERROR - could not launch App, pid not found for %s\n", [executableName UTF8String]); 499 | return 1; 500 | } else { 501 | isCycriptRunning = isLocalPortOpen(8556); 502 | fprintf(stderr, "Waiting for Cycript to become active...\n"); 503 | for (int i = 0; i < 5 && !isCycriptRunning; i++) { 504 | [NSThread sleepForTimeInterval:1.0f]; 505 | isCycriptRunning = isLocalPortOpen(8556); 506 | } 507 | 508 | if (!isCycriptRunning) { 509 | fprintf(stderr, "ERROR - could not connect to Cycript\n"); 510 | return 1; 511 | } else { 512 | fprintf(stderr, "Successfully enabled, you may now run\n cycript -r 127.0.0.1:8556\n"); 513 | } 514 | } 515 | } 516 | 517 | dispatch_release(semaphore); 518 | [systemService release]; 519 | [options release]; 520 | } else { 521 | if (executable) { 522 | if ([executableName isEqualToString:@"backboardd"]) { 523 | fprintf(stderr, "Waiting for backboardd to launch...\n"); 524 | pid = 0; 525 | [NSThread sleepForTimeInterval:2.0f]; 526 | } else { 527 | fprintf(stderr, "Waiting for Process to launch...\n"); 528 | pid = getPID(executableName); 529 | for (int i = 0; i < 60 && pid == -1; i++) { 530 | [NSThread sleepForTimeInterval:1.0f]; 531 | pid = getPID(executableName); 532 | } 533 | } 534 | } else { 535 | pid = 0; 536 | fprintf(stderr, "Waiting for SpringBoard to launch...\n"); 537 | [NSThread sleepForTimeInterval:2.0f]; 538 | } 539 | 540 | if (pid == -1) { 541 | fprintf(stderr, "ERROR - could not launch Process, pid not found for %s\n", [executableName UTF8String]); 542 | return 1; 543 | } else { 544 | isCycriptRunning = isLocalPortOpen(8556); 545 | fprintf(stderr, "Waiting for Cycript to become active...\n"); 546 | for (int i = 0; i < 5 && !isCycriptRunning; i++) { 547 | [NSThread sleepForTimeInterval:1.0f]; 548 | isCycriptRunning = isLocalPortOpen(8556); 549 | } 550 | 551 | if (!isCycriptRunning) { 552 | fprintf(stderr, "ERROR - could not connect to Cycript\n"); 553 | return 1; 554 | } else { 555 | fprintf(stderr, "Success, you may now run\n cycript -r 127.0.0.1:8556\n"); 556 | } 557 | } 558 | } 559 | } else { 560 | if ([NSFileManager.defaultManager fileExistsAtPath:enabledPath]) { 561 | NSError *error = NULL; 562 | BOOL result = YES; 563 | if ([NSFileManager.defaultManager fileExistsAtPath:disabledPath]) { 564 | // this might happen right after reinstalling the tweak 565 | result = [NSFileManager.defaultManager removeItemAtPath:disabledPath error:&error]; 566 | } 567 | 568 | result = [NSFileManager.defaultManager moveItemAtPath:enabledPath toPath:disabledPath error:&error]; 569 | if (!result) { 570 | fprintf(stderr, "ERROR - setting up dylib file\n (%ld) %s\n", error.code, [error.localizedDescription UTF8String]); 571 | return 1; 572 | } 573 | } 574 | 575 | pid_t p; 576 | int lastpid = pid; 577 | char pids[8]; 578 | sprintf(pids, "%d", pid); 579 | char *argv[] = {"inject_criticald", pids, (char *)[disabledPath UTF8String], NULL}; 580 | posix_spawn(&p, "/electra/inject_criticald", NULL, NULL, argv, NULL); 581 | 582 | fprintf(stderr, "Waiting for injection process...\n"); 583 | [NSThread sleepForTimeInterval:2.0f]; 584 | pid = getPID(executableName); 585 | if (lastpid != pid) { 586 | fprintf(stderr, "ERROR - something went wrong with the injection process and the process crashed\n"); 587 | fprintf(stderr, " It is much more reliable to use Tweak Mode (without the '-i' option)\n"); 588 | return 1; 589 | } 590 | 591 | isCycriptRunning = isLocalPortOpen(8556); 592 | fprintf(stderr, "Waiting for Cycript to become active...\n"); 593 | for (int i = 0; i < 5 && !isCycriptRunning; i++) { 594 | [NSThread sleepForTimeInterval:1.0f]; 595 | isCycriptRunning = isLocalPortOpen(8556); 596 | } 597 | 598 | if (!isCycriptRunning) { 599 | fprintf(stderr, "ERROR - could not connect to Cycript\n"); 600 | return 1; 601 | } else { 602 | fprintf(stderr, "Success, you may now run\n cycript -r 127.0.0.1:8556\n"); 603 | } 604 | } 605 | } else { 606 | if ([NSFileManager.defaultManager fileExistsAtPath:enabledPath]) { 607 | NSError *error = NULL; 608 | BOOL result = YES; 609 | if ([NSFileManager.defaultManager fileExistsAtPath:disabledPath]) { 610 | // this might happen right after reinstalling the tweak 611 | result = [NSFileManager.defaultManager removeItemAtPath:disabledPath error:&error]; 612 | } 613 | 614 | result = [NSFileManager.defaultManager moveItemAtPath:enabledPath toPath:disabledPath error:&error]; 615 | if (!result) { 616 | fprintf(stderr, "ERROR - disabling dylib file\n (%ld) %s\n", error.code, [error.localizedDescription UTF8String]); 617 | return 1; 618 | } 619 | } 620 | 621 | if (isCycriptRunning) { 622 | if (pid != -1) { 623 | BOOL success = killProcessByName(executableName, &pid); 624 | if (!success) { 625 | return 1; 626 | } 627 | 628 | isCycriptRunning = isLocalPortOpen(8556); 629 | fprintf(stderr, "Waiting for Cycript to be inactive...\n"); 630 | for (int i = 0; i < 5 && isCycriptRunning; i++) { 631 | [NSThread sleepForTimeInterval:1.0f]; 632 | isCycriptRunning = isLocalPortOpen(8556); 633 | } 634 | 635 | if (isCycriptRunning) { 636 | fprintf(stderr, "ERROR - Cycript is still running\n %s was killed\n", [executableName UTF8String]); 637 | return 1; 638 | } else { 639 | fprintf(stderr, "Successfully disabled\n %s was killed\n", [executableName UTF8String]); 640 | } 641 | } else { 642 | fprintf(stderr, "Successfully disabled\n"); 643 | } 644 | } else { 645 | fprintf(stderr, "Successfully disabled\n Cycript was not active, so %s was not killed\n", [executableName UTF8String]); 646 | } 647 | } 648 | 649 | return 0; 650 | } 651 | -------------------------------------------------------------------------------- /packages/net.tateu.cyrun_1.0.5_iphoneos-arm.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tateu/cyrun/eed1a002948518010fd00a5b0a3b4101ab2c5164/packages/net.tateu.cyrun_1.0.5_iphoneos-arm.deb --------------------------------------------------------------------------------