├── LICENSE ├── Makefile ├── README.md ├── Tap2Debug.plist ├── Tweak.xm └── control /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 TalkingData 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 | THEOS_DEVICE_IP=localhost 2 | THEOS_DEVICE_PORT=2222 3 | ARCHS = arm64 4 | TARGET = iPhone:latest:8.0 5 | 6 | include $(THEOS)/makefiles/common.mk 7 | 8 | TWEAK_NAME = Tap2Debug 9 | Tap2Debug_FILES = Tweak.xm 10 | 11 | include $(THEOS_MAKE_PATH)/tweak.mk 12 | 13 | after-install:: 14 | install.exec "killall -9 SpringBoard" 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tap2debug 2 | 3 | Usage: 4 | 5 | ``` 6 | git clone git@github.com:TalkingData/tap2debug.git 7 | cd tap2debug 8 | make && make install 9 | ``` 10 | 11 | Double clicke the icon of the App you want to debug to start the debugerServer in iOS. 12 | 13 | Open lldb in MacOS terminal: 14 | 15 | ``` 16 | lldb 17 | process connect connect://your_ip:port 18 | ``` 19 | 20 | Happy hacking :-) 21 | -------------------------------------------------------------------------------- /Tap2Debug.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | -------------------------------------------------------------------------------- /Tweak.xm: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | @interface NSTask : NSObject 4 | 5 | - (id)init; 6 | - (void)setLaunchPath:(NSString *)path; 7 | - (void)setArguments:(NSArray *)arguments; 8 | - (void)launch; 9 | - (int)processIdentifier; 10 | 11 | @end 12 | 13 | 14 | @interface UIView(findvc) 15 | -(UIViewController*)findViewController; 16 | @end 17 | 18 | @implementation UIView(find) 19 | -(UIViewController*)findViewController 20 | { 21 | UIResponder* target= self; 22 | while (target) { 23 | target = target.nextResponder; 24 | if ([target isKindOfClass:[UIViewController class]]) { 25 | break; 26 | } 27 | } 28 | return (UIViewController*)target; 29 | } 30 | @end 31 | 32 | @interface LSApplicationProxy : NSObject 33 | + (id) applicationProxyForIdentifier:(id)arg1; 34 | @property (readonly, nonatomic) NSString* canonicalExecutablePath; 35 | @end 36 | 37 | @interface TaskManager : NSObject 38 | + (TaskManager*)sharedManager; 39 | @property (nonatomic,strong) NSTask * runningTask; 40 | @end 41 | 42 | @implementation TaskManager 43 | + (TaskManager*)sharedManager { 44 | static TaskManager *_sharedSingleton = nil; 45 | static dispatch_once_t onceToken; 46 | dispatch_once(&onceToken, ^{ 47 | _sharedSingleton = [[self alloc] init]; 48 | }); 49 | return _sharedSingleton; 50 | } 51 | @end 52 | 53 | 54 | @interface SBIconView : UIView 55 | 56 | @property(nullable, nonatomic,copy) NSArray *gestureRecognizers; 57 | @property(nonatomic,copy) NSString *applicationBundleIdentifierForShortcuts; 58 | 59 | @end 60 | 61 | 62 | 63 | %hook SBIconView 64 | 65 | %new 66 | -(void)handleDoubleClick:(UITapGestureRecognizer*)doubleTap 67 | { 68 | NSLog(@"double click begin"); 69 | 70 | NSString * bundle = self.applicationBundleIdentifierForShortcuts; 71 | if(!bundle){ 72 | NSLog(@"error bundleid is null"); 73 | return; 74 | } 75 | UIViewController * vc = [self findViewController]; 76 | 77 | NSString * debugserver = @"/iOSRE/tools/debugserver"; 78 | NSString * ip_port = @"127.0.0.1:1234"; 79 | NSString * last_server = [[NSUserDefaults standardUserDefaults] objectForKey:@"server_bin_path"] ; 80 | NSString * last_ip =[[NSUserDefaults standardUserDefaults] objectForKey:@"ip_port"] ; 81 | if(last_server!=nil){ 82 | debugserver = last_server; 83 | } 84 | if(last_ip!=nil){ 85 | ip_port = last_ip; 86 | } 87 | 88 | 89 | 90 | Class LSApplicationProxy_class = objc_getClass("LSApplicationProxy"); 91 | NSObject* proxyObj = [LSApplicationProxy_class performSelector:@selector(applicationProxyForIdentifier:) withObject:bundle]; 92 | NSString * canonicalExecutablePath = [proxyObj performSelector:@selector(canonicalExecutablePath)]; 93 | 94 | 95 | UIAlertController * panel = [UIAlertController alertControllerWithTitle:@"🍎 SERVER LAUNCHER" message:canonicalExecutablePath preferredStyle:UIAlertControllerStyleAlert]; 96 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 97 | textField.placeholder = @"server path(not null)"; 98 | textField.text = debugserver; 99 | }]; 100 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 101 | textField.placeholder = @"ip:port(nullable)"; 102 | textField.text = ip_port; 103 | 104 | }]; 105 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 106 | textField.placeholder = @"executable path(not null)"; 107 | textField.text = canonicalExecutablePath; 108 | textField.enabled = NO; 109 | textField.textColor = [UIColor lightGrayColor]; 110 | }]; 111 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 112 | textField.placeholder = @"-x"; 113 | textField.text = @"-x"; 114 | textField.enabled = NO; 115 | textField.textColor = [UIColor lightGrayColor]; 116 | }]; 117 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 118 | textField.placeholder = @"backboard"; 119 | textField.text = @"backboard"; 120 | textField.enabled = NO; 121 | textField.textColor = [UIColor lightGrayColor]; 122 | }]; 123 | 124 | UIAlertAction * okaction = [UIAlertAction actionWithTitle:@"▶ START️ SERVER" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { 125 | 126 | UITextField * tf_server = panel.textFields[0]; 127 | UITextField * tf_ip = panel.textFields[1]; 128 | UITextField * tf_exepath = panel.textFields[2]; 129 | UITextField * tf_x = panel.textFields[3]; 130 | UITextField * tf_board = panel.textFields[4]; 131 | 132 | NSString * bin_serverpath = [tf_server.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 133 | if (!bin_serverpath || bin_serverpath.length == 0) { 134 | NSLog(@"server path is null,stop"); 135 | return ; 136 | } 137 | 138 | NSString * arg_ipport = [tf_ip.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 139 | if (!arg_ipport || arg_ipport.length == 0) { 140 | NSLog(@"ipport is null,continue"); 141 | } 142 | 143 | NSString * arg_exepath = [tf_exepath.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 144 | if (!arg_exepath || arg_exepath.length == 0) { 145 | NSLog(@"exe path is null,stop"); 146 | return ; 147 | } 148 | 149 | NSString * arg_x = [tf_x.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 150 | if (!arg_x || arg_x.length == 0) { 151 | NSLog(@"arg_x is null,user default -x"); 152 | arg_x = @"-x"; 153 | } 154 | 155 | NSString * arg_board = [tf_board.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 156 | if (!arg_board || arg_board.length == 0) { 157 | NSLog(@"arg_board is null,user default -x backboard"); 158 | arg_board = @"-x backboard"; 159 | } 160 | NSLog(@"launch path %@",bin_serverpath); 161 | NSLog(@"%@ %@ %@ %@",bin_serverpath,arg_ipport,arg_exepath,arg_board); 162 | NSMutableArray * args = [NSMutableArray array]; 163 | [args addObject:arg_ipport]; 164 | [args addObject:arg_exepath]; 165 | [args addObject:arg_x]; 166 | [args addObject:arg_board]; 167 | [[NSUserDefaults standardUserDefaults] setObject:bin_serverpath forKey:@"server_bin_path"] ; 168 | [[NSUserDefaults standardUserDefaults] setObject:arg_ipport forKey:@"ip_port"] ; 169 | [[NSUserDefaults standardUserDefaults] synchronize]; 170 | 171 | NSTask * task = [TaskManager sharedManager].runningTask; 172 | if(task){ 173 | kill(task.processIdentifier,SIGKILL); 174 | task = nil; 175 | } 176 | task = [[NSTask alloc]init]; 177 | [task setLaunchPath:bin_serverpath]; 178 | [task setArguments:args]; 179 | [task launch]; 180 | [TaskManager sharedManager].runningTask = task; 181 | }]; 182 | UIAlertAction * cancelaction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 183 | NSLog(@"cancel"); 184 | }]; 185 | UIAlertAction * stopAction = [UIAlertAction actionWithTitle:@"⏹ STOP SERVER" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 186 | NSTask * task = [TaskManager sharedManager].runningTask; 187 | if(task){ 188 | kill(task.processIdentifier,SIGKILL); 189 | task = nil; 190 | } 191 | }]; 192 | 193 | [panel addAction:okaction]; 194 | [panel addAction:stopAction]; 195 | [panel addAction:cancelaction]; 196 | [vc presentViewController:panel animated:YES completion:nil]; 197 | NSLog(@"double click end"); 198 | } 199 | %end 200 | 201 | 202 | %hook SBIconView 203 | 204 | - (void)didMoveToWindow 205 | { 206 | %orig; 207 | UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleClick:)]; 208 | [doubleTap setNumberOfTapsRequired:2]; 209 | [self addGestureRecognizer:doubleTap]; 210 | NSArray * ges = self.gestureRecognizers; 211 | for(UITapGestureRecognizer * each in ges){ 212 | if([each isKindOfClass:[UITapGestureRecognizer class]]){ 213 | [each requireGestureRecognizerToFail: doubleTap]; 214 | } 215 | } 216 | } 217 | 218 | - (void)tapGestureDidChange:(id)ges 219 | { 220 | NSLog(@"single click"); 221 | %orig; 222 | } 223 | 224 | %end 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.dodo.tap2debug 2 | Name: Tap2Debug 3 | Depends: mobilesubstrate 4 | Version: 0.0.1 5 | Architecture: iphoneos-arm 6 | Description: An awesome MobileSubstrate tweak! 7 | Maintainer: bliss_ddo 8 | Author: bliss_ddo 9 | Section: Tweaks 10 | --------------------------------------------------------------------------------