mirror of
https://github.com/objective-see/TaskExplorer.git
synced 2026-03-22 07:02:39 +00:00
v.1.2.0 beta
-autocomplete for filter boxes
-keyboard shortcuts
-save includes dylibs/files/connections
-sync on filtered tasks (was crashing)
-code cleanup
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// PrefsWindowController.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/6/15.
|
||||
// Copyright (c) 2015 Objective-See, LLC. All rights reserved.
|
||||
|
||||
+23
-2
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// AppDelegate.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
@@ -19,6 +19,7 @@
|
||||
#import "ResultsWindowController.h"
|
||||
#import "RequestRootWindowController.h"
|
||||
#import "SearchWindowController.h"
|
||||
#import "CustomTextField.h"
|
||||
|
||||
|
||||
#import "Task.h"
|
||||
@@ -163,6 +164,17 @@
|
||||
//flagged items
|
||||
@property(nonatomic, retain) NSMutableArray* flaggedItems;
|
||||
|
||||
//array of autocomplete keywords
|
||||
//@property NSMutableArray *builtInKeywords;
|
||||
|
||||
@property BOOL completePosting;
|
||||
@property BOOL commandHandling;
|
||||
|
||||
//custom search field for tasks
|
||||
@property CustomTextField* customTasksFilter;
|
||||
|
||||
//custom search field for items
|
||||
@property CustomTextField* customItemsFilter;
|
||||
|
||||
/* METHODS */
|
||||
|
||||
@@ -173,7 +185,8 @@
|
||||
//init (setup) XPC connection
|
||||
-(BOOL)initXPC;
|
||||
|
||||
- (IBAction)switchView:(id)sender;
|
||||
//switch between flat/tree view
|
||||
-(IBAction)switchView:(id)sender;
|
||||
|
||||
//init tracking areas for buttons
|
||||
// ->provide mouse over effects
|
||||
@@ -232,4 +245,12 @@
|
||||
// ->also set text flagged items button label to red
|
||||
-(void)saveFlaggedBinary:(Binary*)binary;
|
||||
|
||||
//callback for custom search fields
|
||||
// ->handle auto-complete filterings
|
||||
-(void)filterAutoComplete:(NSTextView*)textField;
|
||||
|
||||
//code to complete filtering/search
|
||||
// ->reload table/scroll to top etc
|
||||
-(void)finalizeFiltration:(NSUInteger)pane;
|
||||
|
||||
@end
|
||||
|
||||
+472
-77
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// AppDelegate.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
|
||||
#import "Consts.h"
|
||||
@@ -21,13 +21,18 @@
|
||||
|
||||
|
||||
//TODO: autolayout vertically
|
||||
//TODO: filter VT results
|
||||
//TODO: # autocomplete
|
||||
//TODO: keyboard shortcuts
|
||||
//TODO: filter VT results - HUH?
|
||||
//TODO: # autocomplete - DONE
|
||||
|
||||
//TODO: keyboard shortcuts - DONE!
|
||||
// see: https://mail.google.com/mail/u/0/#inbox/14eeb163d4dd2852
|
||||
//TODO: show 'from where' via quarantine attrz
|
||||
//TODO: show user (after pid): -> (pid, user)?
|
||||
//TODO: check if VT can be reached! if not, error? or don't show '0 VT results detected' etc...
|
||||
|
||||
//TODO: syncronize filtered tasks - DONE!
|
||||
|
||||
//TODO: add files/dylibs/connections to save - DONE!
|
||||
//TODO: sync while saving
|
||||
|
||||
//TODO: JavaW (iWorm) dylibs...
|
||||
|
||||
@@ -36,34 +41,35 @@
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
|
||||
@synthesize topPane;
|
||||
@synthesize filterObj;
|
||||
@synthesize startTime;
|
||||
@synthesize vtThreads;
|
||||
@synthesize saveButton;
|
||||
@synthesize isConnected;
|
||||
@synthesize virusTotalObj;
|
||||
@synthesize taskTableController;
|
||||
@synthesize aboutWindowController;
|
||||
@synthesize prefsWindowController;
|
||||
@synthesize resultsWindowController;
|
||||
@synthesize bottomPane;
|
||||
@synthesize bottomViewController;
|
||||
@synthesize saveButton;
|
||||
@synthesize currentTask;
|
||||
@synthesize requestRootWindowController;
|
||||
@synthesize taskViewFormat;
|
||||
@synthesize flagItemsWindowController;
|
||||
@synthesize searchWindowController;
|
||||
|
||||
@synthesize scannerThread;
|
||||
@synthesize progressIndicator;
|
||||
|
||||
@synthesize topPane;
|
||||
@synthesize taskEnumerator;
|
||||
@synthesize viewSelector;
|
||||
@synthesize searchButton;
|
||||
@synthesize xpcConnection;
|
||||
@synthesize isConnected;
|
||||
@synthesize flaggedItems;
|
||||
|
||||
@synthesize searchButton;
|
||||
@synthesize viewSelector;
|
||||
@synthesize scannerThread;
|
||||
@synthesize virusTotalObj;
|
||||
@synthesize xpcConnection;
|
||||
@synthesize taskEnumerator;
|
||||
@synthesize taskViewFormat;
|
||||
@synthesize commandHandling;
|
||||
@synthesize completePosting;
|
||||
@synthesize customItemsFilter;
|
||||
@synthesize customTasksFilter;
|
||||
@synthesize progressIndicator;
|
||||
@synthesize taskTableController;
|
||||
@synthesize bottomViewController;
|
||||
@synthesize aboutWindowController;
|
||||
@synthesize searchWindowController;
|
||||
@synthesize resultsWindowController;
|
||||
@synthesize flagItemsWindowController;
|
||||
@synthesize requestRootWindowController;
|
||||
|
||||
//center window
|
||||
// ->also make front
|
||||
@@ -87,7 +93,9 @@
|
||||
{
|
||||
//first thing...
|
||||
// ->install exception handlers!
|
||||
installExceptionHandlers();
|
||||
|
||||
//TODO: CHANGE B4 RELEASE!!
|
||||
//installExceptionHandlers();
|
||||
|
||||
//init virus total object
|
||||
virusTotalObj = [[VirusTotal alloc] init];
|
||||
@@ -98,6 +106,18 @@
|
||||
//alloc flagged items
|
||||
flaggedItems = [NSMutableArray array];
|
||||
|
||||
//alloc/init custom search field for tasks
|
||||
customTasksFilter = [[CustomTextField alloc] init];
|
||||
|
||||
//alloc/init custom search field for items
|
||||
customItemsFilter = [[CustomTextField alloc] init];
|
||||
|
||||
//set field editor for tasks
|
||||
[self.customTasksFilter setFieldEditor:YES];
|
||||
|
||||
//set field editor for items
|
||||
[self.customItemsFilter setFieldEditor:YES];
|
||||
|
||||
//set start time
|
||||
self.startTime = [NSDate timeIntervalSinceReferenceDate];
|
||||
|
||||
@@ -117,6 +137,9 @@
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//register for hotkey presses
|
||||
[self registerKeypressHandler];
|
||||
|
||||
//check if authenticated
|
||||
// ->display authentication request if needed
|
||||
if(YES != [self isAuthenticated])
|
||||
@@ -165,9 +188,146 @@
|
||||
// ->ensures our 'windowWillClose' method, which has logic to fully exit app
|
||||
self.window.delegate = self;
|
||||
|
||||
/*
|
||||
//init list of keyword strings for our type completion dropdown list in NSSearchField
|
||||
self.builtInKeywords = [NSMutableArray array];
|
||||
|
||||
//iterate over all const keywords
|
||||
// ->add to array
|
||||
for(NSUInteger i=0; i<sizeof(KEYWORDS)/sizeof(KEYWORDS[0]); i++)
|
||||
{
|
||||
//add
|
||||
[self.builtInKeywords addObject:KEYWORDS[i]];
|
||||
}
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//register handler for hot keys
|
||||
-(void)registerKeypressHandler
|
||||
{
|
||||
NSEvent * (^keypressHandler)(NSEvent *);
|
||||
|
||||
keypressHandler = ^NSEvent * (NSEvent * theEvent){
|
||||
|
||||
return [self handleKeypress:theEvent];
|
||||
|
||||
};
|
||||
|
||||
//register for key-down events
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask handler:keypressHandler];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//invoked for any (and only) key-down events
|
||||
-(NSEvent*)handleKeypress:(NSEvent*)event
|
||||
{
|
||||
//flag indicating event was handled
|
||||
BOOL wasHandled = NO;
|
||||
|
||||
//refresh (cmd+r)
|
||||
//save (cmd+s)
|
||||
//search (cmd+f)
|
||||
//close window (cmd+w)
|
||||
//info for selected task (cmd+i)
|
||||
|
||||
//only care about 'cmd' + something
|
||||
if(NSCommandKeyMask != (event.modifierFlags & NSCommandKeyMask))
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
NSLog(@"key press: %x", [event keyCode]);
|
||||
|
||||
//handle key-code
|
||||
switch ([event keyCode])
|
||||
{
|
||||
//'r' (refresh)
|
||||
case KEYCODE_R:
|
||||
|
||||
//refresh
|
||||
[self refreshTasks:nil];
|
||||
|
||||
//set flag
|
||||
wasHandled = YES;
|
||||
|
||||
break;
|
||||
|
||||
//'f' (find, search)
|
||||
case KEYCODE_F:
|
||||
|
||||
//find
|
||||
[self search:nil];
|
||||
|
||||
//set flag
|
||||
wasHandled = YES;
|
||||
|
||||
break;
|
||||
|
||||
|
||||
//'s' (save)
|
||||
case KEYCODE_S:
|
||||
|
||||
//save
|
||||
[self saveResults:nil];
|
||||
|
||||
//set flag
|
||||
wasHandled = YES;
|
||||
|
||||
break;
|
||||
|
||||
//'i' (info)
|
||||
//case KEYCODE_I:
|
||||
|
||||
//info
|
||||
//TODO...this will take some work, search, flagged, item....
|
||||
|
||||
//set flag
|
||||
//wasHandled = YES;
|
||||
|
||||
//break;
|
||||
|
||||
//'w' (close window)
|
||||
case KEYCODE_W:
|
||||
|
||||
//close
|
||||
// ->if not main window
|
||||
if(self.window != [[NSApplication sharedApplication] keyWindow])
|
||||
{
|
||||
//close window
|
||||
[[[NSApplication sharedApplication] keyWindow] close];
|
||||
|
||||
//set flag
|
||||
wasHandled = YES;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
//nil out event if it was handled
|
||||
if(YES == wasHandled)
|
||||
{
|
||||
event = nil;
|
||||
}
|
||||
|
||||
// Return the event, a new event, or, to stop
|
||||
// the event from being dispatched, nil
|
||||
return event;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//complete a few inits
|
||||
// ->then invoke helper method to start enum'ing task (in bg thread)
|
||||
-(void)go
|
||||
@@ -616,6 +776,7 @@ bail:
|
||||
return;
|
||||
}
|
||||
|
||||
//finish bottom reload
|
||||
-(void)finalizeBottomReload
|
||||
{
|
||||
//stop progress indicator
|
||||
@@ -1038,6 +1199,7 @@ bail:
|
||||
|
||||
//invoked when user clicks 'save' icon
|
||||
// ->show popup that allows user to save results
|
||||
//TODO: make alert have local 'hyperlink' to file!
|
||||
-(IBAction)saveResults:(id)sender
|
||||
{
|
||||
//save panel
|
||||
@@ -1079,7 +1241,7 @@ bail:
|
||||
//get tasks
|
||||
for(NSNumber* taskPid in self.taskEnumerator.tasks)
|
||||
{
|
||||
//JSON
|
||||
//append task JSON
|
||||
[output appendFormat:@"{%@},", [self.taskEnumerator.tasks[taskPid] toJSON]];
|
||||
}
|
||||
|
||||
@@ -1126,7 +1288,7 @@ bail:
|
||||
return;
|
||||
}
|
||||
|
||||
//automatically invoked when user clicks 'search' button
|
||||
//automatically invoked when user clicks 'search' button/ cmd+f hotkey
|
||||
// ->perform global search
|
||||
-(IBAction)search:(id)sender
|
||||
{
|
||||
@@ -1262,8 +1424,14 @@ bail:
|
||||
//always reset filter text
|
||||
[self.filterTasksBox setStringValue:@""];
|
||||
|
||||
//sync
|
||||
@synchronized(self.taskTableController.filteredItems)
|
||||
{
|
||||
|
||||
//remove all filtered tasks
|
||||
[self.taskTableController.filteredItems removeAllObjects];
|
||||
|
||||
}//sync
|
||||
|
||||
//reset current task
|
||||
self.currentTask = nil;
|
||||
@@ -1450,6 +1618,20 @@ bail:
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//prevent calling "complete" too often
|
||||
if( (YES != self.completePosting) &&
|
||||
(YES != self.commandHandling) )
|
||||
{
|
||||
//set flag
|
||||
self.completePosting = YES;
|
||||
|
||||
//invoke complete
|
||||
[aNotification.userInfo[@"NSFieldEditor"] complete:nil];
|
||||
|
||||
//unset flag
|
||||
self.completePosting = NO;
|
||||
}
|
||||
|
||||
//top pane
|
||||
if(YES == [aNotification.object isEqualTo:self.filterTasksBox])
|
||||
@@ -1465,45 +1647,29 @@ bail:
|
||||
else
|
||||
{
|
||||
//'#' indicates a keyword search
|
||||
// ->check for keyword match, then filter by keyword
|
||||
// ->this is handled by customized auto-complete logic, so ignore
|
||||
if(YES == [search.string hasPrefix:@"#"])
|
||||
{
|
||||
//ignore #search strings that don't match a keyword
|
||||
if(YES != [filterObj isKeyword:search.string])
|
||||
{
|
||||
//ignore
|
||||
goto bail;
|
||||
}
|
||||
//ignore
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//filter
|
||||
//sync
|
||||
@synchronized(self.taskTableController.filteredItems)
|
||||
{
|
||||
|
||||
//normal filter
|
||||
[self.filterObj filterTasks:search.string items:self.taskEnumerator.tasks results:self.taskTableController.filteredItems];
|
||||
|
||||
}
|
||||
|
||||
//set flag
|
||||
self.taskTableController.isFiltered = YES;
|
||||
}
|
||||
|
||||
//always reload task (top) pane
|
||||
// ->will trigger bottom load too
|
||||
[self.taskTableController.itemView reloadData];
|
||||
|
||||
//scroll to top
|
||||
[self.taskTableController scrollToTop];
|
||||
|
||||
//when nothing matches
|
||||
// ->reset current task and bottom pane
|
||||
if( (YES == self.taskTableController.isFiltered) &&
|
||||
(0 == self.taskTableController.filteredItems.count) )
|
||||
{
|
||||
//remove bottom pane's items
|
||||
[self.bottomViewController.tableItems removeAllObjects];
|
||||
|
||||
//reset current task
|
||||
self.currentTask = nil;
|
||||
|
||||
//reload bottom pane
|
||||
[self.bottomViewController.itemView reloadData];
|
||||
}
|
||||
//finalize filtering/search
|
||||
// ->updates UI, etc
|
||||
[self finalizeFiltration:PANE_TOP];
|
||||
}
|
||||
//bottom pane
|
||||
else if(YES == [aNotification.object isEqualTo:self.filterItemsBox])
|
||||
@@ -1519,6 +1685,14 @@ bail:
|
||||
//filter items
|
||||
else
|
||||
{
|
||||
//'#' indicates a keyword search
|
||||
// ->this is handled by customized auto-complete logic, so ignore
|
||||
if(YES == [search.string hasPrefix:@"#"])
|
||||
{
|
||||
//ignore
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//get segment tag
|
||||
segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]];
|
||||
|
||||
@@ -1529,19 +1703,7 @@ bail:
|
||||
//dylibs
|
||||
case DYLIBS_VIEW:
|
||||
{
|
||||
//'#' indicates a keyword search
|
||||
// ->check for keyword match, then filter by keyword
|
||||
if(YES == [search.string hasPrefix:@"#"])
|
||||
{
|
||||
//ignore #search strings that don't match a keyword
|
||||
if(YES != [filterObj isKeyword:search.string])
|
||||
{
|
||||
//ignore
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
//filter
|
||||
//normal filter
|
||||
[self.filterObj filterFiles:search.string items:self.currentTask.dylibs results:self.bottomViewController.filteredItems];
|
||||
|
||||
break;
|
||||
@@ -1574,6 +1736,52 @@ bail:
|
||||
self.bottomViewController.isFiltered = YES;
|
||||
}
|
||||
|
||||
//finalize filtering/searching
|
||||
// ->updates UI, etc
|
||||
[self finalizeFiltration:PANE_BOTTOM];
|
||||
}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//code to complete filtering/search
|
||||
// ->reload table/scroll to top etc
|
||||
-(void)finalizeFiltration:(NSUInteger)pane
|
||||
{
|
||||
//top pane (task)
|
||||
if(PANE_TOP == pane)
|
||||
{
|
||||
//always reload task (top) pane
|
||||
// ->will trigger bottom load too
|
||||
[self.taskTableController.itemView reloadData];
|
||||
|
||||
//scroll to top
|
||||
[self.taskTableController scrollToTop];
|
||||
|
||||
//when nothing matches
|
||||
// ->reset current task and bottom pane
|
||||
if( (YES == self.taskTableController.isFiltered) &&
|
||||
(0 == self.taskTableController.filteredItems.count) )
|
||||
{
|
||||
//remove bottom pane's items
|
||||
[self.bottomViewController.tableItems removeAllObjects];
|
||||
|
||||
//reset current task
|
||||
self.currentTask = nil;
|
||||
|
||||
//stop progress indicator
|
||||
[self.bottomPaneSpinner stopAnimation:nil];
|
||||
|
||||
//reload bottom pane
|
||||
[self.bottomViewController.itemView reloadData];
|
||||
}
|
||||
}
|
||||
//bottom pane (dylibs, files, etc)
|
||||
else
|
||||
{
|
||||
//always reload item (bottom) pane
|
||||
[self.bottomViewController.itemView reloadData];
|
||||
|
||||
@@ -1581,14 +1789,10 @@ bail:
|
||||
[self.bottomViewController scrollToTop];
|
||||
}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
//action for 'refresh' button
|
||||
//action for 'refresh' button / cmd+r hotkey
|
||||
// ->query OS to refresh/reload all tasks
|
||||
-(IBAction)refreshTasks:(id)sender
|
||||
{
|
||||
@@ -1601,9 +1805,15 @@ bail:
|
||||
//unset filter flag
|
||||
self.taskTableController.isFiltered = NO;
|
||||
|
||||
//sync
|
||||
@synchronized(self.taskTableController.filteredItems)
|
||||
{
|
||||
|
||||
//remove all filtered items
|
||||
[self.taskTableController.filteredItems removeAllObjects];
|
||||
|
||||
}
|
||||
|
||||
//reset filter box
|
||||
self.filterTasksBox.stringValue = @"";
|
||||
|
||||
@@ -1768,5 +1978,190 @@ bail:
|
||||
return;
|
||||
}
|
||||
|
||||
//delegate method, automatically called
|
||||
// ->generate list of matches to return for drop-down
|
||||
-(NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index
|
||||
{
|
||||
//matches
|
||||
NSMutableArray *matches = nil;
|
||||
|
||||
//range options
|
||||
NSUInteger rangeOptions = {0};
|
||||
|
||||
//segment tag
|
||||
NSUInteger segmentTag = 0;
|
||||
|
||||
//init array for matches
|
||||
matches = [[NSMutableArray alloc] init];
|
||||
|
||||
//init range options
|
||||
rangeOptions = NSAnchoredSearch | NSCaseInsensitiveSearch;
|
||||
|
||||
//grab segment tag
|
||||
segmentTag = [[self.bottomPaneBtn selectedCell] tagForSegment:[self.bottomPaneBtn selectedSegment]];
|
||||
|
||||
//for now, only filter binaries
|
||||
// ->top pane: any (well, just tasks)
|
||||
// bottom pane: only dylibs
|
||||
if( (textView != self.customTasksFilter) &&
|
||||
(DYLIBS_VIEW != segmentTag) )
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//check all filters
|
||||
for(NSString* filter in self.filterObj.binaryFilters)
|
||||
{
|
||||
//check if found
|
||||
// ->add to match when found
|
||||
if([filter rangeOfString:textView.string options:rangeOptions range:NSMakeRange(0, filter.length)].location != NSNotFound)
|
||||
{
|
||||
//add
|
||||
[matches addObject:filter];
|
||||
}
|
||||
}
|
||||
|
||||
//sort matches
|
||||
[matches sortUsingComparator:^(NSString *a, NSString *b)
|
||||
{
|
||||
//sort
|
||||
return [a localizedStandardCompare:b];
|
||||
}];
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
//delegate method, automatically invoked
|
||||
// ->handle invocations for text view
|
||||
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector
|
||||
{
|
||||
//flag
|
||||
BOOL didPerformRequestedSelectorOnTextView = NO;
|
||||
|
||||
//invocation
|
||||
NSInvocation *textViewInvocationForSelector = nil;
|
||||
|
||||
//check if text view can handle selector
|
||||
if(YES != [textView respondsToSelector:commandSelector])
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set iVar flag
|
||||
self.commandHandling = YES;
|
||||
|
||||
//init invocation
|
||||
textViewInvocationForSelector = [NSInvocation invocationWithMethodSignature:[textView methodSignatureForSelector:commandSelector]];
|
||||
|
||||
//set target
|
||||
[textViewInvocationForSelector setTarget:textView];
|
||||
|
||||
//set selector
|
||||
[textViewInvocationForSelector setSelector:commandSelector];
|
||||
|
||||
//invoke selector
|
||||
[textViewInvocationForSelector invoke];
|
||||
|
||||
//unset iVar
|
||||
self.commandHandling = NO;
|
||||
|
||||
//indicate that selector was performed
|
||||
didPerformRequestedSelectorOnTextView = YES;
|
||||
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return didPerformRequestedSelectorOnTextView;
|
||||
}
|
||||
|
||||
|
||||
//callback for custom search fields
|
||||
// ->handle auto-complete filterings
|
||||
-(void)filterAutoComplete:(NSTextView*)textView
|
||||
{
|
||||
//filter string
|
||||
NSString* filterString = nil;
|
||||
|
||||
//extract filter
|
||||
filterString = textView.textStorage.string;
|
||||
|
||||
//handle top pane (tasks)
|
||||
if(textView == self.customTasksFilter)
|
||||
{
|
||||
//sync
|
||||
@synchronized(self.taskTableController.filteredItems)
|
||||
{
|
||||
//filter
|
||||
[self.filterObj filterTasks:filterString items:self.taskEnumerator.tasks results:self.taskTableController.filteredItems];
|
||||
}
|
||||
|
||||
//set flag
|
||||
self.taskTableController.isFiltered = YES;
|
||||
|
||||
//finalize filtering
|
||||
[self finalizeFiltration:PANE_TOP];
|
||||
|
||||
}
|
||||
//handle bottom pane
|
||||
// ->just dylibs
|
||||
else if(textView == self.customItemsFilter)
|
||||
{
|
||||
//filter
|
||||
[self.filterObj filterFiles:filterString items:self.currentTask.dylibs results:self.bottomViewController.filteredItems];
|
||||
|
||||
//set flag
|
||||
self.bottomViewController.isFiltered = YES;
|
||||
|
||||
//finalize filtering
|
||||
[self finalizeFiltration:PANE_BOTTOM];
|
||||
}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//automatically invoked
|
||||
// ->set all NSSearchFields to be instances of our custom NSTextView
|
||||
-(id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client
|
||||
{
|
||||
//field editor
|
||||
id fieldEditor = nil;
|
||||
|
||||
//ignore non-NSSearchField classes
|
||||
if(YES != [client isKindOfClass:[NSSearchField class]])
|
||||
{
|
||||
//ingnore
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set task's filter search field
|
||||
if(client == self.filterTasksBox)
|
||||
{
|
||||
//assign for return
|
||||
fieldEditor = self.customTasksFilter;
|
||||
}
|
||||
//set item's filter search field
|
||||
else if(client == self.filterItemsBox)
|
||||
{
|
||||
//assign for return
|
||||
fieldEditor = self.customItemsFilter;
|
||||
}
|
||||
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return fieldEditor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -161,10 +161,10 @@
|
||||
#define KERNEL_YOSEMITE @"/System/Library/Kernels/kernel"
|
||||
|
||||
//top pane
|
||||
|
||||
//top
|
||||
#define PANE_TOP 0x0
|
||||
|
||||
//bottom pane
|
||||
#define PANE_BOTTOM 0x1
|
||||
|
||||
//for prefs
|
||||
//#define PREF_FIRST_RUN @"isFirstRun"
|
||||
@@ -175,10 +175,6 @@
|
||||
//tree view
|
||||
#define TREE_VIEW 101
|
||||
|
||||
//bottom pane
|
||||
|
||||
//top
|
||||
#define PANE_BOTTOM 0x1
|
||||
|
||||
//any view
|
||||
// ->not in UI
|
||||
@@ -314,6 +310,19 @@
|
||||
//pls wait (search) message
|
||||
#define PLS_WAIT_MESSAGE @"completing (intial) task/dylib/file enumeration please wait"
|
||||
|
||||
//hotkey 's'
|
||||
#define KEYCODE_S 0x1
|
||||
|
||||
//hotkey 'f'
|
||||
#define KEYCODE_F 0x3
|
||||
|
||||
//hotkey 'w'
|
||||
#define KEYCODE_W 0xD
|
||||
|
||||
//hotkey 'r'
|
||||
#define KEYCODE_R 0xF
|
||||
|
||||
//hotkey 'i'
|
||||
#define KEYCODE_I 0x22
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// CustomTextField.h
|
||||
// SearchField
|
||||
//
|
||||
// Created by Patrick Wardle on 8/27/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
//NSTextView subclass
|
||||
// 1) fixes issue with non-alphanumeric characters in keyword matches
|
||||
// 2) triggers action when user hits enter (1x)
|
||||
@interface CustomTextField : NSTextView
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// CustomTextField.m
|
||||
// SearchField
|
||||
//
|
||||
// Created by Patrick Wardle on 8/27/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import "CustomTextField.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@implementation CustomTextField
|
||||
|
||||
|
||||
//subclass override
|
||||
// ->see: http://stackoverflow.com/questions/5163646/how-to-make-nssearchfield-send-action-upon-autocompletion/5360535#5360535
|
||||
-(void)insertCompletion:(NSString *)word forPartialWordRange:(NSRange)charRange movement:(NSInteger)movement isFinal:(BOOL)flag
|
||||
{
|
||||
//suppress completion if user types a space
|
||||
if(movement == NSRightTextMovement)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//show full replacements
|
||||
if(0 != charRange.location)
|
||||
{
|
||||
//update length
|
||||
charRange.length += charRange.location;
|
||||
|
||||
//reset location
|
||||
charRange.location = 0;
|
||||
}
|
||||
|
||||
//insert completion
|
||||
// ->will use updated char range!
|
||||
[super insertCompletion:word forPartialWordRange:charRange movement:movement isFinal:flag];
|
||||
|
||||
//on enter
|
||||
// ->call up into app delegate to process (filter)
|
||||
if(movement == NSReturnTextMovement)
|
||||
{
|
||||
//call up//filterAutoComplete
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) filterAutoComplete:self];
|
||||
}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Filter.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/21/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
@@ -35,9 +35,6 @@
|
||||
// ->determine if binary is flagged by VT
|
||||
-(BOOL)isFlagged:(Binary*)item;
|
||||
|
||||
|
||||
|
||||
|
||||
//filter tasks
|
||||
-(void)filterTasks:(NSString*)filterText items:(NSMutableDictionary*)items results:(NSMutableArray*)results;
|
||||
|
||||
@@ -47,5 +44,13 @@
|
||||
//filter network connections
|
||||
-(void)filterConnections:(NSString*)filterText items:(NSMutableArray*)items results:(NSMutableArray*)results;
|
||||
|
||||
/* PROPERTIES */
|
||||
|
||||
//binary filter keywords
|
||||
@property(nonatomic, retain)NSMutableArray* binaryFilters;
|
||||
|
||||
//file filter keywords
|
||||
@property(nonatomic, retain)NSMutableArray* fileFilters;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Filter.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/21/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
@@ -12,14 +12,48 @@
|
||||
#import "ItemBase.h"
|
||||
#import "Connection.h"
|
||||
|
||||
//file filter keywords
|
||||
//NSString * const FILE_FILTERS[] = {@"#apple", @"#nonapple", @"#signed", @"#unsigned", @"#flagged"};
|
||||
|
||||
//binary filter keywords
|
||||
NSString * const BINARY_KEYWORDS[] = {@"#apple", @"#nonapple", @"#signed", @"#unsigned", @"#flagged"};
|
||||
|
||||
@implementation Filter
|
||||
|
||||
//filter keywords
|
||||
NSString * const KEYWORDS[] = {@"#apple", @"#nonapple", @"#signed", @"#unsigned", @"#flagged"};
|
||||
//@synthesize fileFilters;
|
||||
@synthesize binaryFilters;
|
||||
|
||||
//init
|
||||
-(id)init
|
||||
{
|
||||
//init super
|
||||
self = [super init];
|
||||
if(nil != self)
|
||||
{
|
||||
//alloc file filter keywords
|
||||
//fileFilters = [NSMutableArray array];
|
||||
|
||||
//alloc binary filter keywords
|
||||
binaryFilters = [NSMutableArray array];
|
||||
|
||||
//init binary filters
|
||||
for(NSUInteger i=0; i < sizeof(BINARY_KEYWORDS)/sizeof(BINARY_KEYWORDS[0]); i++)
|
||||
{
|
||||
//add
|
||||
[self.binaryFilters addObject:BINARY_KEYWORDS[i]];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
//determine if search string is #keyword
|
||||
-(BOOL)isKeyword:(NSString*)searchString
|
||||
{
|
||||
//for now just check in binary keywords
|
||||
return [self.binaryFilters containsObject:searchString];
|
||||
|
||||
/*
|
||||
//flag
|
||||
BOOL isKeyword = NO;
|
||||
|
||||
@@ -36,10 +70,11 @@ NSString * const KEYWORDS[] = {@"#apple", @"#nonapple", @"#signed", @"#unsigned"
|
||||
//bail
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return isKeyword;
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// InfoWindowController.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/21/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// InfoWindowController.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/21/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// File.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/19/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// File.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/19/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Extension.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/19/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+3
-6
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// Extension.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/19/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
@@ -108,22 +108,19 @@
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
//convert object to JSON string
|
||||
//convert Connection object to a JSON string
|
||||
-(NSString*)toJSON
|
||||
{
|
||||
//json string
|
||||
NSString *json = nil;
|
||||
|
||||
//init json
|
||||
json = [NSString stringWithFormat:@"\"name\": \"%@\", \"path\": \"%@\", \"identifier\": \"%@\", \"details\": \"%@\", \"browser\": \"%@\"", self.name, self.path, self.identifier, self.details, self.browser];
|
||||
json = [NSString stringWithFormat:@"\"connection\": \"%@\", \"local IP\": \"%@\", \"local port\": \"%d\", \"remote IP\": \"%@\", \"remote port\": \"%d\", \"type\": \"%@\", \"family\": \"%@\", \"protocol\": \"%@\", \"state\": \"%@\"", self.endpoints, self.localIPAddr, [self.localPort unsignedShortValue], self.remoteIPAddr, [self.remotePort unsignedShortValue], self.type, self.family, self.proto, self.state];
|
||||
|
||||
return json;
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// File.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/19/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+40
-79
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// File.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/19/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
@@ -93,8 +93,6 @@ bail:
|
||||
|
||||
//bail
|
||||
bail:
|
||||
;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -117,92 +115,55 @@ bail:
|
||||
//json string
|
||||
NSString *json = nil;
|
||||
|
||||
//json data
|
||||
// ->for intermediate conversions
|
||||
//NSData *jsonData = nil;
|
||||
//attributes
|
||||
NSMutableString* attributesJSON = nil;
|
||||
|
||||
//hashes
|
||||
//NSString* fileHashes = nil;
|
||||
//init
|
||||
attributesJSON = [NSMutableString string];
|
||||
|
||||
//signing info
|
||||
//NSString* fileSigs = nil;
|
||||
|
||||
//init file hash to default string
|
||||
// ->used when hashes are nil, or serialization fails
|
||||
//fileHashes = @"\"unknown\"";
|
||||
|
||||
//init file signature to default string
|
||||
// ->used when signatures are nil, or serialization fails
|
||||
//fileSigs = @"\"unknown\"";
|
||||
|
||||
/*
|
||||
//convert hashes to JSON
|
||||
if(nil != self.hashes)
|
||||
//when attributes are nil
|
||||
// ->init default string
|
||||
if(nil == self.attributes)
|
||||
{
|
||||
//convert hash dictionary
|
||||
// ->wrap since we are serializing JSON
|
||||
@try
|
||||
{
|
||||
//convert
|
||||
jsonData = [NSJSONSerialization dataWithJSONObject:self.hashes options:kNilOptions error:NULL];
|
||||
if(nil != jsonData)
|
||||
{
|
||||
//convert data to string
|
||||
fileHashes = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
//ignore exceptions
|
||||
// ->file hashes will just be 'unknown'
|
||||
@catch(NSException *exception)
|
||||
{
|
||||
;
|
||||
}
|
||||
//init
|
||||
[attributesJSON appendString:@"\"unknown\""];
|
||||
}
|
||||
|
||||
//convert signing dictionary to JSON
|
||||
if(nil != self.signingInfo)
|
||||
{
|
||||
//convert signing dictionary
|
||||
// ->wrap since we are serializing JSON
|
||||
@try
|
||||
{
|
||||
//convert
|
||||
jsonData = [NSJSONSerialization dataWithJSONObject:self.signingInfo options:kNilOptions error:NULL];
|
||||
if(nil != jsonData)
|
||||
{
|
||||
//convert data to string
|
||||
fileSigs = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
//ignore exceptions
|
||||
// ->file sigs will just be 'unknown'
|
||||
@catch(NSException *exception)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
//provide a default string if the file doesn't have a plist
|
||||
if(nil == self.plist)
|
||||
{
|
||||
//set
|
||||
filePlist = @"n/a";
|
||||
}
|
||||
//use plist as is
|
||||
//file has attributes
|
||||
// ->add each
|
||||
else
|
||||
{
|
||||
//set
|
||||
filePlist = self.plist;
|
||||
//start
|
||||
[attributesJSON appendString:@"{"];
|
||||
|
||||
//add each attributes
|
||||
for(NSString* attribute in self.attributes)
|
||||
{
|
||||
//skip NSFileExtendedAttributes
|
||||
// ->binary format
|
||||
if(YES == [attribute isEqualToString:@"NSFileExtendedAttributes"])
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//add
|
||||
[attributesJSON appendFormat:@"\"%@\":\"%@\",", attribute, self.attributes[attribute]];
|
||||
}
|
||||
|
||||
//remove last ','
|
||||
if(YES == [attributesJSON hasSuffix:@","])
|
||||
{
|
||||
//remove
|
||||
[attributesJSON deleteCharactersInRange:NSMakeRange([attributesJSON length]-1, 1)];
|
||||
}
|
||||
|
||||
//end
|
||||
[attributesJSON appendString:@"}"];
|
||||
}
|
||||
|
||||
//init VT detection ratio
|
||||
//vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[self.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[self.vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
|
||||
|
||||
|
||||
//init json
|
||||
json = [NSString stringWithFormat:@"\"name\": \"%@\", \"path\": \"%@\", \"plist\": \"%@\", \"hashes\": %@, \"signature(s)\": %@", self.name, self.path, filePlist, fileHashes, fileSigs];
|
||||
|
||||
*/
|
||||
json = [NSString stringWithFormat:@"\"name\": \"%@\", \"path\": \"%@\", \"type\": \"%@\", \"attributes\": %@", self.name, self.path, self.type, attributesJSON];
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// CategoryRow.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 4/4/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// CategoryRow.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 4/4/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// NSApplicationKeyEvents.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 7/11/15.
|
||||
// Copyright (c) 2015 Objective-See, LLC. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// NSApplicationKeyEvents.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 7/11/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// PrefsWindowController.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/6/15.
|
||||
// Copyright (c) 2015 Objective-See, LLC. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// PrefsWindowController.m
|
||||
// KnockKnock
|
||||
// RequestRootWindowController.m
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/6/15.
|
||||
// Copyright (c) 2015 Objective-See, LLC. All rights reserved.
|
||||
@@ -156,7 +156,7 @@
|
||||
// ->4 at front is setuid
|
||||
//TODO: CHANGE B4 RELEASE!!
|
||||
//TODO: make 4755 before deploy (for testing, 777 makes XCOde be able to del it during build!)
|
||||
installArgs[1] = "4755";
|
||||
installArgs[1] = "4777";
|
||||
|
||||
//3rd arg: XPC service
|
||||
installArgs[2] = [xpcService UTF8String];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// PrefsWindowController.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/6/15.
|
||||
// Copyright (c) 2015 Objective-See, LLC. All rights reserved.
|
||||
|
||||
@@ -497,7 +497,7 @@ bail:
|
||||
}//sync
|
||||
|
||||
//process all new files
|
||||
// ->calculate hash, etc & save into global list
|
||||
// ->determine type, etc & save into global list
|
||||
for(File* newFile in newFiles)
|
||||
{
|
||||
//generate detailed info
|
||||
@@ -559,15 +559,14 @@ bail:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
- (NSComparisonResult)compare:(Task*)otherTask
|
||||
//compare
|
||||
// ->uses binary name
|
||||
-(NSComparisonResult)compare:(Task*)otherTask
|
||||
{
|
||||
return [self.binary.name compare:otherTask.binary.name options:NSCaseInsensitiveSearch];
|
||||
}
|
||||
|
||||
|
||||
//convert self to JSON string
|
||||
// TODO: add dylibs, files, networking
|
||||
-(NSString*)toJSON
|
||||
{
|
||||
//json string
|
||||
@@ -589,6 +588,24 @@ bail:
|
||||
//VT detection ratio
|
||||
NSString* vtDetectionRatio = nil;
|
||||
|
||||
//dylibs
|
||||
NSMutableString* dylibsJSON = nil;
|
||||
|
||||
//files
|
||||
NSMutableString* filesJSON = nil;
|
||||
|
||||
//network connections
|
||||
NSMutableString* connectionsJSON = nil;
|
||||
|
||||
//init string for dylibs
|
||||
dylibsJSON = [NSMutableString string];
|
||||
|
||||
//init string for files
|
||||
filesJSON = [NSMutableString string];
|
||||
|
||||
//init string for connections
|
||||
connectionsJSON = [NSMutableString string];
|
||||
|
||||
//init task's command line
|
||||
taskCommandLine = [self.arguments componentsJoinedByString:@" "];
|
||||
|
||||
@@ -658,8 +675,65 @@ bail:
|
||||
//init VT detection ratio
|
||||
vtDetectionRatio = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)[self.binary.vtInfo[VT_RESULTS_POSITIVES] unsignedIntegerValue], (unsigned long)[self.binary.vtInfo[VT_RESULTS_TOTAL] unsignedIntegerValue]];
|
||||
|
||||
//sync
|
||||
//TODO: make sure this is sync'd elsewhere
|
||||
@synchronized(self.dylibs)
|
||||
{
|
||||
//convert all dylibs and add
|
||||
for(Binary* dylib in self.dylibs)
|
||||
{
|
||||
//convert/add
|
||||
[dylibsJSON appendFormat:@"{%@},", [dylib toJSON]];
|
||||
}
|
||||
}
|
||||
|
||||
//remove last ','
|
||||
if(YES == [dylibsJSON hasSuffix:@","])
|
||||
{
|
||||
//remove
|
||||
[dylibsJSON deleteCharactersInRange:NSMakeRange([dylibsJSON length]-1, 1)];
|
||||
}
|
||||
|
||||
//sync
|
||||
//TODO: make sure this is sync'd elsewhere
|
||||
@synchronized(self.files)
|
||||
{
|
||||
//convert all file and add
|
||||
for(File* file in self.files)
|
||||
{
|
||||
//convert/add
|
||||
[filesJSON appendFormat:@"{%@},", [file toJSON]];
|
||||
}
|
||||
}
|
||||
|
||||
//remove last ','
|
||||
if(YES == [filesJSON hasSuffix:@","])
|
||||
{
|
||||
//remove
|
||||
[filesJSON deleteCharactersInRange:NSMakeRange([filesJSON length]-1, 1)];
|
||||
}
|
||||
|
||||
//sync
|
||||
//TODO: make sure this is sync'd elsewhere
|
||||
@synchronized(self.connections)
|
||||
{
|
||||
//convert all dylibs and add
|
||||
for(Connection* connection in self.connections)
|
||||
{
|
||||
//convert/add
|
||||
[connectionsJSON appendFormat:@"{%@},", [connection toJSON]];
|
||||
}
|
||||
}
|
||||
|
||||
//remove last ','
|
||||
if(YES == [connectionsJSON hasSuffix:@","])
|
||||
{
|
||||
//remove
|
||||
[connectionsJSON deleteCharactersInRange:NSMakeRange([connectionsJSON length]-1, 1)];
|
||||
}
|
||||
|
||||
//init json
|
||||
json = [NSString stringWithFormat:@"\"name\": \"%@\", \"path\": \"%@\", \"pid\": \"%@\", \"hashes\": %@, \"signature(s)\": %@, \"VT detection\": \"%@\"", self.binary.name, self.binary.path, self.pid, fileHashes, fileSigs, vtDetectionRatio];
|
||||
json = [NSString stringWithFormat:@"\"name\": \"%@\", \"path\": \"%@\", \"pid\": \"%@\", \"hashes\": %@, \"signature(s)\": %@, \"VT detection\": \"%@\", \"dylibs\": [%@], \"files\": [%@], \"connections\": [%@]", self.binary.name, self.binary.path, self.pid, fileHashes, fileSigs, vtDetectionRatio, dylibsJSON, filesJSON, connectionsJSON];
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
+13
-2
@@ -46,7 +46,6 @@
|
||||
|
||||
//init binary processing queue
|
||||
binaryQueue = [[Queue alloc] init];
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -161,6 +160,10 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
//nap
|
||||
// ->helps with UI
|
||||
[NSThread sleepForTimeInterval:0.01f];
|
||||
|
||||
//generate signing info
|
||||
[newTask.binary generatedSigningInfo];
|
||||
|
||||
@@ -182,6 +185,10 @@
|
||||
|
||||
//enumerate
|
||||
[newTask enumerateDylibs:xpcConnection allDylibs:self.dylibs];
|
||||
|
||||
//nap
|
||||
// ->helps with UI
|
||||
[NSThread sleepForTimeInterval:0.01f];
|
||||
}
|
||||
|
||||
//begin file enumeration
|
||||
@@ -193,6 +200,10 @@
|
||||
|
||||
//enumerate
|
||||
[newTask enumerateFiles:xpcConnection];
|
||||
|
||||
//nap
|
||||
// ->helps with UI
|
||||
[NSThread sleepForTimeInterval:0.01f];
|
||||
}
|
||||
|
||||
//TODO: add network connection filtering
|
||||
@@ -457,7 +468,7 @@ bail:
|
||||
|
||||
return;
|
||||
}
|
||||
//TODO: test w/ dylib!!
|
||||
|
||||
//ensure that the list of flagged items is correctly updated
|
||||
// when a dead task or any of its dylibs were flagged...
|
||||
-(void)updateFlaggedItems:(Task*)deadTask
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Prefix header for all source files of the 'KnockKnock' target in the 'KnockKnock' project
|
||||
// Prefix header for all source files of the 'TaskExplorer' target in the 'TaskExplorer' project
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
1D21BC4F172AF43D009D1CFD /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D21BC4E172AF43D009D1CFD /* Cocoa.framework */; };
|
||||
7D2F567C1B81BEAB00C7D85E /* SearchWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D2F567B1B81BEAB00C7D85E /* SearchWindow.xib */; };
|
||||
7D2F567F1B81BEB400C7D85E /* SearchWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D2F567E1B81BEB400C7D85E /* SearchWindowController.m */; };
|
||||
7DAA78091B903BF1004840B9 /* CustomTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DAA78081B903BF1004840B9 /* CustomTextField.m */; };
|
||||
CD001B381AB903040089014A /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = CD001B351AB903040089014A /* logo.png */; };
|
||||
CD001B391AB903040089014A /* logoApple.png in Resources */ = {isa = PBXBuildFile; fileRef = CD001B361AB903040089014A /* logoApple.png */; };
|
||||
CD02194F1AD34D8B005148A2 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD02194D1AD34D8B005148A2 /* AboutWindow.xib */; };
|
||||
@@ -155,6 +156,8 @@
|
||||
7D2F567B1B81BEAB00C7D85E /* SearchWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = SearchWindow.xib; path = UI/SearchWindow.xib; sourceTree = "<group>"; };
|
||||
7D2F567D1B81BEB300C7D85E /* SearchWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchWindowController.h; sourceTree = "<group>"; };
|
||||
7D2F567E1B81BEB400C7D85E /* SearchWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchWindowController.m; sourceTree = "<group>"; };
|
||||
7DAA78071B903BF1004840B9 /* CustomTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomTextField.h; sourceTree = "<group>"; };
|
||||
7DAA78081B903BF1004840B9 /* CustomTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomTextField.m; sourceTree = "<group>"; };
|
||||
CD001B351AB903040089014A /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = images/logo.png; sourceTree = SOURCE_ROOT; };
|
||||
CD001B361AB903040089014A /* logoApple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoApple.png; path = images/logoApple.png; sourceTree = SOURCE_ROOT; };
|
||||
CD02194D1AD34D8B005148A2 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AboutWindow.xib; path = UI/AboutWindow.xib; sourceTree = "<group>"; };
|
||||
@@ -328,6 +331,8 @@
|
||||
1D21BC42172AF43D009D1CFD = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7DAA78071B903BF1004840B9 /* CustomTextField.h */,
|
||||
7DAA78081B903BF1004840B9 /* CustomTextField.m */,
|
||||
7D2F567D1B81BEB300C7D85E /* SearchWindowController.h */,
|
||||
7D2F567E1B81BEB400C7D85E /* SearchWindowController.m */,
|
||||
CD74A0781B7F170B00A8AAD3 /* FlaggedItems.h */,
|
||||
@@ -774,6 +779,7 @@
|
||||
CD4D541F1B2CE6C400008030 /* Queue.m in Sources */,
|
||||
CD6E54FF1B1162B5007953AB /* ItemView.m in Sources */,
|
||||
CDA81DEE1A99B5F8009790E2 /* Filter.m in Sources */,
|
||||
7DAA78091B903BF1004840B9 /* CustomTextField.m in Sources */,
|
||||
CDA81D7B1A95D29B009790E2 /* TaskTableController.m in Sources */,
|
||||
CDF08CCA1AC4C678009B3423 /* PrefsWindowController.m in Sources */,
|
||||
CDA81DEA1A997BF1009790E2 /* InfoWindowController.m in Sources */,
|
||||
|
||||
BIN
Binary file not shown.
+99
-35
@@ -3,22 +3,6 @@
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "RequestRootWindowController.m"
|
||||
timestampString = "461569181.574758"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "134"
|
||||
endingLineNumber = "134"
|
||||
landmarkName = "-authenticate:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
@@ -83,22 +67,6 @@
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "462091427.171131"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "1593"
|
||||
endingLineNumber = "1593"
|
||||
landmarkName = "-refreshTasks:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
@@ -154,11 +122,11 @@
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "462091427.171131"
|
||||
timestampString = "462785295.692202"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "1371"
|
||||
endingLineNumber = "1371"
|
||||
startingLineNumber = "1537"
|
||||
endingLineNumber = "1537"
|
||||
landmarkName = "-selectBottomPaneContent:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
@@ -211,5 +179,101 @@
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "462695042.305349"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "206"
|
||||
endingLineNumber = "206"
|
||||
landmarkName = "-registerKeypressHandler"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "462695042.305349"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "223"
|
||||
endingLineNumber = "223"
|
||||
landmarkName = "-handleKeypress:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "AppDelegate.m"
|
||||
timestampString = "462695042.305349"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "244"
|
||||
endingLineNumber = "244"
|
||||
landmarkName = "-handleKeypress:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Items/File.m"
|
||||
timestampString = "462700393.667462"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "166"
|
||||
endingLineNumber = "166"
|
||||
landmarkName = "-toJSON"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Items/Connection.m"
|
||||
timestampString = "462786540.058618"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "115"
|
||||
endingLineNumber = "115"
|
||||
landmarkName = "-toJSON"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "RequestRootWindowController.m"
|
||||
timestampString = "462783965.798309"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "134"
|
||||
endingLineNumber = "134"
|
||||
landmarkName = "-authenticate:"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
|
||||
-20
@@ -59,26 +59,6 @@
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "DYLD_INSERT_LIBRARIES"
|
||||
value = "/usr/lib/libgmalloc.dylib"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "MallocGuardEdges"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "MallocScribble"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ItemTableController.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/18/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// ItemTableController.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 2/18/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// vtButton.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 3/26/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// vtButton.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 3/26/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// VTInfoWindow.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 3/29/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// VTInfoWindow.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 3/29/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// VirusTotal.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 3/8/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// VirusTotal.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 3/8/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// kkRowCell.h
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 4/6/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// kkRowCell.m
|
||||
// KnockKnock
|
||||
// TaskExplorer
|
||||
//
|
||||
// Created by Patrick Wardle on 4/6/15.
|
||||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
|
||||
+46
-48
@@ -10,13 +10,38 @@
|
||||
#import "remoteTaskService.h"
|
||||
#import "serviceInterface.h"
|
||||
|
||||
#import <syslog.h>
|
||||
#import <libproc.h>
|
||||
#import <sys/proc_info.h>
|
||||
#import <syslog.h>
|
||||
|
||||
|
||||
//interface for 'extension' to NSXPCConnection
|
||||
// ->allows us to access the 'private' auditToken iVar
|
||||
@interface ExtendedNSXPCConnection : NSXPCConnection
|
||||
{
|
||||
//private iVar
|
||||
audit_token_t auditToken;
|
||||
}
|
||||
//private iVar
|
||||
@property audit_token_t auditToken;
|
||||
|
||||
@end
|
||||
|
||||
//implementation for 'extension' to NSXPCConnection
|
||||
// ->allows us to access the 'private' auditToken iVar
|
||||
@implementation ExtendedNSXPCConnection
|
||||
|
||||
//private iVar
|
||||
@synthesize auditToken;
|
||||
|
||||
@end
|
||||
|
||||
//function def
|
||||
OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
|
||||
|
||||
//TODO: CHANGE B4 RELEASE!!
|
||||
//-> for testing: @"Mac Developer: patrick wardle (5SKKU32KLJ)"
|
||||
#define SIGNING_AUTH @"Developer ID Application: Objective-See, LLC (VBG97UB4TA)"
|
||||
#define SIGNING_AUTH @"Mac Developer: patrick wardle (5SKKU32KLJ)"//@"Developer ID Application: Objective-See, LLC (VBG97UB4TA)"
|
||||
|
||||
//skeleton interface
|
||||
@interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
|
||||
@@ -24,7 +49,6 @@
|
||||
|
||||
@implementation ServiceDelegate
|
||||
|
||||
|
||||
//automatically invoked
|
||||
//->allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection
|
||||
// note: we only allow binaries signed by Objective-See to talk to this!
|
||||
@@ -33,63 +57,32 @@
|
||||
//flag
|
||||
BOOL shouldAccept = NO;
|
||||
|
||||
//status
|
||||
int status = -1;
|
||||
|
||||
//buffer for process path
|
||||
char pathBuffer[PROC_PIDPATHINFO_MAXSIZE] = {0};
|
||||
|
||||
//code
|
||||
SecStaticCodeRef staticCode = NULL;
|
||||
|
||||
//signing reqs
|
||||
SecRequirementRef requirementRef = NULL;
|
||||
|
||||
//task ref
|
||||
SecTaskRef taskRef = 0;
|
||||
|
||||
//signing req string
|
||||
NSString *requirementString = nil;
|
||||
|
||||
//init signing req string
|
||||
// ->check for Ojective-See's dev cert
|
||||
requirementString = [NSString stringWithFormat:@"anchor trusted and certificate leaf [subject.CN] = \"%@\"", SIGNING_AUTH];
|
||||
|
||||
//get path
|
||||
status = proc_pidpath(newConnection.processIdentifier, pathBuffer, sizeof(pathBuffer));
|
||||
|
||||
//sanity check
|
||||
// ->this generally just fails if process has exited....
|
||||
if( (status < 0) ||
|
||||
(0 == strlen(pathBuffer)) )
|
||||
|
||||
//step 1: create task ref
|
||||
// ->uses NSXPCConnection's (private) 'auditToken' iVar
|
||||
taskRef = SecTaskCreateWithAuditToken(NULL, ((ExtendedNSXPCConnection*)newConnection).auditToken);
|
||||
if(0 == taskRef)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//create static code
|
||||
if(0 != SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:[NSString stringWithUTF8String:pathBuffer]]), kSecCSDefaultFlags, &staticCode))
|
||||
//step 2: validate
|
||||
// ->check that client is signed with Objective-See's dev cert
|
||||
if(0 != SecTaskValidateForRequirement(taskRef, (__bridge CFStringRef)(requirementString)))
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//create req string w/ 'anchor apple'
|
||||
// (3rd party: 'anchor apple generic')
|
||||
if(0 != SecRequirementCreateWithString((__bridge CFStringRef)requirementString, kSecCSDefaultFlags, &requirementRef))
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//check if file is signed by apple
|
||||
// ->i.e. it conforms to req string
|
||||
if(0 != SecStaticCodeCheckValidity(staticCode, kSecCSDefaultFlags, requirementRef))
|
||||
{
|
||||
//err msg
|
||||
syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: SecStaticCodeCheckValidity() failed on %s", pathBuffer);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set the interface that the exported object implements
|
||||
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(remoteTaskProto)];
|
||||
|
||||
@@ -112,14 +105,19 @@ bail:
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
// Create the delegate for the service.
|
||||
//create the delegate for the service.
|
||||
ServiceDelegate *delegate = [ServiceDelegate new];
|
||||
|
||||
// Set up the one NSXPCListener for this service. It will handle all incoming connections.
|
||||
//set up the one NSXPCListener for this service
|
||||
// ->handles incoming connections
|
||||
NSXPCListener *listener = [NSXPCListener serviceListener];
|
||||
|
||||
//set delegate
|
||||
listener.delegate = delegate;
|
||||
|
||||
// Resuming the serviceListener starts this service. This method does not return.
|
||||
//resuming the listener starts this service
|
||||
// ->method does not return
|
||||
[listener resume];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user