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
@@ -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()]];
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
github "getsentry/sentry-cocoa" "4.1.0"
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
|
||||
#import "PluginBase.h"
|
||||
|
||||
/* GLOBALS */
|
||||
|
||||
//shared enumerator
|
||||
extern ItemEnumerator* sharedItemEnumerator;
|
||||
|
||||
|
||||
@interface DylibInserts : PluginBase
|
||||
{
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"]) )
|
||||
{
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
|
||||
#import "PluginBase.h"
|
||||
|
||||
/* GLOBALS */
|
||||
|
||||
//shared enumerator
|
||||
extern ItemEnumerator* sharedItemEnumerator;
|
||||
|
||||
|
||||
@interface LaunchItems : PluginBase
|
||||
{
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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}];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
//
|
||||
|
||||
#import "ItemBase.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
|
||||
@@ -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]];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
@@ -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 "Friends of Objective-See" 💕" 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"/>
|
||||
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||