diff --git a/AppDelegate.h b/AppDelegate.h
index 2c5a6b4..a7b2007 100755
--- a/AppDelegate.h
+++ b/AppDelegate.h
@@ -31,8 +31,10 @@
}
-//@property (readonly) NSViewController *currentViewController;
-//@property(nonatomic, retain)NSViewController *currentViewController;
+//'filter task' search box
+// ->top pane
+@property (weak) IBOutlet NSSearchField *filterTasksBox;
+
//(current) bottom view controller
@property(nonatomic, retain)TaskTableController *bottomViewController;
@@ -47,11 +49,6 @@
//task table controller object
@property (nonatomic, retain)TaskTableController *taskTableController;
-//tree (outline) controller
-//@property (nonatomic, retain)TreeViewController* treeViewController;
-
-//array to hold binary objects that are in array
-//@property (nonatomic, retain)NSMutableArray *tableContents;
//current task view format
// ->flat or tree
@@ -72,6 +69,10 @@
@property (weak) IBOutlet NSView *bottomPane;
+//'filter items' search box
+// ->bottom pane
+@property (weak) IBOutlet NSSearchField *filterItemsBox;
+
@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSButton *logoButton;
@@ -176,5 +177,8 @@
// ->either name (flat view) or pid (tree view)
-(void)sortTasksForView:(OrderedDictionary*)tasks;
+//filter tasks
+-(void)filterTasks:(NSString*)filterText;
+
@end
diff --git a/AppDelegate.m b/AppDelegate.m
index 3194ba5..83ff731 100755
--- a/AppDelegate.m
+++ b/AppDelegate.m
@@ -5,6 +5,7 @@
#import "Consts.h"
#import "Binary.h"
+#import "Connection.h"
#import "Exception.h"
#import "Utilities.h"
#import "AppDelegate.h"
@@ -341,6 +342,15 @@
}
}
+ //always unset filter flag
+ self.taskTableController.isFiltered = NO;
+
+ //always reset filter text
+ [self.filterTasksBox setStringValue:@""];
+
+ //set bottom view?
+ self.bottomPaneBtn.selectedSegment = DYLIBS_VIEW;
+
//add subview
[self.topPane addSubview:[self.taskTableController view]];
@@ -353,20 +363,42 @@
//reload (to re-draw) a specific row in table
-(void)reloadRow:(Task*)task item:(ItemBase*)item pane:(NSUInteger)pane
{
+ //item's task
+ // ->will use current task if task arg is nil
+ __block Task* itemTask = nil;
+
//table view
__block NSTableView* tableView = nil;
//row
__block NSUInteger row = 0;
+ //segment (for bottom pane
+ __block NSUInteger segmentTag = 0;
+
//run everything on main thread
// ->ensures table view isn't changed out from under us....
dispatch_async(dispatch_get_main_queue(), ^{
+
+ //get item's task
+ // ->use passed in task if non-nil
+ if(nil != itemTask)
+ {
+ //set
+ itemTask = task;
+ }
+ //passed in task is nil
+ // ->use currently selected one
+ else
+ {
+ //set
+ itemTask = self.currentTask;
+ }
//top table (pane)
if(PANE_TOP == pane)
{
- //get row that task is loaded in
+ //top table view
tableView = [((id)self.taskTableController) itemView];
//reloadItem
@@ -375,7 +407,7 @@
{
//get index where task is
// TODO: doesn't account for filtering, etc!!!
- row = [self.taskEnumerator.tasks indexOfKey:task.pid];
+ row = [self.taskEnumerator.tasks indexOfKey:itemTask.pid];
if(NSNotFound == row)
{
//bail
@@ -400,7 +432,7 @@
[tableView beginUpdates];
//reload
- [(NSOutlineView*)tableView reloadItem:task];
+ [(NSOutlineView*)tableView reloadItem:itemTask];
//end updates
[tableView endUpdates];
@@ -408,10 +440,97 @@
}
-
- //TODO: bottom pane
-
-
+ //bottom pane
+ else
+ {
+ //bottom table view
+ tableView = [((id)self.bottomViewController) itemView];
+
+ //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:
+
+ //make sure item class/type matches current view
+ if(YES != [item isKindOfClass:[Binary class]])
+ {
+ //bail
+ goto bail;
+ }
+
+ //sync
+ @synchronized(itemTask.dylibs)
+ {
+ //get row
+ row = [itemTask.dylibs indexOfObject:item];
+ }
+
+ break;
+
+ //files
+ case FILES_VIEW:
+
+ //make sure item class/type matches current view
+ if(YES != [item isKindOfClass:[File class]])
+ {
+ //bail
+ goto bail;
+ }
+
+ //sync
+ @synchronized(itemTask.files)
+ {
+ //get row
+ row = [itemTask.files indexOfObject:item];
+ }
+
+ break;
+
+ //networking
+ case NETWORKING_VIEW:
+
+ //make sure item class/type matches current view
+ if(YES != [item isKindOfClass:[Connection class]])
+ {
+ //bail
+ goto bail;
+ }
+ //sync
+ @synchronized(itemTask.connections)
+ {
+ //get row
+ row = [itemTask.connections indexOfObject:item];
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ //make sure item was found
+ if(NSNotFound == row)
+ {
+ //bail
+ goto bail;
+ }
+
+
+ //begin updates
+ [tableView beginUpdates];
+
+ //reload row
+ [tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:(row)] columnIndexes:[NSIndexSet indexSetWithIndex:0]];
+
+ //end updates
+ [tableView endUpdates];
+ }
+
//bail
bail:
;
@@ -472,6 +591,7 @@ bail:
//set table items
self.bottomViewController.tableItems = self.currentTask.connections;
+
break;
default:
@@ -486,7 +606,7 @@ bail:
{
//reload
// ->in main UI thread
- dispatch_sync(dispatch_get_main_queue(), ^{
+ dispatch_async(dispatch_get_main_queue(), ^{
[self finalizeBottomReload];
});
@@ -500,7 +620,7 @@ bail:
-(void)finalizeBottomReload
{
- //stop progress indicator
+ //stop progress indicator
[self.bottomPaneSpinner stopAnimation:nil];
//invoke refresh
@@ -1299,6 +1419,21 @@ bail:
//save selected view
self.taskViewFormat = [[sender selectedCell] tag];
+ //flat view
+ // ->enable 'filter tasks' search field
+ if(FLAT_VIEW == self.taskViewFormat)
+ {
+ //enable
+ self.filterTasksBox.enabled = YES;
+ }
+ //tree view
+ // ->disable 'filter tasks' search field
+ else
+ {
+ //disable
+ self.filterTasksBox.enabled = NO;
+ }
+
//switch (top) view/pane
[self changeViewController];
@@ -1390,4 +1525,104 @@ bail:
return;
}
+//automatically invoked when user enters text in filter search boxes
+// ->filter tasks and/or items
+- (void)controlTextDidChange:(NSNotification *)aNotification
+{
+ //search text
+ NSTextView* search = nil;
+
+ //extract search (text) view
+ search = aNotification.userInfo[@"NSFieldEditor"];
+
+ //sanity check
+ if(nil == search)
+ {
+ //bail
+ goto bail;
+ }
+
+ //top pane
+ if(YES == [aNotification.object isEqualTo:self.filterTasksBox])
+ {
+ //when text is reset
+ // ->just reset flag
+ if(0 == search.string.length)
+ {
+ //set flag
+ self.taskTableController.isFiltered = NO;
+ }
+ //filter tasks
+ else
+ {
+ //filter
+ [self filterTasks:search.string];
+
+ //set flag
+ self.taskTableController.isFiltered = YES;
+ }
+
+ //always reload task table
+ [self.taskTableController.itemView reloadData];
+ }
+ //bottom pane
+ else if(YES == [aNotification.object isEqualTo:self.filterItemsBox])
+ {
+
+ }
+
+
+
+ //NSLog(@"changed!");
+
+//bail
+bail:
+
+ return;
+
+}
+
+//filter tasks
+// ->for now, just name & path
+// TODO filter on everything
+// TODO: move into task enumerator!?
+-(void)filterTasks:(NSString*)filterText
+{
+ //task
+ Task* task = nil;
+
+ //name range
+ NSRange nameRange = {0};
+
+ //path range
+ NSRange pathRange = {0};
+
+ //first reset filter'd items
+ [self.taskTableController.filteredItems removeAllObjects];
+
+ //iterate over all tasks
+ for(NSNumber* taskKey in self.taskEnumerator.tasks)
+ {
+ //extract task
+ task = self.taskEnumerator.tasks[taskKey];
+
+ //init name range
+ nameRange = [task.binary.name rangeOfString:filterText options:NSCaseInsensitiveSearch];
+
+ //init path range
+ pathRange = [task.binary.path rangeOfString:filterText options:NSCaseInsensitiveSearch];
+
+ //check for match
+ if( (NSNotFound != nameRange.location) ||
+ (NSNotFound != pathRange.location) )
+ {
+ //save match
+ [self.taskTableController.filteredItems addObject:task];
+ }
+
+ }//all tasks
+
+ return;
+}
+
@end
diff --git a/ItemView.h b/ItemView.h
index 76b1da4..f14acfd 100644
--- a/ItemView.h
+++ b/ItemView.h
@@ -36,4 +36,8 @@ void addTrackingArea(NSTableCellView* itemView, NSUInteger subviewTag, id owner)
//set code signing image
// ->either signed, unsigned, or unknown
-NSImage* getCodeSigningIcon(Binary* binary);
\ No newline at end of file
+NSImage* getCodeSigningIcon(Binary* binary);
+
+//configure the VT button
+// ->also set's binary name to red if known malware
+void configVTButton(NSTableCellView *itemCell, id owner, Binary* binary);
\ No newline at end of file
diff --git a/ItemView.m b/ItemView.m
index 669d621..0bcff19 100644
--- a/ItemView.m
+++ b/ItemView.m
@@ -573,6 +573,9 @@ NSTableCellView* createTaskView(NSTableView* tableView, id owner, Task* task)
//set path
[[taskCell viewWithTag:TABLE_ROW_SUB_TEXT_TAG] setStringValue:task.binary.path];
+
+ //config VT button
+ configVTButton(taskCell, owner, task.binary);
//bail
bail:
@@ -625,6 +628,9 @@ NSTableCellView* createDylibView(NSTableView* tableView, id owner, Binary* dylib
//set path
[[dylibCell viewWithTag:TABLE_ROW_SUB_TEXT_TAG] setStringValue:dylib.path];
+ //config VT button
+ configVTButton(dylibCell, owner, dylib);
+
//bail
bail:
@@ -786,6 +792,159 @@ bail:
}
+//configure the VT button
+// ->also set's binary name to red if known malware
+void configVTButton(NSTableCellView *itemCell, id owner, Binary* binary)
+{
+ //virus total button
+ // ->for File objects only...
+ VTButton* vtButton;
+
+ //paragraph style
+ NSMutableParagraphStyle *paragraphStyle = nil;
+
+ //attribute dictionary
+ NSMutableDictionary *stringAttributes = nil;
+
+ //VT detection ratio as string
+ NSString* vtDetectionRatio = nil;
+
+ //grab virus total button
+ vtButton = [itemCell viewWithTag:TABLE_ROW_VT_BUTTON];
+
+
+ //[itemCell viewWithTag:TABLE_ROW_VT_BUTTON];
+
+ //configure/show VT info
+ // ->only if 'disable' preference not set
+ //if(YES != ((AppDelegate*)[[NSApplication sharedApplication] delegate]).prefsWindowController.disableVTQueries)
+ //{
+ //set button delegate
+ vtButton.delegate = owner;
+
+ //save file obj
+ vtButton.binary = binary;
+
+ //check if have vt results
+ if(nil != binary.vtInfo)
+ {
+ //set font
+ [vtButton setFont:[NSFont fontWithName:@"Menlo-Bold" size:12]];
+
+ //enable
+ vtButton.enabled = YES;
+
+ //got VT results
+ // ->check 'permalink' to determine if file is known to VT
+ // then, show ratio and set to red if file is flagged
+ if(nil != binary.vtInfo[VT_RESULTS_URL])
+ {
+ //alloc paragraph style
+ paragraphStyle = [[NSMutableParagraphStyle alloc] init];
+
+ //center the text
+ [paragraphStyle setAlignment:NSCenterTextAlignment];
+
+ //alloc attributes dictionary
+ stringAttributes = [NSMutableDictionary dictionary];
+
+ //set underlined attribute
+ stringAttributes[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);
+
+ //set alignment (center)
+ stringAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
+
+ //set font
+ stringAttributes[NSFontAttributeName] = [NSFont fontWithName:@"Menlo-Bold" size:12];
+
+ //compute detection ratio
+ vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[binary.vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
+
+ //known 'good' files (0 positivies)
+ if(0 == [binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue])
+ {
+ //(re)set title black
+ itemCell.textField.textColor = [NSColor blackColor];
+
+ //set color (black)
+ stringAttributes[NSForegroundColorAttributeName] = [NSColor blackColor];
+
+ //set string (vt ratio), with attributes
+ [vtButton setAttributedTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
+
+ //set color (gray)
+ stringAttributes[NSForegroundColorAttributeName] = [NSColor grayColor];
+
+ //set selected text color
+ [vtButton setAttributedAlternateTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
+ }
+ //files flagged by VT
+ // ->set name and detection to red
+ else
+ {
+ //set title red
+ itemCell.textField.textColor = [NSColor redColor];
+
+ //set color (red)
+ stringAttributes[NSForegroundColorAttributeName] = [NSColor redColor];
+
+ //set string (vt ratio), with attributes
+ [vtButton setAttributedTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
+
+ //set selected text color
+ [vtButton setAttributedAlternateTitle:[[NSAttributedString alloc] initWithString:vtDetectionRatio attributes:stringAttributes]];
+
+ }
+
+ //enable
+ [vtButton setEnabled:YES];
+ }
+
+ //file is not known
+ // ->reset title to '?'
+ else
+ {
+ //set title
+ [vtButton setTitle:@"?"];
+ }
+ }
+
+ //no VT results (e.g. unknown file)
+ else
+ {
+ //set font
+ [vtButton setFont:[NSFont fontWithName:@"Menlo-Bold" size:8]];
+
+ //set title
+ [vtButton setTitle:@"▪ ▪ ▪"];
+
+ //disable
+ vtButton.enabled = NO;
+ }
+
+ //show virus total button
+ vtButton.hidden = NO;
+
+ //show virus total label
+ //[[itemCell viewWithTag:TABLE_ROW_VT_BUTTON+1] setHidden:NO];
+
+ //}//show VT info (pref not disabled)
+
+ /*
+ //hide VT info
+ else
+ {
+ //hide virus total button
+ vtButton.hidden = YES;
+
+ //hide virus total button label
+ [[itemCell viewWithTag:TABLE_ROW_VT_BUTTON+1] setHidden:YES];
+ }
+ */
+
+ return;
+}
+
diff --git a/Items/Binary.h b/Items/Binary.h
index 6e6fca4..34cd5cb 100644
--- a/Items/Binary.h
+++ b/Items/Binary.h
@@ -41,6 +41,10 @@
/* VIRUS TOTAL INFO */
+//flag saying item is 'last'
+// ->thus VT items should all be queried
+@property BOOL lastItem;
+
//dictionary returned by VT
@property (nonatomic, retain)NSDictionary* vtInfo;
diff --git a/Items/Binary.m b/Items/Binary.m
index 8dcd4fa..3a17d38 100644
--- a/Items/Binary.m
+++ b/Items/Binary.m
@@ -23,7 +23,7 @@
@synthesize isTaskBinary;
@synthesize vtInfo;
-
+@synthesize lastItem;
//init method
-(id)initWithParams:(NSDictionary*)params
diff --git a/Queue.m b/Queue.m
index dd0c175..6e36b85 100644
--- a/Queue.m
+++ b/Queue.m
@@ -90,7 +90,6 @@
//add item for VT processing
[vtObject addItem:binary];
-
//unlock
[self.queueCondition unlock];
diff --git a/Task.m b/Task.m
index 8cfd0b6..99cda40 100644
--- a/Task.m
+++ b/Task.m
@@ -110,22 +110,17 @@
goto bail;
}
+ //indicate that binary is a task (main) executable
+ self.binary.isTaskBinary = YES;
+
//add to queue
// ->this will processing
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.binaryQueue enqueue:self.binary];
- //add to VT queue
- // ->this will trigger background submission to VT
- [((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.binaryQueue enqueue:self.binary];
-
//add it to 'global' list
existingBinaries[taskPath] = self.binary;
-
}
- //indicate that binary is a task (main) executable
- //self.binary.isTaskBinary = YES;
-
}//init self
//bail
@@ -404,7 +399,7 @@ bail:
//add to task's dylibs
[self.dylibs addObject:dylib];
}
- }
+ } //all dylibs
//sync to sort
@synchronized(self.dylibs)
diff --git a/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout b/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout
index a240ad9..72b1950 100644
--- a/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout
+++ b/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout
@@ -10,14 +10,14 @@
TaskExplorer
IDESourceControlProjectOriginsDictionary
- A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D
+ 61F07AFB33748EF0C810BEEF6126283DAC63A899
https://bitbucket.org/objective-see/knockknock.git
IDESourceControlProjectPath
TaskExplorer.xcodeproj
IDESourceControlProjectRelativeInstallPathDictionary
- A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D
+ 61F07AFB33748EF0C810BEEF6126283DAC63A899
../..
IDESourceControlProjectURL
@@ -25,14 +25,14 @@
IDESourceControlProjectVersion
111
IDESourceControlProjectWCCIdentifier
- A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D
+ 61F07AFB33748EF0C810BEEF6126283DAC63A899
IDESourceControlProjectWCConfigurations
IDESourceControlRepositoryExtensionIdentifierKey
public.vcs.git
IDESourceControlWCCIdentifierKey
- A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D
+ 61F07AFB33748EF0C810BEEF6126283DAC63A899
IDESourceControlWCCName
TaskExplorer
diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
index 2ddd5ee..e054392 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 = "456469787.454434"
+ timestampString = "456607885.071145"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "343"
- endingLineNumber = "343"
+ startingLineNumber = "344"
+ endingLineNumber = "344"
landmarkName = "-removeTask:"
landmarkType = "5">
@@ -36,11 +36,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
- timestampString = "456541711.785304"
+ timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "661"
- endingLineNumber = "661"
+ startingLineNumber = "775"
+ endingLineNumber = "775"
landmarkName = "-reloadTaskTable"
landmarkType = "5">
@@ -52,27 +52,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
- timestampString = "456474649.232255"
+ timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "711"
- endingLineNumber = "711"
- landmarkName = "-refresh"
- landmarkType = "5">
-
-
-
-
@@ -84,11 +68,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
- timestampString = "456474649.232255"
+ timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "1115"
- endingLineNumber = "1115"
+ startingLineNumber = "1167"
+ endingLineNumber = "1167"
landmarkName = "-outlineView:viewForTableColumn:item:"
landmarkType = "5">
@@ -100,11 +84,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
- timestampString = "456474649.232255"
+ timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "1105"
- endingLineNumber = "1105"
+ startingLineNumber = "1157"
+ endingLineNumber = "1157"
landmarkName = "-outlineViewSelectionDidChange:"
landmarkType = "5">
@@ -132,11 +116,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
- timestampString = "456521744.657881"
+ timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "934"
- endingLineNumber = "934"
+ startingLineNumber = "1000"
+ endingLineNumber = "1000"
landmarkName = "-showInfo:"
landmarkType = "5">
@@ -148,11 +132,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
- timestampString = "456521776.780775"
+ timestampString = "456621956.395811"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "317"
- endingLineNumber = "317"
+ startingLineNumber = "318"
+ endingLineNumber = "318"
landmarkName = "-changeViewController"
landmarkType = "5">
@@ -167,5 +151,245 @@
moduleName = "">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TaskTableController.h b/TaskTableController.h
index 8bb5bba..c8c21a3 100644
--- a/TaskTableController.h
+++ b/TaskTableController.h
@@ -23,12 +23,18 @@
//flag for first time init's
@property BOOL didInit;
-//tasks
-// ->updated by task enumerator
-//@property(nonatomic, retain)OrderedDictionary* tasks;
+//flag for ignoring automated row selections
+@property BOOL ignoreSelection;
+//flag for filtering
+@property BOOL isFiltered;
+
+//all table items
@property(nonatomic, retain)NSMutableArray* tableItems;
+//filtered table items
+@property(nonatomic, retain)NSMutableArray* filteredItems;
+
//category table view
@property(weak) IBOutlet NSTableView *itemView;
diff --git a/TaskTableController.m b/TaskTableController.m
index ddbda8b..f4c9e5c 100644
--- a/TaskTableController.m
+++ b/TaskTableController.m
@@ -6,7 +6,7 @@
// Copyright (c) 2015 Objective-See. All rights reserved.
//
-//TODO: list of what's running on my Mac!!!!
+//TODO: list of what's running on my Mac on website!!!!
#import "Binary.h"
#import "Consts.h"
@@ -30,59 +30,39 @@
@implementation TaskTableController
@synthesize itemView;
+@synthesize isFiltered;
@synthesize tableItems;
@synthesize selectedRow;
@synthesize isBottomPane;
+@synthesize filteredItems;
+@synthesize ignoreSelection;
@synthesize vtWindowController;
@synthesize infoWindowController;
@synthesize didInit;
-//@synthesize tasks;
-
-//TODO: called many timesss
-(void)awakeFromNib
{
-
+ //single time init
if(YES != didInit)
{
+ //init selected row
self.selectedRow = -1;
- //for outline (tree) view
- // ->expand
- if(YES == [self.itemView isKindOfClass:[NSOutlineView class]])
- {
- [(NSOutlineView*)self.itemView expandItem:nil expandChildren:YES];
- }
+ //alloc array for filtered items
+ filteredItems = [NSMutableArray array];
+
+ //extand tree view
+ if(YES == [self.itemView isKindOfClass:[NSOutlineView class]])
+ {
+ //expand
+ [(NSOutlineView*)self.itemView expandItem:nil expandChildren:YES];
+ }
//set flag
self.didInit = YES;
-
}
- //self.selectedRow = -1;
-
- /*
- //for outline (tree) view
- // ->expand
- if(YES == [self.itemView isKindOfClass:[NSOutlineView class]])
- {
- [(NSOutlineView*)self.itemView expandItem:nil expandChildren:YES];
-
- //TODO: do this in IB?
- //[itemView setTarget:self];
- }
- */
-
-
- /*
- NSString *title = @"[ all tasks ]";
- NSTableColumn *yourColumn = self.itemView.tableColumns.lastObject;
- [yourColumn.headerCell setStringValue:title];
-
- [self.itemView setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:self.itemView.tableColumns.lastObject];
-
- */
}
@@ -115,13 +95,26 @@
// ->use tasks from enumerator
if(YES != self.isBottomPane)
{
- //grab tasks
- tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
+ //when not filtered
+ // ->use tasks
+ if(YES != isFiltered)
+ {
+ //get tasks
+ tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
- //set row count
- rows = tasks.count;
+ //set count
+ rows = tasks.count;
+ }
+ //when filtered
+ // ->use filtered items
+ else
+ {
+ //set count
+ rows = self.filteredItems.count;
+ }
}
- //bottom pane uses table items
+ //bottom pane uses 'tableItems' iVar
+ //TODO: filter support
else
{
//set row count
@@ -130,14 +123,19 @@
return rows;
- }
+}
//automatically invoked when user selects row
// ->only care about for top pane, trigger load bottom view
-(void)tableViewSelectionDidChange:(NSNotification *)notification
{
- //handle selection
- [self handleRowSelection];
+ //only handle user selections
+ // ->not those from 'reloadData'
+ if(YES != self.ignoreSelection)
+ {
+ //handle selection
+ [self handleRowSelection];
+ }
return;
}
@@ -157,23 +155,45 @@
NSView* rowView = nil;
//for TOP PANE
- // ->use tasks from enumerator
+ // ->use tasks from enumerator or filtered items
if(YES != self.isBottomPane)
{
- //grab tasks
- tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
-
- //sanity check
- // ->make sure there is table item for row
- if(tasks.count <= row)
+ //when not filtered
+ // ->use tasks
+ if(YES != isFiltered)
{
- //bail
- goto bail;
+ //grab tasks
+ tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
+
+ //sanity check
+ // ->make sure there is table item for row
+ if(tasks.count <= row)
+ {
+ //bail
+ goto bail;
+ }
+
+ //get task object
+ // ->by index to get key, then by key
+ item = tasks[[tasks keyAtIndex:row]];
+
}
- //get task object
- // ->by index to get key, then by key
- item = tasks[[tasks keyAtIndex: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;
+ }
+
+ //get task object
+ item = self.filteredItems[row];
+ }
}
//for BOTTOM PANE
@@ -725,9 +745,15 @@ bail:
//get task
selectedTask = [self taskForRow:nil];
+ //ignore selection change though
+ self.ignoreSelection = YES;
+
//always reload
[self.itemView reloadData];
+ //don't ignore selection
+ self.ignoreSelection = NO;
+
//when an item was selected
// ->get its index and make sure that's still selected
if(nil != selectedTask)
@@ -749,6 +775,40 @@ bail:
[self.itemView endUpdates];
}
}
+ /*
+ //otherwise select first row
+ else
+ {
+ //selected row cell
+ NSTableCellView* rowView = nil;
+
+ //default to first row
+ self.selectedRow = 0;
+
+ //sanity check
+ if(0 == [self numberOfRowsInTableView:self.itemView])
+ {
+ //bail
+ goto bail;
+ }
+
+ //get first row
+ rowView = [self.itemView viewAtColumn:0 row:0 makeIfNecessary:YES];
+
+ //extract task
+ // ->pid of task is view's id :)
+ Task* task = tasks[[NSNumber numberWithInteger:(rowView.tag - PID_TAG_DELTA)]];
+
+ //save task
+ ((AppDelegate*)[[NSApplication sharedApplication] delegate]).currentTask = task;
+
+ //reload bottom pane
+ [((AppDelegate*)[[NSApplication sharedApplication] delegate]) selectBottomPaneContent:nil];
+ }
+ */
+
+//bail
+bail:
return;
}
@@ -784,28 +844,34 @@ bail:
{
//grab row
taskRow = [self.itemView selectedRow];
-
}
+ //TODO: add check for filterItems.count
//sanity check(s)
- // ->make sure row has item
+ // ->make sure row is decent
if( (-1 == taskRow) ||
- (tasks.count < taskRow) )
+ ((YES != self.isFiltered) && (tasks.count < taskRow)) ||
+ ((YES == self.isFiltered) && (self.filteredItems.count < taskRow)) )
{
//bail
goto bail;
}
- //get task object
- // ->by index to get key, then by key
- //task = tasks[[tasks keyAtIndex:taskRow]];
-
//get row that's about to be selected
rowView = [self.itemView viewAtColumn:0 row:taskRow makeIfNecessary:YES];
- //extract task
- // ->pid of task is view's id :)
- task = tasks[[NSNumber numberWithInteger:(rowView.tag - PID_TAG_DELTA)]];
+ //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[
+ //}
//bail
bail:
@@ -966,54 +1032,40 @@ bail:
//invoked when the user clicks 'virus total' icon
// ->launch browser and browse to virus total's page
--(void)showVTInfo:(NSView*)button
+-(void)showVTInfo:(id)sender
{
- //array backing table
- NSArray* tableItems = nil;
+ //item
+ // ->task, dylib, file, etc
+ Binary* item = nil;
- //selected item
- File* selectedItem = nil;
+ //for top pane
+ // ->get task
+ if(YES != self.isBottomPane)
+ {
+ //get task
+ item = [(Task*)[self taskForRow:sender] binary];
+ }
+
+ //bottom pane
+ else
+ {
+ //get item
+ item = (Binary*)[self itemForRow:sender];
+ }
- //row that button was clicked on
- NSUInteger rowIndex = -1;
-
- //get row index
- rowIndex = [self.itemView rowForView:button];
-
- //grab item table items
- tableItems = [self getTableItems];
-
- //sanity check
- // ->make sure row has item
- if(tableItems.count < rowIndex)
+ //bail on nil items
+ if(nil == item)
{
//bail
goto bail;
}
-
- //sanity check
- if(-1 != rowIndex)
- {
- //extract selected item
- // ->invoke helper function to get array backing table
- selectedItem = tableItems[rowIndex];
-
- //alloc/init info window
- vtWindowController = [[VTInfoWindowController alloc] initWithItem:selectedItem rowIndex:rowIndex];
-
- //show it
- [self.vtWindowController.windowController showWindow:self];
-
- /*
- //make it modal
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-
- //modal!
- [[NSApplication sharedApplication] runModalForWindow:vtWindowController.windowController.window];
-
- });
- */
- }
+
+ //alloc/init info window
+ vtWindowController = [[VTInfoWindowController alloc] initWithItem:item];
+
+ //show it
+ [self.vtWindowController.windowController showWindow:self];
+
//bail
bail:
@@ -1177,7 +1229,8 @@ bail:
//sanity check
if( (-1 == newlySelectedRow) ||
- (newlySelectedRow >= tasks.count) )
+ ((YES != self.isFiltered) && (newlySelectedRow >= tasks.count)) ||
+ ((YES == self.isFiltered) && (newlySelectedRow >= self.filteredItems.count)) )
{
//bail
goto bail;
@@ -1241,9 +1294,9 @@ bail:
}
-
- //ignore if row selection didn't change
- if([self.itemView selectedRow] == self.selectedRow)
+ //ignore if row selection and task didn't change
+ if( ([self.itemView selectedRow] == self.selectedRow) &&
+ (((AppDelegate*)[[NSApplication sharedApplication] delegate]).currentTask == task) )
{
//ignore
goto bail;
@@ -1262,7 +1315,8 @@ bail:
//bail
bail:
- ;
+
+ return;
}
diff --git a/VTButton.h b/VTButton.h
index a5c7f7b..4254389 100644
--- a/VTButton.h
+++ b/VTButton.h
@@ -24,7 +24,7 @@
@property(assign)TaskTableController *delegate;
//File object
-@property(nonatomic, retain)Binary* fileObj;
+@property(nonatomic, retain)Binary* binary;
//button's row index
diff --git a/VTButton.m b/VTButton.m
index 8daa00b..672499f 100644
--- a/VTButton.m
+++ b/VTButton.m
@@ -13,7 +13,7 @@
@implementation VTButton
-@synthesize fileObj;
+@synthesize binary;
@synthesize delegate;
@synthesize mouseDown;
@synthesize mouseExit;
@@ -53,8 +53,8 @@
//flagged files
// ->make em red!
- if( (nil != self.fileObj.vtInfo) &&
- (0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
+ if( (nil != self.binary.vtInfo) &&
+ (0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
{
//set color (light red)
color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.5];
@@ -94,8 +94,8 @@
//flagged files
// ->make em red!
- if( (nil != self.fileObj.vtInfo) &&
- (0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
+ if( (nil != self.binary.vtInfo) &&
+ (0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
{
//set color (light red)
color = [NSColor redColor];
@@ -126,8 +126,8 @@
//flagged files
// ->make em red!
- if( (nil != self.fileObj.vtInfo) &&
- (0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
+ if( (nil != self.binary.vtInfo) &&
+ (0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
{
//set color (lightish red)
color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.66];
@@ -162,8 +162,8 @@
{
//flagged files
// ->make em red!
- if( (nil != self.fileObj.vtInfo) &&
- (0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
+ if( (nil != self.binary.vtInfo) &&
+ (0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
{
//set color (lightish red)
color = [NSColor colorWithCalibratedRed:(255/255.0f) green:(1.0/255.0f) blue:(1.0/255.0f) alpha:0.66];
@@ -182,8 +182,8 @@
{
//flagged files
// ->make em red!
- if( (nil != self.fileObj.vtInfo) &&
- (0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
+ if( (nil != self.binary.vtInfo) &&
+ (0 != [self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue]) )
{
//set color (light red)
color = [NSColor redColor];
diff --git a/VTInfoWindowController.h b/VTInfoWindowController.h
index 42bd308..c563e20 100644
--- a/VTInfoWindowController.h
+++ b/VTInfoWindowController.h
@@ -22,10 +22,10 @@
@property(nonatomic, strong)VTInfoWindowController *windowController;
//file object
-@property(nonatomic, retain)Binary* fileObj;
+@property(nonatomic, retain)Binary* item;
//row index
-@property NSUInteger rowIndex;
+//@property NSUInteger rowIndex;
//properties in window
@property (weak) IBOutlet NSTextField *unknownFile;
@@ -50,7 +50,7 @@
//init method
// ->save item and load nib
--(id)initWithItem:(File*)selectedItem rowIndex:(NSUInteger)itemRowIndex;
+-(id)initWithItem:(Binary*)binary;
//'submit' button handler
-(IBAction)vtButtonHandler:(id)sender;
diff --git a/VTInfoWindowController.m b/VTInfoWindowController.m
index 606cdf2..6c4f4ab 100644
--- a/VTInfoWindowController.m
+++ b/VTInfoWindowController.m
@@ -23,13 +23,13 @@
@implementation VTInfoWindowController
-@synthesize rowIndex;
+@synthesize item;
@synthesize windowController;
//init method
// ->save item and load nib
--(id)initWithItem:(File*)selectedItem rowIndex:(NSUInteger)itemRowIndex
+-(id)initWithItem:(Binary*)binary
{
self = [super init];
if(nil != self)
@@ -38,10 +38,10 @@
self.windowController = [[VTInfoWindowController alloc] initWithWindowNibName:@"VTInfoWindow"];
//save item
- self.windowController.fileObj = selectedItem;
+ self.windowController.item = binary;
//save row index
- self.windowController.rowIndex = itemRowIndex;
+ //self.windowController.rowIndex = itemRowIndex;
}
return self;
@@ -92,7 +92,7 @@
NSColor* textColor = nil;
//get status
- if(nil != self.fileObj.vtInfo[VT_RESULTS_URL])
+ if(nil != self.item.vtInfo[VT_RESULTS_URL])
{
//known
isKnown = YES;
@@ -105,17 +105,17 @@
textColor = [NSColor blackColor];
//set color to red if its flagged
- if(0 != [self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue])
+ if(0 != [self.item.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue])
{
//red
textColor = [NSColor redColor];
}
//generate detection ratio
- vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[self.fileObj.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[self.fileObj.vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
+ vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[self.item.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[self.item.vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
//set name
- [self.fileName setStringValue:self.fileObj.name];
+ [self.fileName setStringValue:self.item.name];
//set color
self.fileName.textColor = textColor;
@@ -130,7 +130,7 @@
[self.analysisURL setStringValue:@"VirusTotal report"];
//make analyis url a hyperlink
- makeTextViewHyperlink(self.analysisURL, [NSURL URLWithString:self.fileObj.vtInfo[VT_RESULTS_URL]]);
+ makeTextViewHyperlink(self.analysisURL, [NSURL URLWithString:self.item.vtInfo[VT_RESULTS_URL]]);
//set 'submit' button text to 'rescan'
self.submitButton.title = @"rescan?";
@@ -157,7 +157,7 @@
self.analysisURL.hidden = YES;
//set unknown file msg
- [self.unknownFile setStringValue:[NSString stringWithFormat:@"no results found for '%@'", self.fileObj.name]];
+ [self.unknownFile setStringValue:[NSString stringWithFormat:@"no results found for '%@'", self.item.name]];
//show 'unknown file' msg
self.unknownFile.hidden = NO;
@@ -253,7 +253,7 @@
if(YES == [((NSButton*)sender).title isEqualToString:@"rescan?"])
{
//set status msg
- [self.statusMsg setStringValue:[NSString stringWithFormat:@"submitting re-scan request for %@", self.fileObj.name]];
+ [self.statusMsg setStringValue:[NSString stringWithFormat:@"submitting re-scan request for %@", self.item.name]];
//show status msg
self.statusMsg.hidden = NO;
@@ -262,8 +262,8 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//make request to VT
- //TODO: re-enable
- //result = [vtObj reScan:self.fileObj];
+ // ->will also update UI to show '...'
+ result = [vtObj reScan:self.item];
//got result
// ->update UI and launch browswer to show report
@@ -273,6 +273,9 @@
// ->need this for (re)queries
scanID = result[VT_RESULTS_SCANID];
+ //TODO: do something w/ prev flagged files!?
+ // ...i don't think we'll keep a list~
+
/*
//if file was flagged
@@ -290,29 +293,18 @@
*/
- //remove file's VT info (since it'd now out of date)
- self.fileObj.vtInfo = nil;
-
//with a scan id can re-query VT
// ->will update VT button in UI once results are retrieved
if(nil != scanID)
{
- ////TODO: re-enable
-
- /*
//kick off task to re-query VT
// ->wait 60 seconds though to give VT servers some time to process
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [vtObj getInfoForItem:self.fileObj scanID:scanID rowIndex:self.rowIndex];
+ [vtObj getInfoForItem:self.item scanID:scanID];
});
-
- */
+
}
- //ask app delegate to update item in table
- // ->will change the item's VT status to ... (pending)
- [((AppDelegate*)[[NSApplication sharedApplication] delegate]) itemProcessed:self.fileObj rowIndex:self.rowIndex];
-
//nap so user can see msg 'submitting' msg
[NSThread sleepForTimeInterval:0.5];
@@ -340,7 +332,6 @@
[self.window close];
});
-
}
//error
@@ -359,13 +350,13 @@
}
});
- }
+ } //rescan file
//submit file
else
{
//set status msg
- [self.statusMsg setStringValue:[NSString stringWithFormat:@"submitting %@", self.fileObj.name]];
+ [self.statusMsg setStringValue:[NSString stringWithFormat:@"submitting %@", self.item.name]];
//show status msg
self.statusMsg.hidden = NO;
@@ -374,36 +365,26 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//submit file to VT
- //TODO: re-enable
- //result = [vtObj submit:self.fileObj];
+ // ->will also update UI to show '...'
+ result = [vtObj submit:self.item];
// ->need this for (re)queries
scanID = result[VT_RESULTS_SCANID];
- //reset file's VT info
- self.fileObj.vtInfo = nil;
-
//with a scan id can query VT
// ->will update VT button in UI once results are retrieved
if(nil != scanID)
{
- //TODO: re-enable
- /*
//kick off task to re-query VT
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [vtObj getInfoForItem:self.fileObj scanID:scanID rowIndex:self.rowIndex];
+ [vtObj getInfoForItem:self.item scanID:scanID];
});
- */
}
//got response
- // ->update UI and launch browswer to show report
+ // ->launch browswer to show report
if(nil != result)
{
- //ask app delegate to update item in table
- // ->will change the item's VT status to ... (pending)
- [((AppDelegate*)[[NSApplication sharedApplication] delegate]) itemProcessed:self.fileObj rowIndex:self.rowIndex];
-
//update status msg
dispatch_sync(dispatch_get_main_queue(), ^{
@@ -447,7 +428,7 @@
}
});
- }
+ } //submit file
return;
}
diff --git a/VirusTotal.h b/VirusTotal.h
index 8251a28..0b789a7 100644
--- a/VirusTotal.h
+++ b/VirusTotal.h
@@ -34,17 +34,21 @@
-(NSDictionary*)postRequest:(NSURL*)url parameters:(id)params;
//submit a file to VT
-//-(NSDictionary*)submit:(File*)fileObj;
+-(NSDictionary*)submit:(Binary*)item;
//submit a rescan request
-//-(NSDictionary*)reScan:(File*)fileObj;
+-(NSDictionary*)reScan:(Binary*)item;
//process results
// ->updates items (found, detection ratio, etc)
-(void)processResults:(NSMutableDictionary*)queriedItems results:(NSDictionary*)results;
//get info for a single item
-// ->will callback into AppDelegate to reload plugin
-//-(void)getInfoForItem:(File*)fileObj scanID:(NSString*)scanID rowIndex:(NSUInteger)rowIndex;
+// ->will callback into AppDelegate to reload item
+-(void)getInfoForItem:(Binary*)item scanID:(NSString*)scanID;
+
+//call back up to update item in UI
+// ->will either reload task table (top), or just row in item (bottom) table
+-(void)updateUI:(Binary*)item;
@end
diff --git a/VirusTotal.m b/VirusTotal.m
index 207ec8c..eb94a48 100644
--- a/VirusTotal.m
+++ b/VirusTotal.m
@@ -30,6 +30,7 @@
return self;
}
+//TODO: move this in Queue?
//add item
// ->will query VT when 25 items are hit
-(void)addItem:(Binary*)binary
@@ -42,22 +43,26 @@
}
//query VT once 25 items have been gathered
- if(VT_MAX_QUERY_COUNT == self.items.count)
+ // ->or this is a 'last' item
+ if( (VT_MAX_QUERY_COUNT == self.items.count) ||
+ (YES == binary.lastItem) )
{
- //process
- [self queryVT];
+ //kick of thread to make a query to VT
+ [NSThread detachNewThreadSelector:@selector(queryVT) toTarget:self withObject:nil];
}
+
+ return;
}
//make query to VT
-(void)queryVT
{
- //VT query URL
- NSURL* queryURL = nil;
-
//item data
NSMutableDictionary* itemData = nil;
+ //VT query URL
+ NSURL* queryURL = nil;
+
//array of queried items
// ->needed so can save VT results back into binaries
NSMutableDictionary* queriedItems = nil;
@@ -67,9 +72,6 @@
//results
NSDictionary* results = nil;
-
- //init query URL
- queryURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", VT_QUERY_URL, VT_API_KEY]];
//alloc list for items
parameters = [NSMutableArray array];
@@ -77,6 +79,9 @@
//alloc dictionary for queried items
queriedItems = [NSMutableDictionary dictionary];
+ //init query URL
+ queryURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", VT_QUERY_URL, VT_API_KEY]];
+
//sync
@synchronized(self.items)
{
@@ -84,6 +89,14 @@
//add all binaries to VT query
for(Binary* item in self.items)
{
+ //skip items with blank hashes
+ // ->TODO not sure why this would happen
+ if(nil == item.hashes[KEY_HASH_SHA1])
+ {
+ //skip
+ continue;
+ }
+
//alloc item data
itemData = [NSMutableDictionary dictionary];
@@ -115,6 +128,7 @@
}//sync
+
//make query to VT
results = [self postRequest:queryURL parameters:parameters];
if(nil != results)
@@ -122,6 +136,7 @@
//process results
[self processResults:queriedItems results:results];
}
+
return;
}
@@ -272,9 +287,10 @@
return;
}
*/
+
//get VT info for a single item
// ->will then callback into AppDelegate to reload item in UI
--(void)getInfoForItem:(Binary*)fileObj scanID:(NSString*)scanID rowIndex:(NSUInteger)rowIndex
+-(void)getInfoForItem:(Binary*)item scanID:(NSString*)scanID
{
//VT query URL
NSURL* queryURL = nil;
@@ -296,8 +312,9 @@
(1 == [results[VT_RESULTS_RESPONSE] integerValue]) )
{
//save result
- fileObj.vtInfo = results;
+ item.vtInfo = results;
+ //TODO: do something if it's flagged!
//if its flagged save in File's plugin
if(0 != [results[VT_RESULTS_POSITIVES] unsignedIntegerValue])
{
@@ -310,10 +327,12 @@
[fileObj.plugin.flaggedItems addObject:fileObj];
}
*/
+
}
- //callback up into UI to reload item
- [((AppDelegate*)[[NSApplication sharedApplication] delegate]) itemProcessed:fileObj rowIndex:rowIndex];
+ //update UI
+ // ->will make item in task or dylib table have updated VT results
+ [self updateUI:item];
//exit loop
break;
@@ -326,6 +345,7 @@
return;
}
+
//make the (POST)query to VT
-(NSDictionary*)postRequest:(NSURL*)url parameters:(id)params
{
@@ -347,7 +367,7 @@
//response (HTTP) from VT
NSURLResponse* httpResponse = nil;
-
+
//alloc/init request
request = [[NSMutableURLRequest alloc] initWithURL:url];
@@ -399,8 +419,8 @@
//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);
@@ -443,7 +463,7 @@ bail:
}
//submit a file to VT
--(NSDictionary*)submit:(File*)fileObj
+-(NSDictionary*)submit:(Binary*)item
{
//results
NSDictionary* results = nil;
@@ -468,15 +488,23 @@ bail:
//response (HTTP) from VT
NSURLResponse* httpResponse = nil;
+
+ //remove item's vt info
+ // ->as its about to be outdates
+ item.vtInfo = nil;
+
+ //reload UI
+ // ->will change item's VT button back to ...
+ [self updateUI:item];
//init submit URL
- submitURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?apikey=%@&resource=%@", VT_SUBMIT_URL, VT_API_KEY, fileObj.hashes[KEY_HASH_MD5]]];
+ submitURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?apikey=%@&resource=%@", VT_SUBMIT_URL, VT_API_KEY, item.hashes[KEY_HASH_MD5]]];
//init request
request = [[NSMutableURLRequest alloc] initWithURL:submitURL];
//set boundary string
- NSString *boundary = @"qqqq___knockknock___qqqq";
+ NSString *boundary = @"qqqq___taskexplorer___qqqq";
//set HTTP method (POST)
[request setHTTPMethod:@"POST"];
@@ -491,13 +519,13 @@ bail:
body = [NSMutableData data];
//load file into memory
- fileContents = [NSData dataWithContentsOfFile:fileObj.pathForFinder];
+ fileContents = [NSData dataWithContentsOfFile:item.pathForFinder];
//sanity check
if(nil == fileContents)
{
//err msg
- NSLog(@"OBJECTIVE-SEE ERROR: failed to load %@ into memory for submission", fileObj.path);
+ NSLog(@"OBJECTIVE-SEE ERROR: failed to load %@ into memory for submission", item.path);
//bail
goto bail;
@@ -507,7 +535,7 @@ bail:
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
//append 'Content-Disposition' file name, etc
- [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", fileObj.name] dataUsingEncoding:NSUTF8StringEncoding]];
+ [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", item.name] dataUsingEncoding:NSUTF8StringEncoding]];
//append 'Content-Type'
[body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
@@ -576,8 +604,9 @@ bail:
return results;
}
+
//submit a rescan request
--(NSDictionary*)reScan:(File*)fileObj
+-(NSDictionary*)reScan:(Binary*)item
{
//result data
NSDictionary* result = nil;
@@ -585,19 +614,28 @@ bail:
//scan url
NSURL* reScanURL = nil;
+ //remove item's vt info
+ // ->as its about to be outdates
+ item.vtInfo = nil;
+
+ //reload UI
+ // ->will change item's VT button back to ...
+ [self updateUI:item];
+
//init scan url
- reScanURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?apikey=%@&resource=%@", VT_RESCAN_URL, VT_API_KEY, fileObj.hashes[KEY_HASH_MD5]]];
+ reScanURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?apikey=%@&resource=%@", VT_RESCAN_URL, VT_API_KEY, item.hashes[KEY_HASH_MD5]]];
//make request to VT
result = [self postRequest:reScanURL parameters:nil];
if(nil == result)
{
//err msg
- NSLog(@"OBJECTIVE-SEE ERROR: failed to re-scan %@", fileObj.name);
+ NSLog(@"OBJECTIVE-SEE ERROR: failed to re-scan %@", item.name);
//bail
goto bail;
}
+
//bail
bail:
@@ -606,7 +644,7 @@ bail:
}
//process results
-// ->save VT info into
+// ->save VT info into Binary object & reload relevant pane
-(void)processResults:(NSMutableDictionary*)queriedItems results:(NSDictionary*)results
{
//queried binary obj
@@ -616,10 +654,6 @@ bail:
// ->will be set if any of the queried binaries are a task executable
BOOL reloadTopPane = NO;
- //flag for bottom pane reload
- // ->will be set if any of the queried binaries are a dylib
- BOOL reloadBottomPane = NO;
-
//process all results
// ->save VT result dictionary into File obj
for(NSDictionary* result in results[VT_RESULTS])
@@ -646,10 +680,11 @@ bail:
reloadTopPane = YES;
}
//for dylibs
- // ->set flag to reload bottom
+ // ->no dups, update each via row reload
else
{
- reloadBottomPane = YES;
+ //update
+ [self updateUI:queriedItem];
}
//TODO: do something with detections!?
@@ -657,20 +692,38 @@ bail:
}
//reload top pane
+ // ->do full since there might be dups (e.g. Chrome Helper)
if(YES == reloadTopPane)
{
//reload
- [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadTaskTable];
- }
-
- //reload bottom pane
- if(YES == reloadBottomPane)
- {
- //reload
- [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:nil itemView:DYLIBS_VIEW];
+ [self updateUI:nil];
}
return;
}
+//call back up to update item in UI
+// ->will either reload task table (top), or just row in item (bottom) table
+-(void)updateUI:(Binary*)item
+{
+ //handle case where item is a task (top)
+ // ->fully reload task table (since there can be dups)
+ if( (nil == item) ||
+ (YES == item.isTaskBinary) )
+ {
+ //reload
+ [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadTaskTable];
+ }
+ //handle case where item is a dylib (bottom)
+ // ->just reload row
+ else
+ {
+ //reload row
+ [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadRow:nil item:item pane:PANE_BOTTOM];
+ }
+
+ return;
+}
+
+
@end
diff --git a/en.lproj/MainMenu.xib b/en.lproj/MainMenu.xib
index 46f5484..a46d4eb 100755
--- a/en.lproj/MainMenu.xib
+++ b/en.lproj/MainMenu.xib
@@ -1,7 +1,6 @@
-
@@ -99,6 +98,9 @@
+
+
+