diff --git a/3rdParty/OrderedDictionary.h b/3rdParty/OrderedDictionary.h index 74de921..45fd2d4 100644 --- a/3rdParty/OrderedDictionary.h +++ b/3rdParty/OrderedDictionary.h @@ -36,7 +36,6 @@ - (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex; - (id)keyAtIndex:(NSUInteger)anIndex; - (NSUInteger)indexOfKey:(id)aKey; --(void)reverse; //sort // ->by pid, name, etc diff --git a/3rdParty/OrderedDictionary.m b/3rdParty/OrderedDictionary.m index ef84e39..177c83e 100644 --- a/3rdParty/OrderedDictionary.m +++ b/3rdParty/OrderedDictionary.m @@ -101,12 +101,7 @@ NSString *DescriptionForObject(NSObject *object, id locale, NSUInteger indent) return [array objectEnumerator]; } -/* -- (NSEnumerator *)reverseKeyEnumerator -{ - return [array reverseObjectEnumerator]; -} -*/ + -(void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex { @@ -139,19 +134,13 @@ bail: return item; } -//TODO: add sanity checks -//given an key +//given a key // ->return its index -(NSUInteger)indexOfKey:(id)aKey { return [array indexOfObject:aKey]; } --(void)reverse -{ - array = [[[array reverseObjectEnumerator] allObjects] mutableCopy]; -} - //sort // ->by pid, name, etc -(void)sort:(NSUInteger)sortBy @@ -159,13 +148,14 @@ bail: //task sorted by name NSArray* sortedTasks = nil; - // + //sort by pid if(SORT_BY_PID == sortBy) { [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { return [obj1 compare:obj2]; }]; } + //sort by name else if(SORT_BY_NAME == sortBy) { //get array of tasks, sorted by binary name @@ -174,37 +164,9 @@ bail: //extract sorted pids into array array = [[sortedTasks valueForKey:@"pid"] mutableCopy]; - } - return; } - - -/* -- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level -{ - NSMutableString *indentString = [NSMutableString string]; - NSUInteger i, count = level; - for (i = 0; i < count; i++) - { - [indentString appendFormat:@" "]; - } - - NSMutableString *description = [NSMutableString string]; - [description appendFormat:@"%@{\n", indentString]; - for (NSObject *key in self) - { - [description appendFormat:@"%@ %@ = %@;\n", - indentString, - DescriptionForObject(key, locale, level), - DescriptionForObject([self objectForKey:key], locale, level)]; - } - [description appendFormat:@"%@}\n", indentString]; - return description; -} -*/ - @end diff --git a/AppDelegate.h b/AppDelegate.h index 375771b..05f060d 100755 --- a/AppDelegate.h +++ b/AppDelegate.h @@ -138,6 +138,9 @@ //top constraint @property(nonatomic, retain)NSLayoutConstraint* trailingConstraint; +//remote XPC interface +@property (nonatomic, retain) NSXPCConnection* xpcConnection; + //action for 'refresh' button // ->query OS to refresh/reload all tasks - (IBAction)refreshTasks:(id)sender; @@ -145,6 +148,14 @@ /* METHODS */ + +//complete a few inits +// ->then invoke helper method to start enum'ing task (in bg thread) +-(void)go; + +//init (setup) XPC connection +-(BOOL)initXPC; + - (IBAction)switchView:(id)sender; //init tracking areas for buttons diff --git a/AppDelegate.m b/AppDelegate.m index c9a2173..174f500 100755 --- a/AppDelegate.m +++ b/AppDelegate.m @@ -9,18 +9,19 @@ #import "Exception.h" #import "Utilities.h" #import "AppDelegate.h" +#import "serviceInterface.h" #import "TaskTableController.h" #import "RequestRootWindowController.h" #import "Task.h" -//TODO: add IPV6 :: as 0.0.0.0? (since we do this for IPV4 i think) -//TODO: filter out dup'd networks (airportd 0:0..) -not sure want to do this -//TODO: first time (w/ auth) dylibs don't show up? -//TODO: remove 'pref' from menu - or disable? +//TODO: path truncated in 'info' window (1password mini) - but weird when selected :/ +// resize text manually? http://stackoverflow.com/questions/6519995/modifying-an-nstextfields-font-size-according-to-content-length +//TODO: filter out dup'd networks (airportd 0:0..) -not sure want to do this //TODO: 'flagged' items button? +//TODO: add 'am i on main thread' guard and test @implementation AppDelegate @@ -46,6 +47,7 @@ @synthesize taskEnumerator; @synthesize viewSelector; @synthesize searchButton; +@synthesize xpcConnection; //@synthesize taskScrollView; @@ -71,23 +73,11 @@ // ->main entry point -(void)applicationDidFinishLaunching:(NSNotification *)notification { - //TODO: remove - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"]; - - //user defaults - //NSUserDefaults* defaults = nil; - - //flag for first time - //BOOL isFirstRun = NO; - //first thing... // ->install exception handlers! //TODO: re-enable //installExceptionHandlers(); - //self.taskScrollView.wantsLayer = TRUE; - //self.taskScrollView.layer.cornerRadius = 20; - //init virus total object virusTotalObj = [[VirusTotal alloc] init]; @@ -109,39 +99,17 @@ if(YES != [self isAuthenticated]) { //display auth popup - // ->will kick off task emun on successful auth :) + // ->will invoke 'go' method on successful auth [self askForRoot]; } + //go! + // ->setup tracking areas and begin thread that explores tasks else { - //init mouse-over areas - [self initTrackingAreas]; - //go! - [self exploreTasks]; + [self go]; } - - - /* - //load defaults - defaults = [NSUserDefaults standardUserDefaults]; - - //extact first run key - // ->nil means first time! - if(nil == [defaults objectForKey:PREF_FIRST_RUN]) - { - //set flag - isFirstRun = YES; - - //set flag persistently - [defaults setBool:NO forKey:PREF_FIRST_RUN]; - - //flush/save - [defaults synchronize]; - } - */ - //set default top pane view to flat self.taskViewFormat = FLAT_VIEW; @@ -177,10 +145,95 @@ return; } +//complete a few inits +// ->then invoke helper method to start enum'ing task (in bg thread) +-(void)go +{ + //init XPC + if(YES != [self initXPC]) + { + + //bail + goto bail; + } + + //init mouse-over areas + [self initTrackingAreas]; + + //go! + [self exploreTasks]; + +//bail +bail: + + return; +} + + +//init (setup) XPC connection +-(BOOL)initXPC +{ + //status + BOOL initialized = NO; + + //alloc XPC connection + xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.objective-see.remoteTaskService"]; + + //sanity check + if(nil == self.xpcConnection) + { + //err msg + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to find/initialize XPC service"); + + //bail + goto bail; + } + + //set remote object interface + self.xpcConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(remoteTaskProto)]; + + //set classes + // ->arrays & strings are what is ok to vend + [self.xpcConnection.remoteObjectInterface + setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSMutableDictionary class], [NSString class], nil] + forSelector: @selector(enumerateDylibs:withReply:) + argumentIndex: 0 // the first parameter + ofReply: YES // in the method itself. + ]; + + //set classes + // ->arrays & strings are what is ok to vend + [self.xpcConnection.remoteObjectInterface + setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSMutableDictionary class], [NSString class], nil] + forSelector: @selector(enumerateFiles:withReply:) + argumentIndex: 0 // the first parameter + ofReply: YES // in the method itself. + ]; + + //set classes + // ->arrays & strings are what is ok to vend + [self.xpcConnection.remoteObjectInterface + setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSMutableDictionary class], [NSString class], [NSNumber class], nil] + forSelector: @selector(enumerateNetwork:withReply:) + argumentIndex: 0 // the first parameter + ofReply: YES // in the method itself. + ]; + + //resume + [self.xpcConnection resume]; + + //happy + initialized = YES; + +//bail +bail: + + return initialized; +} + //check if app is auth'd // ->specifically, if XPC service is setuid -//TODO: error checking!? -(BOOL)isAuthenticated { //flag @@ -195,9 +248,29 @@ //get path to XPC service xpcService = getPath2XPC(); + //sanity check + if(nil == xpcService) + { + //err msg + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to get path to XPC service"); + + //bail + goto bail; + } + //get XPC services' attributes fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:xpcService error:nil]; + //sanity check + if(nil == fileAttributes) + { + //err msg + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to file attributes for XPC service"); + + //bail + goto bail; + } + //check if (fully) auth'd // ->owned by r00t & SETUID if( (0 == [fileAttributes[NSFileOwnerAccountID] unsignedLongValue]) && @@ -206,6 +279,9 @@ //set flag isAuthenticated = YES; } + +//bail +bail: return isAuthenticated; } @@ -426,6 +502,9 @@ bail: //tag NSUInteger segmentTag = 0; + //not found msg + NSString* noItemsMsg = nil; + //get segment tag segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]]; @@ -456,7 +535,7 @@ bail: self.bottomViewController.tableItems = self.currentTask.dylibs; //if there is none - self.noItemsLabel.stringValue = @"no dylibs found"; + noItemsMsg = @"no dylibs found"; break; @@ -467,7 +546,7 @@ bail: self.bottomViewController.tableItems = self.currentTask.files; //if there is none - self.noItemsLabel.stringValue = @"no files found"; + noItemsMsg = @"no files found"; break; @@ -478,7 +557,7 @@ bail: self.bottomViewController.tableItems = self.currentTask.connections; //if there is none - self.noItemsLabel.stringValue = @"no network connections found"; + noItemsMsg = @"no network connections found"; break; @@ -486,8 +565,13 @@ bail: break; } + //execute on current thread if(YES == [NSThread isMainThread]) { + //set not found label + self.noItemsLabel.stringValue = noItemsMsg; + + //finalize [self finalizeBottomReload]; } else @@ -496,7 +580,12 @@ bail: // ->in main UI thread dispatch_async(dispatch_get_main_queue(), ^{ + //set not found label + self.noItemsLabel.stringValue = noItemsMsg; + + //finalize [self finalizeBottomReload]; + }); } @@ -550,10 +639,14 @@ bail: // ->use all tasks if(YES != self.taskTableController.isFiltered) { - //TODO: sync? YESSS!!!! - + //sync + @synchronized(self.taskEnumerator.tasks) + { + //get tasks tasks = self.taskEnumerator.tasks; + + //reload each row w/ new VT info for(NSNumber* taskPid in tasks) { //extract task @@ -566,11 +659,18 @@ bail: [self reloadRow:task]; } } + + }//sync + } //when filtered // ->use filtered items else { + //sync + @synchronized(self.taskTableController.filteredItems) + { + //filtered items for(Task* task in self.taskTableController.filteredItems) { @@ -581,13 +681,14 @@ bail: [self reloadRow:task]; } } + + }//sync } - }//top pane //bottom pane - // ->can just invoke 'reloadRow' method (which has logic to handle filtering, ignoring 'not found' items, etc. + // ->can just invoke 'reloadRow' method (which has logic to handle filtering, ignoring 'not found' items, etc.) else { //reload @@ -708,9 +809,8 @@ bail: return; } -//TODO: don't think we need to sort by pid, since tree view, just uses kids!!! //sort tasks -// ->either name (flat view) or pid (tree view) +// ->just by name (for flat view) -(void)sortTasksForView:(OrderedDictionary*)tasks; { //sort tasks @@ -720,13 +820,6 @@ bail: //sort [tasks sort:SORT_BY_NAME]; } - //sort tasks - // ->tree view, sort by pid - else - { - //sort - [tasks sort:SORT_BY_PID]; - } return; } @@ -746,7 +839,6 @@ bail: dispatch_async(dispatch_get_main_queue(), ^{ //refresh - //[self.taskTableController refresh]; [(id)self.taskTableController refresh]; }); @@ -756,7 +848,6 @@ bail: // ->just refresh else { - //TODO: currentViewCont?!? //refresh [(id)self.taskTableController refresh]; } @@ -764,85 +855,6 @@ bail: return; } - -/* -//callback method, invoked by virus total when plugin's items have been processed -// ->reload table if plugin matches active plugin --(void)itemsProcessed:(PluginBase*)plugin -{ - //if there are any flagged items - // ->reload category table (to trigger title turning red) - if(0 != plugin.flaggedItems.count) - { - //execute on main (UI) thread - dispatch_sync(dispatch_get_main_queue(), ^{ - - //reload category table - [self.categoryTableController customReload]; - - }); - } - - //check if active plugin matches - if(plugin == self.selectedPlugin) - { - //execute on main (UI) thread - dispatch_sync(dispatch_get_main_queue(), ^{ - - //scroll to top of item table - [self.taskTableController scrollToTop]; - - //reload item table - [self.taskTableController.itemTableView reloadData]; - - }); - } - - return; -} -*/ - -/* - -//update a single row --(void)itemProcessed:(File*)fileObj rowIndex:(NSUInteger)rowIndex -{ - //reload category table (on main thread) - // ->ensures correct title color (red, or reset) - dispatch_sync(dispatch_get_main_queue(), ^{ - - //reload category table - [self.categoryTableController customReload]; - - }); - - - - //check if active plugin matches - if(fileObj.plugin == self.selectedPlugin) - { - //execute on main (UI) thread - dispatch_sync(dispatch_get_main_queue(), ^{ - - //start table updates - [self.taskTableController.itemTableView beginUpdates]; - - //update - [self.taskTableController.itemTableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:rowIndex] columnIndexes:[NSIndexSet indexSetWithIndex:0]]; - - //end table updates - [self.taskTableController.itemTableView endUpdates]; - - }); - } - - - return; -} - -*/ - - //callback when user has updated prefs // ->reload table, etc -(void)applyPreferences @@ -1064,8 +1076,10 @@ bail: //start JSON [output appendString:@"{\"tasks:\":["]; - //TODO: sync taskEnumerator.tasks!! since user can click 'refresh' etc? - + //sync + @synchronized(self.taskEnumerator.tasks) + { + //get tasks for(NSNumber* taskPid in self.taskEnumerator.tasks) { @@ -1073,6 +1087,8 @@ bail: [output appendFormat:@"{%@},", [self.taskEnumerator.tasks[taskPid] toJSON]]; } + }//sync + //remove last ',' if(YES == [output hasSuffix:@","]) { @@ -1088,7 +1104,7 @@ bail: if(YES != [output writeToURL:[panel URL] atomically:NO encoding:NSUTF8StringEncoding error:&error]) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: saving output to %@ failed with %@", [panel URL], error); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: saving output to %s failed with %s", [[panel URL] fileSystemRepresentation], [[error description] UTF8String]); //init popup w/ error msg saveResultPopup = [NSAlert alertWithMessageText:@"ERROR: failed to save output" defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"details: %@", error]; @@ -1117,11 +1133,11 @@ bail: //automatically invoked when user clicks 'search' button // ->perform global search -//TODO: implement +//TODO: implement (in next version) - (IBAction)search:(id)sender { //'unimplemented' msg - __block NSAlert* errorPopup = nil; + NSAlert* errorPopup = nil; //init popup w/ msg errorPopup = [NSAlert alertWithMessageText:@"sorry, 'global search' not yet implemented" defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"...should be in next version :)"]; @@ -1267,7 +1283,6 @@ bail: //(automatically) invoked on segmented button click or (manually) on task (top pane) switch // ->change input (for pane) & then refresh it -//TODO: make xpcConnection appDelegate iVar -(IBAction)selectBottomPaneContent:(id)sender { //tag @@ -1296,21 +1311,6 @@ bail: //get segment tag segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]]; - /* - //for dylibs - // ->don't want to re-enum if initial enumerations is still occuring - if( (DYLIBS_VIEW == segmentTag) && - (YES != [self.taskEnumerator shouldEnumDylibs]) && - (0 != self.currentTask.dylibs.count) ) - { - //just reload pane - [self reloadBottomPane:self.currentTask itemView:segmentTag]; - - //bail - goto bail; - } - */ - //always hide 'no items' label self.noItemsLabel.hidden = YES; @@ -1354,7 +1354,7 @@ bail: //(re)enumerate dylibs via XPC // ->triggers table reload when done - [self.currentTask enumerateDylibs:self.taskEnumerator.xpcConnection allDylibs:self.taskEnumerator.dylibs]; + [self.currentTask enumerateDylibs:self.xpcConnection allDylibs:self.taskEnumerator.dylibs]; break; @@ -1366,7 +1366,7 @@ bail: //(re)enumerate files via XPC // ->triggers table reload when done - [self.currentTask enumerateFiles:self.taskEnumerator.xpcConnection]; + [self.currentTask enumerateFiles:self.xpcConnection]; break; @@ -1378,7 +1378,7 @@ bail: //(re)enumerate network connections via XPC // ->triggers table reload when done - [self.currentTask enumerateNetworking:self.taskEnumerator.xpcConnection]; + [self.currentTask enumerateNetworking:self.xpcConnection]; break; @@ -1571,7 +1571,6 @@ bail: } - //action for 'refresh' button // ->query OS to refresh/reload all tasks -(IBAction)refreshTasks:(id)sender @@ -1581,6 +1580,18 @@ bail: //select top row [self.taskTableController.itemView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; + + //TODO: don't reset filtered items? + // ...will require some smart filtering :/ + + //unset filter flag + self.taskTableController.isFiltered = NO; + + //remove all filtered items + [self.taskTableController.filteredItems removeAllObjects]; + + //reset filter box + self.filterTasksBox.stringValue = @""; //scroll to top [self.taskTableController scrollToTop]; diff --git a/Filter.m b/Filter.m index cfb9956..8d9792d 100644 --- a/Filter.m +++ b/Filter.m @@ -176,39 +176,58 @@ NSString * const KEYWORDS[] = {@"#apple", @"#nonapple", @"#signed", @"#unsigned" } //filter network connections -//TODO: match on state, etc? -//TODO: make format of range seach/check/continue +//TODO: match on family/connection type -(void)filterConnections:(NSString*)filterText items:(NSMutableArray*)items results:(NSMutableArray*)results { - //local IP addr range - NSRange localIPRange = {0}; - - //local port range - NSRange localPortRange = {0}; - - //TODO: add remote ip/port, state, proto, family? - //first reset filter'd items [results removeAllObjects]; //iterate over all tasks for(Connection* item in items) { - //init name range - localIPRange = [item.localIPAddr rangeOfString:filterText options:NSCaseInsensitiveSearch]; - - //init path range - localPortRange = [[NSString stringWithFormat:@"%d", [item.localPort unsignedShortValue]] rangeOfString:filterText options:NSCaseInsensitiveSearch]; - - //check for match - if( (NSNotFound != localIPRange.location) || - (NSNotFound != localPortRange.location) ) + //check local ip + if(NSNotFound != [item.localIPAddr rangeOfString:filterText options:NSCaseInsensitiveSearch].location) { //save match [results addObject:item]; + + //next + continue; } - }//all items + //check local port + if(NSNotFound != [[NSString stringWithFormat:@"%d", [item.localPort unsignedShortValue]] rangeOfString:filterText options:NSCaseInsensitiveSearch].location) + { + //save match + [results addObject:item]; + + //next + continue; + } + + //check remote ip + if( (nil != item.remoteIPAddr) && + (NSNotFound != [item.remoteIPAddr rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) + { + //save match + [results addObject:item]; + + //next + continue; + } + + //check remote port + if( (nil != item.remoteIPAddr) && + (NSNotFound != [[NSString stringWithFormat:@"%d", [item.remotePort unsignedShortValue]] rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) + { + //save match + [results addObject:item]; + + //next + continue; + } + + }//all connections return; } @@ -346,7 +365,7 @@ bail: BOOL isFlagged = NO; //check - //TODO: query VT if needed? + // ->note: assumes that VT query has already completed... if( (nil != item.vtInfo) && (0 != [item.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) ) { diff --git a/InfoWindowController.m b/InfoWindowController.m index a768f01..8a8b75b 100644 --- a/InfoWindowController.m +++ b/InfoWindowController.m @@ -119,6 +119,15 @@ //set name [self.name setStringValue:[self valueForStringItem:task.binary.name default:@"unknown"]]; + //flagged items + // ->make name red! + if( (nil != task.binary.vtInfo) && + (0 != [task.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) ) + { + //red + self.name.textColor = [NSColor redColor]; + } + //set command line // ->done just in time (first time) if(nil == task.arguments) @@ -129,18 +138,6 @@ //set args [self.arguments setStringValue:[self valueForStringItem:[task.arguments componentsJoinedByString:@""] default:@"no arguments"]]; - - //TODO:enable - /* - //flagged files - // ->make name red! - if( (nil != ((File*)self.itemObj).vtInfo) && - (0 != [((File*)self.itemObj).vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) ) - { - //set color (light red) - self.name.textColor = [NSColor redColor]; - } - */ //set path [self.path setStringValue:[self valueForStringItem:task.binary.path default:@"unknown"]]; @@ -174,10 +171,10 @@ [self.sign setStringValue:[self valueForStringItem:[task.binary formatSigningInfo] default:@"not signed"]]; } - //handle binaries + //handle binaries (dylibs) else if(YES == [self.itemObj isKindOfClass:[Binary class]]) { - //type cast + //cast as binary/dylib dylib = (Binary*)self.itemObj; //set icon @@ -186,17 +183,14 @@ //set name [self.name setStringValue:[self valueForStringItem:dylib.name default:@"unknown"]]; - //TODO: enable?! - /* - //flagged files - // ->make name red! - if( (nil != ((File*)self.itemObj).vtInfo) && - (0 != [((File*)self.itemObj).vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) ) - { - //set color (light red) - self.name.textColor = [NSColor redColor]; - } - */ + //flagged items + // ->make name red! + if( (nil != dylib.vtInfo) && + (0 != [dylib.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) ) + { + //red + self.name.textColor = [NSColor redColor]; + } //set path [self.path setStringValue:[self valueForStringItem:dylib.path default:@"unknown"]]; diff --git a/Items/Connection.m b/Items/Connection.m index a3e3d90..ba68dc1 100644 --- a/Items/Connection.m +++ b/Items/Connection.m @@ -19,7 +19,6 @@ { //super //self = [super initWithParams:params]; - //TODO: think about this - Connection doesn't share any baseItem stuffz self = [super init]; if(nil != self) { diff --git a/Items/File.m b/Items/File.m index 03ac056..9e4e7bf 100644 --- a/Items/File.m +++ b/Items/File.m @@ -5,13 +5,13 @@ // Created by Patrick Wardle on 2/19/15. // Copyright (c) 2015 Objective-See. All rights reserved. // - - #import "File.h" #import "Consts.h" #import "Utilities.h" #import "AppDelegate.h" +#import + @implementation File @synthesize type; @@ -26,11 +26,10 @@ if(self) { //always skip not-existent paths - // ->also get set a directory flag at the same time ;) if(YES != [[NSFileManager defaultManager] fileExistsAtPath:params[KEY_RESULT_PATH]]) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: %@ not found", params[KEY_RESULT_PATH]); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: %s not found", [params[KEY_RESULT_PATH] UTF8String]); //set self to nil self = nil; diff --git a/RequestRootWindowController.m b/RequestRootWindowController.m index eb0d3ec..f199215 100644 --- a/RequestRootWindowController.m +++ b/RequestRootWindowController.m @@ -9,9 +9,10 @@ #import "Utilities.h" #import "AppDelegate.h" - #import "RequestRootWindowController.h" +#import + @implementation RequestRootWindowController @@ -123,7 +124,7 @@ if(errAuthorizationSuccess != osStatus) { //err msg - NSLog(@"ERROR: AuthorizationCreate() failed with %d", osStatus); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: AuthorizationCreate() failed with %d", osStatus); //bail goto bail; @@ -134,7 +135,7 @@ if(errAuthorizationSuccess != osStatus) { //err msg - NSLog(@"ERROR: AuthorizationExecuteWithPrivileges() failed with %d", osStatus); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: AuthorizationExecuteWithPrivileges() failed with %d", osStatus); //set result msg [self.statusMsg setStringValue: [NSString stringWithFormat:@"error: failed with %d", osStatus]]; @@ -169,7 +170,7 @@ if(errAuthorizationSuccess != osStatus) { //err msg - NSLog(@"ERROR: AuthorizationExecuteWithPrivileges() failed with %d", osStatus); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: AuthorizationExecuteWithPrivileges() failed with %d", osStatus); //set result msg [self.statusMsg setStringValue: [NSString stringWithFormat:@"error: failed with %d", osStatus]]; @@ -187,9 +188,11 @@ //no exit self.shouldExit = NO; - //start enumerating tasks - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) exploreTasks]; + //call back into app delegate + // ->kick off task enum, etc + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) go]; + //bail bail: diff --git a/Task.h b/Task.h index 11d433d..f4a9a19 100644 --- a/Task.h +++ b/Task.h @@ -77,8 +77,6 @@ struct dyld_image_info_32 { //get command-line args -(void)getArguments; --(void)generateBinaryInfo; - //enumerate all dylibs // ->new ones are added to 'existingDylibs' (global) dictionary -(void)enumerateDylibs:(NSXPCConnection*)xpcConnection allDylibs:(NSMutableDictionary*)allDylibs; @@ -90,7 +88,6 @@ struct dyld_image_info_32 { -(void)enumerateNetworking:(NSXPCConnection*)xpcConnection; //convert self to JSON string -// TODO: add dylibs, files, networking -(NSString*)toJSON; @end diff --git a/Task.m b/Task.m index eb6a1e3..76ec424 100644 --- a/Task.m +++ b/Task.m @@ -32,22 +32,16 @@ @synthesize pid; @synthesize uid; -//@synthesize icon; -//@synthesize name; -//@synthesize path; @synthesize ppid; @synthesize files; @synthesize binary; -//@synthesize bundle; @synthesize dylibs; @synthesize children; @synthesize arguments; @synthesize connections; -//TODO: make sure we only check signature of binary once!!! - //init w/ a pid + path -// note: time consuming init's are done in '' method +// note: time consuming init's are done in other methods -(id)initWithPID:(NSNumber*)taskPID andPath:(NSString*)taskPath { //existing binaries @@ -61,7 +55,6 @@ self = [super init]; if(nil != self) { - //TODO: sync? or always access w/ direct var //grab existings binaries existingBinaries = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.executables; @@ -118,8 +111,12 @@ // ->this will process in background [((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.binaryQueue enqueue:self.binary]; - //add it to 'global' list - existingBinaries[taskPath] = self.binary; + //sync + @synchronized(existingBinaries) + { + //add it to 'global' list + existingBinaries[taskPath] = self.binary; + } } }//init self @@ -130,15 +127,6 @@ bail: return self; } -// --(void)generateBinaryInfo -{ - //create main binary - //self.binary = [[Binary alloc] initWithParams:@{KEY_RESULT_PATH:self.path}]; - - return; -} - //get command-line args -(void)getArguments { @@ -310,7 +298,6 @@ bail: { //free free(processArgs); - } return; @@ -524,9 +511,12 @@ bail: //generate detailed info [newFile generateDetailedInfo]; - //TODO: sync! - //save into global list - [((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.files setObject:newFile forKey:filePath]; + //sync + @synchronized(((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.files) + { + //save into global list + [((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.files setObject:newFile forKey:filePath]; + } } }]; @@ -542,7 +532,8 @@ bail: //remove any existing enum'd networking sockets/connections [self.connections removeAllObjects]; - NSLog(@"invoking XPC to enumer networking"); + //dbg msg + //NSLog(@"invoking XPC to enumer networking"); //invoke XPC service (running as r00t) // ->will enumerate network sockets/connections, then invoke reply block so can save into iVar @@ -565,10 +556,8 @@ bail: } } - ////TODO: on main thead? //reload bottom pane [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:self itemView:NETWORKING_VIEW]; - }]; return; diff --git a/TaskEnumerator.h b/TaskEnumerator.h index 8dbd38b..b407206 100644 --- a/TaskEnumerator.h +++ b/TaskEnumerator.h @@ -19,9 +19,6 @@ /* PROPERTIES */ -//flag indicating first scan is complete -//@property BOOL firstScanComplete; - //all tasks objects @property(nonatomic, retain)OrderedDictionary* tasks; @@ -34,10 +31,6 @@ //all dylibs @property(nonatomic, retain)NSMutableDictionary* dylibs; -//remote XPC interface -//TODO: weak OK? -@property (nonatomic, retain) NSXPCConnection* xpcConnection; - //queue // ->contains binaries that should be processed @property (nonatomic, retain) Queue* binaryQueue; @@ -56,10 +49,6 @@ // ->ensures order of parent's (by pid), is preserved -(void)generateAncestries:(OrderedDictionary*)newTasks; -//determine if dylibs should be (re)enumerated -// ->generally yes, unless the first enumeration (of all tasks) is not complete -//-(BOOL)shouldEnumDylibs; - //remove a task // ->contain extra logic to remove children, etc -(void)removeTask:(Task*)task; diff --git a/TaskEnumerator.m b/TaskEnumerator.m index 198f8d9..a35489f 100644 --- a/TaskEnumerator.m +++ b/TaskEnumerator.m @@ -14,9 +14,10 @@ #import "AppDelegate.h" #import "Utilities.h" #import "TaskEnumerator.h" -#import "serviceInterface.h" -#include -#include + +#import +#import +#import @@ -29,9 +30,8 @@ @synthesize dylibs; @synthesize binaryQueue; @synthesize executables; -@synthesize xpcConnection; -//@synthesize firstScanComplete; + //init -(id)init @@ -49,42 +49,6 @@ //alloc dylibs dictionary dylibs = [NSMutableDictionary dictionary]; - //alloc XPC connection - xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.objective-see.remoteTaskService"]; - - //set remote object interface - self.xpcConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(remoteTaskProto)]; - - //set classes - // ->arrays & strings are what is ok to vend - [self.xpcConnection.remoteObjectInterface - setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSMutableDictionary class], [NSString class], nil] - forSelector: @selector(enumerateDylibs:withReply:) - argumentIndex: 0 // the first parameter - ofReply: YES // in the method itself. - ]; - - //set classes - // ->arrays & strings are what is ok to vend - [self.xpcConnection.remoteObjectInterface - setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSMutableDictionary class], [NSString class], nil] - forSelector: @selector(enumerateFiles:withReply:) - argumentIndex: 0 // the first parameter - ofReply: YES // in the method itself. - ]; - - //set classes - // ->arrays & strings are what is ok to vend - [self.xpcConnection.remoteObjectInterface - setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSMutableDictionary class], [NSString class], [NSNumber class], nil] - forSelector: @selector(enumerateNetwork:withReply:) - argumentIndex: 0 // the first parameter - ofReply: YES // in the method itself. - ]; - - //resume - [self.xpcConnection resume]; - //init binary processing queue binaryQueue = [[Queue alloc] init]; @@ -96,7 +60,7 @@ //enumerate all tasks // ->calls back into app delegate to update task (top) table when pau -// TOOD: call every x # of seconds? +// TODO: call every x # of seconds? -(void)enumerateTasks { //(new) task item @@ -150,10 +114,14 @@ continue; } - //TODO: sync? + //sync + @synchronized(self.tasks) + { //add new task [self.tasks setObject:newTask forKey:newTask.pid]; + + }//sync }//add new tasks @@ -243,7 +211,7 @@ if(status < 0) { //err - NSLog(@"OBJECTIVE-SEE ERROR: proc_listpids() failed with %d", status); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: proc_listpids() failed with %d", status); //bail goto bail; @@ -313,11 +281,8 @@ bail: return allTasks; } -//TODO: remove! //insert tasks into appropriate parent // ->ensures order of parent's (by pid), is preserved -//TODO: what about parentless procs!? (e.g. malware?) -//TODO: what about dead-parents, 'desktop helper' -(void)generateAncestries:(OrderedDictionary*)newTasks { //task @@ -353,12 +318,20 @@ bail: //get task task = newTasks[key]; + //ignore tasks that have died + if(YES != isAlive([task.pid intValue])) + { + //next + continue; + } + //get parent parent = newTasks[task.ppid]; - //when parent is nil + //when parent is nil or dead // ->default to launchd (pid 0x1) - if(nil == parent) + if( (nil == parent) || + (YES != isAlive([task.pid intValue])) ) { //default parent = self.tasks[@1]; diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 70d2e4c..80041c9 100644 --- a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -46,11 +46,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "VirusTotal.m" - timestampString = "457651407.339698" + timestampString = "459880884.303039" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "121" - endingLineNumber = "121" + startingLineNumber = "123" + endingLineNumber = "123" landmarkName = "-addItem:" landmarkType = "5"> @@ -62,27 +62,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Task.m" - timestampString = "458643111.392416" + timestampString = "460097895.698263" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "345" - endingLineNumber = "345" - landmarkName = "-enumerateDylibs:allDylibs:" - landmarkType = "5"> - - - - @@ -103,22 +87,6 @@ landmarkType = "5"> - - - - @@ -158,11 +126,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Task.m" - timestampString = "458643111.392416" + timestampString = "460097895.698263" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "438" - endingLineNumber = "438" + startingLineNumber = "425" + endingLineNumber = "425" landmarkName = "-enumerateDylibs:allDylibs:" landmarkType = "5"> @@ -174,11 +142,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "VirusTotal.m" - timestampString = "457651407.339698" + timestampString = "459880884.303039" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "112" - endingLineNumber = "112" + startingLineNumber = "114" + endingLineNumber = "114" landmarkName = "-addItem:" landmarkType = "5"> @@ -190,11 +158,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "RequestRootWindowController.m" - timestampString = "457652630.623627" + timestampString = "459880884.303039" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "24" - endingLineNumber = "24" + startingLineNumber = "25" + endingLineNumber = "25" landmarkName = "-awakeFromNib" landmarkType = "5"> @@ -222,11 +190,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Filter.m" - timestampString = "457848671.809721" + timestampString = "460097193.779482" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "217" - endingLineNumber = "217" + startingLineNumber = "236" + endingLineNumber = "236" landmarkName = "-binaryFulfillsKeyword:binary:" landmarkType = "5"> @@ -238,31 +206,15 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Filter.m" - timestampString = "457943064.104332" + timestampString = "460097193.779482" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "343" - endingLineNumber = "343" + startingLineNumber = "362" + endingLineNumber = "362" landmarkName = "-isFlagged:" landmarkType = "5"> - - - - @@ -286,31 +238,15 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskEnumerator.m" - timestampString = "458803386.948431" + timestampString = "459880884.303039" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "156" - endingLineNumber = "156" + startingLineNumber = "123" + endingLineNumber = "123" landmarkName = "-enumerateTasks" landmarkType = "5"> - - - - @@ -334,11 +270,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "AppDelegate.m" - timestampString = "459044856.502796" + timestampString = "460150711.336469" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "259" - endingLineNumber = "259" + startingLineNumber = "338" + endingLineNumber = "338" landmarkName = "@implementation AppDelegate" landmarkType = "3"> @@ -350,14 +286,46 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "459048374.675901" + timestampString = "459840842.999072" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "882" - endingLineNumber = "882" + startingLineNumber = "868" + endingLineNumber = "868" landmarkName = "-outlineView:rowViewForItem:" landmarkType = "5"> + + + + + + + + diff --git a/TaskTableController.m b/TaskTableController.m index f17998e..c16f9f5 100644 --- a/TaskTableController.m +++ b/TaskTableController.m @@ -25,8 +25,6 @@ #import -//TODO: need to do some sync or logic to handle swaps -otherwise crashes!!! - @implementation TaskTableController @synthesize itemView; @@ -520,8 +518,6 @@ bail: return; } - -//TODO: make sure this works for outline view!!! //grab a task at a row -(Task*)taskForRow:(id)sender { @@ -566,19 +562,9 @@ bail: //get row that's about to be selected rowView = [self.itemView viewAtColumn:0 row:taskRow makeIfNecessary:YES]; - //TODO: need this? - //when not filtered, use all tasks - //if(YES != isFiltered) - //{ - //extract task - // ->pid of task is view's id :) - task = tasks[[NSNumber numberWithInteger:(rowView.tag - PID_TAG_DELTA)]]; - //} - //when filtered, use filtered items - //else - //{ - // task = self.filteredItems[ - //} + //extract task + // ->pid of task is view's id :) + task = tasks[[NSNumber numberWithInteger:(rowView.tag - PID_TAG_DELTA)]]; //bail bail: @@ -837,9 +823,9 @@ bail: } -//TODO: combine logic - -//TODO: when combine, use pid of task is view's id - to lookup task :) -- (void)outlineViewSelectionDidChange:(NSNotification *)notification +//automatically ccalled when row is selected in outline view +// ->invoke helper function to handle selection +-(void)outlineViewSelectionDidChange:(NSNotification *)notification { //handle selection [self handleRowSelection]; diff --git a/UI/FileInfoWindow.xib b/UI/FileInfoWindow.xib index c2f57ea..397aaef 100644 --- a/UI/FileInfoWindow.xib +++ b/UI/FileInfoWindow.xib @@ -1,5 +1,5 @@ - + @@ -36,7 +36,7 @@ - + diff --git a/UI/FlatView.xib b/UI/FlatView.xib index 2a8c648..e336252 100755 --- a/UI/FlatView.xib +++ b/UI/FlatView.xib @@ -48,11 +48,11 @@ - - + + - - + + @@ -169,11 +169,12 @@ + - + - + diff --git a/UI/NetworkInfoWindow.xib b/UI/NetworkInfoWindow.xib index e458612..38b6dc1 100644 --- a/UI/NetworkInfoWindow.xib +++ b/UI/NetworkInfoWindow.xib @@ -1,5 +1,5 @@ - + @@ -8,16 +8,11 @@ - - - - - diff --git a/UI/TaskInfoWindow.xib b/UI/TaskInfoWindow.xib index ada1991..38563d5 100644 --- a/UI/TaskInfoWindow.xib +++ b/UI/TaskInfoWindow.xib @@ -1,5 +1,5 @@ - + @@ -38,7 +38,7 @@ - + diff --git a/UI/TreeView.xib b/UI/TreeView.xib index 092e4e8..30208f7 100755 --- a/UI/TreeView.xib +++ b/UI/TreeView.xib @@ -48,11 +48,11 @@ - - + + - - + + @@ -172,13 +172,14 @@ - + - + + diff --git a/Utilities.m b/Utilities.m index 60fa30f..c9b622f 100644 --- a/Utilities.m +++ b/Utilities.m @@ -11,6 +11,7 @@ #import #import +#import #import #import #import @@ -126,7 +127,7 @@ NSDictionary* extractSigningInfo(NSString* path) if(STATUS_SUCCESS != status) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: SecStaticCodeCreateWithPath() failed on %@ with %d", path, status); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: SecStaticCodeCreateWithPath() failed on %s with %d", [path UTF8String], status); //bail goto bail; @@ -149,7 +150,7 @@ NSDictionary* extractSigningInfo(NSString* path) if(STATUS_SUCCESS != status) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: SecCodeCopySigningInformation() failed on %@ with %d", path, status); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: SecCodeCopySigningInformation() failed on %s with %d", [path UTF8String], status); //bail goto bail; @@ -158,9 +159,13 @@ NSDictionary* extractSigningInfo(NSString* path) //determine if binary is signed by Apple signingStatus[KEY_SIGNING_IS_APPLE] = [NSNumber numberWithBool:isApple(path)]; } - - //TODO: bail, unsigned? - + //error + // ->not signed, or something else, so no need to check cert's names + else + { + //bail + goto bail; + } //init array for certificate names signingStatus[KEY_SIGNING_AUTHORITIES] = [NSMutableArray array]; @@ -245,7 +250,7 @@ BOOL isApple(NSString* path) if(STATUS_SUCCESS != status) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: SecStaticCodeCreateWithPath() failed on %@ with %d", path, status); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: SecStaticCodeCreateWithPath() failed on %s with %d", [path UTF8String], status); //bail goto bail; @@ -258,7 +263,7 @@ BOOL isApple(NSString* path) (requirementRef == NULL) ) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: SecRequirementCreateWithString() failed on %@ with %d", path, status); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: SecRequirementCreateWithString() failed on %s with %d", [path UTF8String], status); //bail goto bail; @@ -409,8 +414,7 @@ NSDictionary* hashFile(NSString* filePath) if(nil == (fileContents = [NSData dataWithContentsOfFile:filePath])) { //err msg - //TODO: re-enable - //NSLog(@"OBJECTIVE-SEE ERROR: couldn't load %@ to hash", filePath); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: couldn't load %s to hash", [filePath UTF8String]); //bail goto bail; @@ -694,8 +698,6 @@ BOOL isAlive(pid_t targetPID) } - //NSLog(@"killing %d: %d/%d", targetPID, result, errno); - return isAlive; } diff --git a/VirusTotal.m b/VirusTotal.m index 4b14826..614f443 100644 --- a/VirusTotal.m +++ b/VirusTotal.m @@ -12,6 +12,8 @@ #import "VirusTotal.h" #import "AppDelegate.h" +#import + @implementation VirusTotal @synthesize items; @@ -439,7 +441,7 @@ if(nil == postData) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: failed to convert request %@ to JSON", postData); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to convert request %s to JSON", [[postData description] UTF8String]); //bail goto bail; @@ -472,11 +474,11 @@ //sanity check(s) if( (nil == vtData) || - (nil != error) || - (200 != (long)[(NSHTTPURLResponse *)httpResponse statusCode]) ) + (nil != error) || + (200 != (long)[(NSHTTPURLResponse *)httpResponse statusCode]) ) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: failed to query VirusTotal (%@, %@)", error, httpResponse); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to query VirusTotal (%s, %s)", [[error description] UTF8String], [[httpResponse description] UTF8String]); //bail goto bail; @@ -493,7 +495,7 @@ @catch (NSException *exception) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: converting response %@ to JSON threw %@", vtData, exception); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: converting response %s to JSON threw %s", [[vtData description] UTF8String], [[exception description] UTF8String]); //bail goto bail; @@ -503,7 +505,7 @@ if(nil == results) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: failed to convert response %@ to JSON", vtData); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to convert response %s to JSON", [[vtData description] UTF8String]); //bail goto bail; @@ -578,7 +580,7 @@ bail: if(nil == fileContents) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: failed to load %@ into memory for submission", item.path); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to load %s into memory for submission", [item.path UTF8String]); //bail goto bail; @@ -618,7 +620,7 @@ bail: (200 != (long)[(NSHTTPURLResponse *)httpResponse statusCode]) ) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: failed to query VirusTotal (%@, %@)", error, httpResponse); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to query VirusTotal (%s, %s)", [[error description] UTF8String], [[httpResponse description] UTF8String]); //bail goto bail; @@ -635,7 +637,7 @@ bail: @catch (NSException *exception) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: converting response %@ to JSON threw %@", vtData, exception); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: converting response %s to JSON threw %s", [[vtData description] UTF8String], [[exception description] UTF8String]); //bail goto bail; @@ -645,7 +647,7 @@ bail: if(nil == results) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: failed to convert response %@ to JSON", vtData); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to convert response %s to JSON", [[vtData description] UTF8String]); //bail goto bail; @@ -683,13 +685,12 @@ bail: if(nil == result) { //err msg - NSLog(@"OBJECTIVE-SEE ERROR: failed to re-scan %@", item.name); + syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: failed to re-scan %s", [item.name UTF8String]); //bail goto bail; } - //bail bail: @@ -726,6 +727,7 @@ bail: //TODO: do something with detections!? + // ->blinking button, user's can click to see 'flagged items' popup //if(0 != [result[VT_RESULTS_POSITIVES] unsignedIntegerValue]) } diff --git a/en.lproj/MainMenu.xib b/en.lproj/MainMenu.xib index 4d62de1..8433ff0 100755 --- a/en.lproj/MainMenu.xib +++ b/en.lproj/MainMenu.xib @@ -2,8 +2,9 @@ - + + @@ -24,7 +25,7 @@ - +