diff --git a/AAExecutorDaemon/AAExecutorDaemon/AAOpenCloseExecutor.m b/AAExecutorDaemon/AAExecutorDaemon/AAOpenCloseExecutor.m index 8cc5eae..91d6fb8 100644 --- a/AAExecutorDaemon/AAExecutorDaemon/AAOpenCloseExecutor.m +++ b/AAExecutorDaemon/AAExecutorDaemon/AAOpenCloseExecutor.m @@ -26,6 +26,15 @@ - (BOOL)startExecution { sleep(5); } else { DDLogError(@"Execution aborted! - Unable to make app frontmost again!"); + DDLogInfo(@"Trying to perform workaround for iOS 9"); + //simulate tapping to the screen center + UIATarget* localTarget = [UIATarget localTarget]; + CGSize screenSize = [localTarget.rect CGRectValue].size; + CGPoint point; + point.x = screenSize.width / 2; + point.y = screenSize.height / 2; + [localTarget tap:[NSValue valueWithCGPoint:point]]; + sleep(5); } [self setExecutionFinished]; }]; diff --git a/AAExecutorDaemon/Makefile b/AAExecutorDaemon/Makefile index 456707f..10967ab 100644 --- a/AAExecutorDaemon/Makefile +++ b/AAExecutorDaemon/Makefile @@ -4,10 +4,18 @@ export DEBUG=1 ARCHS=armv7 arm64 TARGET = iphone:latest:8.0 -CLANG = xcrun -sdk iphoneos clang -TARGET_CC=$(CLANG) -TARGET_CXX=$(CLANG) -TARGET_LD=$(CLANG) +ifeq ($(OS),Windows_NT) + detected_OS := Windows +else + detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown') +endif + +ifeq ($(detected_OS), Darwin) + CLANG = xcrun -sdk iphoneos clang + TARGET_CC=$(CLANG) + TARGET_CXX=$(CLANG) + TARGET_LD=$(CLANG) +endif # add entitlements TARGET_CODESIGN_FLAGS ?= -Sentitlements.xml @@ -19,8 +27,13 @@ TOOL_NAME = aaexecutord ${TOOL_NAME}_FILES += $(shell find AAExecutorDaemon -name '*.m' -print) ${TOOL_NAME}_FILES += $(shell find AAExecutorDaemon -name '*.mm' -print) -${TOOL_NAME}_FILES += $(shell find ../Common/CocoaLumberjack/Classes -depth 1 -name '*.m' -print) -${TOOL_NAME}_FILES += $(shell find ../Common/NSData+Base64 -depth 1 -name '*.m' -print) +ifeq ($(detected_OS), Linux) + ${TOOL_NAME}_FILES += $(shell find ../Common/CocoaLumberjack/Classes -maxdepth 1 -name '*.m' -print) + ${TOOL_NAME}_FILES += $(shell find ../Common/NSData+Base64 -maxdepth 1 -name '*.m' -print) +else + ${TOOL_NAME}_FILES += $(shell find ../Common/CocoaLumberjack/Classes -depth 1 -name '*.m' -print) + ${TOOL_NAME}_FILES += $(shell find ../Common/NSData+Base64 -depth 1 -name '*.m' -print) +endif ${TOOL_NAME}_CFLAGS += -fobjc-arc ${TOOL_NAME}_CFLAGS += -I./Header @@ -34,6 +47,6 @@ ${TOOL_NAME}_LDFLAGS = -lstdc++ -F./Frameworks -lAAClientLib -lCCGraphT -LAAExec ${TOOL_NAME}_FRAMEWORKS = UIKit CoreGraphics # PrivateFrameworks -${TOOL_NAME}_FRAMEWORKS = UIAutomation +${TOOL_NAME}_PRIVATE_FRAMEWORKS = UIAutomation include $(THEOS_MAKE_PATH)/tool.mk diff --git a/README.md b/README.md index 16eb4e6..983d93e 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ The `AAClientLib` is a static library that simplifies the development of DiOS an ## Requirements * theos (installed to `/opt/theos`) + * Clutch2 (installed on jailbroken device to `/usr/bin`) See [Initial Setup](https://github.com/DiOS-Analysis/DiOS/wiki/Initial-Setup) and [Running DiOS](https://github.com/DiOS-Analysis/DiOS/wiki/Running-DiOS) for detailed build and setup instructions. diff --git a/SBServerTweak/Makefile b/SBServerTweak/Makefile index d93f4b2..009a6d4 100644 --- a/SBServerTweak/Makefile +++ b/SBServerTweak/Makefile @@ -4,10 +4,18 @@ export DEBUG=1 TARGET = iphone:latest:8.0 #export ARCHS="armv7" -CLANG = xcrun -sdk iphoneos clang -TARGET_CC=$(CLANG) -TARGET_CXX=$(CLANG) -TARGET_LD=$(CLANG) +ifeq ($(OS),Windows_NT) + detected_OS := Windows +else + detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown') +endif + +ifeq ($(detected_OS), Darwin) + CLANG = xcrun -sdk iphoneos clang + TARGET_CC=$(CLANG) + TARGET_CXX=$(CLANG) + TARGET_LD=$(CLANG) +endif include theos/makefiles/common.mk @@ -15,7 +23,11 @@ TWEAK_NAME = SBServerTweak ${TWEAK_NAME}_FILES += $(shell find ${TWEAK_NAME} -name '*.m' -print) ${TWEAK_NAME}_FILES += $(shell find ${TWEAK_NAME} -name '*.mm' -print) -${TWEAK_NAME}_FILES += $(shell find ../Common/CocoaLumberjack/Classes -depth 1 -name '*.m' -print) +ifeq ($(detected_OS), Linux) + ${TWEAK_NAME}_FILES += $(shell find ../Common/CocoaLumberjack/Classes -maxdepth 1 -name '*.m' -print) +else + ${TWEAK_NAME}_FILES += $(shell find ../Common/CocoaLumberjack/Classes -depth 1 -name '*.m' -print) +endif ${TWEAK_NAME}_FILES += $(shell find RoutingHTTPServer/Source -name '*.m' -print) ${TWEAK_NAME}_FILES += $(shell find RoutingHTTPServer/External/CocoaHTTPServer/Core -name '*.m' -print) ${TWEAK_NAME}_FILES += $(shell find RoutingHTTPServer/External/CocoaHTTPServer/Vendor/CocoaAsyncSocket -name '*.m' -print) @@ -33,7 +45,7 @@ ${TWEAK_NAME}_LDFLAGS = -lstdc++ -read_only_relocs suppress ${TWEAK_NAME}_FRAMEWORKS = CFNetwork Security CoreGraphics UIKit # PrivateFrameworks ${TWEAK_NAME}_LDFLAGS = -F../Common/PrivateFrameworks -${TWEAK_NAME}_FRAMEWORKS = StoreServices SpringBoardUI +${TWEAK_NAME}_PRIVATE_FRAMEWORKS = StoreServices SpringBoardUI include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/SBServerTweak/SBServerTweak/SBSTHTTPServer.m b/SBServerTweak/SBServerTweak/SBSTHTTPServer.m index a545682..6f901e7 100644 --- a/SBServerTweak/SBServerTweak/SBSTHTTPServer.m +++ b/SBServerTweak/SBServerTweak/SBSTHTTPServer.m @@ -3,14 +3,41 @@ // #import +//#import +#import +#import #import "SBSTHTTPServer.h" #import "Common.h" +@interface LSApplicationWorkspace : NSObject +- (BOOL)applicationIsInstalled:(NSString *)appIdentifier; +@end + +@interface LSApplicationProxy : NSObject + +@property(readonly) NSString* applicationIdentifier; +@property(readonly) NSString * bundleVersion; +@property(readonly) NSString * bundleExecutable; +@property(readonly) NSArray * deviceFamily; +@property(readonly) NSURL * bundleContainerURL; +@property(readonly) NSString * bundleIdentifier; +@property(readonly) NSURL * bundleURL; +@property(readonly) NSURL * containerURL; +@property(readonly) NSURL * dataContainerURL; +@property(readonly) NSString * localizedShortName; +@property(readonly) NSString * localizedName; +@property(readonly) NSString * shortVersionString; + ++ (LSApplicationProxy*)applicationProxyForIdentifier:(id)appIdentifier; + +@end + #import "SBSTAppStoreManager.h" #import "SBSTCydiaStoreManager.h" #import "SBSTSpringBoardManager.h" #import "SBSTCycriptExecutor.h" #import "SBSTAppExecutionManager.h" +#import "SBSTShellExecutor.h" #define HTTP_CODE_BAD_REQUEST @400 #define HTTP_CODE_LOCKED @423 @@ -97,18 +124,69 @@ - (NSMutableDictionary*)_defaultResponseDict{ #pragma mark The routes +- (void)sendResponse:(RouteResponse*)response dict:(NSDictionary*)responseDict { + if ([responseDict objectForKey:RESPONSE_CODE]) { + [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; + } + [response respondWithData:[NSJSONSerialization dataWithJSONObject:responseDict + options:0 + error:nil]]; +} + +- (BOOL)getApplicationInfo:(NSMutableDictionary*)info bundleId:(NSString*)bundleId { + Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace"); + if (LSApplicationWorkspace_class == nil) { + return NO; + } + + LSApplicationWorkspace *workspace = [LSApplicationWorkspace_class + performSelector:@selector(defaultWorkspace)]; + if (workspace == nil || [workspace applicationIsInstalled:bundleId] == NO) { + return NO; + } + + Class LSApplicationProxy_class = objc_getClass("LSApplicationProxy"); + if (LSApplicationProxy_class == nil) { + return NO; + } + + LSApplicationProxy *app = [LSApplicationProxy_class applicationProxyForIdentifier:bundleId]; + if (app == nil) { + return NO; + } + + FBApplicationInfo *appInfo = app; + if (appInfo == nil) { + return NO; + } + + [info setObject:(NSObject*)app.bundleIdentifier forKey:@"APP_ID"]; + [info setObject:(NSString*)[app.bundleContainerURL path] forKey:@"BUNDLE_PATH"]; + [info setObject:(NSString*)[app.bundleURL path] forKey:@"APP_PATH"]; + [info setObject:(NSString*)[app.dataContainerURL path] forKey:@"DATA_PATH"]; + [info setObject:(NSString*)app.bundleVersion forKey:@"VERSION"]; + [info setObject:(NSString*)app.shortVersionString forKey:@"SHORT_VERSION"]; + [info setObject:(NSString*)app.localizedName forKey:@"NAME"]; + [info setObject:(NSString*)app.localizedShortName forKey:@"DISPLAY_NAME"]; + [info setObject:(NSString*)appInfo.bundleExecutable forKey:@"EXECUTABLE"]; + + return YES; +} + - (void)setupRoutes { [self.http get:@"/status" withBlock:^(RouteRequest *request, RouteResponse *response) { - [response respondWithData:[NSJSONSerialization dataWithJSONObject:statusDict + /*[response respondWithData:[NSJSONSerialization dataWithJSONObject:statusDict options:0 - error:nil]]; + error:nil]];*/ //TODO + [self sendResponse:response dict:statusDict]; }]; [self.http get:@"/applications" withBlock:^(RouteRequest *request, RouteResponse *response) { NSDictionary *responseDict = [SBSTSpringBoardManager applicationInfo]; - [response respondWithData:[NSJSONSerialization dataWithJSONObject:responseDict + /*[response respondWithData:[NSJSONSerialization dataWithJSONObject:responseDict options:0 - error:nil]]; + error:nil]];*/ + [self sendResponse:response dict:responseDict]; }]; [self.http post:@"/install/appstore" withBlock:^(RouteRequest *request, RouteResponse *response) { @@ -177,10 +255,11 @@ - (void)setupRoutes { } - [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; + /* [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; [response respondWithData:[NSJSONSerialization dataWithJSONObject:responseDict options:0 - error:nil]]; + error:nil]]; */ + [self sendResponse:response dict:responseDict]; }]; [self.http post:@"/install/cydia" withBlock:^(RouteRequest *request, RouteResponse *response) { @@ -218,10 +297,11 @@ - (void)setupRoutes { responseDict[RESPONSE_CODE] = HTTP_CODE_LOCKED; } } - [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; + /* [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; [response respondWithData:[NSJSONSerialization dataWithJSONObject:responseDict options:0 - error:nil]]; + error:nil]]; */ + [self sendResponse:response dict:responseDict]; }]; @@ -246,10 +326,11 @@ - (void)setupRoutes { responseDict[RESPONSE_MESSAGE] = @"A task is already running"; } } - [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; + /* [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; [response respondWithData:[NSJSONSerialization dataWithJSONObject:responseDict options:0 - error:nil]]; + error:nil]]; */ + [self sendResponse:response dict:responseDict]; }]; @@ -285,10 +366,11 @@ - (void)setupRoutes { responseDict[RESPONSE_MESSAGE] = @"A task is already running"; } } - [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; + /* [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; [response respondWithData:[NSJSONSerialization dataWithJSONObject:responseDict options:0 - error:nil]]; + error:nil]]; */ + [self sendResponse:response dict:responseDict]; }]; @@ -329,10 +411,11 @@ - (void)setupRoutes { } } } - [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; + /* [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; [response respondWithData:[NSJSONSerialization dataWithJSONObject:responseDict options:0 - error:nil]]; + error:nil]]; */ + [self sendResponse:response dict:responseDict]; }]; @@ -345,6 +428,85 @@ - (void)setupRoutes { [response setStatusCode:[responseDict[RESPONSE_CODE] integerValue]]; }]; + [self.http get:@"/archive/:bundleId" withBlock:^(RouteRequest *request, RouteResponse *response) { + NSMutableDictionary *responseDict = [self _defaultResponseDict]; + + NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:9]; + + NSString *bundleId = [request param:@"bundleId"];; + if ([bundleId length] == 0) { + responseDict[RESPONSE_CODE] = HTTP_CODE_BAD_REQUEST; + responseDict[RESPONSE_MESSAGE] = @"bundleId missing"; + [self sendResponse:response dict:responseDict]; + return; + } + + if ([self getApplicationInfo:info bundleId:bundleId] == NO) { + responseDict[RESPONSE_CODE] = HTTP_CODE_BAD_REQUEST; + responseDict[RESPONSE_MESSAGE] = @"Cannot get app info"; + [self sendResponse:response dict:responseDict]; + return; + } + + if (info[@"BUNDLE_PATH"]) { + NSString *cmd = [NSString stringWithFormat:@"%@; %@; %@; cp -r %@/*.app/ Payload/; cp %@/iTunes* .; %@; %@; %@%@.ipa", + @"mkdir /tmp/apparchive", + @"cd /tmp/apparchive", + @"mkdir Payload", + info[@"BUNDLE_PATH"], + info[@"BUNDLE_PATH"], + @"zip -r tmp Payload/ iTunes*", + @"rm -R Payload/ iTunes*", + @"mv tmp.zip /tmp/apparchive/", + info[@"APP_ID"]]; + NSString *cmd2 = [NSString stringWithFormat:@"cd /var/root; DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib '%@/%@'", info[@"APP_PATH"], info[@"EXECUTABLE"]]; + [SBSTShellExecutor runCommand:cmd2]; + DDLogVerbose(@"CMD: %@", cmd); + NSDictionary *result = [SBSTShellExecutor runCommand:cmd]; + DDLogVerbose(@"Result: %@", result); + responseDict[@"file"] = [NSString stringWithFormat:@"/tmp/apparchive/%@.ipa", info[@"APP_ID"]]; + + [response setHeader:@"Content-Type" value:@"application/json"]; + } else { + responseDict[RESPONSE_CODE] = HTTP_CODE_BAD_REQUEST; + responseDict[RESPONSE_MESSAGE] = @"Bundle not found"; + } + [self sendResponse:response dict:responseDict]; + }]; + + [self.http get:@"/archive/decrypted/:bundleId" withBlock:^(RouteRequest* request, RouteResponse* response) { + NSMutableDictionary *responseDict = [self _defaultResponseDict]; + + NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:9]; + + NSString *bundleId = [request param:@"bundleId"]; + if ([bundleId length] == 0) { + responseDict[RESPONSE_CODE] = HTTP_CODE_BAD_REQUEST; + responseDict[RESPONSE_MESSAGE] = @"bundleId missing"; + [self sendResponse:response dict:responseDict]; + return; + } + + if ([self getApplicationInfo:info bundleId:bundleId] == NO) { + responseDict[RESPONSE_CODE] = HTTP_CODE_BAD_REQUEST; + responseDict[RESPONSE_MESSAGE] = @"Cannot get app info"; + [self sendResponse:response dict:responseDict]; + return; + } + + NSString *cmd = [NSString stringWithFormat:@"%@; sudo Clutch2 -d %2$@; %@; mv /var/mobile/Documents/Dumped/%2$@* /tmp/apparchive/%2$@.ipa", + @"mkdir /tmp/apparchive", + bundleId, + @"sudo chown mobile -R /var/mobile/Documents/Dumped"]; + DDLogVerbose(@"CMD: %@", cmd); + system([cmd UTF8String]); + + responseDict[@"file"] = [NSString stringWithFormat:@"/tmp/apparchive/%@.ipa", info[@"APP_ID"]]; + + [response setHeader:@"Content-Type" value:@"application/json"]; + [self sendResponse:response dict:responseDict]; + }]; + } diff --git a/SBServerTweak/layout/DEBIAN/control b/SBServerTweak/layout/DEBIAN/control index 9bc0727..33cecc3 100644 --- a/SBServerTweak/layout/DEBIAN/control +++ b/SBServerTweak/layout/DEBIAN/control @@ -1,6 +1,6 @@ Package: de.fau.cs.dios.pilot.sbservertweak Name: DiOS Controller -Depends: mobilesubstrate, cycript, apt, sudo +Depends: mobilesubstrate, cycript, apt, sudo, zip, wget Version: 2.0.0 Architecture: iphoneos-arm Description: DiOS Automator SpringBoard Tweak. Allows app installation and execution using a HTTP REST API. diff --git a/SBServerTweak/layout/DEBIAN/postinst b/SBServerTweak/layout/DEBIAN/postinst index 853683e..f61ac0b 100755 --- a/SBServerTweak/layout/DEBIAN/postinst +++ b/SBServerTweak/layout/DEBIAN/postinst @@ -1,10 +1,10 @@ #!/bin/sh -SUDOERS_LINE="mobile ALL=(ALL) NOPASSWD:/usr/bin/apt-get" +SUDOERS_LINE="mobile ALL=(ALL) NOPASSWD:/usr/bin/apt-get,/usr/bin/Clutch2,/bin/chown -R mobile /var/mobile/Documents/Dumped/" SUDOERS_FILE="/etc/sudoers" cat "$SUDOERS_FILE" | grep "$SUDOERS_LINE" > /dev/null if [ $? -eq 1 ] then echo "$SUDOERS_LINE" >>/etc/sudoers -fi +fi \ No newline at end of file