diff --git a/AppDelegate.m b/AppDelegate.m
index 276a9a4..3194ba5 100755
--- a/AppDelegate.m
+++ b/AppDelegate.m
@@ -89,7 +89,7 @@
//filterObj = [[Filter alloc] init];
//init virus total object
- //virusTotalObj = [[VirusTotal alloc] init];
+ virusTotalObj = [[VirusTotal alloc] init];
//init array for virus total threads
//vtThreads = [NSMutableArray array];
@@ -329,11 +329,7 @@
{
//alloc/init
taskTableController = [[TaskTableController alloc] initWithNibName:@"FlatView" bundle:nil];
- /*if(self.taskTableController != nil)
- {
- //update iVar
- self.currentViewController = self.taskTableController;
- }*/
+
break;
}
case TREE_VIEW:
@@ -341,13 +337,6 @@
//alloc/init
taskTableController = [[TaskTableController alloc] initWithNibName:@"TreeView" bundle:nil];
-
-
- /*if(self.taskTableController != nil)
- {
- //update iVar
- self.currentViewController = self.taskTableController;
- }*/
break;
}
}
@@ -361,16 +350,19 @@
return;
}
-//TODO: add checks to make sure or handle switch to tree view!!!!
//reload (to re-draw) a specific row in table
-(void)reloadRow:(Task*)task item:(ItemBase*)item pane:(NSUInteger)pane
{
//table view
- NSTableView* tableView = nil;
+ __block NSTableView* tableView = nil;
//row
- NSUInteger row = 0;
+ __block NSUInteger row = 0;
+ //run everything on main thread
+ // ->ensures table view isn't changed out from under us....
+ dispatch_async(dispatch_get_main_queue(), ^{
+
//top table (pane)
if(PANE_TOP == pane)
{
@@ -390,20 +382,15 @@
goto bail;
}
- //reload just the row
- // ->on main thread
- dispatch_async(dispatch_get_main_queue(), ^{
-
- //begin updates
- [tableView beginUpdates];
-
- //reload row
- [tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:(row)] columnIndexes:[NSIndexSet indexSetWithIndex:0]];
-
- //end updates
- [tableView endUpdates];
-
- });
+ //begin updates
+ [tableView beginUpdates];
+
+ //reload row
+ [tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:(row)] columnIndexes:[NSIndexSet indexSetWithIndex:0]];
+
+ //end updates
+ [tableView endUpdates];
+
}
//reload item
// ->tree view
@@ -411,10 +398,10 @@
{
//begin updates
[tableView beginUpdates];
-
+
//reload
[(NSOutlineView*)tableView reloadItem:task];
-
+
//end updates
[tableView endUpdates];
}
@@ -427,6 +414,9 @@
//bail
bail:
+ ;
+
+ }); //dispatch on main thread
return;
}
@@ -438,20 +428,14 @@ bail:
//tag
NSUInteger segmentTag = 0;
- /*
- if(YES == [task.binary.name isEqualToString:@"launchd"])
- {
- NSLog(@"asdf");
- }*/
-
//get segment tag
segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]];
//ignore reloads for unselected tasks
- if(self.currentTask != task)
+ // ->note: when no task is passed in, always reload though
+ if( (nil != task) &&
+ (self.currentTask != task))
{
- //NSLog(@"selected task: %@ not match %@", self.currentTask.binary.name, task.binary.name);
-
//ignore
goto bail;
}
@@ -1321,6 +1305,9 @@ bail:
//reload top pane
[self reloadTaskTable];
+ //select top row
+ [self.taskTableController.itemView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
+
return;
}
diff --git a/ItemView.m b/ItemView.m
index a97634f..669d621 100644
--- a/ItemView.m
+++ b/ItemView.m
@@ -489,6 +489,9 @@ NSTableCellView* createTaskView(NSTableView* tableView, id owner, Task* task)
//task's name frame
CGRect nameFrame = {0};
+ //task's path frame
+ CGRect pathFrame = {0};
+
//sanity check
if(nil == task.binary)
{
@@ -552,6 +555,22 @@ NSTableCellView* createTaskView(NSTableView* tableView, id owner, Task* task)
// ->immediately follows name
[((NSTextField*)[taskCell viewWithTag:TABLE_ROW_PID_LABEL]) setStringValue:[NSString stringWithFormat:@"(%@)", task.pid]];
+ /*
+ //outline view has indentations
+ // ->adjust path width to account for this
+ if(YES == [tableView isKindOfClass:[NSOutlineView class]])
+ {
+ //get path frame
+ pathFrame = ((NSTextField*)[tableView viewWithTag:TABLE_ROW_SUB_TEXT_TAG]).frame;
+
+ //subtract indendtation for level
+ pathFrame.size.width -= [(NSOutlineView*) tableView levelForItem:task];
+
+ //set path frame
+ ((NSTextField*)[tableView viewWithTag:TABLE_ROW_SUB_TEXT_TAG]).frame = pathFrame;
+ }
+ */
+
//set path
[[taskCell viewWithTag:TABLE_ROW_SUB_TEXT_TAG] setStringValue:task.binary.path];
diff --git a/Items/Binary.m b/Items/Binary.m
index 7f0d579..8dcd4fa 100644
--- a/Items/Binary.m
+++ b/Items/Binary.m
@@ -50,17 +50,7 @@
//grab attributes
//self.attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:self.path error:nil];
-
- //do this in bg!
- //set signing info
- //self.signingInfo = extractSigningInfo(self.path);
-
- //computes hashes
- // ->set 'md5' and 'sha1' iVars
- //self.hashes = hashFile(self.path);
-
-
//call into filter object to check if file is known
// ->apple-signed or whitelisted
//self.isTrusted = [((AppDelegate*)[[NSApplication sharedApplication] delegate]).filterObj isTrustedFile:self];
@@ -165,7 +155,6 @@ bail:
return taskIcon;
}
-//TODO: green signing for apple!!!
//get signing info (which takes a while to generate)
// ->this method should be called in the background
-(void)generatedSigningInfo
diff --git a/Queue.h b/Queue.h
index 4849758..53f8ac4 100644
--- a/Queue.h
+++ b/Queue.h
@@ -25,6 +25,8 @@
}
+/* PROPERTIES */
+
//event queue
@property(retain, atomic)NSMutableArray* eventQueue;
diff --git a/Queue.m b/Queue.m
index 77688e3..dd0c175 100644
--- a/Queue.m
+++ b/Queue.m
@@ -9,6 +9,7 @@
#import "Queue.h"
#import "Consts.h"
#import "Binary.h"
+#import "VirusTotal.h"
#import "AppDelegate.h"
@implementation Queue
@@ -50,6 +51,12 @@
// ->don't want UI thread, etc to suffer
[NSThread sleepForTimeInterval:5.0f];
+ //VT object
+ VirusTotal* vtObject = nil;
+
+ //grab VT object
+ vtObject = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).virusTotalObj;
+
//for ever
while(YES)
{
@@ -69,15 +76,21 @@
//get item off queue
binary = [eventQueue dequeue];
- //process binary
- // ->hash, etc
- if(YES == [binary isKindOfClass:[Binary class]])
+ //sanity check
+ if(YES != [binary isKindOfClass:[Binary class]])
{
- //process
- //->for now, just hash, etc
- [binary generateDetailedInfo];
+ //ignore
+ continue;
}
+ //process
+ //->for now, just hash, etc
+ [binary generateDetailedInfo];
+
+ //add item for VT processing
+ [vtObject addItem:binary];
+
+
//unlock
[self.queueCondition unlock];
diff --git a/Task.m b/Task.m
index cad6381..8cfd0b6 100644
--- a/Task.m
+++ b/Task.m
@@ -44,6 +44,8 @@
@synthesize arguments;
@synthesize connections;
+//TODO: make sure we only check signature of binary once!!!
+
//init w/ a pid + path
// note: time consuming init's are done in '' method
-(id)initWithPID:(NSNumber*)taskPID andPath:(NSString*)taskPath
@@ -112,6 +114,10 @@
// ->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;
@@ -376,7 +382,7 @@ bail:
}
//add to queue
- // ->this will processing
+ // ->this will trigger background processing
[((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.binaryQueue enqueue:dylib];
//add to list of new dylibs
diff --git a/TaskEnumerator.h b/TaskEnumerator.h
index b956adb..8dbd38b 100644
--- a/TaskEnumerator.h
+++ b/TaskEnumerator.h
@@ -38,12 +38,11 @@
//TODO: weak OK?
@property (nonatomic, retain) NSXPCConnection* xpcConnection;
-//queue object
-// ->contains watch items that should be processed
+//queue
+// ->contains binaries that should be processed
@property (nonatomic, retain) Queue* binaryQueue;
-
/* METHODS */
//enumerate all tasks
diff --git a/TaskEnumerator.m b/TaskEnumerator.m
index cdd0446..9dafb79 100644
--- a/TaskEnumerator.m
+++ b/TaskEnumerator.m
@@ -87,6 +87,7 @@
//init binary processing queue
binaryQueue = [[Queue alloc] init];
+
}
return self;
diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
index ca56366..2ddd5ee 100644
--- a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -36,11 +36,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
- timestampString = "456474906.073599"
+ timestampString = "456541711.785304"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "671"
- endingLineNumber = "671"
+ startingLineNumber = "661"
+ endingLineNumber = "661"
landmarkName = "-reloadTaskTable"
landmarkType = "5">
@@ -115,15 +115,57 @@
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
- filePath = "AppDelegate.m"
- timestampString = "456474979.625707"
+ filePath = "ItemView.m"
+ timestampString = "456521289.11776"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "416"
- endingLineNumber = "416"
- landmarkName = "-reloadRow:item:pane:"
+ startingLineNumber = "484"
+ endingLineNumber = "484"
+ landmarkName = "createTaskView()"
+ landmarkType = "7">
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UI/FlatView.xib b/UI/FlatView.xib
index d9ecca1..aa4a35b 100755
--- a/UI/FlatView.xib
+++ b/UI/FlatView.xib
@@ -18,9 +18,9 @@
-
-
-
+
+
+
@@ -31,7 +31,7 @@
-
+
@@ -45,7 +45,7 @@
-
+
@@ -185,7 +185,7 @@
-
+
@@ -302,7 +302,7 @@
-
+
@@ -385,7 +385,7 @@
-
+
@@ -471,8 +471,10 @@
-
-
+
+
+
+
diff --git a/UI/TreeView.xib b/UI/TreeView.xib
index 529f55b..66d91e0 100755
--- a/UI/TreeView.xib
+++ b/UI/TreeView.xib
@@ -15,12 +15,12 @@
-
+
-
-
-
+
+
+
@@ -31,7 +31,7 @@
-
+
@@ -44,117 +44,123 @@
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
@@ -199,7 +206,13 @@
-
+
+
+
+
+
+
+
diff --git a/Utilities.m b/Utilities.m
index 18fcde4..5d79c4b 100644
--- a/Utilities.m
+++ b/Utilities.m
@@ -112,9 +112,13 @@ NSDictionary* extractSigningInfo(NSString* path)
//init signing status
signingStatus = [NSMutableDictionary dictionary];
+ //signingStatus[KEY_SIGNATURE_STATUS] = @0;
+ //return signingStatus;
+
//create static code
status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &staticCode);
+ //TODO: called same before!?
//save signature status
signingStatus[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
@@ -131,6 +135,7 @@ NSDictionary* extractSigningInfo(NSString* path)
//check signature
status = SecStaticCodeCheckValidityWithErrors(staticCode, kSecCSDoNotValidateResources, NULL, NULL);
+ //TODO: called same above?
//(re)save signature status
signingStatus[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
diff --git a/VTInfoWindowController.m b/VTInfoWindowController.m
index d95d826..606cdf2 100644
--- a/VTInfoWindowController.m
+++ b/VTInfoWindowController.m
@@ -262,7 +262,8 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//make request to VT
- result = [vtObj reScan:self.fileObj];
+ //TODO: re-enable
+ //result = [vtObj reScan:self.fileObj];
//got result
// ->update UI and launch browswer to show report
@@ -296,11 +297,16 @@
// ->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];
});
+
+ */
}
//ask app delegate to update item in table
@@ -368,7 +374,8 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//submit file to VT
- result = [vtObj submit:self.fileObj];
+ //TODO: re-enable
+ //result = [vtObj submit:self.fileObj];
// ->need this for (re)queries
scanID = result[VT_RESULTS_SCANID];
@@ -380,10 +387,13 @@
// ->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];
});
+ */
}
//got response
diff --git a/VirusTotal.h b/VirusTotal.h
index a0f4ad2..8251a28 100644
--- a/VirusTotal.h
+++ b/VirusTotal.h
@@ -6,6 +6,7 @@
// Copyright (c) 2015 Objective-See. All rights reserved.
//
+#import "Binary.h"
#import
@interface VirusTotal : NSObject
@@ -13,8 +14,18 @@
}
+/* PROPERTIES */
+
+//array for (up to 25) items
+@property (nonatomic, retain)NSMutableArray* items;
+
+
/* METHODS */
+//add item
+// ->will query VT when 25 items are hit
+-(void)addItem:(Binary*)binary;
+
//thread function
// ->runs in the background to get virus total info about a plugin's items
//-(void)getInfo:(PluginBase*)plugin;
@@ -23,17 +34,17 @@
-(NSDictionary*)postRequest:(NSURL*)url parameters:(id)params;
//submit a file to VT
--(NSDictionary*)submit:(File*)fileObj;
+//-(NSDictionary*)submit:(File*)fileObj;
//submit a rescan request
--(NSDictionary*)reScan:(File*)fileObj;
+//-(NSDictionary*)reScan:(File*)fileObj;
//process results
// ->updates items (found, detection ratio, etc)
--(void)processResults:(NSArray*)items results:(NSDictionary*)results;
+-(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;
+//-(void)getInfoForItem:(File*)fileObj scanID:(NSString*)scanID rowIndex:(NSUInteger)rowIndex;
@end
diff --git a/VirusTotal.m b/VirusTotal.m
index e9a5349..207ec8c 100644
--- a/VirusTotal.m
+++ b/VirusTotal.m
@@ -14,6 +14,118 @@
@implementation VirusTotal
+@synthesize items;
+
+//init
+-(id)init
+{
+ //init super
+ self = [super init];
+ if(nil != self)
+ {
+ //alloc array for items
+ items = [NSMutableArray array];
+ }
+
+ return self;
+}
+
+//add item
+// ->will query VT when 25 items are hit
+-(void)addItem:(Binary*)binary
+{
+ //sync
+ @synchronized(self.items)
+ {
+ //add item
+ [self.items addObject:binary];
+ }
+
+ //query VT once 25 items have been gathered
+ if(VT_MAX_QUERY_COUNT == self.items.count)
+ {
+ //process
+ [self queryVT];
+ }
+}
+
+//make query to VT
+-(void)queryVT
+{
+ //VT query URL
+ NSURL* queryURL = nil;
+
+ //item data
+ NSMutableDictionary* itemData = nil;
+
+ //array of queried items
+ // ->needed so can save VT results back into binaries
+ NSMutableDictionary* queriedItems = nil;
+
+ //parameters
+ NSMutableArray* parameters = nil;
+
+ //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];
+
+ //alloc dictionary for queried items
+ queriedItems = [NSMutableDictionary dictionary];
+
+ //sync
+ @synchronized(self.items)
+ {
+
+ //add all binaries to VT query
+ for(Binary* item in self.items)
+ {
+ //alloc item data
+ itemData = [NSMutableDictionary dictionary];
+
+ //auto start location
+ itemData[@"autostart_location"] = @"n/a";
+
+ //set item name
+ itemData[@"autostart_entry"] = item.name;
+
+ //set item path
+ itemData[@"image_path"] = item.path;
+
+ //set hash
+ itemData[@"hash"] = item.hashes[KEY_HASH_SHA1];
+
+ //set creation times
+ itemData[@"creation_datetime"] = [item.attributes.fileCreationDate description];
+
+ //add item to parameters
+ [parameters addObject:itemData];
+
+ //save as queried item
+ queriedItems[item.hashes[KEY_HASH_SHA1]] = item;
+ }
+
+ //remove all items
+ // ->since they've been added to VT request
+ [self.items removeAllObjects];
+
+ }//sync
+
+ //make query to VT
+ results = [self postRequest:queryURL parameters:parameters];
+ if(nil != results)
+ {
+ //process results
+ [self processResults:queriedItems results:results];
+ }
+
+ return;
+}
+
/*
//thread function
// ->runs in the background to get virus total info about a plugin's items
@@ -494,45 +606,68 @@ bail:
}
//process results
-// ->save VT info into each File obj and all flagged files
--(void)processResults:(NSArray*)items results:(NSDictionary*)results
+// ->save VT info into
+-(void)processResults:(NSMutableDictionary*)queriedItems results:(NSDictionary*)results
{
+ //queried binary obj
+ Binary* queriedItem = nil;
+
+ //flag for top pane reload
+ // ->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])
{
- //sync
- // ->since array will be reset if user clicks 'stop' scan
- @synchronized(items)
+ //extract ('match') queried item
+ // ->VT gives us back a hash
+ queriedItem = queriedItems[result[@"hash"]];
+
+ //sanity check
+ if(nil == queriedItem)
{
-
- //find all items that match
- // ->might be dupes, which is fine
- for(Binary* item in items)
- {
- //for matches, save vt info
- if(YES == [result[@"hash"] isEqualToString:item.hashes[KEY_HASH_SHA1]])
- {
- //save
- item.vtInfo = result;
-
- //if its flagged save in File's plugin
- if(0 != [result[VT_RESULTS_POSITIVES] unsignedIntegerValue])
- {
- /*
- //sync
- // ->since array will be reset if user clicks 'stop' scan
- @synchronized(item.plugin.flaggedItems)
- {
- //save
- [item.plugin.flaggedItems addObject:item];
- }
- */
- }
- }
+ //skip
+ continue;
}
-
- }//sync
+
+ //save VT results into item
+ queriedItem.vtInfo = result;
+
+ //for task executables
+ // ->set flag to reload top
+ if(YES == queriedItem.isTaskBinary)
+ {
+ //set
+ reloadTopPane = YES;
+ }
+ //for dylibs
+ // ->set flag to reload bottom
+ else
+ {
+ reloadBottomPane = YES;
+ }
+
+ //TODO: do something with detections!?
+ //if(0 != [result[VT_RESULTS_POSITIVES] unsignedIntegerValue])
+ }
+
+ //reload top pane
+ 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];
}
return;