diff --git a/AppDelegate.h b/AppDelegate.h index 8e4414c..c43d7b5 100755 --- a/AppDelegate.h +++ b/AppDelegate.h @@ -15,6 +15,7 @@ #import "AboutWindowController.h" #import "PrefsWindowController.h" +#import "FlaggedItems.h" #import "ResultsWindowController.h" #import "RequestRootWindowController.h" @@ -27,7 +28,6 @@ @interface AppDelegate : NSObject { - //NSViewController *bottomViewController; } @@ -111,6 +111,9 @@ //results window controller @property(nonatomic, retain)ResultsWindowController* resultsWindowController; +//flagged items window controller +@property(nonatomic, retain)FlaggedItems* flagItemsWindowController; + //currently selected task @property(nonatomic, retain)Task* currentTask; @@ -119,11 +122,19 @@ //'no items' found label for bottom pane @property (weak) IBOutlet NSTextField *noItemsLabel; + +//search button @property (weak) IBOutlet NSButton *searchButton; //refresh button @property (weak) IBOutlet NSButton *refreshButton; +//flagged items button +@property (weak) IBOutlet NSButton *flaggedButton; + +//flagged items label +@property (weak) IBOutlet NSTextField *flaggedLabel; + //top constraint @property(nonatomic, retain)NSLayoutConstraint* topConstraint; @@ -137,7 +148,10 @@ @property(nonatomic, retain)NSLayoutConstraint* trailingConstraint; //remote XPC interface -@property (nonatomic, retain) NSXPCConnection* xpcConnection; +@property(nonatomic, retain) NSXPCConnection* xpcConnection; + +//flagged items +@property(nonatomic, retain) NSMutableArray* flaggedItems; /* METHODS */ @@ -201,4 +215,11 @@ //constrain subview to parent view -(void)constrainView:(NSView*)containerView subView:(NSView*)subView; +//display (in separate popup) all flagged items +-(IBAction)showFlaggedItems:(id)sender; + +//save a flagged binary +// ->also set text flagged items button label to red +-(void)saveFlaggedBinary:(Binary*)binary; + @end diff --git a/AppDelegate.m b/AppDelegate.m index 761e859..d34887a 100755 --- a/AppDelegate.m +++ b/AppDelegate.m @@ -24,6 +24,15 @@ //TODO: add 'am i on main thread' guard and test //TODO: filter dylibs, no first responder! +//TODO: autolayout vertically +//TODO: filter VT results +//TODO: # autocomplete +//TODO: keyboard shortcuts +// see: https://mail.google.com/mail/u/0/#inbox/14eeb163d4dd2852 +//TODO: show 'from where' via quarantine attrz +//TODO: show user (after pid): -> (pid, user)? +//TODO: when filtering, and then refresh, doesn't go to row #0 :/ + @implementation AppDelegate @@ -41,6 +50,7 @@ @synthesize currentTask; @synthesize requestRootWindowController; @synthesize taskViewFormat; +@synthesize flagItemsWindowController; @synthesize scannerThread; @synthesize progressIndicator; @@ -50,11 +60,14 @@ @synthesize viewSelector; @synthesize searchButton; @synthesize xpcConnection; +@synthesize flaggedItems; //@synthesize taskScrollView; //TODO: check if VT can be reached! if not, error? or don't show '0 VT results detected' etc... +//TODO: JavaW (iWorm) dylibs... + //center window // ->also make front -(void)awakeFromNib @@ -77,8 +90,7 @@ { //first thing... // ->install exception handlers! - //TODO: re-enable - //installExceptionHandlers(); + installExceptionHandlers(); //init virus total object virusTotalObj = [[VirusTotal alloc] init]; @@ -86,6 +98,9 @@ //init filter obj filterObj = [[Filter alloc] init]; + //alloc flagged items + flaggedItems = [NSMutableArray array]; + //no need to have a first responder [self.window makeFirstResponder:nil]; @@ -752,6 +767,13 @@ bail: //add tracking area to logo button [self.logoButton addTrackingArea:trackingArea]; + + //init tracking area + // ->for flagged items button + trackingArea = [[NSTrackingArea alloc] initWithRect:[self.flaggedButton bounds] options:(NSTrackingInVisibleRect|NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways) owner:self userInfo:@{@"tag":[NSNumber numberWithUnsignedInteger:self.flaggedButton.tag]}]; + + //add tracking area to flaggd items button + [self.flaggedButton addTrackingArea:trackingArea]; return; } @@ -963,6 +985,13 @@ bail: //set imageName = @"logoApple"; } + + //set original flagged items image + else if(FLAGGED_BUTTON_TAG == tag) + { + //set + imageName = @"flagged"; + } } //highlight button else @@ -991,6 +1020,13 @@ bail: //set imageName = @"logoAppleOver"; } + + //set mouse over flagged items image + else if(FLAGGED_BUTTON_TAG == tag) + { + //set + imageName = @"flaggedOver"; + } } //set image @@ -1337,6 +1373,9 @@ bail: //init placeholder text for dylibs filterPlaceholder = @"Filter Dylibs"; + //remove all task's dylibs + [self.currentTask.dylibs removeAllObjects]; + //(re)enumerate dylibs via XPC // ->triggers table reload when done [self.currentTask enumerateDylibs:self.xpcConnection allDylibs:self.taskEnumerator.dylibs]; @@ -1349,6 +1388,9 @@ bail: //init placeholder text for files filterPlaceholder = @"Filter Files"; + //remove all task's dylibs + [self.currentTask.files removeAllObjects]; + //(re)enumerate files via XPC // ->triggers table reload when done [self.currentTask enumerateFiles:self.xpcConnection]; @@ -1380,7 +1422,7 @@ bail: dispatch_sync(dispatch_get_main_queue(), ^{ //set placeholder - [self.filterItemsBox setPlaceholderString:filterPlaceholder]; + [[self.filterItemsBox cell] setPlaceholderString:filterPlaceholder]; }); } //in main thread already @@ -1388,7 +1430,7 @@ bail: else { //set placeholder - [self.filterItemsBox setPlaceholderString:filterPlaceholder]; + [[self.filterItemsBox cell] setPlaceholderString:filterPlaceholder]; } @@ -1649,5 +1691,76 @@ bail: return; } +//TODO: handle reset on refresh? +//save a flagged item +// ->also set text flagged items button label to red +-(void)saveFlaggedBinary:(Binary*)binary +{ + //sync to save + @synchronized(self.flaggedItems) + { + //save + [self.flaggedItems addObject:binary]; + } + + //when count is 1 + // ->means first flagged file so set text to red + if(1 == self.flaggedItems.count) + { + //set to red + self.flaggedLabel.textColor = [NSColor redColor]; + } + + return; +} + +//button handle for 'flagged items' button +// ->display (in separate popup) all flagged items +-(IBAction)showFlaggedItems:(id)sender +{ + //alert box + NSAlert* alert = nil; + + //handle case where there aren't any flagged items + // ->just show alert + if(0 == self.flaggedItems.count) + { + //alloc/init alert + alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:@"No items flagged by VirusTotal"] defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"horray! 😇"]; + + //and show it + [alert runModal]; + } + + //show flagged items + else + { + //alloc/init settings window + if(nil == self.flagItemsWindowController) + { + //alloc/init + flagItemsWindowController = [[FlaggedItems alloc] initWithWindowNibName:@"FlaggedItems"]; + } + + //show it + [self.flagItemsWindowController showWindow:self]; + + //invoke function in background that will make window modal + // ->waits until window is non-nil + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + //make modal + makeModal(self.prefsWindowController); + + }); + + + } + + //NSLog(@"would show flagged items"); + + return; +} + @end diff --git a/Consts.h b/Consts.h index 796db4c..99b8e07 100644 --- a/Consts.h +++ b/Consts.h @@ -95,6 +95,9 @@ //logo button #define LOGO_BUTTON_TAG 10004 +//flagged items button +#define FLAGGED_BUTTON_TAG 10005 + //category table diff --git a/FlaggedItems.h b/FlaggedItems.h new file mode 100644 index 0000000..09e0edb --- /dev/null +++ b/FlaggedItems.h @@ -0,0 +1,24 @@ +// +// FlaggedItems.h +// TaskExplorer +// +// Created by Patrick Wardle on 8/14/15. +// Copyright (c) 2015 Lucas Derraugh. All rights reserved. +// + +#import + +@interface FlaggedItems : NSWindowController + +//PROPERTIES + +//flag for first time init's +@property BOOL didInit; + +//table +@property (weak) IBOutlet NSTableView *flaggedItemTable; + +//vt window controller +@property (nonatomic, retain)VTInfoWindowController* vtWindowController; + +@end diff --git a/FlaggedItems.m b/FlaggedItems.m new file mode 100644 index 0000000..82783a1 --- /dev/null +++ b/FlaggedItems.m @@ -0,0 +1,162 @@ +// +// FlaggedItems.m +// TaskExplorer +// +// Created by Patrick Wardle on 8/14/15. +// Copyright (c) 2015 Lucas Derraugh. All rights reserved. +// + +#import "AppDelegate.h" +#import "FlaggedItems.h" +#import "ItemView.h" +#import "KKRow.h" + + +@interface FlaggedItems () + +@end + +@implementation FlaggedItems + +@synthesize didInit; +@synthesize flaggedItemTable; +@synthesize vtWindowController; + +//automatically called when nib is loaded +// ->center window +-(void)awakeFromNib +{ + //single time init + if(YES != self.didInit) + { + //center + [self.window center]; + + //set flag + self.didInit = YES; + } + + return; +} + +//automatically invoked when window is loaded +// ->set to white +-(void)windowDidLoad +{ + //super + [super windowDidLoad]; + + //table reload + [self.flaggedItemTable reloadData]; +} + +//table delegate +// ->return number of rows, which is just number of items in the currently selected plugin +-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return ((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems.count; +} + +//table delegate method +// ->return cell for row +-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + //flagged items + NSMutableArray* flaggedItems = nil; + + //row view + NSView* rowView = nil; + + //grab flagged items + flaggedItems = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems; + + //sanity check + // ->make sure there is table item for row + if(row >= flaggedItems.count) + { + //bail + goto bail; + } + + //create the view + // ->inits row w/ all required info + rowView = createItemView(tableView, self, [flaggedItems objectAtIndex:row]); + +//bail +bail: + + return rowView; +} + +//automatically invoked +// ->create custom (sub-classed) NSTableRowView +-(NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row +{ + //row view + KKRow* rowView = nil; + + //row ID + static NSString* const kRowIdentifier = @"TableRowView"; + + //try grab existing row view + rowView = [tableView makeViewWithIdentifier:kRowIdentifier owner:self]; + + //make new if needed + if(nil == rowView) + { + //create new + // ->size doesn't matter + rowView = [[KKRow alloc] initWithFrame:NSZeroRect]; + + //set row ID + rowView.identifier = kRowIdentifier; + } + + return rowView; +} + +//invoked when the user clicks 'virus total' icon +// ->launch browser and browse to virus total's page +-(void)showVTInfo:(id)sender +{ + //binary + Binary* item = nil; + + //row + NSInteger itemRow = 0; + + //flagged items + NSMutableArray* flaggedItems = nil; + + //grab flagged items + flaggedItems = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems; + + //grab sender's row + itemRow = [self.flaggedItemTable rowForView:sender]; + + //sanity check(s) + // ->make sure row is decent + if( (-1 == itemRow) || + (itemRow >= flaggedItems.count) ) + { + //bail + goto bail; + } + + //extract item for row + item = flaggedItems[itemRow]; + + //alloc/init info window + vtWindowController = [[VTInfoWindowController alloc] initWithItem:item]; + + //show it + [self.vtWindowController.windowController showWindow:self]; + + +//bail +bail: + + return; +} + +@end diff --git a/ItemView.h b/ItemView.h index f14acfd..e3c799d 100644 --- a/ItemView.h +++ b/ItemView.h @@ -19,6 +19,9 @@ //create customize item view NSTableCellView* createItemView(NSTableView* tableView, id owner, id item); +//create & customize flagged item view +NSTableCellView* createFlaggedItemView(NSTableView* tableView, id owner, id item); + //create & customize task view NSTableCellView* createTaskView(NSTableView* tableView, id owner, id item); diff --git a/ItemView.m b/ItemView.m index 31497ed..01d2d6c 100644 --- a/ItemView.m +++ b/ItemView.m @@ -19,15 +19,22 @@ NSTableCellView* createItemView(NSTableView* tableView, id owner, id item) //item cell NSTableCellView *itemCell = nil; - //sanity chec + //sanity check if(nil == item) { //bail goto bail; } + //first handle logic for flagged items + if(YES == [owner isKindOfClass:[FlaggedItems class]]) + { + //create & config view + itemCell = createFlaggedItemView(tableView, owner, item); + } + //logic to create task view - if(YES == [item isKindOfClass:[Task class]]) + else if(YES == [item isKindOfClass:[Task class]]) { //create & config view itemCell = createTaskView(tableView, owner, item); @@ -126,9 +133,147 @@ NSImage* getCodeSigningIcon(Binary* binary) } return codeSignIcon; - } +//create & customize flagged item view +NSTableCellView* createFlaggedItemView(NSTableView* tableView, id owner, Binary* binary) +{ + //item cell + NSTableCellView* flaggedItemCell = nil; + + //matching or host tasks + NSMutableArray* tasks = nil; + + //pid or 'loaded in' string + NSMutableString* pidString = nil; + + //task's name frame + CGRect nameFrame = {0}; + + //for main (task) binaries + // ->just need task's pid + if(YES == binary.isTaskBinary) + { + //get all matching tasks + tasks = [((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator tasksForBinary:binary]; + + //start 'tasks: ...' str + pidString = [NSMutableString stringWithFormat:@"(tasks:"]; + + //add all tasks + for(Task* task in tasks) + { + //append name + [pidString appendFormat:@" %@,", task.pid]; + } + + //remove last ',' + if(YES == [pidString hasSuffix:@","]) + { + //remove + [pidString deleteCharactersInRange:NSMakeRange([pidString length]-1, 1)]; + } + + //terminate list/output + [pidString appendString:@")"]; + } + //for dylibs + // ->list all tasks the flagged dylib is loaded in + else + { + //get host tasks + tasks = [((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator loadedIn:binary]; + + //start 'loaded in: ...' str + pidString = [NSMutableString stringWithFormat:@"(loaded in:"]; + + //add all tasks + for(Task* task in tasks) + { + //append name + [pidString appendFormat:@" %@,", task.binary.name]; + } + + //remove last ',' + if(YES == [pidString hasSuffix:@","]) + { + //remove + [pidString deleteCharactersInRange:NSMakeRange([pidString length]-1, 1)]; + } + + //terminate list/output + [pidString appendString:@")"]; + } + + //create cell + flaggedItemCell = [tableView makeViewWithIdentifier:@"FlaggedItem" owner:owner]; + if(nil == flaggedItemCell) + { + //bail + goto bail; + } + + //brand new cells need tracking areas + // ->determine if new, by checking default (.xib/IB) value + if(YES == [flaggedItemCell.textField.stringValue isEqualToString:@"Flagged Item Name"]) + { + //add tracking area + // ->'vt' button + addTrackingArea(flaggedItemCell, TABLE_ROW_VT_BUTTON, owner); + + //add tracking area + // ->'info' button + addTrackingArea(flaggedItemCell, TABLE_ROW_INFO_BUTTON, owner); + + //add tracking area + // ->'show' button + addTrackingArea(flaggedItemCell, TABLE_ROW_SHOW_BUTTON, owner); + } + + //set icon + flaggedItemCell.imageView.image = [binary icon]; + + //set code signing icon + ((NSImageView*)[flaggedItemCell viewWithTag:TABLE_ROW_SIGNATURE_ICON]).image = getCodeSigningIcon(binary); + + //default + // ->(re)set main textfield's color to black + flaggedItemCell.textField.textColor = [NSColor blackColor]; + + //set main text + // ->name + [flaggedItemCell.textField setStringValue:binary.name]; + + //get name frame + nameFrame = flaggedItemCell.textField.frame; + + //adjust width to fit text + nameFrame.size.width = [flaggedItemCell.textField.stringValue sizeWithAttributes: @{NSFontAttributeName: flaggedItemCell.textField.font}].width + 5; + + //disable autolayout for name + flaggedItemCell.textField.translatesAutoresizingMaskIntoConstraints = YES; + + //update name frame + // ->should now be exact size of text + flaggedItemCell.textField.frame = nameFrame; + + //set pid + // ->immediately follows name + [((NSTextField*)[flaggedItemCell viewWithTag:TABLE_ROW_PID_LABEL]) setStringValue:pidString]; + + //set path + [[flaggedItemCell viewWithTag:TABLE_ROW_SUB_TEXT_TAG] setStringValue:binary.path]; + + //config VT button + configVTButton(flaggedItemCell, owner, binary); + +//bail +bail: + + return flaggedItemCell; +} + + //create & customize Task view NSTableCellView* createTaskView(NSTableView* tableView, id owner, Task* task) { diff --git a/RequestRootWindowController.m b/RequestRootWindowController.m index 45ab92e..4e23eaf 100644 --- a/RequestRootWindowController.m +++ b/RequestRootWindowController.m @@ -155,7 +155,7 @@ //2nd arg: permissions // ->4 at front is setuid //TODO: make 4755 before deploy (for testing, 777 makes XCOde be able to del it during build!) - installArgs[1] = "4755"; + installArgs[1] = "4777"; //3rd arg: XPC service installArgs[2] = [xpcService UTF8String]; diff --git a/TaskEnumerator.h b/TaskEnumerator.h index b407206..515ff93 100644 --- a/TaskEnumerator.h +++ b/TaskEnumerator.h @@ -57,5 +57,15 @@ // ->get list of all child pids -(void)getAllChildren:(Task*)parent children:(NSMutableArray*)children; +//get all tasks a dylib is loaded into +-(NSMutableArray*)loadedIn:(Binary*)dylib; + +//get all task pids for a given binary +-(NSMutableArray*)tasksForBinary:(Binary*)binary; + +//ensure that the list of flagged items is correctly updated +// when a dead task or any of its dylibs were flagged... +-(void)updateFlaggedItems:(Task*)deadTask; + @end diff --git a/TaskEnumerator.m b/TaskEnumerator.m index d8198cc..c62b111 100644 --- a/TaskEnumerator.m +++ b/TaskEnumerator.m @@ -70,7 +70,8 @@ //new tasks OrderedDictionary* newTasks = nil; - //set connected flag + //determine if network is connected + // ->sets 'isConnected' flag ((AppDelegate*)[[NSApplication sharedApplication] delegate]).isConnected = isNetworkConnected(); //get all tasks @@ -138,6 +139,7 @@ //reload bottom pane [((AppDelegate*)[[NSApplication sharedApplication] delegate]) selectBottomPaneContent:nil]; + }); //now generate signing info @@ -167,6 +169,16 @@ }//signing info for all new tasks + //begin dylib enumeration + for(NSNumber* key in newTasks) + { + //get task + newTask = newTasks[key]; + + //enumerate + [newTask enumerateDylibs:((AppDelegate*)[[NSApplication sharedApplication] delegate]).xpcConnection allDylibs:self.dylibs]; + } + return; } @@ -360,7 +372,7 @@ bail: } //remove a task -// ->contains extra logic to remove children, etc +// ->contains extra logic to remove children, flagged items, etc -(void)removeTask:(Task*)deadTask { //parent @@ -379,6 +391,18 @@ bail: //alloc array for children children = [NSMutableArray array]; + //ensure that flagged item list is accurate + // ->the dead task or its dylibs might have been flagged + [self updateFlaggedItems:deadTask]; + + //(re)set label for flagged items to black + // when there are no flagged items + if(0 == ((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems.count) + { + //set to gray + ((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedLabel.textColor = [NSColor lightGrayColor]; + } + //get launchd's task // ->its 'pid' is 0x1 launchdTask = self.tasks[@1]; @@ -415,6 +439,83 @@ bail: return; } +//TODO: test w/ dylib!! +//ensure that the list of flagged items is correctly updated +// when a dead task or any of its dylibs were flagged... +-(void)updateFlaggedItems:(Task*)deadTask +{ + //task + Task* task = nil; + + //number of task instances + NSUInteger taskInstances = 0; + + //tasks that host flagged dylib + NSMutableArray* taskHosts = nil; + + //remove any dylibs that are flagged and loaded (only!) in dead task + for(Binary* dylib in deadTask.dylibs) + { + //skip dylibs that aren't flagged + if(YES != [((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems containsObject:dylib]) + { + //skip + continue; + } + + //get all tasks that host the flagged dylib + taskHosts = [self tasksForBinary:dylib]; + + //skip dylibs that are hosted in more than one task + // or aren't hosted in dead task + if( (1 != taskHosts.count) || + (taskHosts.firstObject != deadTask.binary) ) + { + //skip + continue; + } + + //dylib is flagged and only hosted in dead task + // ->remove it from flaggedItems + @synchronized(((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems) + { + //remove + [((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems removeObject:dylib]; + } + } + + //also remove task if its flagged and only instance + if(YES == [((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems containsObject:deadTask.binary]) + { + //get number of task instances + // ->might be more (flagged) instances that are still alive + for(NSNumber* taskPid in self.tasks) + { + //extract task + task = self.tasks[taskPid]; + + //check for task has dylib + if(task.binary == deadTask.binary) + { + //inc + taskInstances++; + } + } + + //remove if only instance + if(1 == taskInstances) + { + //sync and remove + @synchronized(((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems) + { + //remove + [((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedItems removeObject:deadTask.binary]; + } + } + } + + return; +} //given a task // ->get list of all child pids @@ -441,5 +542,81 @@ bail: return; } +//get all task pids for a given binary +-(NSMutableArray*)tasksForBinary:(Binary*)binary +{ + //array of tasks + NSMutableArray* matchingTasks = nil; + + //task + Task* task = nil; + + //tasks + matchingTasks = [NSMutableArray array]; + + //sync + @synchronized(self.tasks) + { + //reload each row w/ new VT info + for(NSNumber* taskPid in self.tasks) + { + //extract task + task = self.tasks[taskPid]; + + //check for task has dylib + if(task.binary == binary) + { + //save + [matchingTasks addObject:task]; + } + } + + }//sync + + return matchingTasks; +} + + +//get all tasks a dylib is loaded into +-(NSMutableArray*)loadedIn:(Binary*)dylib +{ + //array of tasks + NSMutableArray* hostTasks = nil; + + //task + Task* task = nil; + + //tasks + hostTasks = [NSMutableArray array]; + + //sync + @synchronized(self.tasks) + { + //reload each row w/ new VT info + for(NSNumber* taskPid in self.tasks) + { + //extract task + task = self.tasks[taskPid]; + + //check if dylib is loaded in task + for(Binary* taskDylib in task.dylibs) + { + //check for task has dylib + if(taskDylib == dylib) + { + //save + [hostTasks addObject:task]; + + //can bail, since match was found + break; + } + } + } + + }//sync + + return hostTasks; +} + @end diff --git a/TaskExplorer-Info.plist b/TaskExplorer-Info.plist index 3ed331a..06c5280 100755 --- a/TaskExplorer-Info.plist +++ b/TaskExplorer-Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0.0 + 1.0.1 CFBundleSignature ???? CFBundleVersion - 1.0.0 + 1.0.1 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright diff --git a/TaskExplorer.xcodeproj/project.pbxproj b/TaskExplorer.xcodeproj/project.pbxproj index bde41de..42cdd8e 100755 --- a/TaskExplorer.xcodeproj/project.pbxproj +++ b/TaskExplorer.xcodeproj/project.pbxproj @@ -43,6 +43,10 @@ CD6AFB861B4BABB200D42C34 /* refreshIconBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB841B4BABB200D42C34 /* refreshIconBG.png */; }; CD6AFB871B4BABB200D42C34 /* refreshIconOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB851B4BABB200D42C34 /* refreshIconOver.png */; }; CD6E54FF1B1162B5007953AB /* ItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6E54FE1B1162B5007953AB /* ItemView.m */; }; + CD74A06D1B7DA71200A8AAD3 /* flaggedBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CD74A06B1B7DA71200A8AAD3 /* flaggedBG.png */; }; + CD74A06E1B7DA71200A8AAD3 /* flaggedOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD74A06C1B7DA71200A8AAD3 /* flaggedOver.png */; }; + CD74A07B1B7F170B00A8AAD3 /* FlaggedItems.m in Sources */ = {isa = PBXBuildFile; fileRef = CD74A0791B7F170B00A8AAD3 /* FlaggedItems.m */; }; + CD74A07E1B81B5D400A8AAD3 /* FlaggedItems.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD74A07D1B81B5D400A8AAD3 /* FlaggedItems.xib */; }; CD7B9F4D1ACB959200DF3C71 /* logoAppleOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9F4C1ACB959200DF3C71 /* logoAppleOver.png */; }; CD7B9F501ACB9A8400DF3C71 /* Exception.m in Sources */ = {isa = PBXBuildFile; fileRef = CD7B9F4F1ACB9A8400DF3C71 /* Exception.m */; }; CD7B9FA41ACBCFAD00DF3C71 /* spotlightIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9FA31ACBCFAD00DF3C71 /* spotlightIcon.png */; }; @@ -113,6 +117,7 @@ CDF08CF01ACA677B009B3423 /* kernelIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CDF08CEE1ACA677B009B3423 /* kernelIcon.png */; }; CDF08CF31ACA6864009B3423 /* browserIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CDF08CF11ACA6864009B3423 /* browserIcon.png */; }; CDF08CF41ACA6864009B3423 /* loginIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CDF08CF21ACA6864009B3423 /* loginIcon.png */; }; + CDFCA3561B7940970075492D /* flagged.png in Resources */ = {isa = PBXBuildFile; fileRef = CDFCA3551B7940970075492D /* flagged.png */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -192,6 +197,11 @@ CD6AFB851B4BABB200D42C34 /* refreshIconOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = refreshIconOver.png; path = images/refreshIconOver.png; sourceTree = SOURCE_ROOT; }; CD6E54FD1B1162B5007953AB /* ItemView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ItemView.h; sourceTree = ""; }; CD6E54FE1B1162B5007953AB /* ItemView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ItemView.m; sourceTree = ""; }; + CD74A06B1B7DA71200A8AAD3 /* flaggedBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = flaggedBG.png; path = images/flaggedBG.png; sourceTree = SOURCE_ROOT; }; + CD74A06C1B7DA71200A8AAD3 /* flaggedOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = flaggedOver.png; path = images/flaggedOver.png; sourceTree = SOURCE_ROOT; }; + CD74A0781B7F170B00A8AAD3 /* FlaggedItems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlaggedItems.h; sourceTree = ""; }; + CD74A0791B7F170B00A8AAD3 /* FlaggedItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FlaggedItems.m; sourceTree = ""; }; + CD74A07D1B81B5D400A8AAD3 /* FlaggedItems.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FlaggedItems.xib; path = UI/FlaggedItems.xib; sourceTree = ""; }; 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; }; @@ -285,6 +295,7 @@ CDF08CEE1ACA677B009B3423 /* kernelIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = kernelIcon.png; path = images/kernelIcon.png; sourceTree = SOURCE_ROOT; }; CDF08CF11ACA6864009B3423 /* browserIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = browserIcon.png; path = images/browserIcon.png; sourceTree = SOURCE_ROOT; }; CDF08CF21ACA6864009B3423 /* loginIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = loginIcon.png; path = images/loginIcon.png; sourceTree = SOURCE_ROOT; }; + CDFCA3551B7940970075492D /* flagged.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = flagged.png; path = images/flagged.png; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -312,6 +323,8 @@ 1D21BC42172AF43D009D1CFD = { isa = PBXGroup; children = ( + CD74A0781B7F170B00A8AAD3 /* FlaggedItems.h */, + CD74A0791B7F170B00A8AAD3 /* FlaggedItems.m */, CD4D54201B2CE6F200008030 /* NSMutableArray+QueueAdditions.h */, CDBE49161B58DC9B0031FC22 /* NSApplicationKeyEvents.h */, CDBE49171B58DC9B0031FC22 /* NSApplicationKeyEvents.m */, @@ -410,6 +423,9 @@ CD6095501A8329FA00E091CD /* images */ = { isa = PBXGroup; children = ( + CD74A06B1B7DA71200A8AAD3 /* flaggedBG.png */, + CD74A06C1B7DA71200A8AAD3 /* flaggedOver.png */, + CDFCA3551B7940970075492D /* flagged.png */, CD6AFB841B4BABB200D42C34 /* refreshIconBG.png */, CD6AFB851B4BABB200D42C34 /* refreshIconOver.png */, CD6AFB821B4BAA2100D42C34 /* refreshIcon.png */, @@ -535,6 +551,7 @@ CDA81E621AA020E8009790E2 /* UI */ = { isa = PBXGroup; children = ( + CD74A07D1B81B5D400A8AAD3 /* FlaggedItems.xib */, CD4D54271B2EAC7800008030 /* NetworkInfoWindow.xib */, CD4D54231B2D082300008030 /* DylibInfoWindow.xib */, CDA5F6C01B16E1D6003CE340 /* RequestRootWindow.xib */, @@ -651,7 +668,9 @@ CDA81D5B1A95B4B4009790E2 /* InfoPlist.strings in Resources */, CD4D53CA1B20296E00008030 /* unknown.png in Resources */, CDEE77081B41220300763826 /* searchOver.png in Resources */, + CD74A07E1B81B5D400A8AAD3 /* FlaggedItems.xib in Resources */, CDA81D6B1A95B4E9009790E2 /* show.png in Resources */, + CD74A06D1B7DA71200A8AAD3 /* flaggedBG.png in Resources */, CDF08CF31ACA6864009B3423 /* browserIcon.png in Resources */, CDEE77061B41220300763826 /* search.png in Resources */, CDAB98A11AEAFAFA00C75B4B /* authorizationIcon.png in Resources */, @@ -680,6 +699,7 @@ CD6AFB7F1B4736DF00D42C34 /* flatIcon.png in Resources */, CD6AFB811B4737AC00D42C34 /* arrow.png in Resources */, CDA81DCC1A9960A3009790E2 /* virusTotalBG.png in Resources */, + CD74A06E1B7DA71200A8AAD3 /* flaggedOver.png in Resources */, CD001B381AB903040089014A /* logo.png in Resources */, CDA81D6D1A95B4E9009790E2 /* scanIcon.png in Resources */, CDF08CCF1AC4C6E8009B3423 /* settingsOver.png in Resources */, @@ -689,6 +709,7 @@ CD4D543F1B2FF32C00008030 /* signedAppleIcon.png in Resources */, CD3F4D161AF89066002A2647 /* TreeView.xib in Resources */, CD0219501AD34D8B005148A2 /* PrefsWindow.xib in Resources */, + CDFCA3561B7940970075492D /* flagged.png in Resources */, CDA81D6C1A95B4E9009790E2 /* showBG.png in Resources */, CD3F4CFF1AF72BC4002A2647 /* TaskInfoWindow.xib in Resources */, CDEE77001B3FD4B000763826 /* saveIconOver.png in Resources */, @@ -729,6 +750,7 @@ files = ( CD3F4CE81AF5CF68002A2647 /* TaskEnumerator.m in Sources */, CD4D54221B2CE6F200008030 /* NSMutableArray+QueueAdditions.m in Sources */, + CD74A07B1B7F170B00A8AAD3 /* FlaggedItems.m in Sources */, CDA5F6C41B16E20E003CE340 /* RequestRootWindowController.m in Sources */, CDD2483B1AF5CC4D00232422 /* Task.m in Sources */, CD83887F1AACCEDF000EB098 /* VirusTotal.m in Sources */, diff --git a/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout b/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout index c0c67db..df18232 100644 --- a/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout +++ b/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout @@ -7,14 +7,14 @@ IDESourceControlProjectIdentifier FE4103FE-6F26-4639-8C9F-D8D32C76D6A9 IDESourceControlProjectName - project + TaskExplorer IDESourceControlProjectOriginsDictionary 61F07AFB33748EF0C810BEEF6126283DAC63A899 https://bitbucket.org/objective-see/taskexplorer.git IDESourceControlProjectPath - TaskExplorer.xcodeproj/project.xcworkspace + TaskExplorer.xcodeproj IDESourceControlProjectRelativeInstallPathDictionary 61F07AFB33748EF0C810BEEF6126283DAC63A899 diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 8a85ee7..897e481 100644 --- a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -87,22 +87,6 @@ landmarkType = "5"> - - - - @@ -190,11 +174,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "AppDelegate.m" - timestampString = "460362206.963852" + timestampString = "461485530.290068" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1597" - endingLineNumber = "1597" + startingLineNumber = "1638" + endingLineNumber = "1638" landmarkName = "-constrainView:subView:" landmarkType = "5"> @@ -254,31 +238,15 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "AppDelegate.m" - timestampString = "460362206.963852" + timestampString = "461485530.290068" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "806" - endingLineNumber = "806" + startingLineNumber = "827" + endingLineNumber = "827" landmarkName = "-reloadTaskTable" landmarkType = "5"> - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/TaskTableController.h b/TaskTableController.h index 23c3435..89fcd77 100644 --- a/TaskTableController.h +++ b/TaskTableController.h @@ -41,7 +41,7 @@ //info window @property(retain, nonatomic)InfoWindowController* infoWindowController; -//preferences window controller +//virus total window controller @property (nonatomic, retain)VTInfoWindowController* vtWindowController; //currently selected row diff --git a/UI/AboutWindow.xib b/UI/AboutWindow.xib index e745a9a..78dbf1b 100644 --- a/UI/AboutWindow.xib +++ b/UI/AboutWindow.xib @@ -1,5 +1,5 @@ - + diff --git a/UI/FlaggedItems.xib b/UI/FlaggedItems.xib new file mode 100644 index 0000000..81bd7e6 --- /dev/null +++ b/UI/FlaggedItems.xib @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VirusTotal.m b/VirusTotal.m index 454db19..e2740ca 100644 --- a/VirusTotal.m +++ b/VirusTotal.m @@ -370,20 +370,11 @@ //save result item.vtInfo = results; - //TODO: do something if it's flagged! - //if its flagged save in File's plugin + //save flagged item if(0 != [results[VT_RESULTS_POSITIVES] unsignedIntegerValue]) { - /* - //sync - // ->since array will be reset if user clicks 'stop' scan - @synchronized(fileObj.plugin.flaggedItems) - { - //save - [fileObj.plugin.flaggedItems addObject:fileObj]; - } - */ - + //save + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) saveFlaggedBinary:item]; } //call up into app delegate to smartly reload @@ -722,13 +713,15 @@ bail: //save VT results into item queriedItem.vtInfo = result; + //save flagged item + if(0 != [result[VT_RESULTS_POSITIVES] unsignedIntegerValue]) + { + //save + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) saveFlaggedBinary:queriedItem]; + } + //call up into app delegate to smartly reload [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBinary:queriedItem]; - - - //TODO: do something with detections!? - // ->blinking button, user's can click to see 'flagged items' popup - //if(0 != [result[VT_RESULTS_POSITIVES] unsignedIntegerValue]) } return; diff --git a/en.lproj/MainMenu.xib b/en.lproj/MainMenu.xib index 502add9..8936c57 100755 --- a/en.lproj/MainMenu.xib +++ b/en.lproj/MainMenu.xib @@ -1,5 +1,5 @@ - + @@ -155,7 +155,7 @@ + + + + + + + + - + + + @@ -283,6 +307,8 @@ + + @@ -308,6 +334,8 @@ + + diff --git a/images/flagged.png b/images/flagged.png new file mode 100644 index 0000000..dd90cf3 Binary files /dev/null and b/images/flagged.png differ diff --git a/images/flaggedBG.png b/images/flaggedBG.png new file mode 100644 index 0000000..f8b00c6 Binary files /dev/null and b/images/flaggedBG.png differ diff --git a/images/flaggedOver.png b/images/flaggedOver.png new file mode 100644 index 0000000..56f1357 Binary files /dev/null and b/images/flaggedOver.png differ diff --git a/remoteTaskService/main.m b/remoteTaskService/main.m index 55ad89b..ccc6fb6 100644 --- a/remoteTaskService/main.m +++ b/remoteTaskService/main.m @@ -15,9 +15,13 @@ @implementation ServiceDelegate -- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection { - // This method is where the NSXPCListener configures, accepts, and resumes a new incoming NSXPCConnection. - + +//TODO: check for 'signed by Obj-C' +//automatically invoked +//->allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection. +-(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection +{ + // Configure the connection. // First, set the interface that the exported object implements. newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(remoteTaskProto)];