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:
Patrick Wardle
2015-08-31 22:00:25 -10:00
parent aea2ce3b40
commit c813cc583d
41 changed files with 945 additions and 316 deletions
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+15 -6
View File
@@ -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
+19
View File
@@ -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
+54
View File
@@ -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
+9 -4
View File
@@ -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
+39 -4
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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.
+3 -3
View File
@@ -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 -1
View File
@@ -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.
+80 -6
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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__
+6
View File
@@ -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 */,
@@ -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>
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}