From 7870c6a5794b1edf230e0743e1496939c9404d2e Mon Sep 17 00:00:00 2001 From: ZonD80 Date: Tue, 26 May 2020 14:39:58 +0300 Subject: [PATCH] Even more logs & fix crash when copying itself --- Entitlements.xml | 8 +- duppy2.xcodeproj/project.pbxproj | 4 +- .../UserInterfaceState.xcuserstate | Bin 38963 -> 39300 bytes duppy2/ViewController.swift | 113 ++++++++++-------- 4 files changed, 66 insertions(+), 59 deletions(-) diff --git a/Entitlements.xml b/Entitlements.xml index 26569ed..c5eca5a 100644 --- a/Entitlements.xml +++ b/Entitlements.xml @@ -2,15 +2,11 @@ - platform-application - - com.apple.private.security.no-container - com.apple.private.security.no-sandbox com.apple.developer.team-identifier - FUCKAPPLE1 + 36YA66W8E9 application-identifier - FUCKAPPLE1.zond80.duppy2 + 36YA66W8E9.zond80.duppy2 diff --git a/duppy2.xcodeproj/project.pbxproj b/duppy2.xcodeproj/project.pbxproj index fa9bb67..edc2306 100644 --- a/duppy2.xcodeproj/project.pbxproj +++ b/duppy2.xcodeproj/project.pbxproj @@ -377,7 +377,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.2; PRODUCT_BUNDLE_IDENTIFIER = zond80.duppy2; PRODUCT_NAME = Duppy; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -406,7 +406,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.2; PRODUCT_BUNDLE_IDENTIFIER = zond80.duppy2; PRODUCT_NAME = Duppy; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/duppy2.xcodeproj/project.xcworkspace/xcuserdata/zond80.xcuserdatad/UserInterfaceState.xcuserstate b/duppy2.xcodeproj/project.xcworkspace/xcuserdata/zond80.xcuserdatad/UserInterfaceState.xcuserstate index dd3d90370cd486ef06ce83389fa7a537894857e3..cf79bde9a671463c9e0ad192e860f611b85eba3a 100644 GIT binary patch delta 15294 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 MckbT)GiCb!1JA66DF6Tf delta 14916 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 NSString { let task = NSTask.init() task?.setLaunchPath(launchPath) @@ -82,13 +88,13 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele let appName = app.name! as String; let appPath = app.path! as String; - print("cloning \(appName) at path \(appPath)") - print("clearing temp dir: "+localPath+"/work_dir/Payload") + self.log("cloning \(appName) at path \(appPath)") + self.log("clearing temp dir: "+localPath+"/work_dir/Payload") do { try FileManager.default.removeItem(atPath: localPath+"/work_dir/Payload") } catch { - print("unable to remove temp dir \(error) we can give up on it"); + self.log("unable to remove temp dir \(error) we can give up on it"); //self.isAppCloningNow = false; //self.setStatusText(text: "ERROR: unable to remove temp dir") //return; @@ -96,21 +102,20 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele do { try FileManager.default.createDirectory(atPath: localPath+"/work_dir/Payload", withIntermediateDirectories: true, attributes: nil) } catch { - print("unable to create temp dir \(error)"); - NSLog("unable to create temp dir \(error)"); + self.log("unable to create temp dir \(error)"); self.isAppCloningNow = false; - self.setStatusText(text: "ERROR: unable to create temp dir") + self.setStatusText(text: "ERROR: unable to create temp dir \(localPath)/work_dir/Payload") return; } - print("Copying app data") + self.log("Copying app data") self.setStatusText(text: "Copying original app data"); do { try FileManager.default.copyItem(at: URL(string: "file://"+appPath.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)!, to: URL(string: "file://"+localPath+"/work_dir/Payload/\(appName)".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)!) } catch { - print("unable to copy dir \(error)"); + self.log("unable to copy dir \(error)"); self.setStatusText(text: "ERROR: unable to remove temp dir") self.isAppCloningNow = false; return; @@ -118,24 +123,31 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele if separateBinary { do { - print("using separate binary!"); + self.log("using separate binary!"); let destinationBinaryURL = URL(string: "file://"+localPath+"/work_dir/Payload/\(appName)/"+app.mainBundleExecutable!.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!); try FileManager.default.removeItem(at: destinationBinaryURL!); try FileManager.default.copyItem(at: URL(string: "file:///var/mobile/Documents/CrackerXI/"+app.mainBundleExecutable!.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)!, to: destinationBinaryURL!) } catch { - print("unable to copy separate binary \(error)"); + self.log("unable to copy separate binary \(error)"); self.setStatusText(text: "ERROR: unable to copy separate binary") self.isAppCloningNow = false; return; } } - print("App data copied") + self.log("App data copied") + + do { // removing SC_info, as it is not under FairPlay + try FileManager.default.removeItem(at: URL(string: "file://"+localPath+"/work_dir/Payload/\(appName)/SC_Info")!); + } + catch { + self.log("unable to remove SC_Info dir \(error), but we can give up"); + } self.setStatusText(text: "Making some magic"); - print("Searching for PLISTS and converting them to XML formats") + self.log("Searching for PLISTS and converting them to XML formats") let url = URL(fileURLWithPath: localPath+"/work_dir/Payload") @@ -144,14 +156,15 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele var newBundleId:String=""; do { - let mainInfoPlistEntities = try PropertyListSerialization.propertyList(from: Data(contentsOf: mainInfoPlistURL), options: [], format: nil) as! NSMutableDictionary + let mainInfoPlistEntitiesDict = try PropertyListSerialization.propertyList(from: Data(contentsOf: mainInfoPlistURL), options: [], format: nil) as! NSDictionary + let mainInfoPlistEntities:NSMutableDictionary = mainInfoPlistEntitiesDict.mutableCopy() as! NSMutableDictionary let mainBundleId = mainInfoPlistEntities["CFBundleIdentifier"] as! String - print("Main bundle id is \(mainBundleId)") + self.log("Main bundle id is \(mainBundleId)") newBundleId = "duppy."+self.randomString(length: 5)+"."+mainBundleId; - print("Replacement bundle id is \(newBundleId)") + self.log("Replacement bundle id is \(newBundleId)") mainInfoPlistEntities["CFBundleDisplayName"] = app.mainBundleName; @@ -159,7 +172,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele } catch { - print("unable to write to info plist") + self.log("unable to write to info plist") self.setStatusText(text: "Unable to write to Info.plist") return; } @@ -183,28 +196,28 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele var executableName:String = ""; if plistEntities[fileURL.absoluteString]!["CFBundleExecutable"] != nil { executableName = plistEntities[fileURL.absoluteString]!["CFBundleExecutable"] as! String - print("found executable \(executableName) in plist at location \(fileURL.absoluteString), changing entitlements") + self.log("found executable \(executableName) in plist at location \(fileURL.absoluteString), changing entitlements") let executablePath = fileURL.absoluteString.replacingOccurrences(of: "Info.plist", with: executableName).replacingOccurrences(of: "file://", with: "") //print ("command: /usr/bin/ldid -e '\(executablePath)'") let existingEntitlements = self.task(launchPath: "/usr/bin/ldid",arguments: "-e",executablePath); - print ("existing entitlements are: \(existingEntitlements)"); + self.log("existing entitlements are: \(existingEntitlements)"); if (existingEntitlements.contains(mainBundleId)) { var fixedEntitlements = existingEntitlements.replacingOccurrences(of: mainBundleId, with: newBundleId) - print ("FIXED entitlements are: \(fixedEntitlements)"); + self.log("FIXED entitlements are: \(fixedEntitlements)"); try fixedEntitlements.write(toFile: localPath+"/work_dir/Entitlements.xml", atomically: true, encoding: .utf8) let entitlementWriteResult = self.task(launchPath: "/usr/bin/ldid",arguments: "-S"+localPath+"/work_dir/Entitlements.xml",executablePath); - print ("entitlement write result: \(entitlementWriteResult)"); + self.log("entitlement write result: \(entitlementWriteResult)"); } //print ("/usr/bin/ldid -K"+self.selfAppPath+"/Certificates.p12 "+executablePath); //let signResult = self.task(launchPath: "/usr/bin/ldid",arguments: "-K"+self.selfAppPath+"/Certificates.p12",executablePath); //print ("sign result: \(signResult)"); } else { - print("no executables in plist at location \(fileURL.absoluteString)") + self.log("no executables in plist at location \(fileURL.absoluteString)") } } catch { - print("error, unable to parse Info.plist"); + self.log("error, unable to parse Info.plist"); } let plist = PlistConverter(binaryData: plistData); @@ -216,29 +229,29 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele try fixedXML?.write(to: fileURL, atomically: true, encoding: .utf8); } } - } catch { print(error, fileURL); self.isAppCloningNow = false; } + } catch { self.log("\(error), \(fileURL)"); self.isAppCloningNow = false; } } - //print(files) + //self.log(files) } } catch { - print("Error parsing main Info.plist") + self.log("Error parsing main Info.plist \(error)") self.setStatusText(text: "ERROR: unable to parse Info.plist") self.isAppCloningNow = false; return; } - print("modified plists written zipping") + self.log("modified plists written zipping") do { let filePath = URL(string: localPath+"/work_dir/Payload") let zipFilePath = self.localPathURL.appendingPathComponent("archive.ipa") try Zip.zipFiles(paths: [filePath! as URL], zipFilePath: zipFilePath, password: nil, progress: { (progress) -> () in - print(progress) + self.log("\(progress)"); let percents = round(progress*100*100)/100; self.setStatusText(text: "Archiving "+percents.description+"%"); }) //Zip - print ("zipped!"); + self.log("zipped!"); @@ -247,7 +260,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele try FileManager.default.removeItem(atPath: localPath+"/work_dir/Payload") } catch { - print("unable to remove temp dir \(error) we can give up on it"); + self.log("unable to remove temp dir \(error) we can give up on it"); //self.isAppCloningNow = false; //self.setStatusText(text: "ERROR: unable to remove temp dir") //return; @@ -257,7 +270,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele do { try FileManager.default.removeItem(at: URL(string: "file:///var/mobile/Documents/CrackerXI/"+app.mainBundleExecutable!.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)!) }catch { - print("unable to remove separate binary we can give up on it \(error)"); + self.log("unable to remove separate binary we can give up on it \(error)"); //self.isAppCloningNow = false; //self.setStatusText(text: "ERROR: unable to remove temp dir") //return; @@ -272,7 +285,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele DispatchQueue.main.async { let appInstallUrl = "itms-services://?action=download-manifest&url=https%3A%2F%2Fduppy.app%2Fdownload.php%3Fname%3D"+newBundleId; - print("app install URL is \(appInstallUrl)") + self.log("app install URL is \(appInstallUrl)") if let url = URL(string:appInstallUrl) { UIApplication.shared.open(url) } @@ -281,7 +294,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele self.isAppCloningNow = false; } catch { - print("Something went wrong") + self.log("Something went wrong") self.isAppCloningNow = false; self.setStatusText(text: "ERROR: something went wrong") return @@ -292,7 +305,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let appName = appModel[indexPath.row].name! as String - print("selected \(appName)") + self.log("selected \(appName)") var refreshAlert: UIAlertController; @@ -300,7 +313,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele refreshAlert = UIAlertController(title: "Not now", message: "Another app cloning is in progress", preferredStyle: UIAlertController.Style.alert) refreshAlert.addAction(UIAlertAction(title: "Okay", style: .cancel, handler: { (action: UIAlertAction!) in - print("Handle Cancel Logic here") + self.log("Handle Cancel Logic here") })) } else { @@ -312,7 +325,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele refreshAlert = UIAlertController(title: "DRM-protected", message: "This app is iTunes DRM protected and no decrypted binary found in CrackerXI folder\nDump app binary (select \"YES, binary only\") with CrackerXI from https://cydia.iphonecake.com/ to clone this app", preferredStyle: UIAlertController.Style.alert) refreshAlert.addAction(UIAlertAction(title: "Okay", style: .cancel, handler: { (action: UIAlertAction!) in - print("Handle Cancel Logic here") + self.log("Handle Cancel Logic here") })) } else { refreshAlert = UIAlertController(title: "Clone \(appName) with DRM-free binary", message: "Please enter desired app name or leave blank to use original one. Don't worry, we will clear DRM-free binary once finished", preferredStyle: UIAlertController.Style.alert) @@ -330,7 +343,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele })) refreshAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action: UIAlertAction!) in - print("Handle Cancel Logic here") + self.log("Handle Cancel Logic here") })) } } else { @@ -349,7 +362,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele })) refreshAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action: UIAlertAction!) in - print("Handle Cancel Logic here") + self.log("Handle Cancel Logic here") })) } } @@ -376,17 +389,15 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele super.viewDidLoad() - print("app path is \(self.selfAppPath)") - /*let result = task(launchPath: "/usr/bin/ldid"); - - print(result);*/ + self.log("app path is \(self.selfAppPath)") + self.log("documents path URL is \(self.localPathURL)"); do { let appDirs = try FileManager.default.contentsOfDirectory(atPath: self.appsPath) - //print("apps dirs are \(appDirs)") + //self.log("apps dirs are \(appDirs)") appDirs.forEach { appUUIDDir in do { @@ -396,7 +407,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele appDirContents.forEach { appDir in if appDir.hasSuffix(".app") { let finalAppDir = "\(appsPath)/\(appUUIDDir)/\(appDir)"; - //print("found final app dir \(finalAppDir)"); + //self.log("found final app dir \(finalAppDir)"); apps[appDir] = finalAppDir; let mainInfoPlistURL = URL(fileURLWithPath: "\(finalAppDir)/Info.plist"); @@ -409,7 +420,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele do { let mainInfoPlistEntities = try PropertyListSerialization.propertyList(from: Data(contentsOf: mainInfoPlistURL), options: [], format: nil) as! NSDictionary - print("display name is :\(mainInfoPlistEntities["CFBundleDisplayName"])"); + self.log("display name is :\(mainInfoPlistEntities["CFBundleDisplayName"])"); mainBundleId = mainInfoPlistEntities["CFBundleIdentifier"] as! String if (mainBundleId.hasPrefix("com.apple.")) { @@ -423,7 +434,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele mainBundleExecutable = mainInfoPlistEntities["CFBundleExecutable"] as! String } } catch { - print("Unable to get app name") + self.log("Unable to get app name") } var isDRM = false; if (FileManager.default.fileExists(atPath: "\(finalAppDir)/SC_Info/Manifest.plist")) { @@ -437,7 +448,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele statusText.text = "Apps loaded\nTap on app to clone it"; } catch { - print("unable to get contents of app dir \(error)"); + self.log("unable to get contents of app dir \(error)"); } } @@ -446,7 +457,7 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele let localPath = localPathURL.absoluteString.replacingOccurrences(of: "file://", with: "") - print ("local path is \(localPath)"); + self.log("local path is \(localPath)"); DispatchQueue.global(qos: .background).async { let server = HttpServer() @@ -457,18 +468,18 @@ class ViewController: UIViewController , UITableViewDataSource , UITableViewDele //server["/test"] = do { try server.start(44443, forceIPv4: true) - print("Server has started ( port = \(try server.port()) ). Try to connect now...") - print("\(server.state)"); + self.log("Server has started ( port = \(try server.port()) ). Try to connect now...") + self.log("\(server.state)"); //semaphore.wait() } catch { - print("Server start error: \(error)") + self.log("Server start error: \(error)") //semaphore.signal() } } } catch { - print("unable to get app dirs \(error)"); + self.log("unable to get app dirs \(error)"); self.setStatusText(text: "Looks like your device is not jailbroken") }