Skip to content

Commit

Permalink
add local ShadowService capability, update version to 3.2
Browse files Browse the repository at this point in the history
  • Loading branch information
jjolano committed Nov 22, 2022
1 parent 149adf2 commit 6adb314
Show file tree
Hide file tree
Showing 16 changed files with 280 additions and 80 deletions.
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
ARCHS = armv7 arm64 arm64e
TARGET = iphone:clang:13.0:7.0
INSTALL_TARGET_PROCESSES = SpringBoard

include $(THEOS)/makefiles/common.mk
SUBPROJECTS += dylib
Expand Down
1 change: 0 additions & 1 deletion api/Shadow.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
- (BOOL)isURLRestricted:(NSURL *)url;

- (void)setTweakCompatExtra:(BOOL)enabled;
- (void)setService:(ShadowService *)_service;

+ (instancetype)shadowWithService:(ShadowService *)_service;
@end
8 changes: 7 additions & 1 deletion api/ShadowService.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
#import <Foundation/Foundation.h>

#define BYPASS_VERSION "4.1"
#define API_VERSION "3.0"
#define API_VERSION "3.1"

#define CPDMC_SERVICE_NAME "me.jjolano.shadow.service"
#define LOCAL_SERVICE_DB "/Library/Shadow/db.plist"

@interface ShadowService : NSObject
- (void)startService;
- (void)connectService;
- (void)startLocalService;
- (NSDictionary *)generateDatabase;

- (NSDictionary *)sendIPC:(NSString *)messageName withArgs:(NSDictionary *)args;

- (NSString *)resolvePath:(NSString *)path;
- (BOOL)isPathRestricted:(NSString *)path;
- (NSArray*)getURLSchemes;
Expand Down
260 changes: 199 additions & 61 deletions api/ShadowService.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
@implementation ShadowService {
NSCache* responseCache;
NSString* dpkgPath;
NSOperationQueue* opQueue;

CPDistributedMessagingCenter* center;
NSSet* dpkgInstalledDb;
NSSet* dpkgExceptionDb;
}

- (BOOL)isPathRestricted_internal:(NSString *)path {
Expand All @@ -37,53 +39,70 @@ - (BOOL)isPathRestricted_internal:(NSString *)path {
}

BOOL restricted = NO;

// Call dpkg to see if file is part of any installed packages on the system.
NSTask* task = [NSTask new];
NSPipe* stdoutPipe = [NSPipe new];

[task setLaunchPath:dpkgPath];
[task setArguments:@[@"--no-pager", @"-S", path]];
[task setStandardOutput:stdoutPipe];
[task launch];
[task waitUntilExit];
NSArray* base_extra = @[
@"/Library/Application Support",
@"/usr/lib"
];

if(dpkgPath) {
// Call dpkg to see if file is part of any installed packages on the system.
NSTask* task = [NSTask new];
NSPipe* stdoutPipe = [NSPipe new];

HBLogDebug(@"%@: %@", @"dpkg", path);
[task setLaunchPath:dpkgPath];
[task setArguments:@[@"--no-pager", @"-S", path]];
[task setStandardOutput:stdoutPipe];
[task launch];
[task waitUntilExit];

if([task terminationStatus] == 0) {
// Path found in dpkg database - exclude if base package is part of the package list.
NSData* data = [[stdoutPipe fileHandleForReading] readDataToEndOfFile];
NSString* output = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSArray* lines = [output componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
HBLogDebug(@"%@: %@", @"dpkg", path);

for(NSString* line in lines) {
NSArray* line_split = [line componentsSeparatedByString:@": "];
if([task terminationStatus] == 0) {
// Path found in dpkg database - exclude if base package is part of the package list.
NSData* data = [[stdoutPipe fileHandleForReading] readDataToEndOfFile];
NSString* output = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSArray* lines = [output componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];

if([line_split count] == 2) {
NSString* line_packages = line_split[0];
for(NSString* line in lines) {
NSArray* line_split = [line componentsSeparatedByString:@": "];

if([line_packages hasPrefix:@"local diversion"]) {
continue;
}
if([line_split count] == 2) {
NSString* line_packages = line_split[0];

NSString* line_path = line_split[1];
NSArray* line_packages_split = [line_packages componentsSeparatedByString:@", "];
if([line_packages hasPrefix:@"local diversion"]) {
continue;
}

BOOL exception = [line_packages_split containsObject:@"base"] || [line_packages_split containsObject:@"firmware-sbin"];
NSString* line_path = line_split[1];
NSArray* line_packages_split = [line_packages componentsSeparatedByString:@", "];

if(!exception) {
NSArray* base_extra = @[
@"/Library/Application Support",
@"/usr/lib"
];
BOOL exception = [line_packages_split containsObject:@"base"] || [line_packages_split containsObject:@"firmware-sbin"];

if([base_extra containsObject:line_path]) {
exception = YES;
if(!exception) {
if([base_extra containsObject:line_path]) {
exception = YES;
}
}

restricted = !exception;
[responseCache setObject:@(restricted) forKey:line_path];
}
}
}
} else {
// Local service - filter using dpkgInstalledDb and dpkgExceptionDb
if(dpkgInstalledDb) {
restricted = [dpkgInstalledDb containsObject:path];
}

if(restricted && dpkgExceptionDb) {
restricted = ![dpkgExceptionDb containsObject:path];

restricted = !exception;
[responseCache setObject:@(restricted) forKey:line_path];
if(restricted) {
if([base_extra containsObject:path]) {
restricted = NO;
}
}
}
}
Expand All @@ -99,30 +118,51 @@ - (NSArray*)getURLSchemes_internal {

NSMutableArray* schemes = [NSMutableArray new];

NSTask* task = [NSTask new];
NSPipe* stdoutPipe = [NSPipe new];
if(dpkgPath) {
NSTask* task = [NSTask new];
NSPipe* stdoutPipe = [NSPipe new];

[task setLaunchPath:dpkgPath];
[task setArguments:@[@"--no-pager", @"-S", @"app/Info.plist"]];
[task setStandardOutput:stdoutPipe];
[task launch];
[task waitUntilExit];
[task setLaunchPath:dpkgPath];
[task setArguments:@[@"--no-pager", @"-S", @"app/Info.plist"]];
[task setStandardOutput:stdoutPipe];
[task launch];
[task waitUntilExit];

if([task terminationStatus] == 0) {
NSData* data = [[stdoutPipe fileHandleForReading] readDataToEndOfFile];
NSString* output = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
if([task terminationStatus] == 0) {
NSData* data = [[stdoutPipe fileHandleForReading] readDataToEndOfFile];
NSString* output = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

NSCharacterSet* separator = [NSCharacterSet newlineCharacterSet];
NSArray<NSString *>* lines = [output componentsSeparatedByCharactersInSet:separator];
NSCharacterSet* separator = [NSCharacterSet newlineCharacterSet];
NSArray<NSString *>* lines = [output componentsSeparatedByCharactersInSet:separator];

for(NSString* entry in lines) {
NSArray<NSString *>* line = [entry componentsSeparatedByString:@": "];
for(NSString* entry in lines) {
NSArray<NSString *>* line = [entry componentsSeparatedByString:@": "];

if([line count] == 2) {
NSString* plistpath = [line objectAtIndex:1];
if([line count] == 2) {
NSString* plistpath = [line objectAtIndex:1];

if([plistpath hasSuffix:@"Info.plist"]) {
NSDictionary* plist = [NSDictionary dictionaryWithContentsOfFile:plistpath];
if([plistpath hasSuffix:@"Info.plist"]) {
NSDictionary* plist = [NSDictionary dictionaryWithContentsOfFile:plistpath];

if(plist && plist[@"CFBundleURLTypes"]) {
for(NSDictionary* type in plist[@"CFBundleURLTypes"]) {
if(type[@"CFBundleURLSchemes"]) {
for(NSString* scheme in type[@"CFBundleURLSchemes"]) {
[schemes addObject:scheme];
}
}
}
}
}
}
}
}
} else {
// Local service - load using dpkgInstalledDb
if(dpkgInstalledDb) {
for(NSString* path_installed in dpkgInstalledDb) {
if([path_installed hasSuffix:@"app/Info.plist"]) {
NSDictionary* plist = [NSDictionary dictionaryWithContentsOfFile:path_installed];

if(plist && plist[@"CFBundleURLTypes"]) {
for(NSDictionary* type in plist[@"CFBundleURLTypes"]) {
Expand Down Expand Up @@ -162,7 +202,15 @@ - (NSDictionary *)handleMessageNamed:(NSString *)name withUserInfo:(NSDictionary
}

// Resolve and standardize path.
NSString* path = [[rawPath stringByExpandingTildeInPath] stringByStandardizingPath];
NSString* path;

if(center) {
// Unsandboxed and unhooked - safe to resolve
path = [[rawPath stringByExpandingTildeInPath] stringByStandardizingPath];
} else {
// Sandboxed and hooked
return nil;
}

if([path hasPrefix:@"/private/var"] || [path hasPrefix:@"/private/etc"]) {
NSMutableArray* pathComponents = [[path pathComponents] mutableCopy];
Expand Down Expand Up @@ -195,7 +243,7 @@ - (NSDictionary *)handleMessageNamed:(NSString *)name withUserInfo:(NSDictionary
return nil;
}

if(![[NSFileManager defaultManager] fileExistsAtPath:path]) {
if(center && ![[NSFileManager defaultManager] fileExistsAtPath:path]) {
return nil;
}

Expand All @@ -216,6 +264,67 @@ - (NSDictionary *)handleMessageNamed:(NSString *)name withUserInfo:(NSDictionary
return response;
}

- (NSDictionary *)generateDatabase {
NSMutableDictionary* db = [NSMutableDictionary new];
NSMutableSet* db_installed = [NSMutableSet new];
NSMutableSet* db_exception = [NSMutableSet new];

// Determine dpkg info database path.
NSString* dpkgInfoPath;
NSArray* dpkgInfoPaths = @[
@"/Library/dpkg/info",
@"/var/lib/dpkg/info",
@"/var/jb/Library/dpkg/info",
@"/var/jb/var/lib/dpkg/info"
];

for(NSString* path in dpkgInfoPaths) {
if([[NSFileManager defaultManager] fileExistsAtPath:path]) {
dpkgInfoPath = path;
break;
}
}

// Iterate all list files in database.
NSArray* db_files = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSURL fileURLWithPath:dpkgInfoPath] includingPropertiesForKeys:@[] options:0 error:nil];

for(NSURL* db_file in db_files) {
if([db_file pathExtension] && [[db_file pathExtension] isEqualToString:@"list"]) {
NSString* content = [NSString stringWithContentsOfURL:db_file encoding:NSUTF8StringEncoding error:nil];

if(content) {
// Read all lines
NSArray* lines = [content componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];

for(NSString* line in lines) {
if(![line isEqualToString:@""]) {
// Add to relevant set
if([[db_file lastPathComponent] isEqualToString:@"base.list"] || [[db_file lastPathComponent] isEqualToString:@"firmware-sbin.list"]) {
[db_exception addObject:line];
} else {
[db_installed addObject:line];
}
}
}
}
}
}

// Filter some unneeded filenames.
NSArray* filter_names = @[
@"/."
];

for(NSString* name in filter_names) {
[db_installed removeObject:name];
[db_exception removeObject:name];
}

[db setObject:[db_installed allObjects] forKey:@"installed"];
[db setObject:[db_exception allObjects] forKey:@"exception"];
return [db copy];
}

- (void)startService {
NSArray* dpkgPaths = @[
@"/usr/bin/dpkg-query",
Expand All @@ -231,11 +340,12 @@ - (void)startService {
}
}

[self connectService];

if(center) {
[center runServerOnCurrentThread];

// Register messages.
[center registerForMessageName:@"getVersions" target:self selector:@selector(handleMessageNamed:withUserInfo:)];
[center registerForMessageName:@"isPathRestricted" target:self selector:@selector(handleMessageNamed:withUserInfo:)];
[center registerForMessageName:@"getURLSchemes" target:self selector:@selector(handleMessageNamed:withUserInfo:)];
[center registerForMessageName:@"resolvePath" target:self selector:@selector(handleMessageNamed:withUserInfo:)];
Expand All @@ -244,9 +354,38 @@ - (void)startService {
}
}

- (void)startLocalService {
// Load precompiled data from filesystem.
NSDictionary* db_plist = [NSDictionary dictionaryWithContentsOfFile:@LOCAL_SERVICE_DB];

if(!db_plist) {
HBLogDebug(@"%@", @"could not load db");

db_plist = @{
@"installed" : @[],
@"exception" : @[]
};
} else {
HBLogDebug(@"%@", @"successfully loaded db");
}

if(db_plist[@"installed"]) {
dpkgInstalledDb = [NSSet setWithArray:db_plist[@"installed"]];
}

if(db_plist[@"exception"]) {
dpkgExceptionDb = [NSSet setWithArray:db_plist[@"exception"]];
}
}

- (void)connectService {
center = [CPDistributedMessagingCenter centerNamed:@CPDMC_SERVICE_NAME];
rocketbootstrap_distributedmessagingcenter_apply(center);
}

- (NSDictionary *)sendIPC:(NSString *)messageName withArgs:(NSDictionary *)args {
if(!center) {
return nil;
return [self handleMessageNamed:messageName withUserInfo:args];
}

NSError* error = nil;
Expand Down Expand Up @@ -329,10 +468,9 @@ - (NSDictionary *)getVersions {
- (instancetype)init {
if((self = [super init])) {
responseCache = [NSCache new];
opQueue = [NSOperationQueue new];

center = [CPDistributedMessagingCenter centerNamed:@CPDMC_SERVICE_NAME];
rocketbootstrap_distributedmessagingcenter_apply(center);
center = nil;
dpkgInstalledDb = nil;
dpkgExceptionDb = nil;
}

return self;
Expand Down
Loading

0 comments on commit 6adb314

Please sign in to comment.