v 2.0.0 (beta)

-mojave support
  (privacy checks, dark mode, etc)

 -command line interface

 -run as root
  (scan all users)

 -improved whitelisting
  (via path + code signing cert)

 -senty.io error reportiung
This commit is contained in:
Patrick Wardle
2018-11-18 20:43:46 -10:00
parent 32250d8fa4
commit 91cc826865
79 changed files with 2209 additions and 1065 deletions
+7 -2
View File
@@ -32,8 +32,13 @@
//super
[super windowDidLoad];
//make white
[self.window setBackgroundColor: NSColor.whiteColor];
//not in dark mode?
// make window white
if(YES != isDarkMode())
{
//make white
self.window.backgroundColor = NSColor.whiteColor;
}
//set version sting
[self.versionLabel setStringValue:[NSString stringWithFormat:@"version: %@", getAppVersion()]];
+12 -6
View File
@@ -20,6 +20,15 @@
#import <Cocoa/Cocoa.h>
/* GLOBALS */
//shared enumerator
extern ItemEnumerator* sharedItemEnumerator;
//filter object
extern Filter* itemFilter;
@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate, NSMenuDelegate>
{
@@ -28,6 +37,9 @@
/* PROPERTIES */
//friends
@property (weak) IBOutlet NSWindow *friends;
//flag for secondary scan
// ->need to restart shared enumerator
@property BOOL secondaryScan;
@@ -35,9 +47,6 @@
//plugin objects
@property(nonatomic, retain)NSMutableArray* plugins;
//shared item enumerator object
@property(nonatomic, retain)ItemEnumerator* sharedItemEnumerator;
//version string
@property (weak) IBOutlet NSTextField *versionString;
@@ -77,9 +86,6 @@
//non-UI thread that performs actual scan
@property(nonatomic, strong)NSThread *scannerThread;
//filter object
@property(nonatomic, retain)Filter* filterObj;
//virus total object
@property(nonatomic, retain)VirusTotal* virusTotalObj;
+63 -38
View File
@@ -4,31 +4,22 @@
//
#import "Consts.h"
#import "Exception.h"
#import "Utilities.h"
#import "PluginBase.h"
#import "AppDelegate.h"
//supported plugins
NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtensions", @"CronJobs", @"EventRules", @"Extensions", @"Kexts", @"LaunchItems", @"DylibInserts", @"DylibProxies", @"LoginItems", @"LogInOutHooks", @"PeriodicScripts", @"SpotlightImporters", @"StartupScripts"};
//TODO: white list for el capitan! (think we are good, but test in VM)
//TODO: cmdline interface
//TODO: scan other volume
//TODO: delete items
//TODO: search
//TODO: scan other volumes
//TODO: support delete items
//TODO: search in UI
//TODO: better parsing of args for /sh etc? or at least don't say they are 'APPLE' (and thus filter out)
// or make them a cmd!
@implementation AppDelegate
@synthesize friends;
@synthesize plugins;
@synthesize filterObj;
@synthesize vtThreads;
@synthesize scanButton;
@synthesize isConnected;
@@ -40,7 +31,6 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
@synthesize scanButtonLabel;
@synthesize progressIndicator;
@synthesize itemTableController;
@synthesize sharedItemEnumerator;
@synthesize aboutWindowController;
@synthesize prefsWindowController;
@synthesize showPreferencesButton;
@@ -64,18 +54,16 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
}
//automatically invoked by OS
// ->main entry point
-(void)applicationDidFinishLaunching:(NSNotification *)notification
{
//defaults
NSUserDefaults* defaults = nil;
//app's (self) signing status
OSStatus signingStatus = -1;
//first thing...
// ->install exception handlers!
installExceptionHandlers();
//init filter object
filterObj = [[Filter alloc] init];
itemFilter = [[Filter alloc] init];
//init virus total object
virusTotalObj = [[VirusTotal alloc] init];
@@ -86,16 +74,6 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
//alloc shared item enumerator
sharedItemEnumerator = [[ItemEnumerator alloc] init];
//check that OS is supported
if(YES != isSupportedOS())
{
//show alert
[self showUnsupportedAlert];
//exit
exit(0);
}
//verify self
signingStatus = verifySelf();
@@ -111,7 +89,28 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
//kick off thread to begin enumerating shared objects
// ->this takes awhile, so do it now/first!
[self.sharedItemEnumerator start];
[sharedItemEnumerator start];
//load defaults
defaults = [NSUserDefaults standardUserDefaults];
//first time run?
// show thanks to friends window!
if(YES != [defaults boolForKey:NOT_FIRST_TIME])
{
//set key
[defaults setBool:YES forKey:NOT_FIRST_TIME];
//show thanks
[self toggleFriends:nil];
//close after 3 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
//hide
[self.friends close];
});
}
//instantiate all plugins objects
self.plugins = [self instantiatePlugins];
@@ -158,6 +157,27 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
return;
}
//toggle friends view
- (IBAction)toggleFriends:(id)sender
{
//hide
if(YES == self.friends.visible)
{
//close to hide
[self.friends close];
}
//show
else
{
[self.friends makeKeyAndOrderFront:self];
[NSApp activateIgnoringOtherApps:YES];
}
return;
}
//display alert about OS not being supported
-(void)showUnsupportedAlert
{
@@ -239,7 +259,6 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
}
//create instances of all registered plugins
// ->returns list
-(NSMutableArray*)instantiatePlugins
{
//plugin objects
@@ -321,7 +340,7 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
if(YES == self.secondaryScan)
{
//start it
[self.sharedItemEnumerator start];
[sharedItemEnumerator start];
}
//start scanner thread
@@ -370,10 +389,16 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
});
//set callback
plugin.callback = ^(ItemBase* item)
{
[self itemFound:item];
};
//scan
// ->will call back up into UI as items are found
// will invoke callback as items are found
[plugin scan];
//when 'disable VT' prefs not selected and network is reachable
// ->kick of thread to perform VT query in background
if( (YES != self.prefsWindowController.disableVTQueries) &&
@@ -766,13 +791,13 @@ NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtens
-(void)completeScan
{
//tell enumerator to stop
[self.sharedItemEnumerator stop];
[sharedItemEnumerator stop];
//cancel enumerator thread
if(YES == [self.sharedItemEnumerator.enumeratorThread isExecuting])
if(YES == [sharedItemEnumerator.enumeratorThread isExecuting])
{
//cancel
[self.sharedItemEnumerator.enumeratorThread cancel];
[sharedItemEnumerator.enumeratorThread cancel];
}
//sync to cancel all VT threads
@@ -0,0 +1,68 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "icon_16x16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "icon_16x16@2x.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon_32x32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon_32x32@2x.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon_128x128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon_128x128@2x.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon_256x256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon_256x256@2x.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon_512x512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon_512x512@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Before

Width:  |  Height:  |  Size: 269 KiB

After

Width:  |  Height:  |  Size: 269 KiB

+6
View File
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
+35
View File
@@ -0,0 +1,35 @@
{
"images" : [
{
"idiom" : "mac",
"filename" : "digita.pdf"
},
{
"idiom" : "mac",
"filename" : "digitaLight.pdf",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "light"
}
]
},
{
"idiom" : "mac",
"filename" : "digitaDark.pdf",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
]
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,35 @@
{
"images" : [
{
"idiom" : "mac",
"filename" : "malwarebytes.pdf"
},
{
"idiom" : "mac",
"filename" : "malwarebytesLight.pdf",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "light"
}
]
},
{
"idiom" : "mac",
"filename" : "malwarebytesDark.pdf",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
]
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
Binary file not shown.
+35
View File
@@ -0,0 +1,35 @@
{
"images" : [
{
"idiom" : "mac",
"filename" : "sophos.png"
},
{
"idiom" : "mac",
"filename" : "sophosLight.png",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "light"
}
]
},
{
"idiom" : "mac",
"filename" : "sophosDark.png",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
]
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+1
View File
@@ -0,0 +1 @@
github "getsentry/sentry-cocoa" "4.1.0"
+1
View File
@@ -0,0 +1 @@
github "getsentry/sentry-cocoa" "4.1.0"
+3 -3
View File
@@ -138,11 +138,11 @@
[categoryCell.textField setTextColor:[NSColor redColor]];
}
//no flagged items
// ->set title's color to black
// ->set title's color
else
{
//black
[categoryCell.textField setTextColor:[NSColor blackColor]];
//reset
categoryCell.textField.textColor = NSColor.controlTextColor;
}
//set detailed text
+29 -7
View File
@@ -9,6 +9,12 @@
#ifndef KK_Consts_h
#define KK_Consts_h
//not first run
#define NOT_FIRST_TIME @"notFirstTime"
//supported plugins
static NSString * const SUPPORTED_PLUGINS[] = {@"AuthorizationPlugins", @"BrowserExtensions", @"CronJobs", @"EventRules", @"Extensions", @"Kexts", @"LaunchItems", @"DylibInserts", @"DylibProxies", @"LoginItems", @"LogInOutHooks", @"PeriodicScripts", @"SpotlightImporters", @"StartupScripts"};
//button text, start scan
#define START_SCAN @"Start Scan"
@@ -45,16 +51,23 @@
//success
#define STATUS_SUCCESS 0
//keys for signing stuff
//signers
enum Signer{None, Apple, AppStore, DevID, AdHoc};
//signature status
#define KEY_SIGNATURE_STATUS @"signatureStatus"
#define KEY_SIGNING_AUTHORITIES @"signingAuthorities"
#define KEY_SIGNING_IS_APPLE @"signedByApple"
//OS version x
#define OS_MAJOR_VERSION_X 10
//signer
#define KEY_SIGNATURE_SIGNER @"signatureSigner"
//OS version lion
#define OS_MINOR_VERSION_LION 8
//signing auths
#define KEY_SIGNATURE_AUTHORITIES @"signatureAuthorities"
//code signing id
#define KEY_SIGNATURE_IDENTIFIER @"signatureIdentifier"
//entitlements
#define KEY_SIGNATURE_ENTITLEMENTS @"signatureEntitlements"
//OS version yosemite
#define OS_MINOR_VERSION_YOSEMITE 10
@@ -98,6 +111,12 @@
//dyld_ key for applications
#define APPLICATION_DYLD_KEY @"LSEnvironment"
//user name
#define USER_NAME @"userName"
//user (home) directory
#define USER_DIRECTORY @"userDirectory"
//menu
//tag for prefs menu item
@@ -161,6 +180,9 @@
// ->for long paths...
#define ELLIPIS @"..."
//known kexts
#define WHITE_LISTED_KEXTS @"whitelistedKexts"
//known file hashes
#define WHITE_LISTED_FILES @"whitelistedFiles"
-17
View File
@@ -1,17 +0,0 @@
// Created by Patrick Wardle on 2/6/15.
// Copyright (c) 2015 Objective-See, LLC. All rights reserved.
#import <syslog.h>
#import <signal.h>
//install exception/signal handlers
void installExceptionHandlers(void);
//exception handler for Obj-C exceptions
void exceptionHandler(NSException *exception);
//signal handler for *nix style exceptions
void signalHandler(int signal, siginfo_t *info, void *context);
//display an alert
void showAlert(void);
-157
View File
@@ -1,157 +0,0 @@
// Created by Patrick Wardle on 2/6/15.
// Copyright (c) 2015 Objective-See, LLC. All rights reserved.
#import "Consts.h"
#import "Exception.h"
#import "Utilities.h"
//install exception/signal handlers
void installExceptionHandlers()
{
//sigaction struct
struct sigaction sa = {0};
//init struct
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = signalHandler;
//exception handler
NSSetUncaughtExceptionHandler(&exceptionHandler);
//install signal handlers
sigaction(SIGILL, &sa, NULL);
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
sigaction(SIGABRT, &sa, NULL);
sigaction(SIGTRAP, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
return;
}
//display error alert
void showAlert()
{
//response
// ->index of button click
NSModalResponse response = 0;
//alert box
NSAlert* fullScanAlert = nil;
//alloc/init alert
fullScanAlert = [NSAlert alertWithMessageText:@"ERROR: detected unrecoverable fault" defaultButton:@"Exit" alternateButton:@"Info" otherButton:nil informativeTextWithFormat:@"click 'Info' to help fix the issue!"];
//and show it
response = [fullScanAlert runModal];
//handle case where user clicks 'Info'
// ->take 'em to error page
if(0 == response)
{
//open page in browser
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://objective-see.com/errors.html"]];
}
//kill app
exit(0);
return;
}
//exception handler
// will be invoked for Obj-C exceptions
void exceptionHandler(NSException *exception)
{
//error msg
NSString* errMsg = nil;
//err msg
syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: OS version: %s /App version: %s", [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String], [getAppVersion() UTF8String]);
//create error msg
errMsg = [NSString stringWithFormat:@"unhandled obj-c exception caught [name: %@ / reason: %@]", [exception name], [exception reason]];
//err msg
syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s", [errMsg UTF8String]);
//err msg
syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s", [[[NSThread callStackSymbols] description] UTF8String]);
//main thread
// ->just show UI alert
if(YES == [NSThread isMainThread])
{
//show
showAlert();
}
//back thread
// ->have to show it on main thread
else
{
//show alert
// ->in main UI thread
dispatch_sync(dispatch_get_main_queue(), ^{
//show
showAlert();
});
}
return;
}
//handler for signals
// will be invoked for BSD/*nix signals
void signalHandler(int signal, siginfo_t *info, void *context)
{
//error msg
NSString* errMsg = nil;
//context
ucontext_t *uContext = NULL;
//err msg
syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: OS version: %s /App version: %s", [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String], [getAppVersion() UTF8String]);
//typecast context
uContext = (ucontext_t *)context;
//create error msg
errMsg = [NSString stringWithFormat:@"unhandled exception caught, si_signo: %d /si_code: %s /si_addr: %p /rip: %p",
info->si_signo, (info->si_code == SEGV_MAPERR) ? "SEGV_MAPERR" : "SEGV_ACCERR", info->si_addr, (unsigned long*)uContext->uc_mcontext->__ss.__rip];
//err msg
syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s", [errMsg UTF8String]);
//err msg
syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s", [[[NSThread callStackSymbols] description] UTF8String]);
//main thread
// ->just show UI alert
if(YES == [NSThread isMainThread])
{
//show
showAlert();
}
//back thread
// ->have to show it on main thread
else
{
//show alert
// ->in main UI thread
dispatch_sync(dispatch_get_main_queue(), ^{
//show
showAlert();
});
}
return;
}
+7 -4
View File
@@ -25,6 +25,8 @@
//white listed extensions
@property(nonatomic, retain)NSDictionary* trustedExtensions;
//white listed kexts
@property(nonatomic, retain)NSDictionary* trustedKexts;
/* METHODS */
@@ -32,15 +34,16 @@
// ->file hashes, known commands, etc
-(NSDictionary*)loadWhitelist:(NSString*)fileName;
//check if a File obj is whitelisted
//check if a File obj is white listed
-(BOOL)isTrustedFile:(File*)fileObj;
//check if a Command obj is whitelisted
//check if a Command obj is white listed
-(BOOL)isKnownCommand:(Command*)commandObj;
//check if a Extension obj is whitelisted
//check if a Extension obj is white listed
-(BOOL)isTrustedExtension:(Extension*)extensionObj;
//check if kext is white listed
-(BOOL)isTrustedKext:(File*)fileObj;
@end
+74 -9
View File
@@ -11,6 +11,7 @@
@implementation Filter
@synthesize trustedKexts;
@synthesize trustedFiles;
@synthesize knownCommands;
@synthesize trustedExtensions;
@@ -34,6 +35,9 @@
//load known extensions
self.trustedExtensions = [self loadWhitelist:WHITE_LISTED_EXTENSIONS];
//load known kexts
self.trustedKexts = [self loadWhitelist:WHITE_LISTED_KEXTS];
}
return self;
@@ -71,7 +75,7 @@
//check if a File obj is known
// ->whitelisted *or* signed by apple
-(BOOL)isTrustedFile:(File*)fileObj
-(BOOL)isTrustedFile:(File*)file
{
//flag
BOOL isTrusted = NO;
@@ -80,23 +84,37 @@
NSArray* knownHashes = nil;
//lookup based on name
knownHashes = self.trustedFiles[fileObj.path];
knownHashes = self.trustedFiles[file.path];
//first check if hash is known
//check if hash is known
if( (nil != knownHashes) &&
(YES == [knownHashes containsObject:[fileObj.hashes[KEY_HASH_MD5] lowercaseString]]) )
(YES == [knownHashes containsObject:[file.hashes[KEY_HASH_MD5] lowercaseString]]) )
{
//got match
isTrusted = YES;
//bail
goto bail;
}
//otherwise check if its signed by apple
// ->apple-signed files are always trusted
else
//if kext
// check if trusted (apple, or 3rd-party, ships with OS)
if( (YES == [file.path hasPrefix:@"/Library/Extensions/"]) ||
(YES == [file.path hasPrefix:@"/System/Library/Extensions/"]) )
{
//check for apple signature
isTrusted = [fileObj.signingInfo[KEY_SIGNING_IS_APPLE] boolValue];
//check
isTrusted = [self isTrustedKext:file];
//bail
goto bail;
}
//finally, then check if its signed by apple
// note: apple-signed files are always trusted
isTrusted = (Apple == [file.signingInfo[KEY_SIGNATURE_SIGNER] intValue]);
bail:
return isTrusted;
}
@@ -125,5 +143,52 @@
return isTrusted;
}
//check if a kext obj is known
// whitelisted *or* signed by apple
-(BOOL)isTrustedKext:(File*)file
{
//flag
BOOL isTrusted = NO;
//(trusted) signing id
// either list of hashes, or dev id
id whitelistInfo = nil;
//lookup based on name
whitelistInfo = self.trustedKexts[file.path];
//hashes?
if( (YES == [whitelistInfo isKindOfClass:[NSArray class]]) &&
(YES == [whitelistInfo containsObject:[file.hashes[KEY_HASH_MD5] lowercaseString]]) )
{
//got match
isTrusted = YES;
//bail
goto bail;
}
//dev id?
// note: these are only for kexts that ship with macOS!
if( (YES == [whitelistInfo isKindOfClass:[NSString class]]) &&
(YES == [[file.signingInfo[KEY_SIGNATURE_AUTHORITIES] lastObject] isEqualToString:@"Apple Root CA"]) &&
(YES == [file.signingInfo[KEY_SIGNATURE_AUTHORITIES] containsObject:whitelistInfo]) )
{
//got match
isTrusted = YES;
//bail
goto bail;
}
//check for apple signature
// kexts that belong to apple, are trusted
isTrusted = (Apple == [file.signingInfo[KEY_SIGNATURE_SIGNER] intValue]);
bail:
return isTrusted;
}
@end
+7 -2
View File
@@ -28,8 +28,13 @@
//super
[super windowDidLoad];
//make white
[self.window setBackgroundColor: NSColor.whiteColor];
//not in dark mode?
// make window white
if(YES != isDarkMode())
{
//make white
self.window.backgroundColor = NSColor.whiteColor;
}
return;
}
+9 -18
View File
@@ -69,37 +69,28 @@ NSString * const LAUNCHITEM_SEARCH_DIRECTORIES[] = {@"/System/Library/LaunchDaem
}
//generate list of all launch items (daemons & agents)
// ->save into iVar, 'launchItem'
-(void)enumerateLaunchItems
{
//all launch items
NSMutableArray* allLaunchItems = nil;
//number of search directories
NSUInteger directoryCount = 0;
//current launch item directory
NSString* launchItemDirectory = nil;
//all launch item directories, expanded
NSMutableArray* launchItemDirectories = nil;
//alloc array for all launch items
allLaunchItems = [NSMutableArray array];
//get number of search directories
directoryCount = sizeof(LAUNCHITEM_SEARCH_DIRECTORIES)/sizeof(LAUNCHITEM_SEARCH_DIRECTORIES[0]);
//expand list
launchItemDirectories = expandPaths(LAUNCHITEM_SEARCH_DIRECTORIES, sizeof(LAUNCHITEM_SEARCH_DIRECTORIES)/sizeof(LAUNCHITEM_SEARCH_DIRECTORIES[0]));
//iterate over all launch item directories
// ->cumulativelly save all launch items
for(NSUInteger i=0; i < directoryCount; i++)
//iterate over all launch item direcoties
// grab all .plists and add to cumulative array
for(NSString* launchItemDirectory in launchItemDirectories)
{
//extract current directory
launchItemDirectory = [LAUNCHITEM_SEARCH_DIRECTORIES[i] stringByExpandingTildeInPath];
//iterate over all launch item (plists) in current launch item directory
// ->build full path it launch item and save it into array
//grab all plist
for(NSString* plist in directoryContents(launchItemDirectory, @"self ENDSWITH '.plist'"))
{
//build full path to item/plist
// ->save it into array
//build full path to item/plist and save
[allLaunchItems addObject:[NSString stringWithFormat:@"%@/%@", launchItemDirectory, plist]];
}
}
+33 -44
View File
@@ -275,9 +275,8 @@
hasTrackingArea = YES;
}
//default
// ->set main textfield's color to black
itemCell.textField.textColor = [NSColor blackColor];
//default color
itemCell.textField.textColor = NSColor.controlTextColor;
//default
// ->hide plist label
@@ -400,14 +399,14 @@
vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[((File*)item).vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[((File*)item).vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
//known 'good' files (0 positivies)
// ->(re)set to black/gray
// ->(re)set colors
if(0 == [((File*)item).vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue])
{
//(re)set title black
itemCell.textField.textColor = [NSColor blackColor];
//(re)set title color
itemCell.textField.textColor = NSColor.controlTextColor;
//set color (black)
stringAttributes[NSForegroundColorAttributeName] = [NSColor blackColor];
//(re)set color
stringAttributes[NSForegroundColorAttributeName] = NSColor.controlTextColor;
//set string (vt ratio), with attributes
[vtButton setAttributedTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
@@ -489,7 +488,7 @@
customizedItemName = [[NSMutableAttributedString alloc] initWithString:@""];
//add existing name
// ->uses existing color (red or black)
// ->uses existing color
[customizedItemName appendAttributedString:[[NSMutableAttributedString alloc] initWithString:itemCell.textField.stringValue attributes:@{NSForegroundColorAttributeName:itemCell.textField.textColor}]];
//add '('
@@ -889,47 +888,37 @@ NSImage* getCodeSigningIcon(File* binary)
//signature image
NSImage* codeSignIcon = nil;
//set signature status icon
if(nil != binary.signingInfo)
{
//binary is signed by apple
if(YES == [binary.signingInfo[KEY_SIGNING_IS_APPLE] boolValue])
{
//set
codeSignIcon = [NSImage imageNamed:@"signedAppleIcon"];
}
//binary is signed
else if(STATUS_SUCCESS == [binary.signingInfo[KEY_SIGNATURE_STATUS] integerValue])
{
//set
codeSignIcon = [NSImage imageNamed:@"signed"];
}
//binary not signed
else if(errSecCSUnsigned == [binary.signingInfo[KEY_SIGNATURE_STATUS] integerValue])
{
//set
codeSignIcon = [NSImage imageNamed:@"unsigned"];
}
//unknown
else
{
//set
codeSignIcon = [NSImage imageNamed:@"unknown"];
}
}
//signing info is nil
// ->just to unknown
else
//no signing info or signing error
if( (nil == binary.signingInfo) ||
(nil == binary.signingInfo[KEY_SIGNATURE_STATUS]) ||
(errSecSuccess != [binary.signingInfo[KEY_SIGNATURE_STATUS] intValue]) )
{
//set
codeSignIcon = [NSImage imageNamed:@"unknown"];
}
//apple?
else if(Apple == [binary.signingInfo[KEY_SIGNATURE_SIGNER] intValue])
{
//set
codeSignIcon = [NSImage imageNamed:@"signedAppleIcon"];
}
//signed
else if(errSecSuccess == [binary.signingInfo[KEY_SIGNATURE_STATUS] intValue])
{
//set
codeSignIcon = [NSImage imageNamed:@"signed"];
}
//unsigned
else if(errSecCSUnsigned == [binary.signingInfo[KEY_SIGNATURE_STATUS] intValue])
{
//set
codeSignIcon = [NSImage imageNamed:@"unsigned"];
}
return codeSignIcon;
}
@end
+19 -5
View File
@@ -7,6 +7,7 @@
//
#import "KKRow.h"
#import "Utilities.h"
@implementation KKRow
@@ -25,14 +26,27 @@
//make selection rect
selectionRect = NSInsetRect(self.bounds, 2.5, 2.5);
//set stroke
[[NSColor colorWithCalibratedWhite:.65 alpha:1.0] setStroke];
//dark mode highlight
if(YES == isDarkMode())
{
//set stroke
[[NSColor colorWithCalibratedWhite:.25 alpha:1.0] setStroke];
//set fill
[[NSColor colorWithCalibratedWhite:.82 alpha:1.0] setFill];
//set fill
[[NSColor colorWithCalibratedWhite:.50 alpha:1.0] setFill];
}
//light mode highlight
else
{
//set stroke
[[NSColor colorWithCalibratedWhite:.65 alpha:1.0] setStroke];
//set fill
[[NSColor colorWithCalibratedWhite:.82 alpha:1.0] setFill];
}
//create selection path
// ->with rounded corners
// ...with rounded corners
selectionPath = [NSBezierPath bezierPathWithRoundedRect:selectionRect xRadius:5 yRadius:5];
//fill
+2 -2
View File
@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.9.3</string>
<string>2.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.9.3</string>
<string>2.0.0</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
+57 -17
View File
@@ -24,11 +24,13 @@
CD0219501AD34D8B005148A2 /* PrefsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD02194E1AD34D8B005148A2 /* PrefsWindow.xib */; };
CD0219531AD34D9A005148A2 /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD0219521AD34D9A005148A2 /* AboutWindowController.m */; };
CD0219551AD34E4C005148A2 /* kkIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD0219541AD34E4C005148A2 /* kkIcon.png */; };
CD02195C1AD38823005148A2 /* kkRowCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CD02195B1AD38823005148A2 /* kkRowCell.m */; };
CD02195E1AD39A74005148A2 /* ResultsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD02195D1AD39A74005148A2 /* ResultsWindow.xib */; };
CD0219611AD39A83005148A2 /* ResultsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD0219601AD39A83005148A2 /* ResultsWindowController.m */; };
CD24F074219D51210081B0E5 /* whitelistedKexts.json in Resources */ = {isa = PBXBuildFile; fileRef = CD24F073219D51210081B0E5 /* whitelistedKexts.json */; };
CD24F077219DF3DB0081B0E5 /* Signing.m in Sources */ = {isa = PBXBuildFile; fileRef = CD24F075219DF3DA0081B0E5 /* Signing.m */; };
CD2B613320675EEC00BF72E9 /* EventRules.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2B611220675EEB00BF72E9 /* EventRules.m */; };
CD2B61442067656200BF72E9 /* eventRulesIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD2B61432067656200BF72E9 /* eventRulesIcon.png */; };
CD585494219FE61D00A438B0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD585493219FE61D00A438B0 /* Assets.xcassets */; };
CD6095731A87067D00E091CD /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD6095721A87067D00E091CD /* Security.framework */; };
CD6975061B02F60400CE819B /* RFOverlayScroller.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6975031B02F60400CE819B /* RFOverlayScroller.m */; };
CD6975071B02F60400CE819B /* RFOverlayScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6975051B02F60400CE819B /* RFOverlayScrollView.m */; };
@@ -36,8 +38,9 @@
CD6BBBEB1B50DF7100506D0D /* signedAppleIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6BBBEA1B50DF7100506D0D /* signedAppleIcon.png */; };
CD6BBBED1B51C62B00506D0D /* unknown.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6BBBEC1B51C62B00506D0D /* unknown.png */; };
CD6BBBF01B52032D00506D0D /* NSApplicationKeyEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6BBBEF1B52032D00506D0D /* NSApplicationKeyEvents.m */; };
CD6DE4D1219E9AD30058094E /* Sentry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD6DE4D0219E9AD30058094E /* Sentry.framework */; };
CD6DE4D3219E9C560058094E /* Sentry.framework in Copy Framework(s) */ = {isa = PBXBuildFile; fileRef = CD6DE4D0219E9AD30058094E /* Sentry.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
CD7B9F4D1ACB959200DF3C71 /* logoAppleOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9F4C1ACB959200DF3C71 /* logoAppleOver.png */; };
CD7B9F501ACB9A8400DF3C71 /* Exception.m in Sources */ = {isa = PBXBuildFile; fileRef = CD7B9F4F1ACB9A8400DF3C71 /* Exception.m */; };
CD7B9F531ACBAE2900DF3C71 /* SpotlightImporters.m in Sources */ = {isa = PBXBuildFile; fileRef = CD7B9F521ACBAE2900DF3C71 /* SpotlightImporters.m */; };
CD7B9FA41ACBCFAD00DF3C71 /* spotlightIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9FA31ACBCFAD00DF3C71 /* spotlightIcon.png */; };
CD7B9FA71ACCAE5E00DF3C71 /* startScanOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9FA51ACCAE5E00DF3C71 /* startScanOver.png */; };
@@ -59,7 +62,6 @@
CDA81D701A95B4E9009790E2 /* stopScan.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D661A95B4E9009790E2 /* stopScan.png */; };
CDA81D711A95B4E9009790E2 /* stopScanBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D671A95B4E9009790E2 /* stopScanBG.png */; };
CDA81D721A95B4E9009790E2 /* virus.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D681A95B4E9009790E2 /* virus.png */; };
CDA81D741A95B4FB009790E2 /* icon.iconset in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D731A95B4FB009790E2 /* icon.iconset */; };
CDA81D771A95B7C1009790E2 /* CategoryTableController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA81D761A95B7C1009790E2 /* CategoryTableController.m */; };
CDA81D7B1A95D29B009790E2 /* ItemTableController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA81D7A1A95D29B009790E2 /* ItemTableController.m */; };
CDA81D8E1A96F557009790E2 /* Kexts.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA81D8B1A96F557009790E2 /* Kexts.m */; };
@@ -114,6 +116,20 @@
CDF08CF41ACA6864009B3423 /* loginIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CDF08CF21ACA6864009B3423 /* loginIcon.png */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
CD6DE4D2219E9C3A0058094E /* Copy Framework(s) */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
CD6DE4D3219E9C560058094E /* Sentry.framework in Copy Framework(s) */,
);
name = "Copy Framework(s)";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1D21BC4B172AF43D009D1CFD /* KnockKnock.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KnockKnock.app; sourceTree = BUILT_PRODUCTS_DIR; };
1D21BC4E172AF43D009D1CFD /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
@@ -142,14 +158,17 @@
CD0219511AD34D9A005148A2 /* AboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutWindowController.h; sourceTree = "<group>"; };
CD0219521AD34D9A005148A2 /* AboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboutWindowController.m; sourceTree = "<group>"; };
CD0219541AD34E4C005148A2 /* kkIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = kkIcon.png; path = images/kkIcon.png; sourceTree = SOURCE_ROOT; };
CD02195A1AD38823005148A2 /* kkRowCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kkRowCell.h; sourceTree = "<group>"; };
CD02195B1AD38823005148A2 /* kkRowCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = kkRowCell.m; sourceTree = "<group>"; };
CD02195D1AD39A74005148A2 /* ResultsWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ResultsWindow.xib; path = UI/ResultsWindow.xib; sourceTree = "<group>"; };
CD02195F1AD39A83005148A2 /* ResultsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultsWindowController.h; sourceTree = "<group>"; };
CD0219601AD39A83005148A2 /* ResultsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ResultsWindowController.m; sourceTree = "<group>"; };
CD24F072219AAC930081B0E5 /* main.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = SOURCE_ROOT; };
CD24F073219D51210081B0E5 /* whitelistedKexts.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = whitelistedKexts.json; path = WhiteList/whitelistedKexts.json; sourceTree = "<group>"; };
CD24F075219DF3DA0081B0E5 /* Signing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Signing.m; sourceTree = SOURCE_ROOT; };
CD24F076219DF3DB0081B0E5 /* Signing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Signing.h; sourceTree = SOURCE_ROOT; };
CD2B611220675EEB00BF72E9 /* EventRules.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EventRules.m; path = Plugins/EventRules.m; sourceTree = "<group>"; };
CD2B611320675EEB00BF72E9 /* EventRules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EventRules.h; path = Plugins/EventRules.h; sourceTree = "<group>"; };
CD2B61432067656200BF72E9 /* eventRulesIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = eventRulesIcon.png; path = images/eventRulesIcon.png; sourceTree = SOURCE_ROOT; };
CD585493219FE61D00A438B0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = SOURCE_ROOT; };
CD6095721A87067D00E091CD /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
CD6975021B02F60400CE819B /* RFOverlayScroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RFOverlayScroller.h; path = 3rdParty/RFOverlayScroller.h; sourceTree = "<group>"; };
CD6975031B02F60400CE819B /* RFOverlayScroller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RFOverlayScroller.m; path = 3rdParty/RFOverlayScroller.m; sourceTree = "<group>"; };
@@ -160,9 +179,8 @@
CD6BBBEC1B51C62B00506D0D /* unknown.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = unknown.png; path = images/unknown.png; sourceTree = SOURCE_ROOT; };
CD6BBBEE1B52032D00506D0D /* NSApplicationKeyEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSApplicationKeyEvents.h; sourceTree = "<group>"; };
CD6BBBEF1B52032D00506D0D /* NSApplicationKeyEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSApplicationKeyEvents.m; sourceTree = "<group>"; };
CD6DE4D0219E9AD30058094E /* Sentry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sentry.framework; path = Carthage/Build/Mac/Sentry.framework; sourceTree = "<group>"; };
CD7B9F4C1ACB959200DF3C71 /* logoAppleOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoAppleOver.png; path = images/logoAppleOver.png; sourceTree = SOURCE_ROOT; };
CD7B9F4E1ACB9A8400DF3C71 /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = SOURCE_ROOT; };
CD7B9F4F1ACB9A8400DF3C71 /* Exception.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Exception.m; sourceTree = SOURCE_ROOT; };
CD7B9F511ACBAE2900DF3C71 /* SpotlightImporters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SpotlightImporters.h; path = Plugins/SpotlightImporters.h; sourceTree = "<group>"; };
CD7B9F521ACBAE2900DF3C71 /* SpotlightImporters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SpotlightImporters.m; path = Plugins/SpotlightImporters.m; sourceTree = "<group>"; };
CD7B9FA31ACBCFAD00DF3C71 /* spotlightIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = spotlightIcon.png; path = images/spotlightIcon.png; sourceTree = SOURCE_ROOT; };
@@ -192,7 +210,6 @@
CDA81D661A95B4E9009790E2 /* stopScan.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopScan.png; path = images/stopScan.png; sourceTree = SOURCE_ROOT; };
CDA81D671A95B4E9009790E2 /* stopScanBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopScanBG.png; path = images/stopScanBG.png; sourceTree = SOURCE_ROOT; };
CDA81D681A95B4E9009790E2 /* virus.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = virus.png; path = images/virus.png; sourceTree = SOURCE_ROOT; };
CDA81D731A95B4FB009790E2 /* icon.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = icon.iconset; path = images/icon.iconset; sourceTree = SOURCE_ROOT; };
CDA81D751A95B7C1009790E2 /* CategoryTableController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CategoryTableController.h; sourceTree = "<group>"; };
CDA81D761A95B7C1009790E2 /* CategoryTableController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CategoryTableController.m; sourceTree = "<group>"; };
CDA81D791A95D29B009790E2 /* ItemTableController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ItemTableController.h; sourceTree = "<group>"; };
@@ -275,6 +292,7 @@
buildActionMask = 2147483647;
files = (
CDBE491A1B5B25E30031FC22 /* SystemConfiguration.framework in Frameworks */,
CD6DE4D1219E9AD30058094E /* Sentry.framework in Frameworks */,
CDDBC2301B04771100B021E0 /* ServiceManagement.framework in Frameworks */,
CDF08CEA1AC8D97B009B3423 /* Quartz.framework in Frameworks */,
CD6095731A87067D00E091CD /* Security.framework in Frameworks */,
@@ -292,8 +310,6 @@
CD6BBBEF1B52032D00506D0D /* NSApplicationKeyEvents.m */,
CDAB989A1AEAC95500C75B4B /* ItemEnumerator.h */,
CDAB989B1AEAC95500C75B4B /* ItemEnumerator.m */,
CD02195A1AD38823005148A2 /* kkRowCell.h */,
CD02195B1AD38823005148A2 /* kkRowCell.m */,
CD7B9FA91AD08FA100DF3C71 /* KKRow.h */,
CD7B9FAA1AD08FA100DF3C71 /* KKRow.m */,
CDF08CE31AC89FD4009B3423 /* 3rdParty */,
@@ -324,6 +340,7 @@
1D21BC4D172AF43D009D1CFD /* Frameworks */ = {
isa = PBXGroup;
children = (
CD6DE4D0219E9AD30058094E /* Sentry.framework */,
CDBE49191B5B25E30031FC22 /* SystemConfiguration.framework */,
CDDBC22F1B04771100B021E0 /* ServiceManagement.framework */,
CDF08CE91AC8D97B009B3423 /* Quartz.framework */,
@@ -347,21 +364,21 @@
1D21BC54172AF43D009D1CFD /* KnockKnock */ = {
isa = PBXGroup;
children = (
CD7B9F4E1ACB9A8400DF3C71 /* Exception.h */,
CD7B9F4F1ACB9A8400DF3C71 /* Exception.m */,
CDF08CC71AC4C678009B3423 /* PrefsWindowController.h */,
CDF08CC81AC4C678009B3423 /* PrefsWindowController.m */,
CDA81D731A95B4FB009790E2 /* icon.iconset */,
CDA81D561A95B4B4009790E2 /* MainMenu.xib */,
CDF08CC41AC46E75009B3423 /* VTButton.h */,
CDF08CC51AC46E75009B3423 /* VTButton.m */,
CDA81D441A95B492009790E2 /* AppDelegate.h */,
CDA81D451A95B492009790E2 /* AppDelegate.m */,
CDA81D481A95B492009790E2 /* Consts.h */,
CD24F076219DF3DB0081B0E5 /* Signing.h */,
CD24F075219DF3DA0081B0E5 /* Signing.m */,
CDA81D4D1A95B492009790E2 /* Utilities.h */,
CDA81D4E1A95B492009790E2 /* Utilities.m */,
CD6095501A8329FA00E091CD /* images */,
1D21BC55172AF43D009D1CFD /* Supporting Files */,
CD585493219FE61D00A438B0 /* Assets.xcassets */,
);
name = KnockKnock;
path = "Lesson 53";
@@ -374,6 +391,7 @@
CDA81D581A95B4B4009790E2 /* KnockKnock-Info.plist */,
CDA81D591A95B4B4009790E2 /* KnockKnock-Prefix.pch */,
CDA81D5A1A95B4B4009790E2 /* main.m */,
CD24F072219AAC930081B0E5 /* main.h */,
);
name = "Supporting Files";
sourceTree = "<group>";
@@ -506,6 +524,7 @@
CDA81DEF1A99B8B2009790E2 /* WhiteList */ = {
isa = PBXGroup;
children = (
CD24F073219D51210081B0E5 /* whitelistedKexts.json */,
CDA81DF01A99B8C2009790E2 /* whitelistedCommands.json */,
CDA81DF11A99B8C2009790E2 /* whitelistedExtensions.json */,
CDA81DF21A99B8C2009790E2 /* whitelistedFiles.json */,
@@ -558,6 +577,7 @@
1D21BC47172AF43D009D1CFD /* Sources */,
1D21BC48172AF43D009D1CFD /* Frameworks */,
1D21BC49172AF43D009D1CFD /* Resources */,
CD6DE4D2219E9C3A0058094E /* Copy Framework(s) */,
);
buildRules = (
);
@@ -574,7 +594,7 @@
1D21BC43172AF43D009D1CFD /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = "Objective-See";
TargetAttributes = {
1D21BC4A172AF43D009D1CFD = {
@@ -611,6 +631,7 @@
CD02195E1AD39A74005148A2 /* ResultsWindow.xib in Resources */,
CDA81D5B1A95B4B4009790E2 /* InfoPlist.strings in Resources */,
CDA81D6B1A95B4E9009790E2 /* show.png in Resources */,
CD24F074219D51210081B0E5 /* whitelistedKexts.json in Resources */,
CDF08CF31ACA6864009B3423 /* browserIcon.png in Resources */,
CDAB98A11AEAFAFA00C75B4B /* authorizationIcon.png in Resources */,
CD6BBBEB1B50DF7100506D0D /* signedAppleIcon.png in Resources */,
@@ -630,6 +651,7 @@
CD7B9F4D1ACB959200DF3C71 /* logoAppleOver.png in Resources */,
CDA81DCB1A9960A3009790E2 /* virusTotal.png in Resources */,
CDA81DF41A99B8C2009790E2 /* whitelistedExtensions.json in Resources */,
CD585494219FE61D00A438B0 /* Assets.xcassets in Resources */,
CDA81DD41A9970A0009790E2 /* unsigned.png in Resources */,
CD2B61442067656200BF72E9 /* eventRulesIcon.png in Resources */,
CD7B9FA71ACCAE5E00DF3C71 /* startScanOver.png in Resources */,
@@ -655,7 +677,6 @@
CDBE491F1B5B46040031FC22 /* logInOutIcon.png in Resources */,
CDA81D721A95B4E9009790E2 /* virus.png in Resources */,
CDA81DC91A9960A3009790E2 /* info.png in Resources */,
CDA81D741A95B4FB009790E2 /* icon.iconset in Resources */,
CDA81D6E1A95B4E9009790E2 /* startScan.png in Resources */,
CD02194F1AD34D8B005148A2 /* AboutWindow.xib in Resources */,
CDA81DCA1A9960A3009790E2 /* infoBG.png in Resources */,
@@ -687,7 +708,6 @@
CDA81E071A9AFFA7009790E2 /* LoginItems.m in Sources */,
CD2B613320675EEC00BF72E9 /* EventRules.m in Sources */,
CDA81DEA1A997BF1009790E2 /* InfoWindowController.m in Sources */,
CD02195C1AD38823005148A2 /* kkRowCell.m in Sources */,
CDA81E041A9AB89C009790E2 /* LaunchItems.m in Sources */,
CDF08CE61AC89FE1009B3423 /* HyperlinkTextField.m in Sources */,
CDA81E001A9A7D26009790E2 /* File.m in Sources */,
@@ -696,13 +716,13 @@
CDA81D5E1A95B4B4009790E2 /* main.m in Sources */,
7DE2FE2E1D3F30BE006C1438 /* Extensions.m in Sources */,
7DE29CA41CA7BC5600DFA6A6 /* StartupScripts.m in Sources */,
CD7B9F501ACB9A8400DF3C71 /* Exception.m in Sources */,
CD6975061B02F60400CE819B /* RFOverlayScroller.m in Sources */,
CDA81E0A1A9B0AD8009790E2 /* BrowserExtensions.m in Sources */,
CDD83FD41B50C48C0037124E /* Cronjobs.m in Sources */,
CDAB989F1AEADE5A00C75B4B /* DylibInserts.m in Sources */,
CDAB98991AEAA6CB00C75B4B /* AuthorizationPlugins.m in Sources */,
CDA81DFE1A9A7D26009790E2 /* Command.m in Sources */,
CD24F077219DF3DB0081B0E5 /* Signing.m in Sources */,
CD0219531AD34D9A005148A2 /* AboutWindowController.m in Sources */,
CDA81E011A9A7D26009790E2 /* ItemBase.m in Sources */,
CDA81DFF1A9A7D26009790E2 /* Extension.m in Sources */,
@@ -751,11 +771,13 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
@@ -799,11 +821,13 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
@@ -832,12 +856,20 @@
1D21BC69172AF43D009D1CFD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Developer ID Application";
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = VBG97UB4TA;
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KnockKnock-Prefix.pch";
INFOPLIST_FILE = "KnockKnock-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = KnockKnock;
WRAPPER_EXTENSION = app;
@@ -847,12 +879,20 @@
1D21BC6A172AF43D009D1CFD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Developer ID Application";
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = VBG97UB4TA;
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KnockKnock-Prefix.pch";
INFOPLIST_FILE = "KnockKnock-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = KnockKnock;
WRAPPER_EXTENSION = app;
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -20,11 +20,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Plugins/DylibProxies.m"
timestampString = "543929808.128709"
timestampString = "564302535.652194"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "148"
endingLineNumber = "148"
startingLineNumber = "189"
endingLineNumber = "189"
landmarkName = "-enumLoadedDylibs"
landmarkType = "7">
</BreakpointContent>
@@ -36,7 +36,7 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "ItemTableController.m"
timestampString = "543929808.129369"
timestampString = "564302535.652258"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "136"
@@ -52,7 +52,7 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "ItemTableController.m"
timestampString = "543929808.129438"
timestampString = "564302535.652302"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "251"
@@ -68,7 +68,7 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "ItemTableController.m"
timestampString = "543929808.129501"
timestampString = "564302535.652339"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "254"
@@ -77,5 +77,53 @@
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "ItemTableController.m"
timestampString = "564302535.652374"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "886"
endingLineNumber = "886"
landmarkName = "getCodeSigningIcon"
landmarkType = "9">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "kkRowCell.m"
timestampString = "564208966.188289"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "22"
endingLineNumber = "22"
landmarkName = "-setBackgroundStyle:"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "ResultsWindowController.m"
timestampString = "564298058.888056"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "32"
endingLineNumber = "32"
landmarkName = "-windowDidLoad"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@@ -46,7 +45,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
debugAsWhichUser = "root"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
@@ -63,6 +62,12 @@
ReferencedContainer = "container:KnockKnock.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-whosthere"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
+3 -17
View File
@@ -48,12 +48,7 @@ NSString* const AUTHORIZATION_SEARCH_DIRECTORIES[] = {@"/System/Library/CoreServ
//scan for auth plugins
-(void)scan
{
//auth plugin directory
NSString* authPluginDirectory = nil;
//number of search directories
NSUInteger directoryCount = 0;
//all auth plugins
NSArray* allAuthPlugins = nil;
@@ -63,19 +58,10 @@ NSString* const AUTHORIZATION_SEARCH_DIRECTORIES[] = {@"/System/Library/CoreServ
//File obj
File* fileObj = nil;
//dbg msg
//NSLog(@"%@: scanning", PLUGIN_NAME);
//get number of search directories
directoryCount = sizeof(AUTHORIZATION_SEARCH_DIRECTORIES)/sizeof(AUTHORIZATION_SEARCH_DIRECTORIES[0]);
//iterate over all auth plugin search directories
// ->get all authorization plugins and process each of them
for(NSUInteger i=0; i < directoryCount; i++)
// get all authorization plugins and process each of them
for(NSString* authPluginDirectory in expandPaths(AUTHORIZATION_SEARCH_DIRECTORIES, sizeof(AUTHORIZATION_SEARCH_DIRECTORIES)/sizeof(AUTHORIZATION_SEARCH_DIRECTORIES[0])))
{
//extract current directory
authPluginDirectory = [AUTHORIZATION_SEARCH_DIRECTORIES[i] stringByExpandingTildeInPath];
//get all items in current directory
allAuthPlugins = directoryContents(authPluginDirectory, nil);
+219 -171
View File
@@ -40,6 +40,7 @@
// ->chrome
#define CHROME_SECURE_PREFERENCES_FILE @"~/Library/Application Support/Google/Chrome/Default/Secure Preferences"
//plugin search directory
// ->firefox
#define FIREFOX_EXTENSION_DIRECTORY @"~/Library/Application Support/Firefox/Profiles/"
@@ -164,8 +165,8 @@
return browsers;
}
//scan for Safari extensions
// note: on Mojave+ this will just silently fail :(
-(void)scanExtensionsSafari:(NSString*)browserPath
{
//status
@@ -197,7 +198,7 @@
Extension* extensionObj = nil;
//query keychain to get safari extensions
status = SecKeychainFindGenericPassword (NULL, (UInt32)strlen(SAFARI_KEYCHAIN_SERVICE), SAFARI_KEYCHAIN_SERVICE, (UInt32)strlen(SAFARI_KEYCHAIN_ACCOUNT), SAFARI_KEYCHAIN_ACCOUNT, &keychainDataLength, &keychainData, &keychainItemRef);
status = SecKeychainFindGenericPassword(NULL, (UInt32)strlen(SAFARI_KEYCHAIN_SERVICE), SAFARI_KEYCHAIN_SERVICE, (UInt32)strlen(SAFARI_KEYCHAIN_ACCOUNT), SAFARI_KEYCHAIN_ACCOUNT, &keychainDataLength, &keychainData, &keychainItemRef);
//on success
// ->convert binary plist keychain data (extensions) into dictionary
@@ -217,18 +218,15 @@
}
//make sure extensions were found
// ->bail if nothing was found/parsed
// bail if nothing was found/parsed
if(nil == extensions)
{
//err msg
//NSLog(@"OBJECTIVE-SEE ERROR: querying keychain for Safari extensions failed with %d", status);
//bail
goto bail;
}
//iterate over all installed extensions
// ->save/report enabled ones
// save/report enabled ones
for(NSDictionary* extension in extensions[@"Installed Extensions"])
{
//alloc extension info
@@ -327,12 +325,18 @@ bail:
//scan for Chrome extensions
-(void)scanExtensionsChrome:(NSString*)browserPath
{
//all users
NSMutableDictionary* users = nil;
//preference files
NSMutableArray* preferenceFiles = nil;
//profile directories
NSArray* profiles = nil;
//(current) profile directory
NSString* profileDirectory = nil;
//preferences
NSDictionary* preferences = nil;
@@ -357,28 +361,52 @@ bail:
//alloc list for preference files
preferenceFiles = [NSMutableArray array];
//add default ('Preferences')
[preferenceFiles addObject:[CHROME_PREFERENCES_FILE stringByExpandingTildeInPath]];
//alloc users dictionary
users = [NSMutableDictionary dictionary];
//add default ('Secure Preferences')
[preferenceFiles addObject:[CHROME_SECURE_PREFERENCES_FILE stringByExpandingTildeInPath]];
//get profile dirs
// ->'Profile 1', etc...
profiles = directoryContents([CHROME_BASE_PROFILE_DIRECTORY stringByExpandingTildeInPath], @"self BEGINSWITH 'Profile'");
//build and append full paths of preferences files to list
for(NSString* profile in profiles)
//root?
// can scan all users
if(0 == geteuid())
{
//add default prefs
[preferenceFiles addObject:[NSString stringWithFormat:@"%@/%@/Preferences", [CHROME_BASE_PROFILE_DIRECTORY stringByExpandingTildeInPath], profile]];
//add secure prefs
[preferenceFiles addObject:[NSString stringWithFormat:@"%@/%@/Secure Preferences", [CHROME_BASE_PROFILE_DIRECTORY stringByExpandingTildeInPath], profile]];
//all
users = allUsers();
}
//just current user
else
{
//current
users[getConsoleUser()] = @{USER_NAME:getConsoleUser(), USER_DIRECTORY:NSHomeDirectoryForUser(getConsoleUser())};
}
//process all preference files
// ->load/parse/extract extensions
//get profile files for all users
for(NSString* userID in users)
{
//add default ('Preferences')
[preferenceFiles addObject:[users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[CHROME_PREFERENCES_FILE substringFromIndex:1]]];
//add default ('Secure Preferences')
[preferenceFiles addObject:[users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[CHROME_SECURE_PREFERENCES_FILE substringFromIndex:1]]];
//get profile dirs
// 'Profile 1', etc...
profiles = directoryContents([users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[CHROME_BASE_PROFILE_DIRECTORY substringFromIndex:1]], @"self BEGINSWITH 'Profile'");
//build and append full paths of preferences files to list
for(NSString* profile in profiles)
{
//init profile directory
profileDirectory = [users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[CHROME_BASE_PROFILE_DIRECTORY substringFromIndex:1]];
//add default prefs
[preferenceFiles addObject:[NSString stringWithFormat:@"%@/%@/Preferences", profileDirectory, profile]];
//add secure prefs
[preferenceFiles addObject:[NSString stringWithFormat:@"%@/%@/Secure Preferences", profileDirectory, profile]];
}
}
//now process all preference files
// load/parse/extract extensions from each file
for(NSString* preferenceFile in preferenceFiles)
{
//skip non-existent preference files
@@ -520,9 +548,12 @@ bail:
//scan for Firefox extensions
-(void)scanExtensionsFirefox:(NSString*)browserPath
{
//users
NSMutableDictionary* users = nil;
//Firefox profiles
NSArray* profiles = nil;
//path to extensions
NSString* extensionsFile = nil;
@@ -541,8 +572,7 @@ bail:
//extension path
NSMutableString* path = nil;
//extension info
//extension info
NSMutableDictionary* extensionInfo = nil;
//Extension object
@@ -551,186 +581,204 @@ bail:
//init extension IDs array
extensionIDs = [NSMutableArray array];
//get all profiles
profiles = directoryContents([FIREFOX_EXTENSION_DIRECTORY stringByExpandingTildeInPath], nil);
//alloc users dictionary
users = [NSMutableDictionary dictionary];
//iterate over all addons and extensions files in profile directories
//->extact all addons and extensions
for(NSString* profile in profiles)
//root?
// can scan all users
if(0 == geteuid())
{
//init extension files array
extensionFiles = [NSMutableArray array];
//init extension info dictionary
extensionInfo = [NSMutableDictionary dictionary];
//init path to first extensions (addons.json) file
extensionsFile = [NSString stringWithFormat:@"%@/%@/addons.json", [FIREFOX_EXTENSION_DIRECTORY stringByExpandingTildeInPath], profile];
//only add to list if it exists
if(YES == [[NSFileManager defaultManager] fileExistsAtPath:extensionsFile])
//all
users = allUsers();
}
//just current user
else
{
//current
users[getConsoleUser()] = @{USER_NAME:getConsoleUser(), USER_DIRECTORY:NSHomeDirectoryForUser(getConsoleUser())};
}
//get profile files for all users
for(NSString* userID in users)
{
//get user profiles
profiles = directoryContents([users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[FIREFOX_EXTENSION_DIRECTORY substringFromIndex:1]], nil);
//iterate over all addons and extensions files in profile directories
//->extact all addons and extensions
for(NSString* profile in profiles)
{
//save
[extensionFiles addObject:extensionsFile];
}
//init path to second extensions (extensions.json) file
extensionsFile = [NSString stringWithFormat:@"%@/%@/extensions.json", [FIREFOX_EXTENSION_DIRECTORY stringByExpandingTildeInPath], profile];
//only add to list if it exists
if(YES == [[NSFileManager defaultManager] fileExistsAtPath:extensionsFile])
{
//save
[extensionFiles addObject:extensionsFile];
}
//process both files
for(NSString* extensionFile in extensionFiles)
{
//load extensions
// ->wrap since we are serializing JSON
@try
//init extension files array
extensionFiles = [NSMutableArray array];
//init extension info dictionary
extensionInfo = [NSMutableDictionary dictionary];
//init path to first extensions (addons.json) file
extensionsFile = [NSString stringWithFormat:@"%@/%@/addons.json", [users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[FIREFOX_EXTENSION_DIRECTORY substringFromIndex:1]], profile];
if(YES == [[NSFileManager defaultManager] fileExistsAtPath:extensionsFile])
{
//load em
// ->extension files, under 'addons' key
extensions = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:extensionFile] options:kNilOptions error:NULL][@"addons"];
}
//catch any exceptions
// ->just try next
@catch(NSException *exception)
{
//next
continue;
//save
[extensionFiles addObject:extensionsFile];
}
//parse out all extensions
for(NSDictionary* extension in extensions)
//init path to second extensions (extensions.json) file
extensionsFile = [NSString stringWithFormat:@"%@/%@/extensions.json", [users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[FIREFOX_EXTENSION_DIRECTORY substringFromIndex:1]], profile];
if(YES == [[NSFileManager defaultManager] fileExistsAtPath:extensionsFile])
{
//ignore dups
if(YES == [extensionIDs containsObject:extension[@"id"]])
//save
[extensionFiles addObject:extensionsFile];
}
//process both files
for(NSString* extensionFile in extensionFiles)
{
//load extensions
// ->wrap since we are serializing JSON
@try
{
//skip
//load em
// ->extension files, under 'addons' key
extensions = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:extensionFile] options:kNilOptions error:NULL][@"addons"];
}
//catch any exceptions
// ->just try next
@catch(NSException *exception)
{
//next
continue;
}
//extract/save extension ID
extensionInfo[KEY_EXTENSION_ID] = extension[@"id"];
//extract/save path, name, details
// ->case: addons.json file
if(YES == [[extensionFile lastPathComponent] isEqualToString:@"addons.json"])
//parse out all extensions
for(NSDictionary* extension in extensions)
{
//extract path
path = [NSMutableString stringWithFormat:@"%@/extensions/%@.xpi", [extensionFile stringByDeletingLastPathComponent], extension[@"id"]];
//skip invalid/not found paths
if(YES != [[NSFileManager defaultManager] fileExistsAtPath:path])
//ignore dups
if(YES == [extensionIDs containsObject:extension[@"id"]])
{
//skip
continue;
}
//save path
extensionInfo[KEY_RESULT_PATH] = path;
//skip blank names
if(nil == extension[@"name"])
{
//skip
continue;
}
//extract/save extension ID
extensionInfo[KEY_EXTENSION_ID] = extension[@"id"];
//extract/save name
extensionInfo[KEY_RESULT_NAME] = extension[@"name"];
//extract/save details
if(nil != extension[@"description"])
//extract/save path, name, details
// ->case: addons.json file
if(YES == [[extensionFile lastPathComponent] isEqualToString:@"addons.json"])
{
//save
extensionInfo[KEY_EXTENSION_DETAILS] = extension[@"description"];
}
}
//extract/save path, name, details
// ->case: extensions.json file
else
{
//extract path
path = [NSMutableString stringWithFormat:@"%@/extensions/%@", [extensionFile stringByDeletingLastPathComponent], extension[@"id"]];
//skip invalid/not found paths
// ->note: also checks for extensions that end in .xpi (to account for newer versions of firefox)
if(YES != [[NSFileManager defaultManager] fileExistsAtPath:path])
{
//create .xpi version
[path appendString:@".xpi"];
//extract path
path = [NSMutableString stringWithFormat:@"%@/extensions/%@.xpi", [extensionFile stringByDeletingLastPathComponent], extension[@"id"]];
//check this variation too
//skip invalid/not found paths
if(YES != [[NSFileManager defaultManager] fileExistsAtPath:path])
{
//skip
continue;
}
//save path
extensionInfo[KEY_RESULT_PATH] = path;
//skip blank names
if(nil == extension[@"name"])
{
//skip
continue;
}
//extract/save name
extensionInfo[KEY_RESULT_NAME] = extension[@"name"];
//extract/save details
if(nil != extension[@"description"])
{
//save
extensionInfo[KEY_EXTENSION_DETAILS] = extension[@"description"];
}
}
//extract/save path, name, details
// ->case: extensions.json file
else
{
//extract path
path = [NSMutableString stringWithFormat:@"%@/extensions/%@", [extensionFile stringByDeletingLastPathComponent], extension[@"id"]];
//skip invalid/not found paths
// ->note: also checks for extensions that end in .xpi (to account for newer versions of firefox)
if(YES != [[NSFileManager defaultManager] fileExistsAtPath:path])
{
//create .xpi version
[path appendString:@".xpi"];
//check this variation too
if(YES != [[NSFileManager defaultManager] fileExistsAtPath:path])
{
//skip
continue;
}
}
//save path
extensionInfo[KEY_RESULT_PATH] = path;
//extract default locale
defaultLocale = extension[@"defaultLocale"];
//skip nil defaultLocales
if(nil == defaultLocale)
{
//skip
continue;
}
//skip blank names
if(nil == defaultLocale[@"name"])
{
//skip
continue;
}
//extract/save name
extensionInfo[KEY_RESULT_NAME] = defaultLocale[@"name"];
//extract/save details
if(nil != defaultLocale[@"description"])
{
//save
extensionInfo[KEY_EXTENSION_DETAILS] = defaultLocale[@"description"];
}
}
//save path
extensionInfo[KEY_RESULT_PATH] = path;
//save extension ID
// ->prevents dups (since multiple files are being parsed)
[extensionIDs addObject:extensionInfo[KEY_EXTENSION_ID]];
//extract default locale
defaultLocale = extension[@"defaultLocale"];
//save browser path (i.e. Firefox)
extensionInfo[KEY_EXTENSION_BROWSER] = browserPath;
//skip nil defaultLocales
if(nil == defaultLocale)
//save plugin
extensionInfo[KEY_RESULT_PLUGIN] = self;
//create Extension object for launch item
// ->skip those that err out for any reason
if(nil == (extensionObj = [[Extension alloc] initWithParams:extensionInfo]))
{
//skip
continue;
}
//skip blank names
if(nil == defaultLocale[@"name"])
{
//skip
continue;
}
//process item
// ->save and report to UI
[super processItem:extensionObj];
//extract/save name
extensionInfo[KEY_RESULT_NAME] = defaultLocale[@"name"];
//extract/save details
if(nil != defaultLocale[@"description"])
{
//save
extensionInfo[KEY_EXTENSION_DETAILS] = defaultLocale[@"description"];
}
}
}//for all extension in file
//save extension ID
// ->prevents dups (since multiple files are being parsed)
[extensionIDs addObject:extensionInfo[KEY_EXTENSION_ID]];
//save browser path (i.e. Firefox)
extensionInfo[KEY_EXTENSION_BROWSER] = browserPath;
//save plugin
extensionInfo[KEY_RESULT_PLUGIN] = self;
//create Extension object for launch item
// ->skip those that err out for any reason
if(nil == (extensionObj = [[Extension alloc] initWithParams:extensionInfo]))
{
//skip
continue;
}
//process item
// ->save and report to UI
[super processItem:extensionObj];
}//for all extension in file
}//for all extension files
}//for all profiles
}//for all extension files
}//for all profiles
}//for all users
return;
}
+62 -23
View File
@@ -21,7 +21,7 @@
@implementation CronJobs
//init
// ->set name, description, etc
// set name, description, etc
-(id)init
{
//super
@@ -47,32 +47,72 @@
//output from crontab
NSData* taskOutput = nil;
//cron file
// for now, just current user's
NSString* cronFile = nil;
//root?
// scan all user's cron jobs
if(0 == geteuid())
{
//get all users
for(NSString* user in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:CRON_FILES_DIRECTORY error:nil])
{
//path
cronFile = [NSString stringWithFormat:@"%@/%@", CRON_FILES_DIRECTORY, user];
//exec cron
// pass in user
taskOutput = execTask(CRONTAB, @[@"-l", @"-u", user]);
if( (nil == taskOutput) ||
(0 == taskOutput.length) )
{
//skip
continue;
}
//process
[self processJobs:taskOutput path:cronFile];
}
}
//no root
// only scan current user's
else
{
//init cron file to current user
cronFile = [NSString stringWithFormat:@"%@/%@", CRON_FILES_DIRECTORY, NSUserName()];
//exec cron
// just for current user
taskOutput = execTask(CRONTAB, @[@"-l"]);
if( (nil == taskOutput) ||
(0 == taskOutput.length) )
{
//bail
goto bail;
}
//process
[self processJobs:taskOutput path:cronFile];
}
bail:
return;
}
//parse/process cron jobs
-(void)processJobs:(NSData*)output path:(NSString*)path
{
//converted to string
NSString* cronJobs = nil;
//cron file
// ->for now, just current user's
NSString* cronFile = nil;
//Command obj
Command* commandObj = nil;
//init cron file
// ->for now, just path to current users & only used for path of command (not directly read, etc)
cronFile = [NSString stringWithFormat:@"%@/%@", CRON_FILES_DIRECTORY, NSUserName()];
//exec cron
// ->just for current user
taskOutput = execTask(CRONTAB, @[@"-l"]);
if( (nil == taskOutput) ||
(0 == taskOutput.length) )
{
//bail
goto bail;
}
//convert to (trimmed) string
cronJobs = [[[NSString alloc] initWithData:taskOutput encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cronJobs = [[[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//sanity check
// ->skip blank results
@@ -82,7 +122,7 @@
//bail
goto bail;
}
//create Command obj for each
// ->and call back up into UI to add
for(NSString* cronJob in [cronJobs componentsSeparatedByString:@"\n"])
@@ -96,7 +136,7 @@
}
//create Command object for job
commandObj = [[Command alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_COMMAND:cronJob, KEY_RESULT_PATH:cronFile}];
commandObj = [[Command alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_COMMAND:cronJob, KEY_RESULT_PATH:path}];
//skip Command objects that err'd out for any reason
if(nil == commandObj)
@@ -110,7 +150,6 @@
[super processItem:commandObj];
}
//bail
bail:
return;
+6
View File
@@ -10,6 +10,12 @@
#import "PluginBase.h"
/* GLOBALS */
//shared enumerator
extern ItemEnumerator* sharedItemEnumerator;
@interface DylibInserts : PluginBase
{
+2 -2
View File
@@ -111,7 +111,7 @@
//try grab launch items
// ->will only !nil, when enumeration is complete
launchItems = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).sharedItemEnumerator.launchItems;
launchItems = sharedItemEnumerator.launchItems;
//keep trying until we get em!
} while(nil == launchItems);
@@ -223,7 +223,7 @@
//try grab installed apps
// ->will only !nil, when enumeration is complete
installedApps = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).sharedItemEnumerator.applications;
installedApps = sharedItemEnumerator.applications;
//exit loop once we have apps
if(nil != installedApps)
+45 -4
View File
@@ -17,6 +17,9 @@
//plugin icon
#define PLUGIN_ICON @"proxyIcon"
//(privacy) protected directories
NSString * const PROTECTED_DIRECTORIES[] = {@"~/Library/Application Support/AddressBook", @"~/Library/Calendars", @"~/Pictures", @"~/Library/Mail", @"~/Library/Messages", @"~/Library/Safari", @"~/Library/Cookies", @"~/Library/HomeKit", @"~/Library/IdentityServices", @"~/Library/Metadata/CoreSpotlight", @"~/Library/PersonalizationPortrait", @"~/Library/Suggestions"};
@implementation DylibProxies
//init
@@ -74,13 +77,23 @@
//file path
NSString* filePath = nil;
//(privacy) protected directories
NSArray* protectedDirectories = nil;
//flag
BOOL isProtected = NO;
//pool
@autoreleasepool
{
//alloc array
dylibs = [NSMutableArray array];
//init set of (privacy) protected directories
// these will be skipped, as otherwise we will generate a privacy prompt
protectedDirectories = expandPaths(PROTECTED_DIRECTORIES, sizeof(PROTECTED_DIRECTORIES)/sizeof(PROTECTED_DIRECTORIES[0]));
//exec 'file' to get file type
results = execTask(LSOF, @[@"-Fn", @"/"]);
if( (nil == results) ||
@@ -102,9 +115,12 @@
}
//iterate over all results
// ->make file info dictionary for files (not sockets, etc)
// make file info dictionary for files (not sockets, etc)
for(NSString* result in splitResults)
{
//reset
isProtected = NO;
//skip any odd/weird/short lines
// lsof outpupt will be in format: 'n<filePath'>
if( (YES != [result hasPrefix:@"n"]) ||
@@ -115,12 +131,37 @@
}
//init file path
// ->result, minus first (lsof-added) char
// result, minus first (lsof-added) char
filePath = [result substringFromIndex:0x1];
//skip any files in (privacy) protected directories
// as otherwise we will generate a privacy prompt (on Mojave)
for(NSString* directory in protectedDirectories)
{
//reset
isProtected = NO;
//check
if(YES == [filePath hasPrefix:directory])
{
//set flag
isProtected = YES;
//done
break;
}
}
//skip (privacy) protected files
if(YES == isProtected)
{
//skip
continue;
}
//skip 'non files' / non-executable files
if( (YES != [[NSFileManager defaultManager] fileExistsAtPath:filePath]) ||
(YES != isURLExecutable([NSURL fileURLWithPath:filePath])) )
(YES != isExecutable(filePath)) )
{
//skip
continue;
+2 -1
View File
@@ -3,6 +3,7 @@
// KnockKnock
//
// Notes: view via these via System Preferences->Extensions, or pluginkit -vmA
// only for current user, since we utilized 'pluginkit' which is "for current user"
#import "File.h"
#import "Utilities.h"
@@ -69,7 +70,7 @@
[extensions addObjectsFromArray:[self parseExtensions:[[[NSString alloc] initWithData:taskOutput encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]];
//load finder syncs from plist
finderSyncs = [NSDictionary dictionaryWithContentsOfFile:[FINDER_SYNCS stringByExpandingTildeInPath]];
finderSyncs = [NSDictionary dictionaryWithContentsOfFile:[NSHomeDirectoryForUser(getConsoleUser()) stringByAppendingPathComponent:[FINDER_SYNCS substringFromIndex:1]]];
if( (nil == finderSyncs) ||
(nil == finderSyncs[@"displayOrder"]) )
{
+6
View File
@@ -10,6 +10,12 @@
#import "PluginBase.h"
/* GLOBALS */
//shared enumerator
extern ItemEnumerator* sharedItemEnumerator;
@interface LaunchItems : PluginBase
{
+1 -1
View File
@@ -77,7 +77,7 @@
//try grab launch items
// ->will only !nil, when enumeration is complete
launchItems = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).sharedItemEnumerator.launchItems;
launchItems = sharedItemEnumerator.launchItems;
//keep trying until we get em!
} while(nil == launchItems);
+1 -14
View File
@@ -52,25 +52,13 @@ NSString* const HOOK_SEARCH_FILES[] = {@"/Library/Preferences/com.apple.loginwin
//scan for login items
-(void)scan
{
//number of search directories
NSUInteger fileCount = 0;
//login window plist
NSString* loginWindowPlist = nil;
//plist data
NSDictionary* plistContents = nil;
//get number of login/out files
fileCount = sizeof(HOOK_SEARCH_FILES)/sizeof(HOOK_SEARCH_FILES[0]);
//iterate over all login/out file
// ->get all hooks and process em
for(NSUInteger i=0; i < fileCount; i++)
for(NSString* loginWindowPlist in expandPaths(HOOK_SEARCH_FILES, sizeof(HOOK_SEARCH_FILES)/sizeof(HOOK_SEARCH_FILES[0])))
{
//extract current file
loginWindowPlist = [HOOK_SEARCH_FILES[i] stringByExpandingTildeInPath];
//load plist contents
plistContents = [NSDictionary dictionaryWithContentsOfFile:loginWindowPlist];
@@ -89,7 +77,6 @@ NSString* const HOOK_SEARCH_FILES[] = {@"/Library/Preferences/com.apple.loginwin
}
}
//bail
bail:
return;
-5
View File
@@ -16,10 +16,6 @@
/* PROPERTIES */
//all enabled jobs
// ->includes (sandboxed) login items
@property(nonatomic, retain) NSMutableArray* enabledJobs;
/* (custom) METHODS */
//enumerate traditional login items
@@ -30,5 +26,4 @@
// ->scan /Applications for 'Contents/Library/LoginItems/' and xref w/ launchd jobs
-(NSMutableArray*)enumSandboxItems;
@end
+297 -55
View File
@@ -18,9 +18,13 @@
//plugin icon
#define PLUGIN_ICON @"loginIcon"
@implementation LoginItems
//plist (old)
#define LOGIN_ITEM_PLIST_OLD @"~/Library/Preferences/com.apple.loginitems.plist"
@synthesize enabledJobs;
//plist (new)
#define LOGIN_ITEM_PLIST_NEW @"~/Library/Application Support/com.apple.backgroundtaskmanagementagent/backgrounditems.btm"
@implementation LoginItems
//init
// ->set name, description, etc
@@ -30,9 +34,6 @@
self = [super init];
if(self)
{
//alloc array for enabled jobs
enabledJobs = [NSMutableArray array];
//set name
self.name = PLUGIN_NAME;
@@ -49,9 +50,6 @@
//scan for login items
-(void)scan
{
//all jobs
NSArray* jobs = nil;
//detected (auto-started) login item
File* fileObj = nil;
@@ -59,32 +57,9 @@
//NSLog(@"%@: scanning", PLUGIN_NAME);
//login items
// ->both traditional and sandboxed
// both traditional and sandboxed
NSMutableArray* loginItems = nil;
//reset enabled jobs
[self.enabledJobs removeAllObjects];
//get all jobs
// ->includes all enabled (sandboxed) login items, even if not running :)
jobs = (__bridge NSArray *)SMCopyAllJobDictionaries(kSMDomainUserLaunchd);
//build list of enabled jobs
// ->save their bundle IDs
for(NSDictionary* job in jobs)
{
//skip non-enabled jobs or jobs w/o bundles ids
if( (YES != [[job objectForKey:@"OnDemand"] boolValue]) ||
(nil == [job objectForKey:@"Label"]) )
{
//next
continue;
}
//save enabled job
[enabledJobs addObject:[job objectForKey:@"Label"]];
}
//first get traditional items
loginItems = [self enumTraditionalItems];
@@ -94,13 +69,11 @@
//remove any duplicates
loginItems = [[[NSSet setWithArray:loginItems] allObjects] mutableCopy];
//enum and create traditional login items
//process all
for(NSString* loginItem in loginItems)
{
//create File object for login item
fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:loginItem}];
//skip File objects that err'd out for any reason
if(nil == fileObj)
{
//skip
@@ -108,18 +81,15 @@
}
//process item
// ->save and report to UI
// save and report to UI
[super processItem:fileObj];
}
//release jobs
CFRelease((CFArrayRef)jobs);
return;
}
//enumerate traditional login items
// ->basically just invoke LSSharedFileListCopySnapshot(), etc to get list of items
// invoke LSSharedFileListCopySnapshot(), etc to get list of items
-(NSMutableArray*)enumTraditionalItems
{
//(traditional) login items
@@ -132,7 +102,7 @@
CFArrayRef loginItems = nil;
//seed
// ->needed for 'LSSharedFileListCopySnapshot' function
// needed for 'LSSharedFileListCopySnapshot' function
UInt32 snapshotSeed = 0;
//login item reference
@@ -151,7 +121,7 @@
loginItems = LSSharedFileListCopySnapshot(sharedListRef, &snapshotSeed);
//iterate over all items
// ->extract path, init File obj, and report to UI
// extracting path for each
for(id item in (__bridge NSArray *)loginItems)
{
//type-cast
@@ -181,8 +151,277 @@
return traditionalItems;
}
//extract login items from alias data
// older versions of OSX use this format...
-(NSMutableDictionary*)extractFromAlias:(NSDictionary*)data
{
//login items
NSMutableDictionary* loginItems = nil;
//init
loginItems = [NSMutableDictionary dictionary];
//name
NSString* name = nil;
//alias
NSData* alias = nil;
//bookmark
CFDataRef bookmark = NULL;
//bookmark url
CFURLRef url = NULL;
//path
NSString* path = nil;
//extract current login items
for(NSDictionary* loginItem in data[@"SessionItems"][@"CustomListItems"])
{
//extract alias
alias = loginItem[@"Alias"];
if(nil == alias)
{
//skip
continue;
}
//create bookmark
bookmark = CFURLCreateBookmarkDataFromAliasRecord(kCFAllocatorDefault,(__bridge CFDataRef)(alias));
if(NULL == bookmark)
{
//skip
continue;
}
//resolve bookmark data into URL
url = CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, bookmark, kCFBookmarkResolutionWithoutUIMask, nil, nil, nil, nil);
//now release bookmark
CFRelease(bookmark);
//sanity check
if(nil == url)
{
//skip
continue;
}
//extract path
path = CFBridgingRelease(CFURLCopyPath(url));
//now release url
CFRelease(url);
//sanity check
if(nil == path)
{
//skip
continue;
}
//use name from app bundle
// otherwise from 'NSURLNameKey'
name = [NSBundle bundleWithPath:path].infoDictionary[@"CFBundleName"];
if(0 == name.length)
{
//extract name
name = loginItem[@"Name"];
}
//sanity check
if(nil == name)
{
//skip
continue;
}
//add
// key: path
// value: name
loginItems[path] = name;
}
return loginItems;
}
//extract login items from bookmark data
// newer versions of macOS use this format...
-(NSMutableDictionary*)extractFromBookmark:(NSDictionary*)data
{
//login items
NSMutableDictionary* loginItems = nil;
//init
loginItems = [NSMutableDictionary dictionary];
//bookmark data
NSData* bookmark = nil;
//bookmark properties
NSDictionary* properties = nil;
//name
NSString* name = nil;
//path
NSString* path = nil;
//extract current login items
for(id object in data[@"$objects"])
{
//reset
bookmark = nil;
//straight data?
if(YES == [object isKindOfClass:[NSData class]])
{
//assign
bookmark = object;
}
//dictionary w/ data?
if(YES == [object isKindOfClass:[NSDictionary class]])
{
//extract bookmark data
bookmark = [object objectForKey:@"NS.data"];
}
//no data?
if(nil == bookmark)
{
//skip
continue;
}
//extact properties
// 'resourceValuesForKeys' returns a dictionary, but we want the 'NSURLBookmarkAllPropertiesKey' dictionary inside that
properties = [NSURL resourceValuesForKeys:@[@"NSURLBookmarkAllPropertiesKey"] fromBookmarkData:bookmark][@"NSURLBookmarkAllPropertiesKey"];
if(nil == properties)
{
//skip
continue;
}
//extract path
path = properties[@"_NSURLPathKey"];
//use name from app bundle
// otherwise from 'NSURLNameKey'
name = [NSBundle bundleWithPath:path].infoDictionary[@"CFBundleName"];
if(0 == name.length)
{
//extract name
name = properties[@"NSURLNameKey"];
}
//skip any issues
if( (nil == name) ||
(nil == path) )
{
//skip
continue;
}
//add
// key: path
// value: name
loginItems[path] = name;
}
return loginItems;
}
//enumerate registered login items
-(NSMutableDictionary*)enumRegisteredItems
{
//flag
BOOL bookmarkFormat = NO;
//plist file
NSString* plist = nil;
//plist data
NSDictionary* plistData = nil;
//users
NSMutableDictionary* users = nil;
//registered items
NSMutableDictionary* registeredItems = nil;
//alloc registered login items
registeredItems = [NSMutableDictionary dictionary];
//alloc users dictionary
users = [NSMutableDictionary dictionary];
//set flag
// pre-10.13, did not use bookmark format
bookmarkFormat = (13 < getVersion(gestaltSystemVersionMinor));
//root?
// can scan all users
if(0 == geteuid())
{
//all
users = allUsers();
}
//just current user
else
{
//current
users[getConsoleUser()] = @{USER_NAME:getConsoleUser(), USER_DIRECTORY:NSHomeDirectoryForUser(getConsoleUser())};
}
//process all plists
for(NSString* userID in users)
{
//new format?
// use new plist
if(YES == bookmarkFormat)
{
//new plist
plist = [users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[LOGIN_ITEM_PLIST_NEW substringFromIndex:1]];
//load plist data
plistData = [NSDictionary dictionaryWithContentsOfFile:plist];
if(0 == plistData.count)
{
//skip
continue;
}
//extract login items
[registeredItems addEntriesFromDictionary:[self extractFromBookmark:plistData]];
}
//old format
// use old plist
else
{
//old plist
plist = [users[userID][USER_DIRECTORY] stringByAppendingPathComponent:[LOGIN_ITEM_PLIST_OLD substringFromIndex:1]];
//load plist data
plistData = [NSDictionary dictionaryWithContentsOfFile:plist];
if(0 == plistData.count)
{
//skip
continue;
}
//extract login items
[registeredItems addEntriesFromDictionary:[self extractFromAlias:plistData]];
}
}
return registeredItems;
}
//enumerate sandboxed (app) login items
// ->scan /Applications for 'Contents/Library/LoginItems/' and xref w/ launchd jobs
// scan /Applications for 'Contents/Library/LoginItems/' and xref w/ those in various plists jobs
-(NSMutableArray*)enumSandboxItems
{
//(sandbox) login items
@@ -194,6 +433,10 @@
//path to (sandboxed) login item directory
NSString* loginItemDir = nil;
//registered items
// extracted from various plists
NSMutableDictionary* registeredItems = nil;
//candidate login items
NSArray* candidateItems = nil;
@@ -203,6 +446,9 @@
//alloc array
sandboxItems = [NSMutableArray array];
//generate list of registered items
registeredItems = [self enumRegisteredItems];
//get all installed applications
applications = [[NSFileManager defaultManager] directoryContentsAtPath:@"/Applications"];
@@ -211,8 +457,6 @@
{
//init path to possible (sandboxed) login item dir
loginItemDir = [NSString stringWithFormat:@"/Applications/%@/Contents/Library/LoginItems/", application];
//skip if app doesn't have any login items
if(YES != [[NSFileManager defaultManager] fileExistsAtPath:loginItemDir])
{
//next
@@ -220,18 +464,16 @@
}
//get all app's login items
// ->these should (each) be apps/bundles themselves
// these should (each) be apps/bundles themselves
candidateItems = [[NSFileManager defaultManager] directoryContentsAtPath:loginItemDir];
//process app's candidate login items
// ->get bundle, path, and bundle id
// then check to make sure there is a job that matches!
// get bundle, path, and bundle id
// then check to make sure there is a registered item that matches!
for(NSString* candidateItem in candidateItems)
{
//get bundle for candidate login item
candidateItemBundle = [NSBundle bundleWithPath:[NSString stringWithFormat:@"%@/%@", loginItemDir, candidateItem]];
//skip ones that don't have bundles, binary paths, etc
if( (nil == candidateItemBundle) ||
(nil == candidateItemBundle.executablePath) )
{
@@ -239,15 +481,15 @@
continue;
}
//skip items that aren't enabled
if(YES != [self.enabledJobs containsObject:candidateItemBundle.bundleIdentifier])
//skip if does match any registered items
if(nil == registeredItems[candidateItemBundle.bundlePath])
{
//next
//skip
continue;
}
//save (sandboxed) login item
[sandboxItems addObject:candidateItemBundle.executablePath];
[sandboxItems addObject:candidateItemBundle.bundlePath];
}//app's login item(s)
+4 -10
View File
@@ -50,9 +50,6 @@ NSString* const PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[] = {@"/etc/periodic/daily",
//scan for periodic scripts
-(void)scan
{
//periodic scripts directory
NSString* periodScriptDirectory = nil;
//number of search directories
NSUInteger directoryCount = 0;
@@ -69,7 +66,7 @@ NSString* const PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[] = {@"/etc/periodic/daily",
directoryCount = sizeof(PERIODIC_SCRIPTS_SEARCH_DIRECTORIES)/sizeof(PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[0]);
//always a period script config file
// ->its executed by each period script, so should be reported
// its executed by each period script, so should be reported
fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:PERIOD_CONFIG}];
if(nil != fileObj)
{
@@ -79,21 +76,18 @@ NSString* const PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[] = {@"/etc/periodic/daily",
}
//iterate over all script directories
// ->get all script files and process them
// get all script files and process them
for(NSUInteger i=0; i < directoryCount; i++)
{
//extract current directory
periodScriptDirectory = [PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[i] stringByExpandingTildeInPath];
//get all items in current directory
allPeriodicScripts = directoryContents(periodScriptDirectory, nil);
allPeriodicScripts = directoryContents(PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[i], nil);
//iterate over all importers
// ->perform some sanity checks and then save
for(NSString* periodicScript in allPeriodicScripts)
{
//build full path to script
periodScriptPathPath = [NSString stringWithFormat:@"%@/%@", periodScriptDirectory, periodicScript];
periodScriptPathPath = [NSString stringWithFormat:@"%@/%@", PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[i], periodicScript];
//create File object for script
fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:periodScriptPathPath}];
+3 -4
View File
@@ -15,6 +15,9 @@
}
//callback
@property(copy, nonatomic) void (^callback)(ItemBase*);
//name
@property(retain, nonatomic)NSString* name;
@@ -46,8 +49,4 @@
// ->save and report (if necessary)
-(void)processItem:(ItemBase*)item;
@end
+8 -4
View File
@@ -75,7 +75,7 @@
//process and item
// ->save and report (if necessary)
// save and report (if necessary)
-(void)processItem:(ItemBase*)item
{
//exit if scanner (self) thread was cancelled
@@ -107,8 +107,12 @@
}
}
//report it to the UI
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) itemFound:item];
//invoke callback
if(nil != self.callback)
{
//invoke
self.callback(item);
}
return;
}
@@ -129,4 +133,4 @@
return;
}
@end
@end
+2 -14
View File
@@ -46,12 +46,6 @@ NSString * const SPOTLIGHT_SEARCH_DIRECTORIES[] = {@"/System/Library/Spotlight",
//scan for spotlight importers
-(void)scan
{
//spotlight importer directory
NSString* importerDirectory = nil;
//number of search directories
NSUInteger directoryCount = 0;
//all spotlight importers
NSArray* allImporters = nil;
@@ -64,16 +58,10 @@ NSString * const SPOTLIGHT_SEARCH_DIRECTORIES[] = {@"/System/Library/Spotlight",
//dbg msg
//NSLog(@"%@: scanning", PLUGIN_NAME);
//get number of search directories
directoryCount = sizeof(SPOTLIGHT_SEARCH_DIRECTORIES)/sizeof(SPOTLIGHT_SEARCH_DIRECTORIES[0]);
//iterate over all spotlight importer search directories
// ->get all spotlight importer bundles and process each of them
for(NSUInteger i=0; i < directoryCount; i++)
// get all spotlight importer bundles and process each of them
for(NSString* importerDirectory in expandPaths(SPOTLIGHT_SEARCH_DIRECTORIES, sizeof(SPOTLIGHT_SEARCH_DIRECTORIES)/sizeof(SPOTLIGHT_SEARCH_DIRECTORIES[0])))
{
//extract current directory
importerDirectory = [SPOTLIGHT_SEARCH_DIRECTORIES[i] stringByExpandingTildeInPath];
//get all items in current directory
allImporters = directoryContents(importerDirectory, nil);
+8 -2
View File
@@ -7,6 +7,7 @@
//
#import "Utilities.h"
#import "AppDelegate.h"
#import "PrefsWindowController.h"
@@ -35,8 +36,13 @@
//super
[super windowDidLoad];
//make white
[self.window setBackgroundColor: NSColor.whiteColor];
//not in dark mode?
// make window white
if(YES != isDarkMode())
{
//make white
self.window.backgroundColor = NSColor.whiteColor;
}
//make button selected
[self.window makeFirstResponder:self.okButton];
+1 -1
View File
@@ -30,7 +30,7 @@
//call into filter object to check if file is known
// ->signed or whitelisted
self.isTrusted = [((AppDelegate*)[[NSApplication sharedApplication] delegate]).filterObj isTrustedExtension:self];
self.isTrusted = [itemFilter isTrustedExtension:self];
}
return self;
-1
View File
@@ -7,7 +7,6 @@
//
#import "ItemBase.h"
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
+11 -7
View File
@@ -10,6 +10,7 @@
#import "File.h"
#import "MachO.h"
#import "Consts.h"
#import "Signing.h"
#import "Utilities.h"
#import "AppDelegate.h"
@@ -32,6 +33,9 @@
//flag for directories
BOOL isDirectory = NO;
//cs flags
SecCSFlags flags = kSecCSDefaultFlags | kSecCSCheckNestedCode | kSecCSDoNotValidateResources | kSecCSCheckAllArchitectures;
//mach-O parser
MachO* machoParser = nil;
@@ -108,12 +112,12 @@
//grab attributes
self.attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:self.path error:nil];
//extract signing info
self.signingInfo = extractSigningInfo(self.path);
//extract signing info statically
self.signingInfo = extractSigningInfo(0, self.path, flags);
//call into filter object to check if file is known
// ->apple-signed or whitelisted
self.isTrusted = [((AppDelegate*)[[NSApplication sharedApplication] delegate]).filterObj isTrustedFile:self];
// apple-signed or whitelisted (hash or signing id)
self.isTrusted = [itemFilter isTrustedFile:self];
//alloc macho parser iVar
// ->new instance for each file!
@@ -124,8 +128,8 @@
if(YES == [machoParser parse:self.path classify:YES])
{
//unset 'packed' flag for apple signed binaries
// ->as apple doesn't pack binaries, but packer algo has some false positives
if(YES == [self.signingInfo[KEY_SIGNING_IS_APPLE] boolValue])
// as apple doesn't pack binaries, but packer algo has some false positives
if(Apple == [self.signingInfo[KEY_SIGNATURE_SIGNER] intValue])
{
//unset
machoParser.binaryInfo[KEY_IS_PACKED] = @NO;
@@ -232,7 +236,7 @@ bail:
prettyPrint = [NSMutableString string];//stringWithString:@"signed by:"];
//add each signing auth
for(NSString* signingAuthority in self.signingInfo[KEY_SIGNING_AUTHORITIES])
for(NSString* signingAuthority in self.signingInfo[KEY_SIGNATURE_AUTHORITIES])
{
//append
[prettyPrint appendString:[NSString stringWithFormat:@"%@, ", signingAuthority]];
+7 -2
View File
@@ -34,8 +34,13 @@
//super
[super windowDidLoad];
//make white
[self.window setBackgroundColor: NSColor.whiteColor];
//not in dark mode?
// make window white
if(YES != isDarkMode())
{
//make white
self.window.backgroundColor = NSColor.whiteColor;
}
//set details
self.detailsLabel.stringValue = self.details;
+32
View File
@@ -0,0 +1,32 @@
//
// File: Signing.h
// Project: Proc Info
//
// Created by: Patrick Wardle
// Copyright: 2017 Objective-See
// License: Creative Commons Attribution-NonCommercial 4.0 International License
//
#ifndef Signing_h
#define Signing_h
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
/* FUNCTIONS */
//get the signing info of a item
// pid specified: extract dynamic code signing info
// path specified: generate static code signing info
NSMutableDictionary* extractSigningInfo(pid_t pid, NSString* path, SecCSFlags flags);
//determine who signed item
NSNumber* extractSigner(SecStaticCodeRef code, SecCSFlags flags, BOOL isDynamic);
//validate a requirement
OSStatus validateRequirement(SecStaticCodeRef code, SecRequirementRef requirement, SecCSFlags flags, BOOL isDynamic);
//extract (names) of signing auths
NSMutableArray* extractSigningAuths(NSDictionary* signingDetails);
#endif
+323
View File
@@ -0,0 +1,323 @@
//
// File: Signing.m
// Project: Proc Info
//
// Created by: Patrick Wardle
// Copyright: 2017 Objective-See
// License: Creative Commons Attribution-NonCommercial 4.0 International License
//
#import "Consts.h"
#import "Signing.h"
#import "Utilities.h"
#import <Security/Security.h>
#import <SystemConfiguration/SystemConfiguration.h>
//get the signing info of a item
// pid specified: extract dynamic code signing info
// path specified: generate static code signing info
NSMutableDictionary* extractSigningInfo(pid_t pid, NSString* path, SecCSFlags flags)
{
//info dictionary
NSMutableDictionary* signingInfo = nil;
//status
OSStatus status = !errSecSuccess;
//static code ref
SecStaticCodeRef staticCode = NULL;
//dynamic code ref
SecCodeRef dynamicCode = NULL;
//signing details
CFDictionaryRef signingDetails = NULL;
//signing authorities
NSMutableArray* signingAuths = nil;
//init signing status
signingInfo = [NSMutableDictionary dictionary];
//dynamic code checks
// no path, dynamic check via pid
if(nil == path)
{
//generate dynamic code ref via pid
status = SecCodeCopyGuestWithAttributes(NULL, (__bridge CFDictionaryRef _Nullable)(@{(__bridge NSString *)kSecGuestAttributePid : [NSNumber numberWithInt:pid]}), kSecCSDefaultFlags, &dynamicCode);
if(errSecSuccess != status)
{
//set error
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
//bail
goto bail;
}
//validate code
status = SecCodeCheckValidity(dynamicCode, flags, NULL);
if(errSecSuccess != status)
{
//set error
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
//bail
goto bail;
}
//happily signed
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:errSecSuccess];
//determine signer
// apple, app store, dev id, adhoc, etc...
signingInfo[KEY_SIGNATURE_SIGNER] = extractSigner(dynamicCode, flags, YES);
//extract signing info
status = SecCodeCopySigningInformation(dynamicCode, kSecCSSigningInformation, &signingDetails);
if(errSecSuccess != status)
{
//bail
goto bail;
}
}
//static code checks
else
{
//create static code ref via path
status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &staticCode);
if(errSecSuccess != status)
{
//set error
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
//bail
goto bail;
}
//check signature
status = SecStaticCodeCheckValidity(staticCode, flags, NULL);
if(errSecSuccess != status)
{
//set error
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
//bail
goto bail;
}
//happily signed
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:errSecSuccess];
//determine signer
// apple, app store, dev id, adhoc, etc...
signingInfo[KEY_SIGNATURE_SIGNER] = extractSigner(staticCode, flags, NO);
//extract signing info
status = SecCodeCopySigningInformation(staticCode, kSecCSSigningInformation, &signingDetails);
if(errSecSuccess != status)
{
//bail
goto bail;
}
}
//extract code signing id
if(nil != [(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoIdentifier])
{
//extract/save
signingInfo[KEY_SIGNATURE_IDENTIFIER] = [(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoIdentifier];
}
//extract entitlements
if(nil != [(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoEntitlementsDict])
{
//extract/save
signingInfo[KEY_SIGNATURE_ENTITLEMENTS] = [(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoEntitlementsDict];
}
//extract signing authorities
signingAuths = extractSigningAuths((__bridge NSDictionary *)(signingDetails));
if(0 != signingAuths.count)
{
//save
signingInfo[KEY_SIGNATURE_AUTHORITIES] = signingAuths;
}
bail:
//free signing info
if(NULL != signingDetails)
{
//free
CFRelease(signingDetails);
//unset
signingDetails = NULL;
}
//free dynamic code
if(NULL != dynamicCode)
{
//free
CFRelease(dynamicCode);
//unset
dynamicCode = NULL;
}
//free static code
if(NULL != staticCode)
{
//free
CFRelease(staticCode);
//unset
staticCode = NULL;
}
return signingInfo;
}
//determine who signed item
NSNumber* extractSigner(SecStaticCodeRef code, SecCSFlags flags, BOOL isDynamic)
{
//result
NSNumber* signer = nil;
//"anchor apple"
static SecRequirementRef isApple = nil;
//"anchor apple generic"
static SecRequirementRef isDevID = nil;
//"anchor apple generic and certificate leaf [subject.CN] = \"Apple Mac OS Application Signing\""
static SecRequirementRef isAppStore = nil;
//token
static dispatch_once_t onceToken = 0;
//only once
// init requirements
dispatch_once(&onceToken, ^{
//init apple signing requirement
SecRequirementCreateWithString(CFSTR("anchor apple"), kSecCSDefaultFlags, &isApple);
//init dev id signing requirement
SecRequirementCreateWithString(CFSTR("anchor apple generic"), kSecCSDefaultFlags, &isDevID);
//init app store signing requirement
SecRequirementCreateWithString(CFSTR("anchor apple generic and certificate leaf [subject.CN] = \"Apple Mac OS Application Signing\""), kSecCSDefaultFlags, &isAppStore);
});
//check 1: "is apple" (proper)
if(errSecSuccess == validateRequirement(code, isApple, flags, isDynamic))
{
//set signer to apple
signer = [NSNumber numberWithInt:Apple];
}
//check 2: "is app store"
// note: this is more specific than dev id, so do it first
else if(errSecSuccess == validateRequirement(code, isAppStore, flags, isDynamic))
{
//set signer to app store
signer = [NSNumber numberWithInt:AppStore];
}
//check 3: "is dev id"
else if(errSecSuccess == validateRequirement(code, isDevID, flags, isDynamic))
{
//set signer to dev id
signer = [NSNumber numberWithInt:DevID];
}
//otherwise
// has to be adhoc?
else
{
//set signer to ad hoc
signer = [NSNumber numberWithInt:AdHoc];
}
return signer;
}
//validate a requirement
OSStatus validateRequirement(SecStaticCodeRef code, SecRequirementRef requirement, SecCSFlags flags, BOOL isDynamic)
{
//result
OSStatus result = -1;
//dynamic check?
if(YES == isDynamic)
{
//validate dynamically
result = SecCodeCheckValidity((SecCodeRef)code, flags, requirement);
}
//static check
else
{
//validate statically
result = SecStaticCodeCheckValidity(code, flags, requirement);
}
return result;
}
//extract (names) of signing auths
NSMutableArray* extractSigningAuths(NSDictionary* signingDetails)
{
//signing auths
NSMutableArray* authorities = nil;
//cert chain
NSArray* certificateChain = nil;
//index
NSUInteger index = 0;
//cert
SecCertificateRef certificate = NULL;
//common name on chert
CFStringRef commonName = NULL;
//init array for certificate names
authorities = [NSMutableArray array];
//get cert chain
certificateChain = [signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoCertificates];
if(0 == certificateChain.count)
{
//no certs
goto bail;
}
//extract/save name of all certs
for(index = 0; index < certificateChain.count; index++)
{
//reset
commonName = NULL;
//extract cert
certificate = (__bridge SecCertificateRef)([certificateChain objectAtIndex:index]);
//get common name
if( (errSecSuccess == SecCertificateCopyCommonName(certificate, &commonName)) &&
(NULL != commonName) )
{
//save
[authorities addObject:(__bridge id _Nonnull)(commonName)];
//release
CFRelease(commonName);
}
}
bail:
return authorities;
}
+18 -10
View File
@@ -9,16 +9,23 @@
#ifndef KnockKnock_Utilities_h
#define KnockKnock_Utilities_h
/* METHODS */
//check if OS is supported
BOOL isSupportedOS(void);
/* FUNCTIONS */
//get OS's major or minor version
SInt32 getVersion(OSType selector);
//get the signing info of a file
NSDictionary* extractSigningInfo(NSString* path);
//disable std err
void disableSTDERR(void);
//get name of logged in user
NSString* getConsoleUser(void);
//get all users
NSMutableDictionary* allUsers(void);
//give a list of paths
// convert any `~` to all or current user
NSMutableArray* expandPaths(const __strong NSString* const paths[], int count);
//if string is too long to fit into a the text field
// ->truncate and insert ellipises before /file
@@ -46,9 +53,6 @@ NSString* getAppVersion(void);
//convert a textview to a clickable hyperlink
void makeTextViewHyperlink(NSTextField* textField, NSURL* url);
//determine if a file is signed by Apple proper
BOOL isApple(NSString* path);
//set the color of an attributed string
NSMutableAttributedString* setStringColor(NSAttributedString* string, NSColor* color);
@@ -81,10 +85,14 @@ NSString* which(NSString* processName);
NSMutableArray* runningProcesses(void);
//check if a file is an executable
BOOL isURLExecutable(NSURL* file);
BOOL isExecutable(NSString* file);
//lookup object in dictionary
// note: key can be case-insensitive
id extractFromDictionary(NSDictionary* dictionary, NSString* sensitiveKey);
//check if (full) dark mode
// meaning, Mojave+ and dark mode enabled
BOOL isDarkMode(void);
#endif
+164 -268
View File
@@ -14,64 +14,10 @@
#import <Security/Security.h>
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <CoreServices/CoreServices.h>
#import <Collaboration/Collaboration.h>
#import <SystemConfiguration/SystemConfiguration.h>
/* GLOBALS */
//flag for yosemite+
// ->needed for code-signing flags
BOOL isYosemitePlus = NO;
//check if OS is supported
// ->also set's Yosemite+ flag (for signing check flags)
BOOL isSupportedOS()
{
//return
BOOL isSupported = NO;
//major version
SInt32 versionMajor = 0;
//minor version
SInt32 versionMinor = 0;
//get major version
versionMajor = getVersion(gestaltSystemVersionMajor);
//get minor version
versionMinor = getVersion(gestaltSystemVersionMinor);
//sanity check
if( (-1 == versionMajor) ||
(-1 == versionMinor) )
{
//err
goto bail;
}
//check that OS is supported
// ->10.8+ ?
if( (versionMajor == OS_MAJOR_VERSION_X) &&
(versionMinor >= OS_MINOR_VERSION_LION) )
{
//set flag
isSupported = YES;
}
//also set yosemite+ flag
if( (versionMajor == OS_MAJOR_VERSION_X) &&
(versionMinor >= OS_MINOR_VERSION_YOSEMITE) )
{
//set flag
isYosemitePlus = YES;
}
//bail
bail:
return isSupported;
}
//get OS's major or minor version
SInt32 getVersion(OSType selector)
@@ -90,223 +36,158 @@ SInt32 getVersion(OSType selector)
goto bail;
}
//bail
bail:
return version;
}
//get the signing info of a file
NSDictionary* extractSigningInfo(NSString* path)
{
//info dictionary
NSMutableDictionary* signingStatus = nil;
//code
SecStaticCodeRef staticCode = NULL;
//status
OSStatus status = !STATUS_SUCCESS;
//signing information
CFDictionaryRef signingInformation = NULL;
//cert chain
NSArray* certificateChain = nil;
//index
NSUInteger index = 0;
//cert
SecCertificateRef certificate = NULL;
//common name on chert
CFStringRef commonName = NULL;
//flags
SecCSFlags csFlags = kSecCSDefaultFlags;
//init signing status
signingStatus = [NSMutableDictionary dictionary];
//create static code
status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &staticCode);
//save signature status
signingStatus[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
//init flags
// ->yosemite+ can do 'stronger' checks
if(YES == isYosemitePlus)
{
//set
csFlags = kSecCSCheckNestedCode|kSecCSStrictValidate|kSecCSDoNotValidateResources;
}
//check signature
status = SecStaticCodeCheckValidity(staticCode, csFlags, NULL);
//(re)save signature status
signingStatus[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
if(STATUS_SUCCESS != status)
{
//bail
goto bail;
}
//grab signing authorities
status = SecCodeCopySigningInformation(staticCode, kSecCSSigningInformation, &signingInformation);
//disable std err
void disableSTDERR()
{
//file handle
int devNull = -1;
//(re)save signature status
signingStatus[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
if(STATUS_SUCCESS != status)
{
//bail
goto bail;
}
//determine if binary is signed by Apple
signingStatus[KEY_SIGNING_IS_APPLE] = [NSNumber numberWithBool:isApple(path)];
//open /dev/null
devNull = open("/dev/null", O_RDWR);
//init array for certificate names
signingStatus[KEY_SIGNING_AUTHORITIES] = [NSMutableArray array];
//dup
dup2(devNull, STDERR_FILENO);
//get cert chain
certificateChain = [(__bridge NSDictionary*)signingInformation objectForKey:(__bridge NSString*)kSecCodeInfoCertificates];
//close
close(devNull);
//handle case there is no cert chain
// ->adhoc? (/Library/Frameworks/OpenVPN.framework/Versions/Current/bin/openvpn-service)
if(0 == certificateChain.count)
{
//set
[signingStatus[KEY_SIGNING_AUTHORITIES] addObject:@"signed, but no signing authorities (adhoc?)"];
}
//got cert chain
// ->add each to list
else
{
//get name of all certs
for(index = 0; index < certificateChain.count; index++)
{
//extract cert
certificate = (__bridge SecCertificateRef)([certificateChain objectAtIndex:index]);
//get common name
status = SecCertificateCopyCommonName(certificate, &commonName);
//skip ones that error out
if( (STATUS_SUCCESS != status) ||
(NULL == commonName))
{
//skip
continue;
}
//save
[signingStatus[KEY_SIGNING_AUTHORITIES] addObject:(__bridge NSString*)commonName];
//release name
CFRelease(commonName);
}
}
//bail
bail:
//free signing info
if(NULL != signingInformation)
{
//free
CFRelease(signingInformation);
}
//free static code
if(NULL != staticCode)
{
//free
CFRelease(staticCode);
}
return signingStatus;
return;
}
//determine if a file is signed by Apple proper
BOOL isApple(NSString* path)
//get name of logged in user
NSString* getConsoleUser()
{
//flag
BOOL isApple = NO;
//copy/return user
return CFBridgingRelease(SCDynamicStoreCopyConsoleUser(NULL, NULL, NULL));
}
//get all user
// includes name/home directory
NSMutableDictionary* allUsers()
{
//users
NSMutableDictionary* users = nil;
//code
SecStaticCodeRef staticCode = NULL;
//query
CSIdentityQueryRef query = nil;
//signing reqs
SecRequirementRef requirementRef = NULL;
//query results
CFArrayRef results = NULL;
//flags
SecCSFlags csFlags = kSecCSDefaultFlags;
//error
CFErrorRef error = NULL;
//status
OSStatus status = -1;
//identiry
CBIdentity* identity = NULL;
//create static code
status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &staticCode);
if(STATUS_SUCCESS != status)
//alloc dictionary
users = [NSMutableDictionary dictionary];
//init query
query = CSIdentityQueryCreate(NULL, kCSIdentityClassUser, CSGetLocalIdentityAuthority());
//exec query
if(true != CSIdentityQueryExecute(query, 0, &error))
{
//bail
goto bail;
}
//create req string w/ 'anchor apple'
// (3rd party: 'anchor apple generic')
status = SecRequirementCreateWithString(CFSTR("anchor apple"), kSecCSDefaultFlags, &requirementRef);
if( (STATUS_SUCCESS != status) ||
(requirementRef == NULL) )
{
//bail
goto bail;
}
//grab results
results = CSIdentityQueryCopyResults(query);
//init flags
// ->yosemite+ can do 'stronger' checks
if(YES == isYosemitePlus)
//process all results
// add user and home directory
for (int i = 0; i < CFArrayGetCount(results); ++i)
{
//set
csFlags = kSecCSCheckNestedCode|kSecCSStrictValidate|kSecCSDoNotValidateResources;
//grab identity
identity = [CBIdentity identityWithCSIdentity:(CSIdentityRef)CFArrayGetValueAtIndex(results, i)];
//add user
users[identity.uniqueIdentifier] = @{USER_NAME:identity.posixName, USER_DIRECTORY:NSHomeDirectoryForUser(identity.posixName)};
}
//check if file is signed by apple
// ->i.e. it conforms to req string
status = SecStaticCodeCheckValidity(staticCode, csFlags, requirementRef);
if(STATUS_SUCCESS != status)
{
//bail
// ->just means app isn't signed by apple, or something didn't validate
goto bail;
}
//ok, happy (SecStaticCodeCheckValidity() didn't fail)
// ->file is signed by Apple
isApple = YES;
//bail
bail:
//free req reference
if(NULL != requirementRef)
//release results
if(NULL != results)
{
//free
CFRelease(requirementRef);
}
//free static code
if(NULL != staticCode)
{
//free
CFRelease(staticCode);
//release
CFRelease(results);
}
return isApple;
//release query
if(NULL != query)
{
//release
CFRelease(query);
}
return users;
}
//give a list of paths
// convert any `~` to all or current user
NSMutableArray* expandPaths(const __strong NSString* const paths[], int count)
{
//expanded paths
NSMutableArray* expandedPaths = nil;
//(current) path
const NSString* path = nil;
//all users
NSMutableDictionary* users = nil;
//grab all users
users = allUsers();
//alloc list
expandedPaths = [NSMutableArray array];
//iterate/expand
for(NSInteger i = 0; i < count; i++)
{
//grab path
path = paths[i];
//no `~`?
// just add and continue
if(YES != [path hasPrefix:@"~"])
{
//add as is
[expandedPaths addObject:path];
//next
continue;
}
//handle '~' case
// root? add each user
if(0 == geteuid())
{
//add each user
for(NSString* user in users)
{
[expandedPaths addObject:[users[user][USER_DIRECTORY] stringByAppendingPathComponent:[path substringFromIndex:1]]];
}
}
//otherwise
// just convert to current user
else
{
[expandedPaths addObject:[path stringByExpandingTildeInPath]];
}
}
return expandedPaths;
}
//given a path to binary
@@ -368,13 +249,13 @@ NSImage* getIconForBinary(NSString* binary, NSBundle* bundle)
NSString* iconExtension = nil;
//system's document icon
static NSData* documentIcon = nil;
static NSImage* documentIcon = nil;
//icon
NSImage* icon = nil;
//if not bundle was passed in
// ->try find one
//no bundle?
// try find one
if(nil == bundle)
{
//load bundle
@@ -382,7 +263,7 @@ NSImage* getIconForBinary(NSString* binary, NSBundle* bundle)
}
//for app's
// ->extract their icon
// extract their icon
if(nil != bundle)
{
//get file
@@ -414,27 +295,25 @@ NSImage* getIconForBinary(NSString* binary, NSBundle* bundle)
//extract icon
icon = [[NSWorkspace sharedWorkspace] iconForFile:binary];
//load system document icon
// ->static var, so only load once
if(nil == documentIcon)
{
//load
documentIcon = [[[NSWorkspace sharedWorkspace] iconForFileType:
NSFileTypeForHFSTypeCode(kGenericDocumentIcon)] TIFFRepresentation];
documentIcon = [[NSWorkspace sharedWorkspace] iconForFileType:
NSFileTypeForHFSTypeCode(kGenericDocumentIcon)];
}
//if 'iconForFile' method doesn't find and icon, it returns the system 'document' icon
// ->the system 'application' icon seems more applicable, so use that here...
if(YES == [[icon TIFFRepresentation] isEqual:documentIcon])
if(YES == [icon isEqual:documentIcon])
{
//set icon to system 'applicaiton' icon
icon = [[NSWorkspace sharedWorkspace]
iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
}
//'iconForFileType' returns small icons
// ->so set size to 64
[icon setSize:NSMakeSize(64, 64)];
// so set size to 64 @2x
[icon setSize:NSMakeSize(128, 128)];
}
return icon;
@@ -1187,22 +1066,16 @@ bail:
}
//check if a file is an executable
BOOL isURLExecutable(NSURL* file)
BOOL isExecutable(NSString* file)
{
//return
BOOL isExecutable = NO;
//bundle url
CFURLRef bundleURL = NULL;
//architecture ref
CFArrayRef archArrayRef = NULL;
//create bundle
bundleURL = CFURLCreateFromFileSystemRepresentation(NULL, (uint8_t*)[[file path] UTF8String], strlen((const char *)(uint8_t*)[[file path] UTF8String]), true);
//get executable arch's
archArrayRef = CFBundleCopyExecutableArchitecturesForURL(bundleURL);
archArrayRef = CFBundleCopyExecutableArchitecturesForURL((__bridge CFURLRef)[NSURL fileURLWithPath:file]);
//check arch for i386/x6_64
if(NULL != archArrayRef)
@@ -1211,13 +1084,6 @@ BOOL isURLExecutable(NSURL* file)
isExecutable = [(__bridge NSArray*)archArrayRef containsObject:[NSNumber numberWithInt:kCFBundleExecutableArchitectureX86_64]] || [(__bridge NSArray*)archArrayRef containsObject:[NSNumber numberWithInt:kCFBundleExecutableArchitectureI386]];
}
//free bundle url
if(NULL != bundleURL)
{
//free
CFRelease(bundleURL);
}
//free arch ref
if(NULL != archArrayRef)
{
@@ -1250,3 +1116,33 @@ id extractFromDictionary(NSDictionary* dictionary, NSString* sensitiveKey)
return object;
}
//check if (full) dark mode
// meaning, Mojave+ and dark mode enabled
BOOL isDarkMode()
{
//flag
BOOL darkMode = NO;
//not mojave?
// bail, since not true dark mode
if(YES != [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 14, 0}])
{
//bail
goto bail;
}
//not dark mode?
if(YES != [[[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"] isEqualToString:@"Dark"])
{
//bail
goto bail;
}
//ok, mojave dark mode it is!
darkMode = YES;
bail:
return darkMode;
}
+9 -9
View File
@@ -101,11 +101,11 @@
color = [NSColor redColor];
}
//non-flagged files
// ->just black
// color: default
else
{
//gray
color = [NSColor blackColor];
//default
color = NSColor.controlTextColor;
}
//set string
@@ -133,7 +133,7 @@
color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.66];
}
//non-flagged files
// ->just black
// ->color: gray
else
{
//gray
@@ -169,7 +169,7 @@
color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.66];
}
//non-flagged files
// ->just black
// color: gray
else
{
//gray
@@ -177,7 +177,7 @@
}
}
//mouse is up
// ->reset color to black/red
// ->reset color
else
{
//flagged files
@@ -189,11 +189,11 @@
color = [NSColor redColor];
}
//non-flagged files
// ->just black
// color: default
else
{
//gray
color = [NSColor blackColor];
//default
color = NSColor.controlTextColor;
}
}
+10 -8
View File
@@ -51,11 +51,13 @@
//super
[super windowDidLoad];
//make it modal
//[[NSApplication sharedApplication] runModalForWindow:self.window];
//make white
[self.window setBackgroundColor: NSColor.whiteColor];
//not in dark mode?
// make window white
if(YES != isDarkMode())
{
//make white
self.window.backgroundColor = NSColor.whiteColor;
}
//make close button selected
[self.window makeFirstResponder:self.closeButton];
@@ -97,8 +99,8 @@
//file status (known/unknown)
if(YES == isKnown)
{
//default color to black
textColor = [NSColor blackColor];
//reset
textColor = NSColor.controlTextColor;
//set color to red if its flagged
if(0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue])
@@ -227,7 +229,7 @@
//pre-req
[self.overlayView setWantsLayer:YES];
//set overlay's view color to black
//set overlay's view color to white
self.overlayView.layer.backgroundColor = [NSColor whiteColor].CGColor;
//make it semi-transparent
-33
View File
@@ -1,37 +1,4 @@
{
"/Library/Extensions/HighPointIOP.kext/Contents/MacOS/HighPointIOP":["e387f72b2e74fec83e7ea9f0f038d64f", "4d6367d14fa1b6f7c6faf4e48a3293d0"],
"/Library/Extensions/PromiseSTEX.kext/Contents/MacOS/PromiseSTEX":["ba899baf6a8f0cabf81e0b0009fac3c9", "66307f53513760997ace335fef99b95d", "db6dd9dc9421315f4c25b46f8170bcc3"],
"/Library/Extensions/ATTOCelerityFC8.kext/Contents/MacOS/ATTOCelerityFC8":["549e3f145f87b9dff09a068671dd74ce", "b1ec21821b5b6b4ff0735dd01a6ee840"],
"/Library/Extensions/HighPointRR.kext/Contents/MacOS/HighPointRR":["c61804dcfa5447b8bdde8aec93d0fb06", "e36e03df0b95244bbefcf2f074f88411"],
"/Library/Extensions/CalDigitHDProDrv.kext/Contents/MacOS/CalDigitHDProDrv":["9cf6fccbb11ba69de1fa7fe5184660a0"],
"/Library/Extensions/SoftRAID.kext/Contents/MacOS/SoftRAID":["5b031ffe78c8ad0962ad7c74032ded32", "defa280116342c6e9373dc41ba4f6535", "51e477fb53ebeefeeb7f7ce3a5bd8929", "42496f9bbe8a83a796eea5e63e72e8cd"],
"/Library/Extensions/ATTOExpressSASHBA2.kext/Contents/MacOS/ATTOExpressSASHBA2":["65a3c352c56514cdb96468f50474430f", "53e1008f80b148241effa105f3d12199"],
"/Library/Extensions/ArcMSR.kext/Contents/MacOS/ArcMSR":["416efde75a393f9505673ba99f24e873"],
"/Library/Extensions/ATTOExpressSASRAID2.kext/Contents/MacOS/ATTOExpressSASRAID2":["4f43c6550ad647d2416d48c58e41553e", "54e5e3af5485802ce0b98ff2d69086cb"],
"/Library/Extensions/ACS6x.kext/Contents/MacOS/ACS6x":["276f55fccf8a7783b06dbde3b1bd36f5"],
"/System/Library/Extensions/Accusys6xxxx.kext/Contents/MacOS/Accusys6xxxx":["b02c769f3b6635e307b551462a48107d"],
"/System/Library/Extensions/AppleBacklightExpert.kext/AppleBacklightExpert":["6501354452b48465dea904e27fe8c5f9", "8854000a050f4bbadd36db2b8118ffa1", "678c0efdde7c4a90e5e5b76855c9ee85"],
"/System/Library/Extensions/ArcMSR.kext/Contents/MacOS/ArcMSR":["c57237576ff817b13246296ec786cce2"],
"/System/Library/Extensions/ATTOCelerityFC.kext/Contents/MacOS/ATTOCelerityFC":["c061f1786d1e9b07846c1bfa1a906190"],
"/System/Library/Extensions/ATTOCelerityFC8.kext/Contents/MacOS/ATTOCelerityFC8":["bbf4c3a42934c36d8ae804c7c7386547"],
"/System/Library/Extensions/ATTOExpressPCI4.kext/Contents/MacOS/ATTOExpressPCI4":["433e4f9488d90020e480c56893c8a80f"],
"/System/Library/Extensions/ATTOExpressSASHBA.kext/Contents/MacOS/ATTOExpressSASHBA":["4d5ef99ed9d52e8a0550b8a91c6a9aca"],
"/System/Library/Extensions/ATTOExpressSASHBA2.kext/Contents/MacOS/ATTOExpressSASHBA2":["e440639d53144ccb09d9796e675169f9"],
"/System/Library/Extensions/ATTOExpressSASHBA3.kext/Contents/MacOS/ATTOExpressSASHBA3":["864aed4dd2f45fbc39a95fec1efb47db"],
"/System/Library/Extensions/ATTOExpressSASRAID.kext/Contents/MacOS/ATTOExpressSASRAID":["e68c0f60ca8e10bbd241ce1335a3dca8"],
"/System/Library/Extensions/ATTOExpressSASRAID2.kext/Contents/MacOS/ATTOExpressSASRAID2":["ed974b9a9e41b01d648f64bec5959b46"],
"/System/Library/Extensions/AudioAUUC.kext/AudioAUUC":["6e02093ece9dc275a30ecd3417b1b016", "a785d5ccef1991009af1d4d25a0373c2", "020e254d626ea0eb8432880314bdffda"],
"/System/Library/Extensions/CalDigitHDProDrv.kext/Contents/MacOS/CalDigitHDProDrv":["a53366611eed8c2cb2cf12b79f893ee3"],
"/System/Library/Extensions/CoreStorage.kext/Contents/MacOS/CoreStorage":["7ffecdf00647495170b05bb64bc0ca26"],
"/System/Library/Extensions/IOGraphicsFamily.kext/IOGraphicsFamily":["e037d3730c01962ebcd4bba09d69679c", "6c16ebd149ac177978393ee98ff84c2d", "68941445971cf95576ff28831c423d04"],
"/System/Library/Extensions/IONDRVSupport.kext/IONDRVSupport":["013c73074d7993cba3e230b5511cd901", "f470a6cacf052cbe469dc400973511d2", "6688610c05329bfc4909b4bc21230d6d"],
"/System/Library/Extensions/IOPCIFamily.kext/IOPCIFamily":["6a9d57017a18fc470d323547d1ab86e4", "562be2c6d9d55b3ad2d8ee00e9da4ca6", "a899be1ccbe7cdc6fb54f92f7aa09dc3"],
"/System/Library/Extensions/HighPointIOP.kext/Contents/MacOS/HighPointIOP":["64e3e122c1f0d24fd0b225c18f44440d"],
"/System/Library/Extensions/HighPointRR.kext/Contents/MacOS/HighPointRR":["316bb5757bbe7ef70044f85717ff97df"],
"/System/Library/Extensions/JMicronATA.kext/Contents/MacOS/JMicronATA":["9c8207d44446861a5b40e2ac4c6f5dba"],
"/System/Library/Extensions/PromiseSTEX.kext/Contents/MacOS/PromiseSTEX":["1cd38bebacdc6ba85a86a8b65474b8b5"],
"/System/Library/Extensions/SoftRAID.kext/Contents/MacOS/SoftRAID":["18bfb361ae05cff7f2a2310d685a44fc"],
"/System/Library/Extensions/webdav_fs.kext/Contents/MacOS/webdav_fs":["6b9068594520afce60dcf99262d1af12"],
"/usr/libexec/configureLocalKDC":["19f6e328d0286ad7f81ee8224e369726"],
"/usr/libexec/locate.updatedb":["e8cc729ae05233c414eb0c672d836fc1"],
"/usr/libexec/ntpd-wrapper":["baf0968c6df24734e079baeb01851221"],
+35
View File
@@ -0,0 +1,35 @@
{
"/Library/Extensions/HighPointIOP.kext/Contents/MacOS/HighPointIOP":"Developer ID Application: HighPoint Technologies, Inc (DX6G69M9N2)",
"/Library/Extensions/PromiseSTEX.kext/Contents/MacOS/PromiseSTEX":"Developer ID Application: Promise Technology Mobile Apps (268CCUR4WN)",
"/Library/Extensions/ATTOCelerityFC8.kext/Contents/MacOS/ATTOCelerityFC8":"Developer ID Application: ATTO Technology, Inc. (FC94733TZD)",
"/Library/Extensions/HighPointRR.kext/Contents/MacOS/HighPointRR":"Developer ID Application: HighPoint Technologies, Inc (DX6G69M9N2)",
"/Library/Extensions/CalDigitHDProDrv.kext/Contents/MacOS/CalDigitHDProDrv":"Developer ID Application: CalDigit, Inc (8R7PS6VYW7)",
"/Library/Extensions/SoftRAID.kext/Contents/MacOS/SoftRAID":"Developer ID Application: SoftRAID LLC (NDGSU3WA4Y)",
"/Library/Extensions/ATTOExpressSASHBA2.kext/Contents/MacOS/ATTOExpressSASHBA2":"Developer ID Application: ATTO Technology, Inc. (FC94733TZD)",
"/Library/Extensions/ArcMSR.kext/Contents/MacOS/ArcMSR":"Developer ID Application: Areca Technology Corporation (34JN824YNC)",
"/Library/Extensions/ATTOExpressSASRAID2.kext/Contents/MacOS/ATTOExpressSASRAID2":"Developer ID Application: ATTO Technology, Inc. (FC94733TZD)",
"/Library/Extensions/ACS6x.kext/Contents/MacOS/ACS6x":"Developer ID Application: Accusys,Inc (K3TDMD9Y6B)",
"/System/Library/Extensions/Accusys6xxxx.kext/Contents/MacOS/Accusys6xxxx":["b02c769f3b6635e307b551462a48107d"],
"/System/Library/Extensions/AppleBacklightExpert.kext/AppleBacklightExpert":["6501354452b48465dea904e27fe8c5f9", "8854000a050f4bbadd36db2b8118ffa1", "678c0efdde7c4a90e5e5b76855c9ee85"],
"/System/Library/Extensions/ArcMSR.kext/Contents/MacOS/ArcMSR":["c57237576ff817b13246296ec786cce2"],
"/System/Library/Extensions/ATTOCelerityFC.kext/Contents/MacOS/ATTOCelerityFC":["c061f1786d1e9b07846c1bfa1a906190"],
"/System/Library/Extensions/ATTOCelerityFC8.kext/Contents/MacOS/ATTOCelerityFC8":["bbf4c3a42934c36d8ae804c7c7386547"],
"/System/Library/Extensions/ATTOExpressPCI4.kext/Contents/MacOS/ATTOExpressPCI4":["433e4f9488d90020e480c56893c8a80f"],
"/System/Library/Extensions/ATTOExpressSASHBA.kext/Contents/MacOS/ATTOExpressSASHBA":["4d5ef99ed9d52e8a0550b8a91c6a9aca"],
"/System/Library/Extensions/ATTOExpressSASHBA2.kext/Contents/MacOS/ATTOExpressSASHBA2":["e440639d53144ccb09d9796e675169f9"],
"/System/Library/Extensions/ATTOExpressSASHBA3.kext/Contents/MacOS/ATTOExpressSASHBA3":["864aed4dd2f45fbc39a95fec1efb47db"],
"/System/Library/Extensions/ATTOExpressSASRAID.kext/Contents/MacOS/ATTOExpressSASRAID":["e68c0f60ca8e10bbd241ce1335a3dca8"],
"/System/Library/Extensions/ATTOExpressSASRAID2.kext/Contents/MacOS/ATTOExpressSASRAID2":["ed974b9a9e41b01d648f64bec5959b46"],
"/System/Library/Extensions/AudioAUUC.kext/AudioAUUC":["6e02093ece9dc275a30ecd3417b1b016", "a785d5ccef1991009af1d4d25a0373c2", "020e254d626ea0eb8432880314bdffda"],
"/System/Library/Extensions/CalDigitHDProDrv.kext/Contents/MacOS/CalDigitHDProDrv":["a53366611eed8c2cb2cf12b79f893ee3"],
"/System/Library/Extensions/CoreStorage.kext/Contents/MacOS/CoreStorage":["7ffecdf00647495170b05bb64bc0ca26"],
"/System/Library/Extensions/IOGraphicsFamily.kext/IOGraphicsFamily":["e037d3730c01962ebcd4bba09d69679c", "6c16ebd149ac177978393ee98ff84c2d", "68941445971cf95576ff28831c423d04"],
"/System/Library/Extensions/IONDRVSupport.kext/IONDRVSupport":["013c73074d7993cba3e230b5511cd901", "f470a6cacf052cbe469dc400973511d2", "6688610c05329bfc4909b4bc21230d6d"],
"/System/Library/Extensions/IOPCIFamily.kext/IOPCIFamily":["6a9d57017a18fc470d323547d1ab86e4", "562be2c6d9d55b3ad2d8ee00e9da4ca6", "a899be1ccbe7cdc6fb54f92f7aa09dc3"],
"/System/Library/Extensions/HighPointIOP.kext/Contents/MacOS/HighPointIOP":["64e3e122c1f0d24fd0b225c18f44440d"],
"/System/Library/Extensions/HighPointRR.kext/Contents/MacOS/HighPointRR":["316bb5757bbe7ef70044f85717ff97df"],
"/System/Library/Extensions/JMicronATA.kext/Contents/MacOS/JMicronATA":["9c8207d44446861a5b40e2ac4c6f5dba"],
"/System/Library/Extensions/PromiseSTEX.kext/Contents/MacOS/PromiseSTEX":["1cd38bebacdc6ba85a86a8b65474b8b5"],
"/System/Library/Extensions/SoftRAID.kext/Contents/MacOS/SoftRAID":["18bfb361ae05cff7f2a2310d685a44fc"],
"/System/Library/Extensions/webdav_fs.kext/Contents/MacOS/webdav_fs":["6b9068594520afce60dcf99262d1af12"]
}
+91 -13
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -43,10 +43,10 @@
</menuItem>
</items>
</menu>
<window title="KnockKnock" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" showsToolbarButton="NO" animationBehavior="default" id="371">
<window title="KnockKnock" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371" userLabel="Main Window">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="0.0" y="0.0" width="1203" height="597"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
<value key="minSize" type="size" width="1000" height="597"/>
<value key="maxSize" type="size" width="2000" height="1000"/>
<view key="contentView" id="372">
@@ -79,7 +79,7 @@
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="categoryCell" id="xyl-A2-Ges" customClass="kkRowCell">
<tableCellView identifier="categoryCell" id="xyl-A2-Ges">
<rect key="frame" x="1" y="1" width="345" height="66"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@@ -152,11 +152,11 @@
<constraints>
<constraint firstAttribute="width" constant="350" id="bae-13-KkE"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" controlSize="mini" horizontal="YES" id="7vn-ou-LQB">
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" controlSize="mini" horizontal="YES" id="7vn-ou-LQB">
<rect key="frame" x="1" y="298" width="480" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" controlSize="mini" horizontal="NO" id="UN2-nS-XZS" customClass="RFOverlayScroller">
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" controlSize="mini" horizontal="NO" id="UN2-nS-XZS" customClass="RFOverlayScroller">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
@@ -239,7 +239,7 @@
</textFieldCell>
</textField>
<button toolTip="show file info" verticalHuggingPriority="750" tag="105" translatesAutoresizingMaskIntoConstraints="NO" id="1D0-FU-7Yz">
<rect key="frame" x="757" y="22" width="21" height="21"/>
<rect key="frame" x="757" y="23" width="21" height="21"/>
<constraints>
<constraint firstAttribute="width" constant="21" id="H5r-kf-JB8"/>
<constraint firstAttribute="height" constant="21" id="eWB-hd-Kcv"/>
@@ -265,7 +265,7 @@
</textFieldCell>
</textField>
<button toolTip="show in finder" verticalHuggingPriority="750" tag="107" translatesAutoresizingMaskIntoConstraints="NO" id="602">
<rect key="frame" x="798" y="20" width="27" height="24"/>
<rect key="frame" x="798" y="21" width="27" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="27" id="K7d-Mq-cdn"/>
<constraint firstAttribute="height" constant="24" id="PiG-96-MLK"/>
@@ -422,13 +422,13 @@
</connections>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="backgroundColor"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" controlSize="mini" horizontal="YES" id="538">
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" controlSize="mini" horizontal="YES" id="538">
<rect key="frame" x="1" y="298" width="480" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" controlSize="mini" horizontal="NO" id="540" customClass="RFOverlayScroller">
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" controlSize="mini" horizontal="NO" id="540" customClass="RFOverlayScroller">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
@@ -558,6 +558,7 @@
<customObject id="494" customClass="AppDelegate">
<connections>
<outlet property="categoryTableController" destination="SmD-QP-397" id="PIf-PG-Sg9"/>
<outlet property="friends" destination="gD4-T8-B0H" id="bob-rW-SSv"/>
<outlet property="itemTableController" destination="8VH-uv-w4O" id="zNb-sJ-msd"/>
<outlet property="logoButton" destination="HoI-FQ-vTI" id="bzc-wu-4Hv"/>
<outlet property="progressIndicator" destination="839" id="870"/>
@@ -581,10 +582,87 @@
<outlet property="itemTableView" destination="537" id="0xr-LE-bN9"/>
</connections>
</customObject>
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="gD4-T8-B0H" userLabel="Friends">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<rect key="contentRect" x="2843" y="305" width="801" height="384"/>
<rect key="screenRect" x="2560" y="0.0" width="2560" height="1417"/>
<view key="contentView" id="zIY-EJ-oYy">
<rect key="frame" x="0.0" y="0.0" width="801" height="384"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G5i-Vw-RGw">
<rect key="frame" x="18" y="304" width="765" height="60"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="💕 Mahalo to the &quot;Friends of Objective-See&quot; 💕" id="JSF-ba-pCy">
<font key="font" size="20" name="Menlo-Bold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UVJ-lg-XUE">
<rect key="frame" x="81" y="107" width="135" height="19"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Digita Security" id="K4a-be-V59">
<font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zK8-K8-cf6">
<rect key="frame" x="103" y="134" width="91" height="115"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsDigita" id="Zur-8L-PYL"/>
</imageView>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rRX-qq-ej4">
<rect key="frame" x="344" y="148" width="114" height="88"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsSophos" id="Zgf-hp-Cl7"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AgC-lD-Eeh">
<rect key="frame" x="332" y="107" width="138" height="19"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Sophos" id="3l8-CG-zeL">
<font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XfW-um-F1n">
<rect key="frame" x="596" y="144" width="135" height="95"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="FriendsMalwarebytes" id="MSz-0k-clr"/>
</imageView>
<button verticalHuggingPriority="750" fixedFrame="YES" tag="-1" translatesAutoresizingMaskIntoConstraints="NO" id="eD8-BN-Z1D">
<rect key="frame" x="672" y="13" width="115" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Close" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="1mP-i0-2e4">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" size="13" name="Menlo-Regular"/>
</buttonCell>
<connections>
<action selector="toggleFriends:" target="494" id="4tu-GP-sAX"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bDD-y2-4Zr">
<rect key="frame" x="609" y="107" width="108" height="19"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Malwarebytes" id="Dwi-kl-eMS">
<font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
<point key="canvasLocation" x="706.5" y="-545"/>
</window>
</objects>
<resources>
<image name="FriendsDigita" width="450" height="460"/>
<image name="FriendsMalwarebytes" width="792" height="612"/>
<image name="FriendsSophos" width="188" height="190"/>
<image name="NSActionTemplate" width="14" height="14"/>
<image name="NSColorPanel" width="32" height="32"/>
<image name="NSColorPanel" width="128" height="128"/>
<image name="binaryIcon" width="512" height="512"/>
<image name="info" width="256" height="256"/>
<image name="infoBG" width="256" height="256"/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

-13
View File
@@ -1,13 +0,0 @@
//
// kkRowCell.h
// KnockKnock
//
// Created by Patrick Wardle on 4/6/15.
// Copyright (c) 2015 Objective-See. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface kkRowCell : NSTableCellView
@end
-23
View File
@@ -1,23 +0,0 @@
//
// kkRowCell.m
// KnockKnock
//
// Created by Patrick Wardle on 4/6/15.
// Copyright (c) 2015 Objective-See. All rights reserved.
//
#import "kkRowCell.h"
@implementation kkRowCell
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {
[super setBackgroundStyle: NSBackgroundStyleLight];
}
@end
+37
View File
@@ -0,0 +1,37 @@
//
// main.h
// KnockKnock
//
// Created by Patrick Wardle on 11/12/18.
// Copyright © 2018 Objective-See. All rights reserved.
//
#ifndef main_h
#define main_h
#import "Consts.h"
#import "Filter.h"
#import "Utilities.h"
#import "VirusTotal.h"
#import "AppDelegate.h"
#import "ItemEnumerator.h"
#import <Cocoa/Cocoa.h>
/* GLOBALS */
//filter object
Filter* itemFilter;
//shared item enumerator object
ItemEnumerator* sharedItemEnumerator = nil;
/* FUNCTIONS */
//perform a cmdline scan
BOOL cmdlineScan(void);
//pretty print JSON
void prettyPrintJSON(NSString* output);
#endif /* main_h */
+229 -10
View File
@@ -6,33 +6,252 @@
// Copyright (c) 2015 Objective-See. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@import Sentry;
#import "main.h"
int main(int argc, char *argv[])
{
//return var
int retVar = -1;
//status
int status = -1;
@autoreleasepool
{
//disable stderr
// sentry dumps to this, and we want only JSON to output...
disableSTDERR();
//sentry client
SentryClient *client = nil;
//init sentry client
client = [[SentryClient alloc] initWithDsn:@"https://ba5d094e87014a529b25d90bae010b1c@sentry.io/1321683" didFailWithError:nil];
//set shared client
SentryClient.sharedClient = client;
//start crash handler
[SentryClient.sharedClient startCrashHandlerWithError:nil];
//handle '-scan'
// ->cmdline scan without UI
if( (argc >= 2) &&
(YES == [[NSString stringWithUTF8String:argv[1]] isEqualToString:@"-whothere"]) )
// cmdline scan without UI
if(YES == [[[NSProcessInfo processInfo] arguments] containsObject:@"-whosthere"])
{
//scan
if(YES != cmdlineScan())
{
//err msg
printf("\nKNOCKKNOCK ERROR: cmdline scan failed\n\n");
//bail
goto bail;
}
//happy
status = 0;
//done
goto bail;
}
//otherwise
// ->just kick off app, as we're root now
// just kick off app for UI instance
else
{
//app away
retVar = NSApplicationMain(argc, (const char **)argv);
status = NSApplicationMain(argc, (const char **)argv);
}
}//pool
return retVar;
bail:
return status;
}
//perform a cmdline scan
BOOL cmdlineScan()
{
//virus total obj
VirusTotal* virusTotal = nil;
//virus total thread
NSThread* virusTotalThread = nil;
//flag
BOOL scanned = NO;
//flag
BOOL includeApple = NO;
//flag
BOOL skipVirusTotal = NO;
//flag
BOOL prettyPrint = NO;
//output
NSMutableString* output = nil;
//plugin object
PluginBase* plugin = nil;
//init filter object
itemFilter = [[Filter alloc] init];
//init virus total object
virusTotal = [[VirusTotal alloc] init];
//alloc shared item enumerator
sharedItemEnumerator = [[ItemEnumerator alloc] init];
//start shared enumerator
[sharedItemEnumerator start];
//set flag
// include apple items?
includeApple = [[[NSProcessInfo processInfo] arguments] containsObject:@"-apple"];
//set flag
// skip virus total?
skipVirusTotal = [[[NSProcessInfo processInfo] arguments] containsObject:@"-skipVT"];
//set flag
// pretty print json?
prettyPrint = [[[NSProcessInfo processInfo] arguments] containsObject:@"-pretty"];
//init output string
output = [NSMutableString string];
//start JSON
[output appendString:@"{"];
//iterate over all supported plugins
// invoke scan method on each plugin...
for(NSUInteger i=0; i < sizeof(SUPPORTED_PLUGINS)/sizeof(SUPPORTED_PLUGINS[0]); i++)
{
//init plugin
plugin = [(PluginBase*)([NSClassFromString(SUPPORTED_PLUGINS[i]) alloc]) init];
if(nil == plugin)
{
//skip
continue;
}
//no callback needed
plugin.callback = nil;
//scan
[plugin scan];
//query VT
// unless user explicity says otherwise
if(YES != skipVirusTotal)
{
//alloc thread
// will query virus total to get info about all detected items
virusTotalThread = [[NSThread alloc] initWithTarget:virusTotal selector:@selector(getInfo:) object:plugin];
//start thread
[virusTotalThread start];
//wait until thread is done
while(YES != virusTotalThread.isFinished)
{
//nap
[NSThread sleepForTimeInterval:1.0];
}
}
//append plugin name to output
[output appendString:[NSString stringWithFormat:@"\"%@\":[", plugin.name]];
//iterate over all plugin items
// convert to JSON/append to output
for(ItemBase* item in plugin.allItems)
{
//skip apple / trusted items?
if( (YES != includeApple) &&
(YES == item.isTrusted) )
{
//skip
continue;
}
//add item
[output appendFormat:@"{%@},", [item toJSON]];
}
//remove last ','
if(YES == [output hasSuffix:@","])
{
//remove
[output deleteCharactersInRange:NSMakeRange([output length]-1, 1)];
}
//terminate list
[output appendString:@"],"];
}//all plugins
//remove last ','
if(YES == [output hasSuffix:@","])
{
//remove
[output deleteCharactersInRange:NSMakeRange([output length]-1, 1)];
}
//terminate list
[output appendString:@"}"];
//pretty print?
if(YES == prettyPrint)
{
//make me pretty!
prettyPrintJSON(output);
}
else
{
//output
printf("%s\n", output.UTF8String);
}
//happy
scanned = YES;
bail:
return scanned;
}
//pretty print JSON
void prettyPrintJSON(NSString* output)
{
//data
NSData* data = nil;
//object
id object = nil;
//pretty data
NSData* prettyData = nil;
//pretty string
NSString* prettyString = nil;
//covert to data
data = [output dataUsingEncoding:NSUTF8StringEncoding];
//serialize
object = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
//covert to pretty data
prettyData = [NSJSONSerialization dataWithJSONObject:object options:NSJSONWritingPrettyPrinted error:nil];
//covert to pretty string
prettyString = [NSString stringWithUTF8String:prettyData.bytes];
//output
printf("%s\n", prettyString.UTF8String);
return;
}