largely completed virus total logic

began implementing sorting logic (just for top pane)
This commit is contained in:
Patrick Wardle
2015-06-21 21:37:52 -10:00
parent 014f70da94
commit ff77a49ed5
20 changed files with 1020 additions and 287 deletions
+11 -7
View File
@@ -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
+244 -9
View File
@@ -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
+5 -1
View File
@@ -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);
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);
+159
View File
@@ -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;
}
+4
View File
@@ -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;
+1 -1
View File
@@ -23,7 +23,7 @@
@synthesize isTaskBinary;
@synthesize vtInfo;
@synthesize lastItem;
//init method
-(id)initWithParams:(NSDictionary*)params
-1
View File
@@ -90,7 +90,6 @@
//add item for VT processing
[vtObject addItem:binary];
//unlock
[self.queueCondition unlock];
+4 -9
View File
@@ -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)
@@ -10,14 +10,14 @@
<string>TaskExplorer</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D</key>
<key>61F07AFB33748EF0C810BEEF6126283DAC63A899</key>
<string>https://bitbucket.org/objective-see/knockknock.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>TaskExplorer.xcodeproj</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D</key>
<key>61F07AFB33748EF0C810BEEF6126283DAC63A899</key>
<string>../..</string>
</dict>
<key>IDESourceControlProjectURL</key>
@@ -25,14 +25,14 @@
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D</string>
<string>61F07AFB33748EF0C810BEEF6126283DAC63A899</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D</string>
<string>61F07AFB33748EF0C810BEEF6126283DAC63A899</string>
<key>IDESourceControlWCCName</key>
<string>TaskExplorer</string>
</dict>
@@ -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">
</BreakpointContent>
@@ -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">
</BreakpointContent>
@@ -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">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
timestampString = "456474649.232255"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "1122"
endingLineNumber = "1122"
startingLineNumber = "1174"
endingLineNumber = "1174"
landmarkName = "-outlineView:rowViewForItem:"
landmarkType = "5">
</BreakpointContent>
@@ -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">
</BreakpointContent>
@@ -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">
</BreakpointContent>
@@ -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">
</BreakpointContent>
@@ -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">
</BreakpointContent>
@@ -167,5 +151,245 @@
moduleName = "">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "VirusTotal.m"
timestampString = "456607881.829588"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "35"
endingLineNumber = "35"
landmarkName = "-addItem:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "VirusTotal.m"
timestampString = "456638843.665835"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "55"
endingLineNumber = "55"
landmarkName = "-addItem:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "VirusTotal.m"
timestampString = "456638843.665835"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "654"
endingLineNumber = "654"
landmarkName = "-processResults:results:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "545"
endingLineNumber = "545"
landmarkName = "-reloadBottomPane:itemView:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "563"
endingLineNumber = "563"
landmarkName = "-reloadBottomPane:itemView:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Task.m"
timestampString = "456638843.665835"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "344"
endingLineNumber = "344"
landmarkName = "-enumerateDylibs:allDylibs:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Task.m"
timestampString = "456638843.665835"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "320"
endingLineNumber = "320"
landmarkName = "-enumerateDylibs:allDylibs:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "1203"
endingLineNumber = "1203"
landmarkName = "-handleRowSelection"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "731"
endingLineNumber = "731"
landmarkName = "-refresh"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "86"
endingLineNumber = "86"
landmarkName = "-numberOfRowsInTableView:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "1003"
endingLineNumber = "1003"
landmarkName = "-showInfo:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "783"
endingLineNumber = "783"
landmarkName = "-refresh"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Task.m"
timestampString = "456638843.665835"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "433"
endingLineNumber = "433"
landmarkName = "-enumerateDylibs:allDylibs:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "1589"
endingLineNumber = "1589"
landmarkName = "-filterTasks:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TaskTableController.m"
timestampString = "456648442.982284"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "130"
endingLineNumber = "130"
landmarkName = "-tableViewSelectionDidChange:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
+9 -3
View File
@@ -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;
+165 -111
View File
@@ -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;
}
+1 -1
View File
@@ -24,7 +24,7 @@
@property(assign)TaskTableController *delegate;
//File object
@property(nonatomic, retain)Binary* fileObj;
@property(nonatomic, retain)Binary* binary;
//button's row index
+11 -11
View File
@@ -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];
+3 -3
View File
@@ -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;
+25 -44
View File
@@ -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;
}
+8 -4
View File
@@ -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
+93 -40
View File
@@ -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
+8 -1
View File
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<development version="5000" identifier="xcode"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="7706"/>
</dependencies>
@@ -99,6 +98,9 @@
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</searchFieldCell>
<connections>
<outlet property="delegate" destination="494" id="4ig-0K-Oup"/>
</connections>
</searchField>
<button fixedFrame="YES" tag="1001" translatesAutoresizingMaskIntoConstraints="NO" id="gSG-Nq-plb">
<rect key="frame" x="9" y="4" width="35" height="32"/>
@@ -180,6 +182,9 @@
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</searchFieldCell>
<connections>
<outlet property="delegate" destination="494" id="B1g-Qz-f4r"/>
</connections>
</searchField>
</toolbarItem>
<toolbarItem implicitItemIdentifier="A5784C30-D7FC-4958-875B-487768A4E610" label="" paletteLabel="" id="O1y-1z-g0u">
@@ -223,6 +228,8 @@
<outlet property="bottomPane" destination="E4M-PF-VD0" id="Au5-EH-OKZ"/>
<outlet property="bottomPaneBtn" destination="gtq-gn-VPL" id="Uxg-Ab-QzA"/>
<outlet property="bottomPaneSpinner" destination="LMT-Bu-FAk" id="a1H-Ag-GT8"/>
<outlet property="filterItemsBox" destination="bNA-gy-9Ta" id="hAw-Ja-am4"/>
<outlet property="filterTasksBox" destination="4Kr-b9-X6j" id="CB1-Rb-dew"/>
<outlet property="logoButton" destination="HoI-FQ-vTI" id="bzc-wu-4Hv"/>
<outlet property="noItemsLabel" destination="kIC-ZZ-ldy" id="nOm-8E-tZA"/>
<outlet property="progressIndicator" destination="839" id="870"/>
+4
View File
@@ -282,6 +282,10 @@ bail:
mach_vm_deallocate(mach_task_self(), (vm_offset_t)allImageInfo, aifBytesRead);
}
//remove dups
//TODO: this isn't mutable - which is ok, but maybe change reply method def?
[dylibPaths setArray:[[NSSet setWithArray:dylibPaths] allObjects]];
//invoke reply block
reply(dylibPaths);