1- #import < Foundation/Foundation.h>
2- #import < spawn.h>
1+ #include < Foundation/Foundation.h>
2+
3+ #include < spawn.h>
34#include < roothide.h>
5+
46#include " common.h"
57
68extern char **environ;
@@ -78,7 +80,7 @@ static const void *kBlockSchemeTagKey = &kBlockSchemeTagKey;
7880 return result;
7981}
8082
81- - (BOOL )canOpenURL:(NSURL *)url publicSchemes:(BOOL )ispublic privateSchemes:(BOOL )isprivate XPCConnection:(NSXPCConnection *)connection error:(NSError *)err
83+ - (BOOL )canOpenURL:(NSURL *)url publicSchemes:(BOOL )ispublic privateSchemes:(BOOL )isprivate XPCConnection:(NSXPCConnection *)connection error:(NSError **)perror
8284{
8385 BOOL blocked = NO ;
8486
@@ -109,7 +111,7 @@ static const void *kBlockSchemeTagKey = &kBlockSchemeTagKey;
109111 return ret;
110112}
111113
112- %end
114+ %end // %hook _LSCanOpenURLManager
113115
114116
115117@interface _LSDOpenClient : NSObject
@@ -229,12 +231,265 @@ static const void *kBlockSchemeTagKey = &kBlockSchemeTagKey;
229231 %orig (url, options, newcallback);
230232}
231233
232- %end
234+ %end // %hook _LSDOpenClient
235+
236+ %group UTTypeHooks
237+
238+ @interface UTTypeRecord : NSObject
239+ + (id )typeRecordWithIdentifier : (id )identifier ;
240+ - (unsigned int )tableID ;
241+ @end
242+
243+ @interface _UTDeclaredTypeRecord : NSObject
244+ - (id )_initWithContext : (void *)ctx tableID : (unsigned int )tableID unitID : (unsigned int )unitID ;
245+ - (BOOL )isDeclared ;
246+ - (BOOL )isCoreType ;
247+ - (BOOL )isInPublicDomain ;
248+ - (id )identifier ;
249+ - (id )declaringBundleRecord ;
250+ - (unsigned int )unitID ;
251+ - (unsigned int )_rawFlags ;
252+ @end
253+
254+ @interface LSBundleRecord : NSObject
255+ - (NSURL *)URL ;
256+ @end
257+
258+ @interface _LSDReadClient : NSObject
259+ - (NSXPCConnection *)XPCConnection ;
260+ @end
261+
262+ static __thread BOOL g_utrHide = NO ; // raised by the _LSDReadClient hooks for blacklisted requests
263+ static __thread int g_utrBusy = 0 ; // >0 while we ourselves touch the DB, to keep our access out of the filters
264+
265+ static BOOL utrFilterActive (void ) { return g_utrHide && !g_utrBusy; }
266+
267+ static pid_t utrClientPid (_LSDReadClient* client)
268+ {
269+ NSXPCConnection * conn = [client XPCConnection ];
270+ return conn ? conn.processIdentifier : -1 ;
271+ }
272+
273+ static BOOL utrHideClientBlacklisted (_LSDReadClient* client)
274+ {
275+ pid_t pid = utrClientPid (client);
276+ if (pid>0 && jbclient_blacklist_check_pid (pid)) {
277+ return YES ;
278+ }
279+ return NO ;
280+ }
281+
282+ // type-units table id; constant for the database. Read once, off the hot path, via a public accessor.
283+ static unsigned int utrTypeTableID (void )
284+ {
285+ static unsigned int tid = 0 ;
286+ static dispatch_once_t once;
287+ dispatch_once (&once, ^{
288+ // guard this probe's own nested lookup so it is never filtered, independent of the caller.
289+ // g_utrBusy is a counter, so this nests cleanly inside utrUnitIsJailbreak's busy region.
290+ g_utrBusy++;
291+ tid = (unsigned int )[[NSClassFromString (@" UTTypeRecord" ) typeRecordWithIdentifier: @" public.data" ] tableID ];
292+ g_utrBusy--;
293+ });
294+ return tid;
295+ }
296+
297+ // YES only when `rec` is a *declared* type whose active declaring bundle is a jailbreak bundle,
298+ // and which is not an Apple core / public-domain type (those are never touched -> #3).
299+ static BOOL utrRecordIsFromJailbreakApp (_UTDeclaredTypeRecord* rec)
300+ {
301+ if (![rec isDeclared ]) return NO ; // dynamic/undeclared -> already the "absent" shape
302+ if ([rec isCoreType ]) return NO ; // Apple core type -> never touched (#3)
303+ if ([rec isInPublicDomain ]) return NO ; // public.* -> never touched (#3)
304+ LSBundleRecord* bundleRec = [rec declaringBundleRecord ];
305+ NSURL * url = [bundleRec URL ];
306+ if (![url isKindOfClass: [NSURL class ]] || !url.isFileURL ) return NO ;
307+ if (!isJailbreakBundlePath (url.path .fileSystemRepresentation )) return NO ;
308+
309+ NSLog (@" [UTType] hide type id=%@ bundle=%@ " , [rec identifier ], url);
310+ return YES ;
311+ }
312+
313+ // build a record for an enumerated unitID and decide if it belongs to a jailbreak app.
314+ static BOOL utrUnitIsJailbreak (void * db, intptr_t unitID)
315+ {
316+ BOOL result = NO ;
317+ g_utrBusy++; // keep our own nested DB access out of the filters
318+ unsigned int tid = utrTypeTableID ();
319+ if (tid) {
320+ void * ctx = db; // _initWithContext: reads *(void**)ctx (offset 0) == db
321+ _UTDeclaredTypeRecord* rec = [[NSClassFromString (@" _UTDeclaredTypeRecord" ) alloc ]
322+ _initWithContext: (void *)&ctx tableID: tid unitID: (unsigned int )unitID];
323+ result = utrRecordIsFromJailbreakApp (rec);
324+ }
325+ g_utrBusy--;
326+ return result;
327+ }
328+
329+ // //////////////////////////////////////////////////////////////////////////////////////////////////////
330+
331+ typedef intptr_t (^UTREnumBlock)(intptr_t a2, intptr_t unitID, const void * unitBytes, void * a5);
332+ %hookf (void , _UTEnumerateTypesForTag, void * db, void * tagClass, void * tag, id block)
333+ {
334+ if (!utrFilterActive () || !block) { %orig ; return ; }
335+
336+ UTREnumBlock orig = (UTREnumBlock)block;
337+ UTREnumBlock wrapper = ^intptr_t (intptr_t a2, intptr_t unitID, const void * unitBytes, void * a5) {
338+ if (utrUnitIsJailbreak (db, unitID)) return 0 ; // drop -> continue enumeration, nothing recorded
339+ return orig (a2, unitID, unitBytes, a5); // forward to the original callback
340+ };
341+ %orig (db, tagClass, tag, wrapper);
342+ }
343+
344+ %hookf (void , _UTEnumerateTypesForIdentifier, void * db, long identStrId, id block)
345+ {
346+ if (!utrFilterActive () || !block) { %orig ; return ; }
347+
348+ UTREnumBlock orig = (UTREnumBlock)block;
349+ UTREnumBlock wrapper = ^intptr_t (intptr_t a2, intptr_t unitID, const void * unitBytes, void * a5) {
350+ if (utrUnitIsJailbreak (db, unitID)) return 0 ;
351+ return orig (a2, unitID, unitBytes, a5);
352+ };
353+ %orig (db, identStrId, wrapper);
354+ }
355+
356+ typedef void (^UTRConformBlock)(intptr_t unitID, const void * unitBytes, intptr_t kind, unsigned char * outStop);
357+ %hookf (void , _UTTypeSearchConformingTypesWithBlock, void * db, long unitID, long flags, long arg4, id block)
358+ {
359+ if (!utrFilterActive () || !block) { %orig ; return ; }
360+
361+ UTRConformBlock orig = (UTRConformBlock)block;
362+ UTRConformBlock wrapper = ^void (intptr_t uid, const void * unitBytes, intptr_t kind, unsigned char * outStop) {
363+ if (utrUnitIsJailbreak (db, uid)) return ; // drop conforming JB type -> outStop stays 0, keep enumerating
364+ orig (uid, unitBytes, kind, outStop); // forward to the original callback
365+ };
366+ %orig (db, unitID, flags, arg4, wrapper);
367+ }
368+
369+ // parents/forward conformance: filters JB parent types out of related-types (degree>0)
370+ // and out of a record's serialized parentTypeIdentifiers/conformsTo list.
371+ // _UTTypeConformsTo's boolean verdict goes through ...Common (not WithBlock), so it is unaffected.
372+ %hookf (void , _UTTypeSearchConformsToTypesWithBlock, void * db, long unitID, long flags, long arg4, id block)
373+ {
374+ if (!utrFilterActive () || !block) { %orig ; return ; }
375+
376+ UTRConformBlock orig = (UTRConformBlock)block;
377+ UTRConformBlock wrapper = ^void (intptr_t uid, const void * unitBytes, intptr_t kind, unsigned char * outStop) {
378+ if (utrUnitIsJailbreak (db, uid)) return ; // drop conforming-to (parent) JB type -> keep enumerating
379+ orig (uid, unitBytes, kind, outStop); // forward to the original callback
380+ };
381+ %orig (db, unitID, flags, arg4, wrapper);
382+ }
233383
234384
385+ %hookf (void , _LSSchemaCacheRead, void * a1, id block)
386+ {
387+ if (utrFilterActive ()) return ; // force cache miss -> recompute (filtered)
388+ %orig (a1, block);
389+ }
390+
391+ %hookf (void , _LSSchemaCacheWrite, void * a1, id block)
392+ {
393+ if (utrFilterActive ()) return ; // don't cache the hidden result
394+ %orig (a1, block);
395+ }
396+
397+ %hook _LSDReadClient
398+ - (void )getTypeRecordWithTag:(id )tag ofClass:(id )_class conformingToIdentifier:(id )identifier completionHandler:(void (^)(id ))handler
399+ {
400+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
401+ NSLog (@" [UTType] getTypeRecordWithTag:%@ ofClass:%@ conforming:%@ pid=%d " , tag, _class, identifier, utrClientPid (self));
402+ g_utrHide = YES ;
403+ %orig ;
404+ g_utrHide = NO ;
405+ }
406+
407+ - (void )getTypeRecordsWithTag:(id )tag ofClass:(id )_class conformingToIdentifier:(id )identifier completionHandler:(void (^)(id ))handler
408+ {
409+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
410+ NSLog (@" [UTType] getTypeRecordsWithTag:%@ ofClass:%@ conforming:%@ pid=%d " , tag, _class, identifier, utrClientPid (self));
411+ g_utrHide = YES ;
412+ %orig ;
413+ g_utrHide = NO ;
414+ }
415+
416+ - (void )getTypeRecordWithIdentifier:(id )identifier allowUndeclared:(BOOL )allowUndeclared completionHandler:(void (^)(id ))handler
417+ {
418+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
419+ NSLog (@" [UTType] getTypeRecordWithIdentifier:%@ allowUndeclared:%d pid=%d " , identifier, allowUndeclared, utrClientPid (self));
420+ g_utrHide = YES ;
421+ %orig ;
422+ g_utrHide = NO ;
423+ }
424+
425+ - (void )getTypeRecordsWithIdentifiers:(id )identifiers completionHandler:(void (^)(id ))handler
426+ {
427+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
428+ NSLog (@" [UTType] getTypeRecordsWithIdentifiers:%@ pid=%d " , identifiers, utrClientPid (self));
429+ g_utrHide = YES ;
430+ %orig ;
431+ g_utrHide = NO ;
432+ }
433+
434+ - (void )getTypeRecordForImportedTypeWithIdentifier:(id )identifier conformingToIdentifier:(id )conforming completionHandler:(void (^)(id ))handler
435+ {
436+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
437+ NSLog (@" [UTType] getTypeRecordForImportedTypeWithIdentifier:%@ conforming:%@ pid=%d " , identifier, conforming, utrClientPid (self));
438+ g_utrHide = YES ;
439+ %orig ;
440+ g_utrHide = NO ;
441+ }
442+
443+ - (void )getRelatedTypesOfTypeWithIdentifier:(id )identifier maximumDegreeOfSeparation:(NSInteger )degree completionHandler:(void (^)(id , id ))handler
444+ {
445+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
446+ NSLog (@" [UTType] getRelatedTypesOfTypeWithIdentifier:%@ degree:%ld pid=%d " , identifier, (long )degree, utrClientPid (self));
447+ g_utrHide = YES ;
448+ %orig ;
449+ g_utrHide = NO ;
450+ }
451+
452+ - (void )getWhetherTypeIdentifier:(id )identifier conformsToTypeIdentifier:(id )other completionHandler:(void (^)(id ))handler
453+ {
454+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
455+ NSLog (@" [UTType] getWhetherTypeIdentifier:%@ conformsToTypeIdentifier:%@ pid=%d " , identifier, other, utrClientPid (self));
456+ g_utrHide = YES ;
457+ %orig ;
458+ g_utrHide = NO ;
459+ }
460+
461+ - (void )getResourceValuesForKeys:(id )keys URL :(id )url preferredLocalizations:(id )locs completionHandler:(void (^)(id , id , id ))handler
462+ {
463+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
464+ NSLog (@" [UTType] getResourceValuesForKeys:%@ URL:%@ pid=%d " , keys, url, utrClientPid (self));
465+ g_utrHide = YES ;
466+ %orig ;
467+ g_utrHide = NO ;
468+ }
469+
470+ - (void )getBoundIconInfoForDocumentProxy:(id )documentProxy completionHandler:(void (^)(id , id ))handler
471+ {
472+ if (!utrHideClientBlacklisted (self)) { %orig ; return ; }
473+ NSLog (@" [UTType] getBoundIconInfoForDocumentProxy:%@ pid=%d " , documentProxy, utrClientPid (self));
474+ g_utrHide = YES ;
475+ %orig ;
476+ g_utrHide = NO ;
477+ }
478+ %end // %hook _LSDReadClient
479+
480+ %end // %group UTTypeHooks
481+
235482%hook _LSQueryContext
236483
237- -(NSMutableDictionary *)_resolveQueries:(NSMutableSet *)queries XPCConnection:(NSXPCConnection *)connection error:(NSError *)err
484+ @interface LSPlugInQueryWithUnits : NSObject
485+ -(id )initWithPlugInUnits : (id )units forDatabaseWithUUID : (id )dbUUID ;
486+ @end
487+
488+ @interface _LSQueryContext : NSObject
489+ -(NSMutableDictionary *)_resolveQueries : (NSMutableSet *)queries XPCConnection : (NSXPCConnection *)connection error : (NSError **)perror ;
490+ @end
491+
492+ -(NSMutableDictionary *)_resolveQueries:(NSMutableSet *)queries XPCConnection:(NSXPCConnection *)connection error:(NSError **)perror
238493{
239494 NSMutableDictionary * result = %orig ;
240495 /*
@@ -317,7 +572,7 @@ static const void *kBlockSchemeTagKey = &kBlockSchemeTagKey;
317572 NSArray * _pluginUnits = [unitsResult valueForKey: @" _pluginUnits" ];
318573 NSLog (@" LSPlugInQueryAllUnits: _dbUUID=%@ , _pluginUnits count=%ld " , _dbUUID, _pluginUnits.count );
319574 id unitQuery = [[NSClassFromString (@" LSPlugInQueryWithUnits" ) alloc ] initWithPlugInUnits: _pluginUnits forDatabaseWithUUID: _dbUUID];
320- NSMutableDictionary * queriesResult = [self _resolveQueries: [NSSet setWithObject: unitQuery] XPCConnection: connection error: err ];
575+ NSMutableDictionary * queriesResult = [self _resolveQueries: [NSSet setWithObject: unitQuery].mutableCopy XPCConnection: connection error: perror ];
321576 if (queriesResult)
322577 {
323578 for (id queryKey in queriesResult)
@@ -334,7 +589,7 @@ static const void *kBlockSchemeTagKey = &kBlockSchemeTagKey;
334589 return result;
335590}
336591
337- %end
592+ %end // %hook _LSQueryContext
338593
339594
340595// or -[Copier initWithSourceURL:uniqueIdentifier:destURL:callbackTarget:selector:options:] in transitd
@@ -397,5 +652,17 @@ void lsdInit(void)
397652 MSHookFunction (_LSServer_RebuildApplicationDatabases, (void *)&new_LSServer_RebuildApplicationDatabases, (void **)&orig_LSServer_RebuildApplicationDatabases);
398653 }
399654
655+ void * _LSSchemaCacheRead = MSFindSymbol (coreServicesImage, " __LSSchemaCacheRead" );
656+ void * _LSSchemaCacheWrite = MSFindSymbol (coreServicesImage, " __LSSchemaCacheWrite" );
657+ void * _UTEnumerateTypesForTag = MSFindSymbol (coreServicesImage, " __UTEnumerateTypesForTag" );
658+ void * _UTEnumerateTypesForIdentifier = MSFindSymbol (coreServicesImage, " __UTEnumerateTypesForIdentifier" );
659+ void * _UTTypeSearchConformingTypesWithBlock = MSFindSymbol (coreServicesImage, " __UTTypeSearchConformingTypesWithBlock" );
660+ void * _UTTypeSearchConformsToTypesWithBlock = MSFindSymbol (coreServicesImage, " __UTTypeSearchConformsToTypesWithBlock" );
661+ if (_LSSchemaCacheRead && _LSSchemaCacheWrite && _UTEnumerateTypesForTag && _UTEnumerateTypesForIdentifier && _UTTypeSearchConformingTypesWithBlock && _UTTypeSearchConformsToTypesWithBlock)
662+ {
663+ NSLog (@" UTTypeHooks: installing" );
664+ %init (UTTypeHooks, _LSSchemaCacheRead=_LSSchemaCacheRead, _LSSchemaCacheWrite=_LSSchemaCacheWrite, _UTEnumerateTypesForTag=_UTEnumerateTypesForTag, _UTEnumerateTypesForIdentifier=_UTEnumerateTypesForIdentifier, _UTTypeSearchConformingTypesWithBlock=_UTTypeSearchConformingTypesWithBlock, _UTTypeSearchConformsToTypesWithBlock=_UTTypeSearchConformsToTypesWithBlock);
665+ }
666+
400667 %init ();
401668}
0 commit comments