diff --git a/AppDelegate.h b/AppDelegate.h index a7b2007..90fbd43 100755 --- a/AppDelegate.h +++ b/AppDelegate.h @@ -31,6 +31,9 @@ } +//Filter obj +//@property (nonatomic, retain) Filter* filter; + //'filter task' search box // ->top pane @property (weak) IBOutlet NSSearchField *filterTasksBox; diff --git a/AppDelegate.m b/AppDelegate.m index 83ff731..7ecf9b0 100755 --- a/AppDelegate.m +++ b/AppDelegate.m @@ -16,6 +16,13 @@ #import "Task.h" //TODO: bottom pane's progress indicator: center via autolayout +//TODO: fix bottom icons +//TODO: dylib info view, don't show args +//TODO: SHA1 is NULL +//TODO: Time is NULL +//TODO: Software signing is too long (goes into 'close' buttom +//TODO: only update task row(s) on Task VT result! not full table +//TODO: full VT queue!! @implementation AppDelegate @@ -37,11 +44,10 @@ @synthesize scannerThread; @synthesize versionString; @synthesize progressIndicator; +//@synthesize filterObj; @synthesize topPane; @synthesize taskEnumerator; -//@synthesize treeViewController; -//@synthesize currentViewController; @synthesize viewSelector; @@ -92,8 +98,8 @@ //init virus total object virusTotalObj = [[VirusTotal alloc] init]; - //init array for virus total threads - //vtThreads = [NSMutableArray array]; + //init filter obj + filterObj = [[Filter alloc] init]; //check that OS is supported if(YES != isSupportedOS()) @@ -342,12 +348,6 @@ } } - //always unset filter flag - self.taskTableController.isFiltered = NO; - - //always reset filter text - [self.filterTasksBox setStringValue:@""]; - //set bottom view? self.bottomPaneBtn.selectedSegment = DYLIBS_VIEW; @@ -1418,7 +1418,7 @@ bail: { //save selected view self.taskViewFormat = [[sender selectedCell] tag]; - + //flat view // ->enable 'filter tasks' search field if(FLAT_VIEW == self.taskViewFormat) @@ -1437,12 +1437,28 @@ bail: //switch (top) view/pane [self changeViewController]; + //always unset filter flag + self.taskTableController.isFiltered = NO; + + //always reset filter text + [self.filterTasksBox setStringValue:@""]; + + //remove all filtered tasks + [self.taskTableController.filteredItems removeAllObjects]; + + //reset current task + self.currentTask = nil; + //reload top pane [self reloadTaskTable]; //select top row [self.taskTableController.itemView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; + //reload bottom pane + // ->ensures correct info is shown for selected (top) task + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) selectBottomPaneContent:nil]; + return; } @@ -1453,6 +1469,26 @@ bail: { //tag NSUInteger segmentTag = 0; + + //filter box placeholder text + NSString* filterPlaceholder = nil; + + //always reset filter flag + self.bottomViewController.isFiltered = NO; + + //always reset filter box's text + self.filterItemsBox.stringValue = @""; + + //remove all filtered items + [self.bottomViewController.filteredItems removeAllObjects]; + + //when no current task + // ->set to first task in sorted tasks + if(nil == self.currentTask) + { + //set to first + self.currentTask = self.taskEnumerator.tasks[[self.taskEnumerator.tasks keyAtIndex:0]]; + } //get segment tag segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]]; @@ -1490,6 +1526,9 @@ bail: //dylibs case DYLIBS_VIEW: + //init placeholder text for dylibs + filterPlaceholder = @"Filter Dylibs"; + //(re)enumerate dylibs via XPC // ->triggers table reload when done [self.currentTask enumerateDylibs:self.taskEnumerator.xpcConnection allDylibs:self.taskEnumerator.dylibs]; @@ -1499,6 +1538,9 @@ bail: //files case FILES_VIEW: + //init placeholder text for files + filterPlaceholder = @"Filter Files"; + //(re)enumerate files via XPC // ->triggers table reload when done [self.currentTask enumerateFiles:self.taskEnumerator.xpcConnection]; @@ -1508,6 +1550,9 @@ bail: //networking case NETWORKING_VIEW: + //init placeholder text for network + filterPlaceholder = @"Filter Connections"; + //(re)enumerate network connections via XPC // ->triggers table reload when done [self.currentTask enumerateNetworking:self.taskEnumerator.xpcConnection]; @@ -1518,6 +1563,15 @@ bail: break; } + //set filter box's placeholder text + // ->UI change, so do on main thread + dispatch_async(dispatch_get_main_queue(), ^{ + + //set placeholder + [self.filterItemsBox setPlaceholderString:filterPlaceholder]; + }); + + //bail bail: @@ -1527,11 +1581,14 @@ bail: //automatically invoked when user enters text in filter search boxes // ->filter tasks and/or items -- (void)controlTextDidChange:(NSNotification *)aNotification +-(void)controlTextDidChange:(NSNotification *)aNotification { //search text NSTextView* search = nil; + //tag for bottom pane selector + NSUInteger segmentTag = 0; + //extract search (text) view search = aNotification.userInfo[@"NSFieldEditor"]; @@ -1541,7 +1598,7 @@ bail: //bail goto bail; } - + //top pane if(YES == [aNotification.object isEqualTo:self.filterTasksBox]) { @@ -1556,24 +1613,77 @@ bail: else { //filter + //TODO: move into Filter obj [self filterTasks:search.string]; //set flag self.taskTableController.isFiltered = YES; } - //always reload task table + //always reload task (top) pane [self.taskTableController.itemView reloadData]; } //bottom pane else if(YES == [aNotification.object isEqualTo:self.filterItemsBox]) { + //when text is reset + // ->just reset flag + if(0 == search.string.length) + { + //set flag + self.bottomViewController.isFiltered = NO; + } - } + //filter items + else + { + //get segment tag + segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]]; + + //get item + // ->will bail if item isn't in (current) view, etc + switch(segmentTag) + { + //dylibs + case DYLIBS_VIEW: + { + //filter + [self.filterObj filterFiles:search.string items:self.currentTask.dylibs results:self.bottomViewController.filteredItems]; - - - //NSLog(@"changed!"); + break; + } + + //files + case FILES_VIEW: + { + //filter + [self.filterObj filterFiles:search.string items:self.currentTask.files results:self.bottomViewController.filteredItems]; + + break; + } + + //network connections + case NETWORKING_VIEW: + { + //filter + [self.filterObj filterConnections:search.string items:self.currentTask.connections results:self.bottomViewController.filteredItems]; + + + break; + } + + default: + break; + + }//switch + + //set flag + self.bottomViewController.isFiltered = YES; + } + + //always reload task (top) pane + [self.bottomViewController.itemView reloadData]; + } //bail bail: diff --git a/Filter.h b/Filter.h index 8297821..2e89202 100644 --- a/Filter.h +++ b/Filter.h @@ -27,6 +27,12 @@ /* METHODS */ +//filter dylibs and files +-(void)filterFiles:(NSString*)filterText items:(NSMutableArray*)items results:(NSMutableArray*)results; + +//filter network connections +-(void)filterConnections:(NSString*)filterText items:(NSMutableArray*)items results:(NSMutableArray*)results; + //load a (JSON) white list // ->file hashes, known commands, etc -(NSDictionary*)loadWhitelist:(NSString*)fileName; diff --git a/Filter.m b/Filter.m index c9283fd..8871a50 100644 --- a/Filter.m +++ b/Filter.m @@ -8,6 +8,9 @@ #import "Consts.h" #import "Filter.h" #import "Utilities.h" +#import "Task.h" +#import "ItemBase.h" +#import "Connection.h" @implementation Filter @@ -27,18 +30,91 @@ if(self) { //load known file hashes - self.trustedFiles = [self loadWhitelist:WHITE_LISTED_FILES]; + //self.trustedFiles = [self loadWhitelist:WHITE_LISTED_FILES]; //load known commands - self.knownCommands = [self loadWhitelist:WHITE_LISTED_COMMANDS]; + //self.knownCommands = [self loadWhitelist:WHITE_LISTED_COMMANDS]; //load known extensions - self.trustedExtensions = [self loadWhitelist:WHITE_LISTED_EXTENSIONS]; + //self.trustedExtensions = [self loadWhitelist:WHITE_LISTED_EXTENSIONS]; } return self; } +//TODO: add filter tasks + + +//filter dylibs and files +// ->name and path +-(void)filterFiles:(NSString*)filterText items:(NSMutableArray*)items results:(NSMutableArray*)results +{ + //name range + NSRange nameRange = {0}; + + //path range + NSRange pathRange = {0}; + + //first reset filter'd items + [results removeAllObjects]; + + //iterate over all tasks + for(ItemBase* item in items) + { + //init name range + nameRange = [item.name rangeOfString:filterText options:NSCaseInsensitiveSearch]; + + //init path range + pathRange = [item.path rangeOfString:filterText options:NSCaseInsensitiveSearch]; + + //check for match + if( (NSNotFound != nameRange.location) || + (NSNotFound != pathRange.location) ) + { + //save match + [results addObject:item]; + } + + }//all items + + return; +} + +//filter network connections +-(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) ) + { + //save match + [results addObject:item]; + } + + }//all items + + return; +} //load a (JSON) white list // ->file hashes, known commands, etc diff --git a/TaskEnumerator.m b/TaskEnumerator.m index 9dafb79..613c81f 100644 --- a/TaskEnumerator.m +++ b/TaskEnumerator.m @@ -143,6 +143,10 @@ //reload task table [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadTaskTable]; + //TODO: only do if current task is nil? + //reload bottom pane + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) selectBottomPaneContent:nil]; + //now generate signing info // ->for (new) tasks & their dylibs for(NSNumber* key in newTasks) diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index e054392..d1f802f 100644 --- a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -20,11 +20,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskEnumerator.m" - timestampString = "456607885.071145" + timestampString = "456903878.108936" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "344" - endingLineNumber = "344" + startingLineNumber = "348" + endingLineNumber = "348" landmarkName = "-removeTask:" landmarkType = "5"> @@ -36,11 +36,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "AppDelegate.m" - timestampString = "456648442.982284" + timestampString = "456993845.79535" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "775" - endingLineNumber = "775" + startingLineNumber = "771" + endingLineNumber = "771" landmarkName = "-reloadTaskTable" landmarkType = "5"> @@ -52,11 +52,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "456648442.982284" + timestampString = "456993845.79535" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1174" - endingLineNumber = "1174" + startingLineNumber = "1221" + endingLineNumber = "1221" landmarkName = "-outlineView:rowViewForItem:" landmarkType = "5"> @@ -68,11 +68,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "456648442.982284" + timestampString = "456993845.79535" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1167" - endingLineNumber = "1167" + startingLineNumber = "1214" + endingLineNumber = "1214" landmarkName = "-outlineView:viewForTableColumn:item:" landmarkType = "5"> @@ -84,11 +84,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "456648442.982284" + timestampString = "456993845.79535" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1157" - endingLineNumber = "1157" + startingLineNumber = "1204" + endingLineNumber = "1204" landmarkName = "-outlineViewSelectionDidChange:" landmarkType = "5"> @@ -109,22 +109,6 @@ landmarkType = "7"> - - - - @@ -206,11 +190,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "AppDelegate.m" - timestampString = "456648442.982284" + timestampString = "456993845.79535" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "545" - endingLineNumber = "545" + startingLineNumber = "541" + endingLineNumber = "541" landmarkName = "-reloadBottomPane:itemView:" landmarkType = "5"> @@ -222,11 +206,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "AppDelegate.m" - timestampString = "456648442.982284" + timestampString = "456993845.79535" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "563" - endingLineNumber = "563" + startingLineNumber = "559" + endingLineNumber = "559" landmarkName = "-reloadBottomPane:itemView:" landmarkType = "5"> @@ -270,11 +254,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "456648442.982284" + timestampString = "456993845.79535" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1203" - endingLineNumber = "1203" + startingLineNumber = "1250" + endingLineNumber = "1250" landmarkName = "-handleRowSelection" landmarkType = "5"> @@ -286,11 +270,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "456648442.982284" + timestampString = "456908382.278798" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "731" - endingLineNumber = "731" + startingLineNumber = "765" + endingLineNumber = "765" landmarkName = "-refresh" landmarkType = "5"> @@ -302,27 +286,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "456648442.982284" + timestampString = "456993845.79535" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "86" - endingLineNumber = "86" - landmarkName = "-numberOfRowsInTableView:" - landmarkType = "5"> - - - - @@ -334,11 +302,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "456648442.982284" + timestampString = "456908382.278798" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "783" - endingLineNumber = "783" + startingLineNumber = "817" + endingLineNumber = "817" landmarkName = "-refresh" landmarkType = "5"> @@ -366,11 +334,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "AppDelegate.m" - timestampString = "456648442.982284" + timestampString = "456994072.431204" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "1589" - endingLineNumber = "1589" + startingLineNumber = "1695" + endingLineNumber = "1695" landmarkName = "-filterTasks:" landmarkType = "5"> @@ -382,14 +350,126 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "TaskTableController.m" - timestampString = "456648442.982284" + timestampString = "456908382.278798" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "130" - endingLineNumber = "130" + startingLineNumber = "141" + endingLineNumber = "141" landmarkName = "-tableViewSelectionDidChange:" landmarkType = "5"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TaskTableController.m b/TaskTableController.m index f4c9e5c..ae147c7 100644 --- a/TaskTableController.m +++ b/TaskTableController.m @@ -96,7 +96,7 @@ if(YES != self.isBottomPane) { //when not filtered - // ->use tasks + // ->use all tasks if(YES != isFiltered) { //get tasks @@ -114,11 +114,22 @@ } } //bottom pane uses 'tableItems' iVar - //TODO: filter support else { - //set row count - rows = self.tableItems.count; + //when not filtered + // ->use all items + if(YES != isFiltered) + { + //set row count + rows = self.tableItems.count; + } + //when filtered + // ->use filtered items + else + { + //set count + rows = self.filteredItems.count; + } } return rows; @@ -199,17 +210,40 @@ //for BOTTOM PANE else { - //sanity check - // ->make sure there is table item for row - if(self.tableItems.count <= row) + + //when not filtered + // ->use all items + if(YES != isFiltered) { - //bail - goto bail; + //sanity check + // ->make sure there is table item for row + if(self.tableItems.count <= row) + { + //bail + goto bail; + } + + //grab item + // ->dylib/file/network item + item = [self.tableItems objectAtIndex:row]; + } + + //when filtered + // ->use filtered items + else + { + //sanity check + // ->make sure there is table item for row + if(self.filteredItems.count <= row) + { + //bail + goto bail; + } + + //set count + item = [self.filteredItems objectAtIndex:row]; } - //grab item - // ->dylib/file/network item - item = [self.tableItems objectAtIndex:row]; } //create custom item view @@ -846,7 +880,6 @@ bail: taskRow = [self.itemView selectedRow]; } - //TODO: add check for filterItems.count //sanity check(s) // ->make sure row is decent if( (-1 == taskRow) || @@ -860,6 +893,7 @@ 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) //{ @@ -895,14 +929,27 @@ bail: //sanity check(s) // ->make sure row has item if( (-1 == itemRow) || - (self.tableItems.count < itemRow) ) + ((YES != self.isFiltered) && (self.tableItems.count < itemRow)) || + ((YES == self.isFiltered) && (self.filteredItems.count < itemRow)) ) { //bail goto bail; } - //get item object - item = self.tableItems[itemRow]; + //when not filtered + // ->just grab item + if(YES != self.isFiltered) + { + //get item + item = self.tableItems[itemRow]; + } + //when filtered + // ->grab from filtered item + else + { + //get item + item = self.filteredItems[itemRow]; + } //bail bail: diff --git a/en.lproj/MainMenu.xib b/en.lproj/MainMenu.xib index a46d4eb..3110bbe 100755 --- a/en.lproj/MainMenu.xib +++ b/en.lproj/MainMenu.xib @@ -1,6 +1,7 @@ + @@ -44,19 +45,19 @@ - + - + - + @@ -87,23 +88,12 @@ - - + - + - + @@ -131,6 +121,20 @@ + + + + + + + + + + + + + + @@ -172,13 +176,13 @@ - - + + - + - + @@ -187,20 +191,6 @@ - - - - - - - - - - - - - - @@ -221,7 +211,7 @@ - + diff --git a/images/icon.iconset/icon_128x128.png b/images/icon.iconset/icon_128x128.png index 51c54bf..e0aedb0 100644 Binary files a/images/icon.iconset/icon_128x128.png and b/images/icon.iconset/icon_128x128.png differ diff --git a/images/icon.iconset/icon_16x16.png b/images/icon.iconset/icon_16x16.png index 8529501..eb3cf04 100644 Binary files a/images/icon.iconset/icon_16x16.png and b/images/icon.iconset/icon_16x16.png differ diff --git a/images/icon.iconset/icon_16x16@2x.png b/images/icon.iconset/icon_16x16@2x.png index 67c770d..dc4caa3 100644 Binary files a/images/icon.iconset/icon_16x16@2x.png and b/images/icon.iconset/icon_16x16@2x.png differ diff --git a/images/icon.iconset/icon_256x256.png b/images/icon.iconset/icon_256x256.png index 89f3dce..3ac4a8f 100644 Binary files a/images/icon.iconset/icon_256x256.png and b/images/icon.iconset/icon_256x256.png differ diff --git a/images/icon.iconset/icon_256x256@2x.png b/images/icon.iconset/icon_256x256@2x.png index 1bded25..0e07fde 100644 Binary files a/images/icon.iconset/icon_256x256@2x.png and b/images/icon.iconset/icon_256x256@2x.png differ diff --git a/images/icon.iconset/icon_32x32.png b/images/icon.iconset/icon_32x32.png index 67c770d..dc4caa3 100644 Binary files a/images/icon.iconset/icon_32x32.png and b/images/icon.iconset/icon_32x32.png differ diff --git a/images/icon.iconset/icon_32x32@2x.png b/images/icon.iconset/icon_32x32@2x.png index 738cd10..de0b700 100644 Binary files a/images/icon.iconset/icon_32x32@2x.png and b/images/icon.iconset/icon_32x32@2x.png differ diff --git a/images/icon.iconset/icon_512x512.png b/images/icon.iconset/icon_512x512.png index 1bded25..0e07fde 100644 Binary files a/images/icon.iconset/icon_512x512.png and b/images/icon.iconset/icon_512x512.png differ diff --git a/images/icon.iconset/icon_512x512@2x.png b/images/icon.iconset/icon_512x512@2x.png index 9cc0100..a476666 100644 Binary files a/images/icon.iconset/icon_512x512@2x.png and b/images/icon.iconset/icon_512x512@2x.png differ