diff --git a/AboutWindowController.h b/AboutWindowController.h index e04d687..e4f6245 100644 --- a/AboutWindowController.h +++ b/AboutWindowController.h @@ -25,5 +25,4 @@ //'support us' button @property (weak, atomic) IBOutlet NSButton *supportUs; - @end diff --git a/AppDelegate.m b/AppDelegate.m index 5845505..92cce31 100755 --- a/AppDelegate.m +++ b/AppDelegate.m @@ -53,9 +53,6 @@ //kick off main window/logic -(void)taskExplore { - //make foreground so it has an dock icon, etc - transformProcess(kProcessTransformToForegroundApplication); - //for autolayout [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"]; @@ -115,15 +112,21 @@ [self registerKeypressHandler]; //check if authenticated - // ->display authentication request if needed + // display authentication request if needed if(YES != [self isAuthenticated]) { - //display auth popup - // will invoke 'go' method on successful auth - [self askForRoot]; + //wait to allow app to become front + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, .33 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + + //display auth popup + // will invoke 'go' method on successful auth + [self askForRoot]; + + }); } + //go! - // ->setup tracking areas and begin thread that explores tasks + // setup tracking areas and begin thread that explores tasks else { //go! @@ -161,12 +164,23 @@ //set delegate // ->ensures our 'windowWillClose' method, which has logic to fully exit app self.window.delegate = self; + + return; } //automatically invoked by OS // ->main entry point -(void)applicationDidFinishLaunching:(NSNotification *)notification { + + //toggle away + [[[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.loginwindow"] firstObject] activateWithOptions:NSApplicationActivateIgnoringOtherApps]; + + //toggle back + // work-around for menu not showing since we set Application is agent(UIElement): YES + [[[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.objective-see.TaskExplorer"] firstObject] activateWithOptions:NSApplicationActivateIgnoringOtherApps]; + + //first time run? // show thanks to friends window! // note: on close, invokes method to show main window @@ -443,7 +457,7 @@ bail: //kick off thread to enum task // ->will update table as results come in - [NSThread detachNewThreadSelector:@selector(enumerateTasks) toTarget:taskEnumerator withObject:nil]; + [NSThread detachNewThreadSelector:@selector(enumerateTasks:) toTarget:taskEnumerator withObject:nil]; return; } diff --git a/Items/ItemBase.h b/Items/ItemBase.h index 730a49a..888ce4d 100644 --- a/Items/ItemBase.h +++ b/Items/ItemBase.h @@ -1,9 +1,9 @@ // // ItemBase.h -// BlockBlock +// TaskExplorer // // Created by Patrick Wardle on 9/25/14. -// Copyright (c) 2014 Synack. All rights reserved. +// Copyright (c) 2014 Objective-See. All rights reserved. // #import @@ -25,13 +25,6 @@ //file attributes @property(nonatomic, retain)NSDictionary* attributes; -//flag if known -// ->signed by apple and/or whitelisted -//@property BOOL isTrusted; - - - - /* METHODS */ //init method diff --git a/KKRow.m b/KKRow.m index 6e6ef6c..10c4eda 100644 --- a/KKRow.m +++ b/KKRow.m @@ -33,7 +33,7 @@ [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] setStroke]; //set fill - [[NSColor colorWithCalibratedWhite:.65 alpha:1.0] setFill]; + [[NSColor colorWithCalibratedWhite:.50 alpha:1.0] setFill]; } //light mode highlight else diff --git a/NSMutableArray+QueueAdditions.h b/NSMutableArray+QueueAdditions.h index aebd0ab..a234869 100644 --- a/NSMutableArray+QueueAdditions.h +++ b/NSMutableArray+QueueAdditions.h @@ -3,7 +3,7 @@ // BlockBlock // // Created by Patrick Wardle on 9/26/14. -// Copyright (c) 2014 Synack. All rights reserved. +// Copyright (c) 2014 Objective-See. All rights reserved. // #import diff --git a/NSMutableArray+QueueAdditions.m b/NSMutableArray+QueueAdditions.m index 5d5fb54..fa30b01 100644 --- a/NSMutableArray+QueueAdditions.m +++ b/NSMutableArray+QueueAdditions.m @@ -3,7 +3,7 @@ // BlockBlock // // Created by Patrick Wardle on 9/26/14. -// Copyright (c) 2014 Synack. All rights reserved. +// Copyright (c) 2014 Objective-See. All rights reserved. // #import "NSMutableArray+QueueAdditions.h" diff --git a/Queue.h b/Queue.h index bae2edb..980e42b 100644 --- a/Queue.h +++ b/Queue.h @@ -1,9 +1,9 @@ // // Queue.h -// BlockBlock +// TaskExplorer // // Created by Patrick Wardle on 9/26/14. -// Copyright (c) 2014 Synack. All rights reserved. +// Copyright (c) 2014 Objective-See. All rights reserved. // //from: https://github.com/esromneb/ios-queue-object/blob/master/NSMutableArray%2BQueueAdditions.h diff --git a/Queue.m b/Queue.m index 8d6954c..22b9167 100644 --- a/Queue.m +++ b/Queue.m @@ -1,9 +1,9 @@ // // Queue.m -// BlockBlock +// TaskExplorer // // Created by Patrick Wardle on 9/26/14. -// Copyright (c) 2014 Synack. All rights reserved. +// Copyright (c) 2014 Objective-See. All rights reserved. // #import "Queue.h" diff --git a/RequestRootWindowController.m b/RequestRootWindowController.m index 4c42722..85e021e 100644 --- a/RequestRootWindowController.m +++ b/RequestRootWindowController.m @@ -195,7 +195,7 @@ self.cancelButton.enabled = NO; //update auth message - self.statusMsg.stringValue = @"ok: authorization successful"; + self.statusMsg.stringValue = @"...authorization successful!"; //wait a bit // ->then hide window & kick off action diff --git a/Task.m b/Task.m index 3b7d123..19d6580 100644 --- a/Task.m +++ b/Task.m @@ -394,7 +394,11 @@ bail: //reload bottom pane now // note: this will only reload if new task is the currently selected one, etc - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:self itemView:DYLIBS_VIEW]; + if(YES != cmdlineMode) + { + //reload + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:self itemView:DYLIBS_VIEW]; + } //complete dylib processing for new dylib // ->get signing info, hash, etc, & save into global list @@ -415,15 +419,19 @@ bail: newDylib.isPacked = [newDylib.parser.binaryInfo[KEY_IS_PACKED] boolValue]; } - //no need to reload if task is now longer current/selected - if(((AppDelegate*)[[NSApplication sharedApplication] delegate]).currentTask != self) + //need to load? + if(YES != cmdlineMode) { - //skip reload - continue; + //no need to reload if task is now longer current/selected + if(((AppDelegate*)[[NSApplication sharedApplication] delegate]).currentTask != self) + { + //skip reload + continue; + } + + //reload row + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadRow:newDylib]; } - - //reload row - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadRow:newDylib]; } //signal sema @@ -519,7 +527,12 @@ bail: }] mutableCopy]; //reload bottom pane - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:self itemView:FILES_VIEW]; + if(YES != cmdlineMode) + { + //reload + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:self itemView:FILES_VIEW]; + } + }//sync @@ -603,7 +616,11 @@ bail: } //reload bottom pane - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:self itemView:NETWORKING_VIEW]; + if(YES != cmdlineMode) + { + //reload + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:self itemView:NETWORKING_VIEW]; + } }//sync diff --git a/TaskEnumerator.h b/TaskEnumerator.h index 5940905..ddeabce 100644 --- a/TaskEnumerator.h +++ b/TaskEnumerator.h @@ -52,7 +52,7 @@ //enumerate all tasks // ->call back into app delegate to update task (top) table --(void)enumerateTasks; +-(void)enumerateTasks:(NSNumber*)pid; //get list of all pids -(OrderedDictionary*)getAllTasks; diff --git a/TaskEnumerator.m b/TaskEnumerator.m index b1e25b1..aee09bd 100644 --- a/TaskEnumerator.m +++ b/TaskEnumerator.m @@ -44,10 +44,9 @@ return self; } - //enumerate all tasks // calls back into app delegate to update task (top) table when pau --(void)enumerateTasks +-(void)enumerateTasks:(NSNumber*)pid { //(new) task item Task* newTask = nil; @@ -65,18 +64,28 @@ self.state = ENUMERATION_STATE_TASKS; //get all tasks - // ->pids and binary obj with just path/name + // pids and binary obj with just path/name newTasks = [self getAllTasks]; //build ancestries // do here, and use 'new tasks' since there might be new parents too [self generateAncestries:newTasks]; + //only interested in one task? + if(nil != pid) + { + //enumerate task + [self enumerateTask:newTasks[pid]]; + + //done + goto bail; + } + //get all tasks that are pau deadTasks = [self.tasks.allKeys filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"NOT SELF IN %@", newTasks.allKeys]]; //remove any old tasks that have exited/died - // ->invoke custom method to handle kids too... + // invoke custom method to handle kids too... for(NSNumber* key in deadTasks) { //sync to remove @@ -121,23 +130,26 @@ }//add new tasks //sort tasks - // ->ensures that signing info etc w/ be generated for (top) visible tasks - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) sortTasksForView:newTasks]; - - //reload task table - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadTaskTable]; - - //reload bottom pain - // call on main thread - if(YES != [NSThread isMainThread]) + if(YES != cmdlineMode) { - //main thread - dispatch_sync(dispatch_get_main_queue(), ^{ - - //reload bottom pane - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) selectBottomPaneContent:nil]; + //sort + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) sortTasksForView:newTasks]; + + //reload task table + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadTaskTable]; + + //reload bottom pain + // call on main thread + if(YES != [NSThread isMainThread]) + { + //main thread + dispatch_sync(dispatch_get_main_queue(), ^{ - }); + //reload bottom pane + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) selectBottomPaneContent:nil]; + + }); + } } //for new tasks @@ -173,12 +185,16 @@ newTask.binary.isPacked = [newTask.binary.parser.binaryInfo[KEY_IS_PACKED] boolValue]; } - //reload task (row) in table - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadRow:newTask]; - - //reload bottom pane - // ->this will only reload if new task is the currently selected one, etc - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:newTask itemView:CURRENT_VIEW]; + //reload UI + if(YES != cmdlineMode) + { + //reload task (row) in table + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadRow:newTask]; + + //reload bottom pane + // ->this will only reload if new task is the currently selected one, etc + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBottomPane:newTask itemView:CURRENT_VIEW]; + } }//signing info for all new tasks @@ -298,6 +314,53 @@ //set state self.state = ENUMERATION_STATE_COMPLETE; +bail: + + return; +} + +//scan a single task +-(void)enumerateTask:(Task*)task +{ + //sanity check + if(nil == task) + { + //bail + goto bail; + } + + //generate signing info dynamically + task.binary.signingInfo = extractSigningInfo(task.pid.intValue, nil, kSecCSDefaultFlags); + if(nil == task.binary.signingInfo) + { + //extract signing info statically + task.binary.signingInfo = extractSigningInfo(0, task.binary.path, kSecCSCheckAllArchitectures | kSecCSCheckNestedCode | kSecCSDoNotValidateResources); + } + + //parse + if(YES == [task.binary parse]) + { + //save encrypted flag + task.binary.isEncrypted = [task.binary.parser.binaryInfo[KEY_IS_ENCRYPTED] boolValue]; + + //save packed flag + task.binary.isPacked = [task.binary.parser.binaryInfo[KEY_IS_PACKED] boolValue]; + } + + //enumerate dylibs + [task enumerateDylibs:self.dylibs shouldWait:YES]; + + //enumerate files + [task enumerateFiles:YES]; + + //enumerate networking + [task enumerateNetworking:YES]; + + //save task + self.tasks[task.pid] = task; + +bail: + return; } @@ -627,7 +690,8 @@ bail: //when there are no flagged items // ->(re)set flagged icon to black - if(0 == taskEnumerator.flaggedItems.count) + if( (YES != cmdlineMode) && + (0 == taskEnumerator.flaggedItems.count) ) { //set main image [((AppDelegate*)[[NSApplication sharedApplication] delegate]).flaggedButton setImage:[NSImage imageNamed:@"flagged"]]; diff --git a/TaskExplorer-Info.plist b/TaskExplorer-Info.plist index 8d20bfe..ebea5c7 100755 --- a/TaskExplorer-Info.plist +++ b/TaskExplorer-Info.plist @@ -25,7 +25,7 @@ LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright - Copyright © 2018 Objective-See, LLC. All rights reserved. + Copyright © 2019 Objective-See, LLC. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass diff --git a/TaskExplorer.entitlements b/TaskExplorer.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/TaskExplorer.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/TaskExplorer.xcodeproj/project.pbxproj b/TaskExplorer.xcodeproj/project.pbxproj index 9814197..21f8cff 100755 --- a/TaskExplorer.xcodeproj/project.pbxproj +++ b/TaskExplorer.xcodeproj/project.pbxproj @@ -238,6 +238,8 @@ CD3F4CFE1AF72BC4002A2647 /* TaskInfoWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TaskInfoWindow.xib; path = UI/TaskInfoWindow.xib; sourceTree = ""; }; CD3F4D131AF85088002A2647 /* FlatView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FlatView.xib; path = UI/FlatView.xib; sourceTree = ""; }; CD3F4D151AF89066002A2647 /* TreeView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TreeView.xib; path = UI/TreeView.xib; sourceTree = ""; }; + CD42FF8F21CE0CED000A0461 /* TaskExplorer.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TaskExplorer.entitlements; sourceTree = SOURCE_ROOT; }; + CD42FF9021CE0D05000A0461 /* remoteTaskService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = remoteTaskService.entitlements; sourceTree = ""; }; CD4D53C91B20296E00008030 /* unknown.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = unknown.png; path = images/unknown.png; sourceTree = SOURCE_ROOT; }; CD4D53CF1B23ED3900008030 /* connectedIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = connectedIcon.png; path = images/connectedIcon.png; sourceTree = SOURCE_ROOT; }; CD4D53D11B23ED4300008030 /* listeningIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = listeningIcon.png; path = images/listeningIcon.png; sourceTree = SOURCE_ROOT; }; @@ -444,6 +446,7 @@ 1D21BC54172AF43D009D1CFD /* TaskExplorer */ = { isa = PBXGroup; children = ( + CD42FF8F21CE0CED000A0461 /* TaskExplorer.entitlements */, CD1508DE21BB13980081F1AF /* Signing.h */, CD1508DD21BB13980081F1AF /* Signing.m */, CD1D14F221B8F2FC00FF7F4B /* Assets.xcassets */, @@ -565,6 +568,7 @@ CDA5F6AE1B16D805003CE340 /* remoteTaskService */ = { isa = PBXGroup; children = ( + CD42FF9021CE0D05000A0461 /* remoteTaskService.entitlements */, CDA5F6B21B16D805003CE340 /* remoteTaskService.h */, CDA5F6B31B16D805003CE340 /* remoteTaskService.m */, CDA5F6B51B16D805003CE340 /* main.m */, @@ -715,10 +719,20 @@ TargetAttributes = { 1D21BC4A172AF43D009D1CFD = { DevelopmentTeam = VBG97UB4TA; + SystemCapabilities = { + com.apple.HardenedRuntime = { + enabled = 1; + }; + }; }; CDA5F6AC1B16D805003CE340 = { CreatedOnToolsVersion = 6.3.2; DevelopmentTeam = VBG97UB4TA; + SystemCapabilities = { + com.apple.HardenedRuntime = { + enabled = 1; + }; + }; }; }; }; @@ -1008,6 +1022,7 @@ CODE_SIGN_IDENTITY = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; COMBINE_HIDPI_IMAGES = YES; + ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", @@ -1031,6 +1046,7 @@ CODE_SIGN_IDENTITY = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; COMBINE_HIDPI_IMAGES = YES; + ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", @@ -1057,6 +1073,7 @@ CODE_SIGN_IDENTITY = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_HARDENED_RUNTIME = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -1092,6 +1109,7 @@ CODE_SIGN_IDENTITY = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; + ENABLE_HARDENED_RUNTIME = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( diff --git a/TaskExplorer.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/UserInterfaceState.xcuserstate b/TaskExplorer.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index dee3b90..0000000 Binary files a/TaskExplorer.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/TaskExplorer.xcscheme b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/TaskExplorer.xcscheme index a71d917..671cdd1 100644 --- a/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/TaskExplorer.xcscheme +++ b/TaskExplorer.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/TaskExplorer.xcscheme @@ -48,7 +48,15 @@ + + + + diff --git a/Utilities.m b/Utilities.m index bc92873..6bea93a 100644 --- a/Utilities.m +++ b/Utilities.m @@ -763,9 +763,12 @@ void makeModal(NSWindowController* windowController) //make modal on main thread dispatch_sync(dispatch_get_main_queue(), ^{ + //make app front + [NSApp activateIgnoringOtherApps:YES]; + //modal [[NSApplication sharedApplication] runModalForWindow:windowController.window]; - + }); //all done @@ -1375,8 +1378,3 @@ void transformProcess(ProcessApplicationTransformState location) return; } - - - - - diff --git a/VTInfoWindowController.m b/VTInfoWindowController.m index 4b77b77..2077611 100644 --- a/VTInfoWindowController.m +++ b/VTInfoWindowController.m @@ -208,6 +208,9 @@ //VT scan ID __block NSString* scanID = nil; + //new report + __block NSURL* newReport = nil; + //alloc/init VT obj vtObj = [[VirusTotal alloc] init]; @@ -313,8 +316,19 @@ //nap so user can see msg [NSThread sleepForTimeInterval:0.5]; - //launch browser to show rew report - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:result[@"permalink"]]]; + //launch browser to show new report + dispatch_sync(dispatch_get_main_queue(), ^{ + + //sanity check + // then launch browser + if( (nil != result[@"permalink"]) && + (nil != (newReport = [NSURL URLWithString:result[@"permalink"]])) ) + { + //launch browser + [[NSWorkspace sharedWorkspace] openURL:newReport]; + } + + }); //wait to browser is up and happy [NSThread sleepForTimeInterval:0.5]; @@ -390,8 +404,19 @@ //nap so user can see msg [NSThread sleepForTimeInterval:0.5]; - //launch browser to show rew report - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:result[@"permalink"]]]; + //launch browser to show new report + dispatch_sync(dispatch_get_main_queue(), ^{ + + //sanity check + // then launch browser + if( (nil != result[@"permalink"]) && + (nil != (newReport = [NSURL URLWithString:result[@"permalink"]])) ) + { + //launch browser + [[NSWorkspace sharedWorkspace] openURL:newReport]; + } + + }); //wait to browser is up and happy [NSThread sleepForTimeInterval:0.5]; diff --git a/VirusTotal.h b/VirusTotal.h index 96c7f1a..fe9f8d7 100644 --- a/VirusTotal.h +++ b/VirusTotal.h @@ -9,6 +9,11 @@ #import "Binary.h" #import +/* GLOBALS */ + +//cmdline flag +extern BOOL cmdlineMode; + @interface VirusTotal : NSObject { diff --git a/VirusTotal.m b/VirusTotal.m index 85309b6..e572cf6 100644 --- a/VirusTotal.m +++ b/VirusTotal.m @@ -606,11 +606,14 @@ bail: } //call up into app delegate to smartly reload - [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBinary:queriedItem]; + if(YES != cmdlineMode) + { + //reload + [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadBinary:queriedItem]; + } } return; } - @end diff --git a/main.h b/main.h index a5d203e..895c8ee 100644 --- a/main.h +++ b/main.h @@ -3,7 +3,6 @@ // TaskExplorer // // Created by Patrick Wardle on 12/16/18. -// Copyright © 2018 Lucas Derraugh. All rights reserved. // #ifndef main_h @@ -33,6 +32,9 @@ VirusTotal* virusTotal = nil; //network connected flag BOOL isConnected = NO; +//cmdline flag +BOOL cmdlineMode = NO; + //(privacy) protected directories NSArray* protectedDirectories = nil; diff --git a/main.m b/main.m index ec9a248..3fd1bb0 100755 --- a/main.m +++ b/main.m @@ -80,6 +80,9 @@ int main(int argc, char *argv[]) goto bail; } + //set flag + cmdlineMode = YES; + //scan cmdlineExplore(); @@ -94,8 +97,14 @@ int main(int argc, char *argv[]) // just kick off app for UI instance else { + //set flag + cmdlineMode = NO; + + //make foreground so it has an dock icon, etc + transformProcess(kProcessTransformToForegroundApplication); + //invoke app's main - status = NSApplicationMain(argc, (const char **)argv); + status = NSApplicationMain(argc, (const char **)argv); } bail: @@ -114,8 +123,9 @@ void usage() printf(" -explore enumerate all tasks and dylibs\n"); printf("\noptions:\n"); printf(" -pretty json output is 'pretty-printed'\n"); + printf(" -pid [pid] just scan/explore the specified task'\n"); printf(" -skipVT do not query VirusTotal (when '-explore' is specified)\n"); - printf(" -full for each task; include dylibs, files, & network connections\n\n"); + printf(" -detailed for each task; include dylibs, files, & network connections\n\n"); return; } @@ -123,6 +133,9 @@ void usage() //perform a cmdline enumeration of all things void cmdlineExplore() { + //args + NSArray* arguments = nil; + //filter obj Filter* filter = nil; @@ -141,6 +154,16 @@ void cmdlineExplore() //output NSMutableString* output = nil; + //formatter + NSNumberFormatter* formatter = nil; + + //pid + // if single task was specified + NSNumber* pid = nil; + + //grab args + arguments = [[NSProcessInfo processInfo] arguments]; + //init filter obj filter = [[Filter alloc] init]; @@ -149,7 +172,7 @@ void cmdlineExplore() //set flag // skip virus total? - skipVirusTotal = [[[NSProcessInfo processInfo] arguments] containsObject:@"-skipVT"]; + skipVirusTotal = [arguments containsObject:@"-skipVT"]; //virus total? if(YES != skipVirusTotal) @@ -161,8 +184,22 @@ void cmdlineExplore() //be nice nice(15); + //scan just one pid? + if( (YES == [arguments containsObject:@"-pid"]) && + (YES != [@"-pid" isEqualToString:arguments.lastObject]) ) + { + //init formatter + formatter = [[NSNumberFormatter alloc] init]; + + //set style + formatter.numberStyle = NSNumberFormatterDecimalStyle; + + //extract/convert pid + pid = [formatter numberFromString:arguments[[arguments indexOfObject:@"-pid"] + 1]]; + } + //enumerate all tasks/dylibs/files/etc - [taskEnumerator enumerateTasks]; + [taskEnumerator enumerateTasks:pid]; //wait for items to complete processing while(taskEnumerator.binaryQueue.itemsOut != taskEnumerator.binaryQueue.itemsOut) @@ -172,7 +209,7 @@ void cmdlineExplore() } //determine what each dylib is loaded in - // do here as all tasks and all dylibs are enum'd + // do here as all tasks and all dylibs are (now) enum'd for(NSString* dylib in taskEnumerator.dylibs) { //loaded in @@ -189,21 +226,21 @@ void cmdlineExplore() //set flag // include apple items? - includeApple = [[[NSProcessInfo processInfo] arguments] containsObject:@"-apple"]; + includeApple = [arguments containsObject:@"-apple"]; //set flag // pretty print json? - prettyPrint = [[[NSProcessInfo processInfo] arguments] containsObject:@"-pretty"]; + prettyPrint = [arguments containsObject:@"-pretty"]; //set flag // full output? - detailed = [[[NSProcessInfo processInfo] arguments] containsObject:@"-detailed"]; + detailed = [arguments containsObject:@"-detailed"]; //alloc output JSON output = [NSMutableString string]; //only flagged items? - if(YES == [[[NSProcessInfo processInfo] arguments] containsObject:@"-scan"]) + if(YES == [arguments containsObject:@"-scan"]) { //start JSON [output appendString:@"{\"flagged items\":["]; @@ -225,6 +262,7 @@ void cmdlineExplore() [output appendString:@"]}"]; } + //all items else { //start JSON @@ -234,8 +272,10 @@ void cmdlineExplore() for(NSNumber* taskPid in taskEnumerator.tasks) { //skip apple? + // unless we're scanning a single proc if( (YES != includeApple) && - (YES == [filter isApple:((Task*)taskEnumerator.tasks[taskPid]).binary]) ) + (1 != taskEnumerator.tasks.count) && + (YES == [filter isApple:((Task*)taskEnumerator.tasks[taskPid]).binary]) ) { //skip continue; @@ -252,9 +292,10 @@ void cmdlineExplore() [output deleteCharactersInRange:NSMakeRange([output length]-1, 1)]; } - //not detailed? - // add separate array of dylibs - if(YES != detailed) + //not detailed or not just scanning 1 task + // add separate array of for all the dylibs + if( (YES != detailed) && + (1 != taskEnumerator.tasks.count) ) { //append [output appendString:@"],\"dylibs\":["]; diff --git a/patrons.txt b/patrons.txt index 31f7c85..e28a351 100644 --- a/patrons.txt +++ b/patrons.txt @@ -1,5 +1,5 @@ Patrons (2^6+): -Halo Privacy, Ash Morgan, Nando Mendonca, Geoffrey Weber, Randy Wong, Aaron Kiemele, Beau Galbraith, Stuart Ashenbrenner, Gamer_Bot +Halo Privacy, Ash Morgan, Nando Mendonca, Geoffrey Weber, Randy Wong, Aaron Kiemele, Beau Galbraith, Stuart Ashenbrenner, whiskerz, Gamer_Bot Friends of Objective-See: Digita Security, Sophos, Malwarebytes, SmugMug, Guardian Mobile Firewall, SecureMac diff --git a/remoteTaskService/Info.plist b/remoteTaskService/Info.plist index 72f8bbc..cc428a9 100644 --- a/remoteTaskService/Info.plist +++ b/remoteTaskService/Info.plist @@ -23,7 +23,7 @@ CFBundleVersion 2.0.0 NSHumanReadableCopyright - Copyright © 2018 Objective-See, LLC. All rights reserved. + Copyright © 2019 Objective-See, LLC. All rights reserved. XPCService ServiceType diff --git a/remoteTaskService/remoteTaskService.entitlements b/remoteTaskService/remoteTaskService.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/remoteTaskService/remoteTaskService.entitlements @@ -0,0 +1,5 @@ + + + + +