mirror of
https://github.com/NohamR/TrollDecrypt-tvOS.git
synced 2026-07-11 22:41:37 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
badb4f4784 | ||
|
|
05b73595d8 | ||
|
|
869e625770 | ||
|
|
5af58eda88 | ||
|
|
3d40efe291 | ||
|
|
26e6ed4c8d | ||
|
|
8c96736b94 | ||
|
|
491e53072f | ||
|
|
7449682883 |
2
Makefile
2
Makefile
@@ -1,4 +1,4 @@
|
|||||||
TARGET := appletv:clang:16.4:14.0
|
TARGET := appletv:clang:26.2:14.0
|
||||||
INSTALL_TARGET_PROCESSES = TrollDecrypt
|
INSTALL_TARGET_PROCESSES = TrollDecrypt
|
||||||
|
|
||||||
GO_EASY_ON_ME = 1
|
GO_EASY_ON_ME = 1
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# TrollDecrypt
|
# TrollDecrypt
|
||||||
iOS IPA Decrypter for TrollStore
|
tvOS IPA Decrypter for TrollStore
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
1. Download and install TrollDecrypt from [here](https://github.com/donato-fiore/TrollDecrypt/releases)
|
1. Download and install TrollDecrypt from [here](https://github.com/NohamR/TrollDecrypt-tvOS/releases)
|
||||||
2. Choose app you want to decrypt.
|
2. Choose app you want to decrypt.
|
||||||
3. Once finished decrypting, you can get the `.ipa` file from inside the app.
|
3. Once finished decrypting, you can get the `.ipa` file from inside the app.
|
||||||
|
|
||||||
@@ -10,12 +10,14 @@ iOS IPA Decrypter for TrollStore
|
|||||||
1. Install [theos](https://theos.dev/docs/installation)
|
1. Install [theos](https://theos.dev/docs/installation)
|
||||||
2. Run the commands below
|
2. Run the commands below
|
||||||
```
|
```
|
||||||
git clone https://github.com/donato-fiore/TrollDecrypt.git
|
git clone https://github.com/NohamR/TrollDecrypt-tvOS.git
|
||||||
cd TrollDecrypt
|
cd TrollDecrypt
|
||||||
make package
|
make package
|
||||||
```
|
```
|
||||||
|
|
||||||
## Credits / Thanks
|
## Credits / Thanks
|
||||||
|
- [TrollDecrypt-tvOS](https://github.com/straight-tamago/TrollDecrypt-tvOS) by straight-tamago for the original tvOS version of TrollDecrypt
|
||||||
|
- [TrollDecrypt](https://github.com/donato-fiore/TrollDecrypt) by donato-fiore for the original version of TrollDecrypt
|
||||||
- [TrollDecryptor](https://github.com/wh1te4ever/TrollDecryptor) by wh1te4ever
|
- [TrollDecryptor](https://github.com/wh1te4ever/TrollDecryptor) by wh1te4ever
|
||||||
- [dumpdecrypted](https://github.com/stefanesser/dumpdecrypted) by Stefan Esser
|
- [dumpdecrypted](https://github.com/stefanesser/dumpdecrypted) by Stefan Esser
|
||||||
- [bfdecrypt](https://github.com/BishopFox/bfdecrypt) by BishopFox
|
- [bfdecrypt](https://github.com/BishopFox/bfdecrypt) by BishopFox
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<string>App Icon</string>
|
<string>App Icon</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.fiore.trolldecrypt</string>
|
<string>com.nohamr.trolldecrypt</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.1</string>
|
<string>1.4</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
|
|||||||
@@ -12,6 +12,6 @@
|
|||||||
|
|
||||||
- (id)initWithPathToBinary:(NSString *)pathToBinary appName:(NSString *)appName appVersion:(NSString *)appVersion;
|
- (id)initWithPathToBinary:(NSString *)pathToBinary appName:(NSString *)appName appVersion:(NSString *)appVersion;
|
||||||
- (void)createIPAFile:(pid_t)pid;
|
- (void)createIPAFile:(pid_t)pid;
|
||||||
- (BOOL)dumpDecryptedImage:(const struct mach_header *)image_mh fileName:(const char *)encryptedImageFilenameStr image:(int)imageNum task:(vm_map_t)targetTask;
|
- (BOOL)dumpDecryptedImage:(vm_address_t)imageAddress fileName:(const char *)encryptedImageFilenameStr image:(int)imageNum task:(vm_map_t)targetTask;
|
||||||
- (NSString *)IPAPath;
|
- (NSString *)IPAPath;
|
||||||
@end
|
@end
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <spawn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
@@ -357,9 +358,9 @@ int find_off_cryptid(const char *filePath) {
|
|||||||
[self makeDirectories:encryptedImageFilenameStr];
|
[self makeDirectories:encryptedImageFilenameStr];
|
||||||
|
|
||||||
//0x1518
|
//0x1518
|
||||||
uint32_t aslr_slide = 0;
|
uint64_t aslr_slide = 0;
|
||||||
get_image_size(imageAddress, targetTask, &aslr_slide);
|
get_image_size(imageAddress, targetTask, &aslr_slide);
|
||||||
NSLog(@"[trolldecrypt] aslr_slide= 0x%x", aslr_slide);
|
NSLog(@"[trolldecrypt] aslr_slide= 0x%llx", aslr_slide);
|
||||||
|
|
||||||
off_cryptid=find_off_cryptid(encryptedImageFilenameStr);
|
off_cryptid=find_off_cryptid(encryptedImageFilenameStr);
|
||||||
|
|
||||||
@@ -504,14 +505,14 @@ int find_off_cryptid(const char *filePath) {
|
|||||||
if (task_for_pid(mach_task_self(), pid, &targetTask))
|
if (task_for_pid(mach_task_self(), pid, &targetTask))
|
||||||
{
|
{
|
||||||
NSLog(@"[trolldecrypt] Can't execute task_for_pid! Do you have the right permissions/entitlements?\n");
|
NSLog(@"[trolldecrypt] Can't execute task_for_pid! Do you have the right permissions/entitlements?\n");
|
||||||
exit(1);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//numberOfImages
|
//numberOfImages
|
||||||
struct task_dyld_info dyld_info;
|
struct task_dyld_info dyld_info;
|
||||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
|
||||||
if(task_info(targetTask, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) != KERN_SUCCESS) exit(1);
|
if(task_info(targetTask, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) != KERN_SUCCESS) return;
|
||||||
|
|
||||||
mach_msg_type_number_t size = sizeof(struct dyld_all_image_infos);
|
mach_msg_type_number_t size = sizeof(struct dyld_all_image_infos);
|
||||||
uint8_t* data = readProcessMemory(targetTask, dyld_info.all_image_info_addr, &size);
|
uint8_t* data = readProcessMemory(targetTask, dyld_info.all_image_info_addr, &size);
|
||||||
@@ -524,6 +525,9 @@ int find_off_cryptid(const char *filePath) {
|
|||||||
uint32_t numberOfImages = infos->infoArrayCount;
|
uint32_t numberOfImages = infos->infoArrayCount;
|
||||||
mach_vm_address_t imageAddress = 0;
|
mach_vm_address_t imageAddress = 0;
|
||||||
const char *appPath = [[self appPath] UTF8String];
|
const char *appPath = [[self appPath] UTF8String];
|
||||||
|
if(strstr(appPath, "/private") == appPath) {
|
||||||
|
appPath += 8;
|
||||||
|
}
|
||||||
|
|
||||||
NSLog(@"[trolldecrypt] There are %d images mapped.", numberOfImages);
|
NSLog(@"[trolldecrypt] There are %d images mapped.", numberOfImages);
|
||||||
|
|
||||||
@@ -532,8 +536,8 @@ int find_off_cryptid(const char *filePath) {
|
|||||||
mach_msg_type_number_t size3 = PATH_MAX;
|
mach_msg_type_number_t size3 = PATH_MAX;
|
||||||
uint8_t *fpath_addr = readProcessMemory(targetTask, (mach_vm_address_t) info[i].imageFilePath, &size3);
|
uint8_t *fpath_addr = readProcessMemory(targetTask, (mach_vm_address_t) info[i].imageFilePath, &size3);
|
||||||
|
|
||||||
imageAddress = (struct mach_header *)info[i].imageLoadAddress;
|
imageAddress = (mach_vm_address_t)info[i].imageLoadAddress;
|
||||||
const char *imageName = fpath_addr;
|
const char *imageName = (const char *)fpath_addr;
|
||||||
|
|
||||||
if(!imageName || !imageAddress)
|
if(!imageName || !imageAddress)
|
||||||
continue;
|
continue;
|
||||||
@@ -553,7 +557,7 @@ int find_off_cryptid(const char *filePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
-(NSString *)IPAPath {
|
-(NSString *)IPAPath {
|
||||||
return [NSString stringWithFormat:@"%@/%@_%@_decrypted.ipa", [self docPath], self.appName, self.appVersion];
|
return [NSString stringWithFormat:@"%@/%@_%@_decrypted.tipa", [self docPath], self.appName, self.appVersion];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) createIPAFile:(pid_t)pid {
|
-(void) createIPAFile:(pid_t)pid {
|
||||||
@@ -583,6 +587,108 @@ int find_off_cryptid(const char *filePath) {
|
|||||||
// Replace encrypted binaries with decrypted versions
|
// Replace encrypted binaries with decrypted versions
|
||||||
NSLog(@"[trolldecrypt] ======== START DECRYPTION PROCESS ========");
|
NSLog(@"[trolldecrypt] ======== START DECRYPTION PROCESS ========");
|
||||||
[self dumpDecrypted:pid];
|
[self dumpDecrypted:pid];
|
||||||
|
|
||||||
|
// Find embedded app extensions (.appex) and decrypt them
|
||||||
|
NSLog(@"[trolldecrypt] ======== START APP EXTENSION DECRYPTION ========");
|
||||||
|
NSString *pluginsPath = [appDir stringByAppendingPathComponent:@"PlugIns"];
|
||||||
|
NSLog(@"[trolldecrypt] Looking for app extensions in: %@", pluginsPath);
|
||||||
|
if ([fm fileExistsAtPath:pluginsPath]) {
|
||||||
|
NSArray *plugins = [fm contentsOfDirectoryAtPath:pluginsPath error:nil];
|
||||||
|
for (NSString *plugin in plugins) {
|
||||||
|
if ([plugin hasSuffix:@".appex"]) {
|
||||||
|
NSString *appexPath = [pluginsPath stringByAppendingPathComponent:plugin];
|
||||||
|
NSString *executableName = [plugin stringByDeletingPathExtension];
|
||||||
|
NSString *executablePath = [appexPath stringByAppendingPathComponent:executableName];
|
||||||
|
|
||||||
|
if ([fm fileExistsAtPath:executablePath]) {
|
||||||
|
NSLog(@"[trolldecrypt] Found app extension: %@", executablePath);
|
||||||
|
pid_t appex_pid = -1;
|
||||||
|
|
||||||
|
void *handle = dlopen("/usr/lib/libSystem.dylib", RTLD_NOW);
|
||||||
|
int (*my_posix_spawnattr_init)(posix_spawnattr_t *) = (int (*)(posix_spawnattr_t *))dlsym(handle, "posix_spawnattr_init");
|
||||||
|
int (*my_posix_spawnattr_setflags)(posix_spawnattr_t *, short) = (int (*)(posix_spawnattr_t *, short))dlsym(handle, "posix_spawnattr_setflags");
|
||||||
|
int (*my_posix_spawnattr_destroy)(posix_spawnattr_t *) = (int (*)(posix_spawnattr_t *))dlsym(handle, "posix_spawnattr_destroy");
|
||||||
|
int (*my_posix_spawn)(pid_t *, const char *, void *, const posix_spawnattr_t *, char *const *, char *const *) = (int (*)(pid_t *, const char *, void *, const posix_spawnattr_t *, char *const *, char *const *))dlsym(handle, "posix_spawn");
|
||||||
|
|
||||||
|
if (my_posix_spawn && my_posix_spawnattr_init && my_posix_spawnattr_setflags) {
|
||||||
|
posix_spawnattr_t attr;
|
||||||
|
my_posix_spawnattr_init(&attr);
|
||||||
|
my_posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
|
||||||
|
|
||||||
|
const char *argv[] = {[executablePath UTF8String], NULL};
|
||||||
|
extern char **environ;
|
||||||
|
int envCount = 0;
|
||||||
|
while (environ[envCount] != NULL) envCount++;
|
||||||
|
char **new_environ = malloc((envCount + 2) * sizeof(char *));
|
||||||
|
for (int i = 0; i < envCount; i++) {
|
||||||
|
new_environ[i] = environ[i];
|
||||||
|
}
|
||||||
|
new_environ[envCount] = "XPC_SERVICE_NAME=appex_decryption";
|
||||||
|
new_environ[envCount + 1] = NULL;
|
||||||
|
|
||||||
|
int ret = my_posix_spawn(&appex_pid, [executablePath UTF8String], NULL, &attr, (char *const *)argv, new_environ);
|
||||||
|
free(new_environ);
|
||||||
|
if(my_posix_spawnattr_destroy) my_posix_spawnattr_destroy(&attr);
|
||||||
|
|
||||||
|
if (ret == 0 && appex_pid > 0) {
|
||||||
|
NSLog(@"[trolldecrypt] Spawned appex with PID %d, waiting for dyld...", appex_pid);
|
||||||
|
|
||||||
|
vm_map_t targetTask = 0;
|
||||||
|
if (task_for_pid(mach_task_self(), appex_pid, &targetTask) == KERN_SUCCESS) {
|
||||||
|
// Resume the suspended process so dyld can map the binaries into memory
|
||||||
|
kill(appex_pid, SIGCONT);
|
||||||
|
|
||||||
|
BOOL dyld_ready = NO;
|
||||||
|
for (int k = 0; k < 500; k++) {
|
||||||
|
struct task_dyld_info dyld_info;
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
|
||||||
|
if (task_info(targetTask, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) == KERN_SUCCESS) {
|
||||||
|
if (dyld_info.all_image_info_addr != 0) {
|
||||||
|
mach_msg_type_number_t size = sizeof(struct dyld_all_image_infos);
|
||||||
|
uint8_t* data = readProcessMemory(targetTask, dyld_info.all_image_info_addr, &size);
|
||||||
|
|
||||||
|
if (data != NULL) {
|
||||||
|
struct dyld_all_image_infos* infos = (struct dyld_all_image_infos *) data;
|
||||||
|
if (infos->infoArrayCount > 0) {
|
||||||
|
// dyld mapped the images! Suspend the process immediately.
|
||||||
|
kill(appex_pid, SIGSTOP);
|
||||||
|
dyld_ready = YES;
|
||||||
|
// Clean up allocated memory by vm_read in readProcessMemory
|
||||||
|
vm_deallocate(mach_task_self(), (vm_address_t)data, size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vm_deallocate(mach_task_self(), (vm_address_t)data, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usleep(1000); // 1ms
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dyld_ready) {
|
||||||
|
NSLog(@"[trolldecrypt] Appex dyld mapping caught successfully, dumping!");
|
||||||
|
[self dumpDecrypted:appex_pid];
|
||||||
|
} else {
|
||||||
|
NSLog(@"[trolldecrypt] Failed to catch dyld mapping in time for appex.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSLog(@"[trolldecrypt] Can't execute task_for_pid on appex_pid %d", appex_pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
kill(appex_pid, SIGKILL);
|
||||||
|
// Wait for the child to exit
|
||||||
|
int status;
|
||||||
|
waitpid(appex_pid, &status, WNOHANG);
|
||||||
|
} else {
|
||||||
|
NSLog(@"[trolldecrypt] Failed to spawn appex (error %d)", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dlclose(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NSLog(@"[trolldecrypt] ======== DECRYPTION COMPLETE ========");
|
NSLog(@"[trolldecrypt] ======== DECRYPTION COMPLETE ========");
|
||||||
|
|
||||||
// ZIP it up
|
// ZIP it up
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#import "TDFileManagerViewController.h"
|
#import "TDFileManagerViewController.h"
|
||||||
#import "TDUtils.h"
|
#import "TDUtils.h"
|
||||||
|
#import "LSApplicationProxy+AltList.h"
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
@implementation TDFileManagerViewController
|
@implementation TDFileManagerViewController
|
||||||
|
|
||||||
@@ -48,12 +50,12 @@
|
|||||||
|
|
||||||
cell.textLabel.text = self.fileList[indexPath.row];
|
cell.textLabel.text = self.fileList[indexPath.row];
|
||||||
cell.detailTextLabel.text = [dateFormatter stringFromDate:date];
|
cell.detailTextLabel.text = [dateFormatter stringFromDate:date];
|
||||||
cell.detailTextLabel.textColor = [UIColor systemGray2Color];
|
cell.detailTextLabel.textColor = [UIColor grayColor];
|
||||||
cell.imageView.image = [UIImage systemImageNamed:@"doc.fill"];
|
cell.imageView.image = [UIImage systemImageNamed:@"doc.fill"];
|
||||||
|
|
||||||
UILabel *label = [[UILabel alloc] init];
|
UILabel *label = [[UILabel alloc] init];
|
||||||
label.text = [NSString stringWithFormat:@"%.2f MB", [fileSize doubleValue] / 1000000.0f];
|
label.text = [NSString stringWithFormat:@"%.2f MB", [fileSize doubleValue] / 1000000.0f];
|
||||||
label.textColor = [UIColor systemGray2Color];
|
label.textColor = [UIColor grayColor];
|
||||||
label.font = [UIFont systemFontOfSize:12.0f];
|
label.font = [UIFont systemFontOfSize:12.0f];
|
||||||
[label sizeToFit];
|
[label sizeToFit];
|
||||||
label.textAlignment = NSTextAlignmentCenter;
|
label.textAlignment = NSTextAlignmentCenter;
|
||||||
@@ -71,6 +73,7 @@
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !TARGET_OS_TV
|
||||||
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete" handler:^(UIContextualAction *action, UIView *sourceView, void (^completionHandler)(BOOL)) {
|
UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete" handler:^(UIContextualAction *action, UIView *sourceView, void (^completionHandler)(BOOL)) {
|
||||||
NSString *file = self.fileList[indexPath.row];
|
NSString *file = self.fileList[indexPath.row];
|
||||||
@@ -82,16 +85,54 @@
|
|||||||
UISwipeActionsConfiguration *swipeActions = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction]];
|
UISwipeActionsConfiguration *swipeActions = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction]];
|
||||||
return swipeActions;
|
return swipeActions;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UIWindow *kw2 = NULL;
|
||||||
|
UIAlertController *doneController2 = NULL;
|
||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
NSString *file = self.fileList[indexPath.row];
|
NSString *file = self.fileList[indexPath.row];
|
||||||
NSString *path = [docPath() stringByAppendingPathComponent:file];
|
NSString *path = [docPath() stringByAppendingPathComponent:file];
|
||||||
NSURL *url = [NSURL fileURLWithPath:path];
|
|
||||||
|
|
||||||
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[url] applicationActivities:nil];
|
doneController2 = [UIAlertController alertControllerWithTitle:file message:[NSString stringWithFormat:@"Location:\n%@", path] preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[self presentViewController:activityViewController animated:YES completion:nil];
|
|
||||||
|
|
||||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Ok", @"Ok") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
|
[kw2 removeFromSuperview];
|
||||||
|
kw2.hidden = YES;
|
||||||
|
}];
|
||||||
|
[doneController2 addAction:okAction];
|
||||||
|
|
||||||
|
UIAlertAction *openAction = [UIAlertAction actionWithTitle:@"Share IPA with Airdrop" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
|
NSString *filePath = path;
|
||||||
|
NSURL *url = [NSURL fileURLWithPath:filePath];
|
||||||
|
|
||||||
|
NSBundle *bundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/Sharing.framework"];
|
||||||
|
[bundle load];
|
||||||
|
|
||||||
|
NSBundle *sharingUI = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/SharingUI.framework"];
|
||||||
|
[sharingUI load];
|
||||||
|
|
||||||
|
id sharingView = [[objc_getClass("SFAirDropSharingViewControllerTV") alloc] initWithSharingItems:@[url]];
|
||||||
|
[self dismissViewControllerAnimated:NO completion:^{
|
||||||
|
[self presentViewController:sharingView animated:YES completion:nil];
|
||||||
|
[sharingView setCompletionHandler:^(NSError *error) {
|
||||||
|
[self dismissViewControllerAnimated:YES completion:nil];
|
||||||
|
}];
|
||||||
|
}];
|
||||||
|
|
||||||
|
[self presentViewController:sharingView animated:true completion:nil];
|
||||||
|
}];
|
||||||
|
[doneController2 addAction:openAction];
|
||||||
|
|
||||||
|
UIAlertAction *deleteFileAction = [UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
|
||||||
|
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
|
||||||
|
[self refresh];
|
||||||
|
[kw2 removeFromSuperview];
|
||||||
|
kw2.hidden = YES;
|
||||||
|
}];
|
||||||
|
[doneController2 addAction:deleteFileAction];
|
||||||
|
|
||||||
|
[self presentViewController:doneController2 animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -9,13 +9,17 @@
|
|||||||
|
|
||||||
self.apps = appList();
|
self.apps = appList();
|
||||||
self.title = @"TrollDecrypt";
|
self.title = @"TrollDecrypt";
|
||||||
|
#if !TARGET_OS_TV
|
||||||
self.navigationController.navigationBar.prefersLargeTitles = YES;
|
self.navigationController.navigationBar.prefersLargeTitles = YES;
|
||||||
|
#endif
|
||||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"info.circle"] style:UIBarButtonItemStylePlain target:self action:@selector(about:)];
|
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"info.circle"] style:UIBarButtonItemStylePlain target:self action:@selector(about:)];
|
||||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"folder"] style:UIBarButtonItemStylePlain target:self action:@selector(openDocs:)];
|
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"folder"] style:UIBarButtonItemStylePlain target:self action:@selector(openDocs:)];
|
||||||
|
|
||||||
|
#if !TARGET_OS_TV
|
||||||
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
|
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
|
||||||
[refreshControl addTarget:self action:@selector(refreshApps:) forControlEvents:UIControlEventValueChanged];
|
[refreshControl addTarget:self action:@selector(refreshApps:) forControlEvents:UIControlEventValueChanged];
|
||||||
self.refreshControl = refreshControl;
|
self.refreshControl = refreshControl;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidAppear:(bool)animated {
|
- (void)viewDidAppear:(bool)animated {
|
||||||
@@ -48,16 +52,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)about:(id)sender {
|
- (void)about:(id)sender {
|
||||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"TrollDecrypt" message:@"by fiore\nIcon by @super.user\nbfdecrypt by @bishopfox\ndumpdecrypted by @i0n1c\nUpdated for TrollStore by @wh1te4ever\nPorting to tvOS by @straight-tamago" preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"TrollDecrypt" message:@"by fiore\nIcon by @super.user\nbfdecrypt by @bishopfox\ndumpdecrypted by @i0n1c\nUpdated for TrollStore by @wh1te4ever\nPorting to tvOS by @straight-tamago\nFixed by NohamR" preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleCancel handler:nil]];
|
[alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleCancel handler:nil]];
|
||||||
[self presentViewController:alert animated:YES completion:nil];
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !TARGET_OS_TV
|
||||||
- (void)refreshApps:(UIRefreshControl *)refreshControl {
|
- (void)refreshApps:(UIRefreshControl *)refreshControl {
|
||||||
self.apps = appList();
|
self.apps = appList();
|
||||||
[self.tableView reloadData];
|
[self.tableView reloadData];
|
||||||
[refreshControl endRefreshing];
|
[refreshControl endRefreshing];
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -43,3 +43,8 @@ NSString *docPath(void);
|
|||||||
void fetchLatestTrollDecryptVersion(void (^completionHandler)(NSString *version));
|
void fetchLatestTrollDecryptVersion(void (^completionHandler)(NSString *version));
|
||||||
void github_fetchLatedVersion(NSString *repo, void (^completionHandler)(NSString *latestVersion));
|
void github_fetchLatedVersion(NSString *repo, void (^completionHandler)(NSString *latestVersion));
|
||||||
NSString *trollDecryptVersion(void);
|
NSString *trollDecryptVersion(void);
|
||||||
|
|
||||||
|
@interface SFAirDropSharingViewControllerTV : UIViewController
|
||||||
|
-(id)initWithSharingItems:(id)arg1;
|
||||||
|
-(void)setCompletionHandler:(void (^)(NSError *error))arg1;
|
||||||
|
@end
|
||||||
32
TDUtils.m
32
TDUtils.m
@@ -3,13 +3,6 @@
|
|||||||
#import "LSApplicationProxy+AltList.h"
|
#import "LSApplicationProxy+AltList.h"
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
@interface SFAirDropSharingViewControllerTV : UIViewController
|
|
||||||
-(id)initWithSharingItems:(id)arg1;
|
|
||||||
-(void)setCompletionHandler:(void (^)(NSError *error))arg1;
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UIWindow *alertWindow = NULL;
|
UIWindow *alertWindow = NULL;
|
||||||
UIWindow *kw = NULL;
|
UIWindow *kw = NULL;
|
||||||
UIViewController *root = NULL;
|
UIViewController *root = NULL;
|
||||||
@@ -210,29 +203,20 @@ void bfinject_rocknroll(pid_t pid, NSString *appName, NSString *version) {
|
|||||||
|
|
||||||
UIAlertAction *openAction = [UIAlertAction actionWithTitle:@"Share IPA with Airdrop" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
UIAlertAction *openAction = [UIAlertAction actionWithTitle:@"Share IPA with Airdrop" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||||
NSString *filePath = [dd IPAPath];
|
NSString *filePath = [dd IPAPath];
|
||||||
NSDictionary* airdropDictionary;
|
NSURL *url = [NSURL fileURLWithPath:filePath];
|
||||||
|
|
||||||
NSBundle *bundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/Sharing.framework"];
|
NSBundle *bundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/Sharing.framework"];
|
||||||
[bundle load];
|
[bundle load];
|
||||||
|
|
||||||
NSString *suf = @"/System/Library/PrivateFrameworks/SharingUI.framework";
|
NSBundle *sharingUI = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/SharingUI.framework"];
|
||||||
if ([[NSFileManager defaultManager] fileExistsAtPath:suf]){
|
[sharingUI load];
|
||||||
NSBundle *sharingUI = [NSBundle bundleWithPath:suf];
|
|
||||||
[sharingUI load];
|
|
||||||
}
|
|
||||||
|
|
||||||
UIViewController *rvc = [[[UIApplication sharedApplication] keyWindow] rootViewController];
|
|
||||||
NSURL *url = [NSURL fileURLWithPath:filePath];
|
|
||||||
|
|
||||||
id sharingView = [[objc_getClass("SFAirDropSharingViewControllerTV") alloc] initWithSharingItems:@[url]];
|
id sharingView = [[objc_getClass("SFAirDropSharingViewControllerTV") alloc] initWithSharingItems:@[url]];
|
||||||
[sharingView setCompletionHandler:^(NSError *error) {
|
[sharingView setCompletionHandler:^(NSError *error) {
|
||||||
NSString *sender = airdropDictionary[@"sender"];
|
[root dismissViewControllerAnimated:true completion:nil];
|
||||||
if (sender) {
|
|
||||||
id defaultWorkspace = [objc_getClass("LSApplicationWorkspace") defaultWorkspace];
|
|
||||||
[defaultWorkspace performSelector:@selector(openApplicationWithBundleID:) withObject:(id)sender];
|
|
||||||
}
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[rvc presentViewController:sharingView animated:true completion:nil];
|
[root presentViewController:sharingView animated:true completion:nil];
|
||||||
}];
|
}];
|
||||||
[doneController addAction:openAction];
|
[doneController addAction:openAction];
|
||||||
|
|
||||||
@@ -257,7 +241,7 @@ NSArray *decryptedFileList(void) {
|
|||||||
|
|
||||||
NSString *file;
|
NSString *file;
|
||||||
while (file = [directoryEnumerator nextObject]) {
|
while (file = [directoryEnumerator nextObject]) {
|
||||||
if ([[file pathExtension] isEqualToString:@"ipa"]) {
|
if ([[file pathExtension] isEqualToString:@"ipa"] || [[file pathExtension] isEqualToString:@"tipa"]) {
|
||||||
NSString *filePath = [[docPath() stringByAppendingPathComponent:file] stringByStandardizingPath];
|
NSString *filePath = [[docPath() stringByAppendingPathComponent:file] stringByStandardizingPath];
|
||||||
|
|
||||||
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:nil];
|
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:nil];
|
||||||
@@ -402,7 +386,7 @@ void github_fetchLatedVersion(NSString *repo, void (^completionHandler)(NSString
|
|||||||
}
|
}
|
||||||
|
|
||||||
void fetchLatestTrollDecryptVersion(void (^completionHandler)(NSString *version)) {
|
void fetchLatestTrollDecryptVersion(void (^completionHandler)(NSString *version)) {
|
||||||
github_fetchLatedVersion(@"donato-fiore/TrollDecrypt", completionHandler);
|
github_fetchLatedVersion(@"straight-tamago/TrollDecrypt-tvOS", completionHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *trollDecryptVersion(void) {
|
NSString *trollDecryptVersion(void) {
|
||||||
|
|||||||
8
control
8
control
@@ -1,8 +1,8 @@
|
|||||||
Package: com.fiore.trolldecrypt
|
Package: com.nohamr.trolldecrypt
|
||||||
Name: TrollDecrypt
|
Name: TrollDecrypt
|
||||||
Version: 1.1
|
Version: 1.2
|
||||||
Architecture: iphoneos-arm
|
Architecture: iphoneos-arm
|
||||||
Description: An awesome application!
|
Description: An awesome application!
|
||||||
Maintainer: fiore
|
Maintainer: nohamr
|
||||||
Author: fiore
|
Author: nohamr
|
||||||
Section: Utilities
|
Section: Utilities
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<key>platform-application</key>
|
<key>platform-application</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>application-identifier</key>
|
<key>application-identifier</key>
|
||||||
<string>com.fiore.trolldecrypt</string>
|
<string>com.nohamr.trolldecrypt</string>
|
||||||
<key>com.apple.security.exception.files.absolute-path.read-write</key>
|
<key>com.apple.security.exception.files.absolute-path.read-write</key>
|
||||||
<array>
|
<array>
|
||||||
<string>/</string>
|
<string>/</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user