├── .gitignore ├── 3rdParty ├── HyperlinkTextField.h ├── HyperlinkTextField.m ├── RFOverlayScrollView.h ├── RFOverlayScrollView.m ├── RFOverlayScroller.h └── RFOverlayScroller.m ├── AboutWindowController.h ├── AboutWindowController.m ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets ├── AppIcon.appiconset │ ├── Contents.json │ ├── icon_128x128.png │ ├── icon_128x128@2x.png │ ├── icon_16x16.png │ ├── icon_16x16@2x.png │ ├── icon_256x256.png │ ├── icon_256x256@2x.png │ ├── icon_32x32.png │ ├── icon_32x32@2x.png │ ├── icon_512x512.png │ └── icon_512x512@2x.png ├── Compare.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── CompareAlternate.imageset │ ├── Contents.json │ └── compare.png ├── Contents.json ├── Friends1Password.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsHuntress.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsJamf.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsKandji.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsKolide.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsMacPaw.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsMalwarebytes.imageset │ ├── Contents.json │ └── malwarebytes.png ├── FriendsMosyle.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsPANW.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsSophos.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── FriendsiVerify.imageset │ ├── Contents.json │ └── iVerify.png ├── Preferences.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── PreferencesAlternate.imageset │ ├── Contents.json │ └── preferences.png ├── Save.imageset │ ├── darkMode.png │ └── lightMode.png ├── SaveAlternate.imageset │ ├── Contents.json │ └── save.png └── save.imageset │ └── Contents.json ├── Base.lproj └── MainMenu.xib ├── CategoryTableController.h ├── CategoryTableController.m ├── ClickableTextField.h ├── ClickableTextField.m ├── Consts.h ├── DiffWindowController.h ├── DiffWindowController.m ├── English.lproj └── MainMenu.xib ├── Filter.h ├── Filter.m ├── InfoWindowController.h ├── InfoWindowController.m ├── ItemEnumerator.h ├── ItemEnumerator.m ├── ItemTableController.h ├── ItemTableController.m ├── KKRow.h ├── KKRow.m ├── KnockKnock-Info.plist ├── KnockKnock-Prefix.pch ├── KnockKnock.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ ├── KnockKnock.xccheckout │ │ └── KnockKnock.xcscmblueprint │ └── xcuserdata │ │ └── patrick.xcuserdatad │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ ├── patrick.xcuserdatad │ └── xcschemes │ │ └── xcschememanagement.plist │ └── patrickw.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── LICENSE ├── Libraries ├── BTM │ ├── dumpBTM.h │ └── libDumpBTM.a └── MachO │ ├── MachO.h │ └── MachO.m ├── Localizable.xcstrings ├── NSApplicationKeyEvents.h ├── NSApplicationKeyEvents.m ├── PlistWindowController.h ├── PlistWindowController.m ├── Plugins ├── AuthorizationPlugins.h ├── AuthorizationPlugins.m ├── BTM.h ├── BTM.m ├── BrowserExtensions.h ├── BrowserExtensions.m ├── Cronjobs.h ├── Cronjobs.m ├── DirectoryServicesPlugins.h ├── DirectoryServicesPlugins.m ├── DockTiles.h ├── DockTiles.m ├── DylibInserts.h ├── DylibInserts.m ├── DylibProxies.h ├── DylibProxies.m ├── EventRules.h ├── EventRules.m ├── Extensions.h ├── Extensions.m ├── Kexts.h ├── Kexts.m ├── LaunchItems.h ├── LaunchItems.m ├── LogInOutHooks.h ├── LogInOutHooks.m ├── LoginItems.h ├── LoginItems.m ├── PeriodicScrips.h ├── PeriodicScrips.m ├── PluginBase.h ├── PluginBase.m ├── QuicklookPlugins.h ├── QuicklookPlugins.m ├── SpotlightImporters.h ├── SpotlightImporters.m ├── StartupScripts.h ├── StartupScripts.m ├── SystemExtensions.h └── SystemExtensions.m ├── PrefsWindowController.h ├── PrefsWindowController.m ├── README.md ├── Results ├── Command.h ├── Command.m ├── Extension.h ├── Extension.m ├── File.h ├── File.m ├── ItemBase.h └── ItemBase.m ├── ResultsWindowController.h ├── ResultsWindowController.m ├── Signing.h ├── Signing.m ├── UI ├── Base.lproj │ ├── AboutWindow.xib │ ├── DiffWindow.xib │ ├── ExtensionInfoWindow.xib │ ├── FileInfoWindow.xib │ ├── PlistWindow.xib │ ├── PrefsWindow.xib │ ├── ResultsWindow.xib │ ├── UnknownItems.xib │ ├── UpdateWindow.xib │ └── VTInfoWindow.xib ├── en.lproj │ ├── DiffWindow.strings │ └── UnknownItems.strings ├── es.lproj │ └── UnknownItems.strings └── mul.lproj │ ├── AboutWindow.xcstrings │ ├── DiffWindow.xcstrings │ ├── ExtensionInfoWindow.xcstrings │ ├── FileInfoWindow.xcstrings │ ├── PlistWindow.xcstrings │ ├── PrefsWindow.xcstrings │ ├── ResultsWindow.xcstrings │ ├── UnknownItems.xcstrings │ ├── UpdateWindow.xcstrings │ └── VTInfoWindow.xcstrings ├── UnknownItemsWindowController.h ├── UnknownItemsWindowController.m ├── Update.h ├── Update.m ├── UpdateWindowController.h ├── UpdateWindowController.m ├── Utilities.h ├── Utilities.m ├── VTButton.h ├── VTButton.m ├── VTInfoWindowController.h ├── VTInfoWindowController.m ├── VirusTotal.h ├── VirusTotal.m ├── WhiteList ├── whitelistedCommands.json ├── whitelistedExtensions.json ├── whitelistedFiles.json └── whitelistedKexts.json ├── changelog.txt ├── en.lproj └── InfoPlist.strings ├── es.lproj └── KnockKnock-InfoPlist.strings ├── icon.psd ├── images ├── authorizationIcon.png ├── binaryIcon.icns ├── browserIcon.png ├── btmIcon.png ├── bug.png ├── cronIcon.png ├── directoryServicesIcon.png ├── dockTileIcon.png ├── dylibIcon.png ├── eventRulesIcon.png ├── extensionIcon.png ├── info.png ├── infoBG.png ├── infoOver.png ├── kernelIcon.png ├── kkIcon.png ├── kkText.ai ├── kkText.png ├── launchIcon.png ├── logInOutIcon.png ├── loginIcon.png ├── logo.png ├── logoApple.png ├── logoAppleBG.png ├── logoAppleOver.png ├── mainIcon.png ├── periodicIcon.png ├── proxyIcon.png ├── quicklookIcon.png ├── scanIcon.png ├── settings.png ├── settingsBG.png ├── settingsOver.png ├── show.png ├── showBG.png ├── showOver.png ├── signed.png ├── signedAppleIcon.png ├── spotlightIcon.png ├── startScan.png ├── startScanBG.png ├── startScanOver.png ├── startupScriptsIcon.png ├── stopScan.png ├── stopScanBG.png ├── stopScanOver.png ├── systemExtensionIcon.png ├── unknown.png ├── unsigned.png ├── virus.png ├── virusTotal.png ├── virusTotalBG.png └── vtLogo.png ├── main.h ├── main.m ├── mul.lproj ├── DiffWindow.xcstrings └── MainMenu.xcstrings └── patrons.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.xcscheme 2 | *.xcuserstate 3 | KnockKnock.xcodeproj/xcuserdata/* 4 | Carthage/Build 5 | Carthage/Checkouts 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /3rdParty/HyperlinkTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // HyperlinkTextField.h 3 | // NSTextFieldHyperlinks 4 | // 5 | // Created by Toomas Vahter on 25.12.12. 6 | // Copyright (c) 2012 Toomas Vahter. All rights reserved. 7 | // 8 | // This content is released under the MIT License (http://www.opensource.org/licenses/mit-license.php). 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | // THE SOFTWARE. 27 | 28 | #import 29 | 30 | @interface HyperlinkTextField : NSTextField 31 | @end 32 | -------------------------------------------------------------------------------- /3rdParty/RFOverlayScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // RFOverlayScrollView.h 3 | // RFOverlayScrollView 4 | // 5 | // Created by Tim Brückmann on 31.12.12. 6 | // Copyright (c) 2012 Rheinfabrik. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RFOverlayScrollView : NSScrollView 12 | 13 | @property (nonatomic, assign) NSInteger headerOffset; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /3rdParty/RFOverlayScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // RFOverlayScrollView.m 3 | // RFOverlayScrollView 4 | // 5 | // Created by Tim Brückmann on 31.12.12. 6 | // Copyright (c) 2012 Rheinfabrik. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RFOverlayScrollView.h" 11 | #import "RFOverlayScroller.h" 12 | 13 | @implementation RFOverlayScrollView 14 | 15 | static NSComparisonResult scrollerAboveSiblingViewsComparator(NSView *view1, NSView *view2, void *context) 16 | { 17 | if ([view1 isKindOfClass:[RFOverlayScroller class]]) { 18 | return NSOrderedDescending; 19 | } else if ([view2 isKindOfClass:[RFOverlayScroller class]]) { 20 | return NSOrderedAscending; 21 | } 22 | 23 | return NSOrderedSame; 24 | } 25 | 26 | - (id)initWithFrame:(NSRect)frameRect 27 | { 28 | self = [super initWithFrame:frameRect]; 29 | if (self) { 30 | self.wantsLayer = YES; 31 | _headerOffset = [self tableHeaderOffsetFromSuperview]; 32 | } 33 | return self; 34 | } 35 | 36 | - (void)awakeFromNib 37 | { 38 | self.wantsLayer = YES; 39 | _headerOffset = [self tableHeaderOffsetFromSuperview]; 40 | } 41 | 42 | - (void)tile 43 | { 44 | // Fake zero scroller width so the contentView gets drawn to the edge 45 | method_exchangeImplementations(class_getClassMethod([RFOverlayScroller class], @selector(scrollerWidthForControlSize:scrollerStyle:)), 46 | class_getClassMethod([RFOverlayScroller class], @selector(zeroWidth))); 47 | [super tile]; 48 | // Restore original scroller width 49 | method_exchangeImplementations(class_getClassMethod([RFOverlayScroller class], @selector(scrollerWidthForControlSize:scrollerStyle:)), 50 | class_getClassMethod([RFOverlayScroller class], @selector(zeroWidth))); 51 | 52 | // Resize vertical scroller 53 | CGFloat width = [RFOverlayScroller scrollerWidthForControlSize:self.verticalScroller.controlSize 54 | scrollerStyle:self.verticalScroller.scrollerStyle]; 55 | [self.verticalScroller setFrame:(NSRect){ 56 | self.bounds.size.width - width, 57 | self.headerOffset, 58 | width, 59 | self.bounds.size.height - self.headerOffset 60 | }]; 61 | 62 | // Move scroller to front 63 | [self sortSubviewsUsingFunction:scrollerAboveSiblingViewsComparator 64 | context:NULL]; 65 | } 66 | 67 | - (NSInteger)tableHeaderOffsetFromSuperview 68 | { 69 | for (NSView *subView in [self subviews]) 70 | { 71 | if ([subView isKindOfClass:[NSClipView class]]) 72 | { for (NSView *subView2 in [subView subviews]) 73 | { if ([subView2 isKindOfClass:[NSTableView class]]) 74 | { 75 | return [(NSTableView *)subView2 headerView].frame.size.height; 76 | } 77 | } 78 | } 79 | } 80 | return 0; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /3rdParty/RFOverlayScroller.h: -------------------------------------------------------------------------------- 1 | // 2 | // RFTransparentScroller.h 3 | // RFOverlayScrollView 4 | // 5 | // Created by Tim Brückmann on 30.12.12. 6 | // Copyright (c) 2012 Rheinfabrik. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RFOverlayScroller : NSScroller 12 | 13 | + (CGFloat)zeroWidth; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /3rdParty/RFOverlayScroller.m: -------------------------------------------------------------------------------- 1 | // 2 | // RFTransparentScroller.m 3 | // RFOverlayScrollView 4 | // 5 | // Created by Tim Brückmann on 30.12.12. 6 | // Copyright (c) 2012 Rheinfabrik. All rights reserved. 7 | // 8 | 9 | #import "RFOverlayScroller.h" 10 | 11 | @implementation RFOverlayScroller 12 | 13 | - (id)initWithFrame:(NSRect)frameRect 14 | { 15 | self = [super initWithFrame:frameRect]; 16 | if (self == nil) { 17 | return nil; 18 | } 19 | [self commonInitializer]; 20 | return self; 21 | } 22 | 23 | - (void)awakeFromNib 24 | { 25 | [super awakeFromNib]; 26 | [self commonInitializer]; 27 | } 28 | 29 | - (void)commonInitializer 30 | { 31 | NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds 32 | options:( 33 | NSTrackingMouseEnteredAndExited 34 | | NSTrackingActiveInActiveApp 35 | | NSTrackingMouseMoved 36 | ) 37 | owner:self 38 | userInfo:nil]; 39 | [self addTrackingArea:trackingArea]; 40 | } 41 | 42 | - (void)drawRect:(NSRect)dirtyRect 43 | { 44 | // Only draw the knob. drawRect: should only be invoked when overlay scrollers are not used 45 | [self drawKnob]; 46 | } 47 | 48 | - (void)drawKnobSlotInRect:(NSRect)slotRect highlight:(BOOL)flag 49 | { 50 | // Don't draw the background. Should only be invoked when using overlay scrollers 51 | } 52 | 53 | - (void)setFloatValue:(float)aFloat 54 | { 55 | [super setFloatValue:aFloat]; 56 | [self.animator setAlphaValue:1.0f]; 57 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fadeOut) object:nil]; 58 | [self performSelector:@selector(fadeOut) withObject:nil afterDelay:1.5f]; 59 | } 60 | 61 | - (void)mouseExited:(NSEvent *)theEvent 62 | { 63 | [super mouseExited:theEvent]; 64 | [self fadeOut]; 65 | } 66 | 67 | - (void)mouseEntered:(NSEvent *)theEvent 68 | { 69 | [super mouseEntered:theEvent]; 70 | [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) { 71 | context.duration = 0.1f; 72 | [self.animator setAlphaValue:1.0f]; 73 | } completionHandler:^{ 74 | }]; 75 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fadeOut) object:nil]; 76 | } 77 | 78 | - (void)mouseMoved:(NSEvent *)theEvent 79 | { 80 | [super mouseMoved:theEvent]; 81 | self.alphaValue = 1.0f; 82 | } 83 | 84 | - (void)fadeOut 85 | { 86 | [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) { 87 | context.duration = 0.3f; 88 | [self.animator setAlphaValue:0.0f]; 89 | } completionHandler:^{ 90 | }]; 91 | } 92 | 93 | + (BOOL)isCompatibleWithOverlayScrollers 94 | { 95 | return self == [RFOverlayScroller class]; 96 | } 97 | 98 | + (CGFloat)zeroWidth 99 | { 100 | return 0.0f; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /AboutWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: AboutWindowController.h 3 | // project: KnockKnock 4 | // description: about window display/controller (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface AboutWindowController : NSWindowController 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | 19 | //version label/string 20 | @property (weak, atomic) IBOutlet NSTextField *versionLabel; 21 | 22 | //patrons 23 | @property (unsafe_unretained, atomic) IBOutlet NSTextView *patrons; 24 | 25 | //'support us' button 26 | @property (weak, atomic) IBOutlet NSButton *supportUs; 27 | 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /AboutWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: AboutWindowController.m 3 | // project: KnockKnock 4 | // description: about window display/controller 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "Consts.h" 11 | #import "Utilities.h" 12 | #import "AboutWindowController.h" 13 | 14 | @implementation AboutWindowController 15 | 16 | @synthesize patrons; 17 | @synthesize supportUs; 18 | @synthesize versionLabel; 19 | 20 | //automatically called when nib is loaded 21 | // center window 22 | -(void)awakeFromNib 23 | { 24 | //center 25 | [self.window center]; 26 | } 27 | 28 | //automatically invoked when window is loaded 29 | // set to white 30 | -(void)windowDidLoad 31 | { 32 | //super 33 | [super windowDidLoad]; 34 | 35 | //not in dark mode? 36 | // make window white 37 | if(YES != isDarkMode()) 38 | { 39 | //make white 40 | self.window.backgroundColor = NSColor.whiteColor; 41 | } 42 | 43 | //set version sting 44 | self.versionLabel.stringValue = [NSString stringWithFormat:@"Version: %@", getAppVersion()]; 45 | 46 | //load patrons 47 | self.patrons.string = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"patrons" ofType:@"txt"] encoding:NSUTF8StringEncoding error:NULL]; 48 | 49 | //make 'support us' default 50 | [self.supportUs setKeyEquivalent:@"\r"]; 51 | 52 | //make first responder 53 | // calling this without a timeout sometimes fails :/ 54 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{ 55 | 56 | //and make it first responder 57 | [self.window makeFirstResponder:self.supportUs]; 58 | 59 | }); 60 | 61 | return; 62 | } 63 | 64 | //automatically invoked when window is closing 65 | // make ourselves unmodal 66 | -(void)windowWillClose:(NSNotification *)notification 67 | { 68 | #pragma unused(notification) 69 | 70 | //make un-modal 71 | [[NSApplication sharedApplication] stopModal]; 72 | 73 | return; 74 | } 75 | 76 | //automatically invoked when user clicks any of the buttons 77 | // load patreon or products webpage in user's default browser 78 | -(IBAction)buttonHandler:(id)sender 79 | { 80 | //support us button 81 | if(((NSButton*)sender).tag == BUTTON_SUPPORT_US) 82 | { 83 | //open URL 84 | // invokes user's default browser 85 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]]; 86 | } 87 | 88 | //more info button 89 | else if(((NSButton*)sender).tag == BUTTON_MORE_INFO) 90 | { 91 | //open URL 92 | // invokes user's default browser 93 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]]; 94 | } 95 | 96 | return; 97 | } 98 | @end 99 | -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /Assets.xcassets/Compare.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/Compare.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/Compare.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/Compare.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/Compare.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/CompareAlternate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "compare.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Assets.xcassets/CompareAlternate.imageset/compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/CompareAlternate.imageset/compare.png -------------------------------------------------------------------------------- /Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Assets.xcassets/Friends1Password.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/Friends1Password.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/Friends1Password.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/Friends1Password.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/Friends1Password.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsHuntress.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsHuntress.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsHuntress.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsHuntress.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsHuntress.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsJamf.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsJamf.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsJamf.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsJamf.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsJamf.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsKandji.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsKandji.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsKandji.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsKandji.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsKandji.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsKolide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsKolide.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsKolide.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsKolide.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsKolide.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsMacPaw.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsMacPaw.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsMacPaw.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsMacPaw.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsMacPaw.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsMalwarebytes.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "malwarebytes.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytes.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsMosyle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsMosyle.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsMosyle.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsMosyle.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsMosyle.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsPANW.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsPANW.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsPANW.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsPANW.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsPANW.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsSophos.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsSophos.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsSophos.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsSophos.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsSophos.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/FriendsiVerify.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "iVerify.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Assets.xcassets/FriendsiVerify.imageset/iVerify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/FriendsiVerify.imageset/iVerify.png -------------------------------------------------------------------------------- /Assets.xcassets/Preferences.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Assets.xcassets/Preferences.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/Preferences.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/Preferences.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/Preferences.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/PreferencesAlternate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "preferences.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Assets.xcassets/PreferencesAlternate.imageset/preferences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/PreferencesAlternate.imageset/preferences.png -------------------------------------------------------------------------------- /Assets.xcassets/Save.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/Save.imageset/darkMode.png -------------------------------------------------------------------------------- /Assets.xcassets/Save.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/Save.imageset/lightMode.png -------------------------------------------------------------------------------- /Assets.xcassets/SaveAlternate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "save.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Assets.xcassets/SaveAlternate.imageset/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Assets.xcassets/SaveAlternate.imageset/save.png -------------------------------------------------------------------------------- /Assets.xcassets/save.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CategoryTableController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CategoryTableController.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/18/15. 6 | // 7 | 8 | #import 9 | 10 | @interface CategoryTableController : NSObject 11 | { 12 | 13 | } 14 | 15 | //array to hold categories 16 | @property (nonatomic, retain)NSMutableArray *tableContents; 17 | 18 | //category table view 19 | @property (weak) IBOutlet NSTableView *categoryTableView; 20 | 21 | //previously selected row 22 | // ->needed since on 'reloadData' events, .selectedRow is -1 ... 23 | @property NSUInteger selectedRow; 24 | 25 | /* METHODS */ 26 | 27 | 28 | //initialize table 29 | // ->set header text, etc 30 | -(void)initTable:(NSMutableArray*)plugins; 31 | 32 | //reload due to toggle of filter options 33 | -(void)customReload; 34 | 35 | //set the color of all labels in a specified row 36 | -(void)setRowColor:(NSTableCellView*)row color:(NSColor*)textColor; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /ClickableTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClickableTextField.h 3 | // WhatsYourSignExt 4 | // 5 | // Created by Patrick Wardle on 12/19/17. 6 | // Copyright (c) 2017 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ClickableTextField : NSTextField 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ClickableTextField.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClickableTextField.m 3 | // WhatsYourSignExt 4 | // 5 | // Created by Patrick Wardle on 12/19/17. 6 | // Copyright (c) 2017 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "ClickableTextField.h" 10 | 11 | @implementation ClickableTextField 12 | 13 | //show mouse as 'hand cursor' 14 | - (void)resetCursorRects 15 | { 16 | //skip if no plist 17 | if(YES == [self.stringValue hasPrefix:@"no plist"]) 18 | { 19 | //bail 20 | goto bail; 21 | } 22 | 23 | //set as 'hand cursor' 24 | [self addCursorRect:[self bounds] cursor:[NSCursor pointingHandCursor]]; 25 | 26 | bail: 27 | 28 | return; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /DiffWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DiffWindowController.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 09/01/24. 6 | // Copyright (c) 2024 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DiffWindowController : NSWindowController 12 | 13 | //differences 14 | @property(nonatomic, retain)NSString* differences; 15 | 16 | //(path to) plist 17 | //@property(nonatomic, retain)NSString* plist; 18 | 19 | //signing info 20 | //@property(nonatomic, retain)NSDictionary* signingInfo; 21 | 22 | //plist contents 23 | @property (unsafe_unretained) IBOutlet NSTextView *contents; 24 | 25 | //plist path 26 | //@property (weak) IBOutlet NSTextField *path; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /DiffWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DiffWindowController.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 09/01/24. 6 | // Copyright (c) 2024 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Consts.h" 10 | #import "DiffWindowController.h" 11 | 12 | @implementation DiffWindowController 13 | 14 | -(void)awakeFromNib 15 | { 16 | //center 17 | [self.window center]; 18 | 19 | return; 20 | } 21 | 22 | //window load 23 | // init UI stuffz 24 | -(void)windowDidLoad 25 | { 26 | //super 27 | [super windowDidLoad]; 28 | 29 | //set path in ui 30 | //self.path.stringValue = self.plist; 31 | 32 | //set inset 33 | self.contents.textContainerInset = NSMakeSize(0, 10); 34 | 35 | //set font 36 | self.contents.font = [NSFont fontWithName:@"Menlo" size:13]; 37 | 38 | //add plist 39 | self.contents.string = self.differences;//[[NSDictionary dictionaryWithContentsOfFile:self.plist] description]; 40 | /* 41 | if(0 == self.contents.string.length) 42 | { 43 | //display error 44 | self.contents.string = [NSString stringWithFormat:NSLocalizedString(@"failed to load contents of %@", @"failed to load contents of %@"), self.plist]; 45 | } 46 | */ 47 | 48 | return; 49 | } 50 | 51 | //close 52 | // end sheet 53 | -(IBAction)close:(id)sender 54 | { 55 | [self.window close]; 56 | 57 | return; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /Filter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Filter.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/21/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | #import "Results/File.h" 9 | #import "Results/Command.h" 10 | #import "Results/Extension.h" 11 | 12 | #import 13 | 14 | @interface Filter : NSObject 15 | { 16 | 17 | } 18 | 19 | //white listed file hashes 20 | @property(nonatomic, retain)NSDictionary* trustedFiles; 21 | 22 | //white listed commands 23 | @property(nonatomic, retain)NSDictionary* knownCommands; 24 | 25 | //white listed extensions 26 | @property(nonatomic, retain)NSDictionary* trustedExtensions; 27 | 28 | //white listed kexts 29 | @property(nonatomic, retain)NSDictionary* trustedKexts; 30 | 31 | /* METHODS */ 32 | 33 | //load a (JSON) white list 34 | // ->file hashes, known commands, etc 35 | -(NSDictionary*)loadWhitelist:(NSString*)fileName; 36 | 37 | //check if a File obj is white listed 38 | -(BOOL)isTrustedFile:(File*)fileObj; 39 | 40 | //check if a Command obj is white listed 41 | -(BOOL)isKnownCommand:(Command*)commandObj; 42 | 43 | //check if a Extension obj is white listed 44 | -(BOOL)isTrustedExtension:(Extension*)extensionObj; 45 | 46 | //check if kext is white listed 47 | -(BOOL)isTrustedKext:(File*)fileObj; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Filter.m: -------------------------------------------------------------------------------- 1 | // 2 | // Filter.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/21/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | #import "Consts.h" 9 | #import "Filter.h" 10 | #import "Utilities.h" 11 | 12 | @implementation Filter 13 | 14 | @synthesize trustedKexts; 15 | @synthesize trustedFiles; 16 | @synthesize knownCommands; 17 | @synthesize trustedExtensions; 18 | 19 | #define SOFTWARE_SIGNING @"Software Signing" 20 | #define APPLE_SIGNING_AUTH @"Apple Code Signing Certification Authority" 21 | #define APPLE_ROOT_CA @"Apple Root CA" 22 | 23 | //init 24 | -(id)init 25 | { 26 | //super 27 | self = [super init]; 28 | if(self) 29 | { 30 | //load known file hashes 31 | self.trustedFiles = [self loadWhitelist:WHITE_LISTED_FILES]; 32 | 33 | //load known commands 34 | self.knownCommands = [self loadWhitelist:WHITE_LISTED_COMMANDS]; 35 | 36 | //load known extensions 37 | self.trustedExtensions = [self loadWhitelist:WHITE_LISTED_EXTENSIONS]; 38 | 39 | //load known kexts 40 | self.trustedKexts = [self loadWhitelist:WHITE_LISTED_KEXTS]; 41 | } 42 | 43 | return self; 44 | } 45 | 46 | 47 | //load a (JSON) white list 48 | // ->file hashes, known commands, etc 49 | -(NSDictionary*)loadWhitelist:(NSString*)fileName 50 | { 51 | //whitelisted data 52 | NSDictionary* whiteList = nil; 53 | 54 | //path 55 | NSString* path = nil; 56 | 57 | //error var 58 | NSError *error = nil; 59 | 60 | //json data 61 | NSData* whiteListJSON = nil; 62 | 63 | //init path 64 | path = [[NSBundle mainBundle] pathForResource:fileName ofType: @"json"]; 65 | 66 | //load whitelist file data 67 | whiteListJSON = [NSData dataWithContentsOfFile:path]; 68 | 69 | //convert JSON into dictionary 70 | whiteList = [NSJSONSerialization JSONObjectWithData:whiteListJSON options:kNilOptions error:&error]; 71 | 72 | return whiteList; 73 | } 74 | 75 | 76 | //check if a File obj is known 77 | // ->whitelisted *or* signed by apple 78 | -(BOOL)isTrustedFile:(File*)file 79 | { 80 | //flag 81 | BOOL isTrusted = NO; 82 | 83 | //known hashes for file name 84 | NSArray* knownHashes = nil; 85 | 86 | //lookup based on name 87 | knownHashes = self.trustedFiles[file.path]; 88 | 89 | //check if hash is known 90 | if( (nil != knownHashes) && 91 | (YES == [knownHashes containsObject:[file.hashes[KEY_HASH_MD5] lowercaseString]]) ) 92 | { 93 | //got match 94 | isTrusted = YES; 95 | 96 | //bail 97 | goto bail; 98 | } 99 | 100 | //if kext 101 | // check if trusted (apple, or 3rd-party, ships with OS) 102 | if( (YES == [file.path hasPrefix:@"/Library/Extensions/"]) || 103 | (YES == [file.path hasPrefix:@"/System/Library/Extensions/"]) ) 104 | { 105 | //check 106 | isTrusted = [self isTrustedKext:file]; 107 | 108 | //bail 109 | goto bail; 110 | } 111 | 112 | //finally, then check if its signed by apple 113 | // note: apple-signed files are always trusted 114 | isTrusted = (Apple == [file.signingInfo[KEY_SIGNATURE_SIGNER] intValue]); 115 | 116 | bail: 117 | 118 | return isTrusted; 119 | } 120 | 121 | //check if a Command obj is whitelisted 122 | -(BOOL)isKnownCommand:(Command*)commandObj 123 | { 124 | //flag 125 | BOOL isKnown = NO; 126 | 127 | return isKnown; 128 | } 129 | 130 | //check if a Extension obj is whitelisted 131 | -(BOOL)isTrustedExtension:(Extension*)extensionObj 132 | { 133 | //flag 134 | BOOL isTrusted = NO; 135 | 136 | //check if extension ID is known/trusted 137 | if(nil != self.trustedExtensions[extensionObj.identifier]) 138 | { 139 | //trusted 140 | isTrusted = YES; 141 | } 142 | 143 | return isTrusted; 144 | } 145 | 146 | //check if a kext obj is known 147 | // whitelisted *or* signed by apple 148 | -(BOOL)isTrustedKext:(File*)file 149 | { 150 | //flag 151 | BOOL isTrusted = NO; 152 | 153 | //(trusted) signing id 154 | // either list of hashes, or dev id 155 | id whitelistInfo = nil; 156 | 157 | //ignore any signing issues 158 | if(noErr != [file.signingInfo[KEY_SIGNATURE_STATUS] intValue]) goto bail; 159 | 160 | //lookup based on name 161 | whitelistInfo = self.trustedKexts[file.path]; 162 | 163 | //dev id? 164 | if( (YES == [((NSArray*)whitelistInfo).firstObject hasPrefix:@"Developer ID Application"]) && 165 | (YES == [[file.signingInfo[KEY_SIGNATURE_AUTHORITIES] lastObject] isEqualToString:@"Apple Root CA"]) ) 166 | { 167 | //check 168 | isTrusted = [whitelistInfo containsObject:[file.signingInfo[KEY_SIGNATURE_AUTHORITIES] firstObject]]; 169 | if(YES == isTrusted) goto bail; 170 | } 171 | //hash 172 | else 173 | { 174 | isTrusted = [whitelistInfo containsObject:[file.hashes[KEY_HASH_MD5] lowercaseString]]; 175 | if(YES == isTrusted) goto bail; 176 | } 177 | 178 | //check for apple signature 179 | // kexts that belong to apple, are trusted 180 | isTrusted = (Apple == [file.signingInfo[KEY_SIGNATURE_SIGNER] intValue]); 181 | 182 | bail: 183 | 184 | return isTrusted; 185 | } 186 | 187 | @end 188 | -------------------------------------------------------------------------------- /InfoWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // InfoWindowController.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/21/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PlistWindowController.h" 12 | 13 | @class ItemBase; 14 | 15 | @interface InfoWindowController : NSWindowController 16 | { 17 | 18 | } 19 | 20 | //properties in window 21 | // ->attributes about the item 22 | @property(weak)IBOutlet NSImageView *icon; 23 | @property(weak)IBOutlet NSTextField *name; 24 | @property(weak)IBOutlet NSTextField *path; 25 | @property(weak)IBOutlet NSTextField *date; 26 | 27 | 28 | //file window specific outlets 29 | @property(weak)IBOutlet NSTextField *hashes; 30 | @property(weak)IBOutlet NSTextField *size; 31 | @property(weak)IBOutlet NSTextField *sign; 32 | 33 | @property (weak) IBOutlet NSTextField *plistLabel; 34 | @property (weak) IBOutlet NSTextField *plist; 35 | 36 | //extension window specific outlets 37 | @property (weak) IBOutlet NSTextField *details; 38 | @property (weak) IBOutlet NSTextField *identifier; 39 | 40 | //window controller 41 | @property(nonatomic, strong)InfoWindowController *windowController; 42 | 43 | //item 44 | @property(nonatomic, retain)ItemBase* itemObj; 45 | 46 | //plist popup controller 47 | @property (strong) PlistWindowController* plistWindowController; 48 | 49 | /* METHODS */ 50 | 51 | //init method 52 | // ->save item and load nib 53 | -(id)initWithItem:(ItemBase*)selectedItem; 54 | 55 | //configure window 56 | // ->add item's attributes (name, path, etc.) 57 | -(void)configure; 58 | 59 | //close button handler 60 | -(IBAction)closeWindow:(id)sender; 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /ItemEnumerator.h: -------------------------------------------------------------------------------- 1 | // 2 | // ItemEnumerator.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 4/24/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ItemEnumerator : NSObject 12 | { 13 | 14 | } 15 | 16 | /* iVars */ 17 | 18 | //'main' enumerator thread 19 | @property(nonatomic, retain)NSThread* enumeratorThread; 20 | 21 | 22 | //launch daemons and agents 23 | @property(nonatomic, retain)NSMutableArray* launchItems; 24 | 25 | //installed apps 26 | @property(nonatomic, retain)NSMutableArray* applications; 27 | 28 | //launch item enumerator thread 29 | @property(nonatomic, retain)NSThread* launchItemsEnumerator; 30 | 31 | //installed applications enumerator thread 32 | @property(nonatomic, retain)NSThread* applicationsEnumerator; 33 | 34 | /* METHODS */ 35 | 36 | //enumerate all 'shared' items 37 | // ->that is to say, items that multiple plugins scan/process 38 | -(void)start; 39 | 40 | //cancel all enumerator threads 41 | -(void)stop; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /ItemEnumerator.m: -------------------------------------------------------------------------------- 1 | // 2 | // ItemEnumerator.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 4/24/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Consts.h" 10 | #import "Utilities.h" 11 | #import "ItemEnumerator.h" 12 | 13 | @implementation ItemEnumerator 14 | 15 | @synthesize launchItems; 16 | @synthesize applications; 17 | @synthesize launchItemsEnumerator; 18 | @synthesize applicationsEnumerator; 19 | 20 | //plugin search directories 21 | NSString * const LAUNCHITEM_SEARCH_DIRECTORIES[] = {@"/System/Library/LaunchDaemons/", @"/Library/LaunchDaemons/", @"/System/Library/LaunchAgents/", @"/Library/LaunchAgents/", @"~/Library/LaunchAgents/"}; 22 | 23 | //enumerate all 'shared' items 24 | // ->that is to say, items that multiple plugins scan/process 25 | -(void)start 26 | { 27 | //save self's thread 28 | self.enumeratorThread = [NSThread currentThread]; 29 | 30 | //alloc/init thread to enumerate launch items 31 | launchItemsEnumerator = [[NSThread alloc] initWithTarget:self selector:@selector(enumerateLaunchItems) object:nil]; 32 | 33 | //alloc/init thread to enumerate installed applications 34 | applicationsEnumerator = [[NSThread alloc] initWithTarget:self selector:@selector(enumerateApplications) object:nil]; 35 | 36 | //start launch item enumerator thread 37 | [self.launchItemsEnumerator start]; 38 | 39 | //start installed application enumerator thread 40 | [self.applicationsEnumerator start]; 41 | 42 | return; 43 | } 44 | 45 | //cancel all enumerator threads 46 | -(void)stop 47 | { 48 | //cancel launch item enumerator thread 49 | if(YES == [self.launchItemsEnumerator isExecuting]) 50 | { 51 | //cancel 52 | [self.launchItemsEnumerator cancel]; 53 | } 54 | 55 | //cancel installed application enumerator thread 56 | if(YES == [self.applicationsEnumerator isExecuting]) 57 | { 58 | //cancel 59 | [self.applicationsEnumerator cancel]; 60 | } 61 | 62 | //set launch items array to nil 63 | self.launchItems = nil; 64 | 65 | //set installed app array to nil 66 | self.applications = nil; 67 | 68 | return; 69 | } 70 | 71 | //generate list of all launch items (daemons & agents) 72 | -(void)enumerateLaunchItems 73 | { 74 | //all launch items 75 | NSMutableArray* allLaunchItems = nil; 76 | 77 | //all launch item directories, expanded 78 | NSMutableArray* launchItemDirectories = nil; 79 | 80 | //alloc array for all launch items 81 | allLaunchItems = [NSMutableArray array]; 82 | 83 | //expand list 84 | launchItemDirectories = expandPaths(LAUNCHITEM_SEARCH_DIRECTORIES, sizeof(LAUNCHITEM_SEARCH_DIRECTORIES)/sizeof(LAUNCHITEM_SEARCH_DIRECTORIES[0])); 85 | 86 | //iterate over all launch item direcoties 87 | // grab all .plists and add to cumulative array 88 | for(NSString* launchItemDirectory in launchItemDirectories) 89 | { 90 | //grab all plist 91 | for(NSString* plist in directoryContents(launchItemDirectory, @"self ENDSWITH '.plist'")) 92 | { 93 | //build full path to item/plist and save 94 | [allLaunchItems addObject:[launchItemDirectory stringByAppendingPathComponent:plist]]; 95 | } 96 | } 97 | 98 | //save into iVar 99 | self.launchItems = allLaunchItems; 100 | 101 | return; 102 | } 103 | 104 | 105 | //generate list of all installed applications 106 | // ->save into iVar, 'applications' 107 | -(void)enumerateApplications 108 | { 109 | //output from system profiler task 110 | NSData* taskOutput = nil; 111 | 112 | //serialized task output 113 | NSArray* serializedOutput = nil; 114 | 115 | //exec system profiler 116 | taskOutput = execTask(SYSTEM_PROFILER, @[@"SPApplicationsDataType", @"-xml", @"-detailLevel", @"mini"], NULL); 117 | if( (nil == taskOutput) || 118 | (0 == taskOutput.length) ) 119 | { 120 | //bail 121 | goto bail; 122 | } 123 | 124 | //serialize output to array 125 | serializedOutput = [NSPropertyListSerialization propertyListWithData:taskOutput options:kNilOptions format:NULL error:NULL]; 126 | 127 | //grab list of installed apps from '_items' key 128 | // ->save into iVar 'applications' 129 | @try 130 | { 131 | //save 132 | self.applications = serializedOutput[0][@"_items"]; 133 | } 134 | @catch (NSException *exception) 135 | { 136 | //err msg 137 | //NSLog(@"ERROR: serialized output not formatted as expected"); 138 | 139 | //bail 140 | goto bail; 141 | } 142 | 143 | //bail 144 | bail: 145 | 146 | return; 147 | } 148 | 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /ItemTableController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ItemTableController.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/18/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "InfoWindowController.h" 10 | #import "VTInfoWindowController.h" 11 | 12 | #import 13 | 14 | @interface ItemTableController : NSObject 15 | { 16 | 17 | } 18 | 19 | //category table view 20 | @property(weak) IBOutlet NSTableView *itemTableView; 21 | 22 | //info window 23 | @property(retain, nonatomic)InfoWindowController* infoWindowController; 24 | 25 | //preferences window controller 26 | @property (nonatomic, retain)VTInfoWindowController* vtWindowController; 27 | 28 | //no items label 29 | @property (nonatomic, retain) IBOutlet NSTextField *noItemsLabel; 30 | 31 | /* METHODS */ 32 | 33 | //button handler 34 | // ->show item in finder 35 | - (IBAction)showInFinder:(id)sender; 36 | 37 | //button handler 38 | // ->show info window 39 | - (IBAction)showInfo:(id)sender; 40 | 41 | //button handler 42 | // ->show virus total info window 43 | -(void)showVTInfo:(NSView*)button; 44 | 45 | //scroll back up to top of table 46 | -(void)scrollToTop; 47 | 48 | //helper function 49 | // ->get items array (either all or just unknown) 50 | -(NSArray*)getTableItems; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /KKRow.h: -------------------------------------------------------------------------------- 1 | // 2 | // CategoryRow.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 4/4/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KKRow : NSTableRowView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /KKRow.m: -------------------------------------------------------------------------------- 1 | // 2 | // CategoryRow.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 4/4/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "KKRow.h" 10 | #import "Utilities.h" 11 | 12 | @implementation KKRow 13 | 14 | //custom row selection 15 | -(void)drawSelectionInRect:(NSRect)dirtyRect 16 | { 17 | //selection rect 18 | NSRect selectionRect = {0}; 19 | 20 | //selection path 21 | NSBezierPath *selectionPath = nil; 22 | 23 | //highlight selected rows 24 | if(self.selectionHighlightStyle != NSTableViewSelectionHighlightStyleNone) 25 | { 26 | //make selection rect 27 | selectionRect = NSInsetRect(self.bounds, 10.0, 1.0); 28 | 29 | //dark mode highlight 30 | if(YES == isDarkMode()) 31 | { 32 | //set stroke 33 | [[NSColor colorWithCalibratedWhite:.25 alpha:1.0] setStroke]; 34 | 35 | //set fill 36 | [[NSColor colorWithCalibratedWhite:.50 alpha:1.0] setFill]; 37 | } 38 | //light mode highlight 39 | else 40 | { 41 | //set stroke 42 | [[NSColor colorWithCalibratedWhite:.65 alpha:1.0] setStroke]; 43 | 44 | //set fill 45 | [[NSColor colorWithCalibratedWhite:.82 alpha:1.0] setFill]; 46 | } 47 | 48 | //create selection path 49 | // ...with rounded corners 50 | selectionPath = [NSBezierPath bezierPathWithRoundedRect:selectionRect xRadius:5 yRadius:5]; 51 | 52 | //fill 53 | [selectionPath fill]; 54 | 55 | //stroke 56 | [selectionPath stroke]; 57 | } 58 | 59 | return; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /KnockKnock-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | icon 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2025 Objective-See, LLC. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplicationKeyEvents 33 | 34 | 35 | -------------------------------------------------------------------------------- /KnockKnock-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'KnockKnock' target in the 'KnockKnock' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /KnockKnock.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /KnockKnock.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /KnockKnock.xcodeproj/project.xcworkspace/xcshareddata/KnockKnock.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 1ECDBF86-1DFC-4002-A5BE-41FC31ACB68B 9 | IDESourceControlProjectName 10 | KnockKnock 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 7564E3FECD3AE625755C217749E31B3EE2B69E20 14 | https://bitbucket.org/objective-see/macho.git 15 | A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D 16 | https://bitbucket.org/objective-see/knockknock.git 17 | 18 | IDESourceControlProjectPath 19 | KnockKnock.xcodeproj 20 | IDESourceControlProjectRelativeInstallPathDictionary 21 | 22 | 7564E3FECD3AE625755C217749E31B3EE2B69E20 23 | ../../../MachO 24 | A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D 25 | ../.. 26 | 27 | IDESourceControlProjectURL 28 | https://bitbucket.org/objective-see/knockknock.git 29 | IDESourceControlProjectVersion 30 | 111 31 | IDESourceControlProjectWCCIdentifier 32 | A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D 33 | IDESourceControlProjectWCConfigurations 34 | 35 | 36 | IDESourceControlRepositoryExtensionIdentifierKey 37 | public.vcs.git 38 | IDESourceControlWCCIdentifierKey 39 | A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D 40 | IDESourceControlWCCName 41 | KnockKnock 42 | 43 | 44 | IDESourceControlRepositoryExtensionIdentifierKey 45 | public.vcs.git 46 | IDESourceControlWCCIdentifierKey 47 | 7564E3FECD3AE625755C217749E31B3EE2B69E20 48 | IDESourceControlWCCName 49 | MachO 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /KnockKnock.xcodeproj/project.xcworkspace/xcshareddata/KnockKnock.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D" : 0, 8 | "7564E3FECD3AE625755C217749E31B3EE2B69E20" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "1ECDBF86-1DFC-4002-A5BE-41FC31ACB68B", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D" : "KnockKnock\/", 13 | "7564E3FECD3AE625755C217749E31B3EE2B69E20" : "MachO\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "KnockKnock", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "KnockKnock.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/bitbucket.org\/objective-see\/macho.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "7564E3FECD3AE625755C217749E31B3EE2B69E20" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/bitbucket.org\/objective-see\/knockknock.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /KnockKnock.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /KnockKnock.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | KnockKnock.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | KnockKnock.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 1D21BC4A172AF43D009D1CFD 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /KnockKnock.xcodeproj/xcuserdata/patrickw.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | KnockKnock.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1D21BC4A172AF43D009D1CFD 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Libraries/BTM/dumpBTM.h: -------------------------------------------------------------------------------- 1 | // 2 | // dumpBTM.h 3 | // library 4 | // 5 | // Created by Patrick Wardle on 1/20/23. 6 | // 7 | 8 | @import Foundation; 9 | 10 | //keys for dictionary 11 | #define KEY_BTM_PATH @"path" 12 | #define KEY_BTM_ERROR @"error" 13 | #define KEY_BTM_VERSION @"version" 14 | #define KEY_BTM_ITEMS_BY_USER_ID @"itemsByUserIdentifier" 15 | 16 | //keys for item(s) 17 | #define KEY_BTM_ITEM_UUID @"uuid" 18 | #define KEY_BTM_ITEM_NAME @"name" 19 | #define KEY_BTM_ITEM_DEV_NAME @"devName" 20 | #define KEY_BTM_ITEM_TEAM_ID @"teamID" 21 | #define KEY_BTM_ITEM_TYPE @"type" 22 | #define KEY_BTM_ITEM_TYPE_DETAILS @"typeDetails" 23 | #define KEY_BTM_ITEM_DISPOSITION @"disposition" 24 | #define KEY_BTM_ITEM_DISPOSITION_DETAILS @"dispositionDetails" 25 | #define KEY_BTM_ITEM_ID @"id" 26 | #define KEY_BTM_ITEM_URL @"url" 27 | #define KEY_BTM_ITEM_GENERATION @"generation" 28 | #define KEY_BTM_ITEM_BUNDLE_ID @"bundleID" 29 | #define KEY_BTM_ITEM_ASSOCIATED_IDS @"associatedBundleIDs" 30 | #define KEY_BTM_ITEM_PARENT_ID @"parentID" 31 | #define KEY_BTM_ITEM_EMBEDDED_IDS @"embeddedIDs" 32 | 33 | #define KEY_BTM_ITEM_PLIST_PATH @"plistPath" 34 | #define KEY_BTM_ITEM_EXE_PATH @"executablePath" 35 | 36 | //APIs 37 | // note: path is optional 38 | NSInteger dumpBTM(NSURL* path); 39 | NSDictionary* parseBTM(NSURL* path); 40 | -------------------------------------------------------------------------------- /Libraries/BTM/libDumpBTM.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/Libraries/BTM/libDumpBTM.a -------------------------------------------------------------------------------- /Libraries/MachO/MachO.h: -------------------------------------------------------------------------------- 1 | // 2 | // MachO.h 3 | // MachOParser 4 | // 5 | // Created by Patrick Wardle on 2/6/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /* CONSTS */ 12 | 13 | //dictionary keys 14 | #define KEY_BINARY_PATH @"binaryPath" 15 | #define KEY_MACHO_HEADERS @"machoHeaders" 16 | #define KEY_LOAD_COMMANDS @"loadCommands" 17 | 18 | #define KEY_HEADER_OFFSET @"headerOffset" 19 | #define KEY_HEADER_SIZE @"headerSize" 20 | #define KEY_HEADER_BINARY_TYPE @"headerType" 21 | #define KEY_HEADER_BYTE_ORDER @"headerByteOrder" 22 | #define KEY_IS_PACKED @"isPacked" 23 | #define KEY_IS_ENCRYPTED @"isEncryted" 24 | 25 | #define KEY_LC_RPATHS @"lcRpath" 26 | #define KEY_LC_REEXPORT_DYLIBS @"lcRexports" 27 | #define KEY_LC_LOAD_DYLIBS @"lcLoadDylib" 28 | #define KEY_LC_LOAD_WEAK_DYLIBS @"lcLoadWeakDylib" 29 | 30 | 31 | @interface MachO : NSObject 32 | { 33 | 34 | } 35 | 36 | //info dictionary 37 | // ->contains everything parsed out of the file 38 | @property(nonatomic, retain)NSMutableDictionary* binaryInfo; 39 | 40 | //binary's data 41 | @property(nonatomic, retain)NSData* binaryData; 42 | 43 | //segment names found in various packers 44 | @property(nonatomic, retain)NSSet* packerSegmentNames; 45 | 46 | 47 | /* METHODS */ 48 | 49 | //parse a binary 50 | // ->extract all required/interesting stuff 51 | -(BOOL)parse:(NSString*)binaryPath classify:(BOOL)shouldClassify; 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /NSApplicationKeyEvents.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSApplicationKeyEvents.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/11/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSApplicationKeyEvents : NSApplication 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /NSApplicationKeyEvents.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSApplicationKeyEvents.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/11/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "NSApplicationKeyEvents.h" 10 | 11 | @implementation NSApplicationKeyEvents 12 | 13 | //to enable copy/paste etc even though we don't have an 'Edit' menu 14 | // details: http://stackoverflow.com/questions/970707/cocoa-keyboard-shortcuts-in-dialog-without-an-edit-menu 15 | -(void) sendEvent:(NSEvent *)event { 16 | if ([event type] == NSKeyDown) { 17 | if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask) { 18 | if ([[event charactersIgnoringModifiers] isEqualToString:@"x"]) { 19 | if ([self sendAction:@selector(cut:) to:nil from:self]) 20 | return; 21 | } 22 | else if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) { 23 | if ([self sendAction:@selector(copy:) to:nil from:self]) 24 | return; 25 | } 26 | else if ([[event charactersIgnoringModifiers] isEqualToString:@"v"]) { 27 | if ([self sendAction:@selector(paste:) to:nil from:self]) 28 | return; 29 | } 30 | else if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) { 31 | if ([self sendAction:@selector(selectAll:) to:nil from:self]) 32 | return; 33 | } 34 | 35 | //+h (hide window) 36 | else if([event.charactersIgnoringModifiers isEqualToString:@"h"]) 37 | { 38 | //hide 39 | if(YES == [self sendAction:@selector(hide:) to:nil from:self]) 40 | { 41 | return; 42 | } 43 | } 44 | 45 | //+m (minimize window) 46 | else if([event.charactersIgnoringModifiers isEqualToString:@"m"]) 47 | { 48 | //minimize 49 | [NSApplication.sharedApplication.keyWindow miniaturize:nil]; 50 | return; 51 | } 52 | 53 | //+w (close window) 54 | else if([event.charactersIgnoringModifiers isEqualToString:@"w"]) 55 | { 56 | //close 57 | [NSApplication.sharedApplication.keyWindow close]; 58 | return; 59 | } 60 | } 61 | } 62 | [super sendEvent:event]; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /PlistWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PlistWindowController.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 12/19/17. 6 | // Copyright (c) 2016 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PlistWindowController : NSWindowController 12 | 13 | //(path to) plist 14 | @property(nonatomic, retain)NSString* plist; 15 | 16 | //signing info 17 | @property(nonatomic, retain)NSDictionary* signingInfo; 18 | 19 | //plist contents 20 | @property (unsafe_unretained) IBOutlet NSTextView *contents; 21 | 22 | //plist path 23 | @property (weak) IBOutlet NSTextField *path; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /PlistWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // EntitlementsWindowController.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 12/19/17. 6 | // Copyright (c) 2016 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Consts.h" 10 | #import "PlistWindowController.h" 11 | 12 | 13 | @implementation PlistWindowController 14 | 15 | @synthesize plist; 16 | 17 | //window load 18 | // init UI stuffz 19 | -(void)windowDidLoad 20 | { 21 | //super 22 | [super windowDidLoad]; 23 | 24 | //set path in ui 25 | self.path.stringValue = self.plist; 26 | 27 | //set inset 28 | self.contents.textContainerInset = NSMakeSize(0, 10); 29 | 30 | //set font 31 | self.contents.font = [NSFont fontWithName:@"Menlo" size:13]; 32 | 33 | //add plist 34 | self.contents.string = [[NSDictionary dictionaryWithContentsOfFile:self.plist] description]; 35 | if(0 == self.contents.string.length) 36 | { 37 | //display error 38 | self.contents.string = [NSString stringWithFormat:NSLocalizedString(@"failed to load contents of %@", @"failed to load contents of %@"), self.plist]; 39 | } 40 | 41 | return; 42 | } 43 | 44 | //close 45 | // end sheet 46 | -(IBAction)close:(id)sender 47 | { 48 | //end sheet 49 | [self.window.sheetParent endSheet:self.window returnCode:NSModalResponseOK]; 50 | 51 | return; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Plugins/AuthorizationPlugins.h: -------------------------------------------------------------------------------- 1 | // 2 | // AuthorizationPlugins.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 4/24/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface AuthorizationPlugins : PluginBase 13 | { 14 | 15 | } 16 | 17 | /* (custom) METHODS */ 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Plugins/AuthorizationPlugins.m: -------------------------------------------------------------------------------- 1 | // 2 | // AuthorizationPlugins.m 3 | // KnockKnock 4 | // 5 | // Notes: Authorization, or Authentication plugins can be used to customize logins, 6 | // example app (for testing, etc): http://www.rohos.com/2015/10/installing-rohos-logon-in-mac-os-10-11-el-capitan/ 7 | 8 | #import "File.h" 9 | #import "Utilities.h" 10 | #import "AuthorizationPlugins.h" 11 | 12 | //plugin name 13 | #define PLUGIN_NAME @"Authorization Plugins" 14 | 15 | //plugin description 16 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"registered authorization bundles","registered authorization bundles") 17 | 18 | //plugin icon 19 | #define PLUGIN_ICON @"authorizationIcon" 20 | 21 | //plugin search directories 22 | NSString* const AUTHORIZATION_SEARCH_DIRECTORIES[] = {@"/System/Library/CoreServices/SecurityAgentPlugins", @"/Library/Security/SecurityAgentPlugins/"}; 23 | 24 | 25 | @implementation AuthorizationPlugins 26 | 27 | //init 28 | // ->set name, description, etc 29 | -(id)init 30 | { 31 | //super 32 | self = [super init]; 33 | if(self) 34 | { 35 | //set name 36 | self.name = PLUGIN_NAME; 37 | 38 | //set description 39 | self.description = PLUGIN_DESCRIPTION; 40 | 41 | //set icon 42 | self.icon = PLUGIN_ICON; 43 | } 44 | 45 | return self; 46 | } 47 | 48 | //scan for auth plugins 49 | -(void)scan 50 | { 51 | //all auth plugins 52 | NSArray* allAuthPlugins = nil; 53 | 54 | //path to auth plugin 55 | NSString* authPluginPath = nil; 56 | 57 | //File obj 58 | File* fileObj = nil; 59 | 60 | //iterate over all auth plugin search directories 61 | // get all authorization plugins and process each of them 62 | for(NSString* authPluginDirectory in expandPaths(AUTHORIZATION_SEARCH_DIRECTORIES, sizeof(AUTHORIZATION_SEARCH_DIRECTORIES)/sizeof(AUTHORIZATION_SEARCH_DIRECTORIES[0]))) 63 | { 64 | //get all items in current directory 65 | allAuthPlugins = directoryContents(authPluginDirectory, nil); 66 | 67 | //iterate over all importers 68 | // ->perform some sanity checks and then save 69 | for(NSString* authPlugin in allAuthPlugins) 70 | { 71 | //build full path to plugin 72 | authPluginPath = [NSString stringWithFormat:@"%@/%@", authPluginDirectory, authPlugin]; 73 | 74 | //make sure plugin is a bundle 75 | // ->i.e. not just a random directory 76 | if(YES != [[NSWorkspace sharedWorkspace] isFilePackageAtPath:authPluginPath]) 77 | { 78 | //skip 79 | continue; 80 | } 81 | 82 | //create File object for plugin 83 | fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:authPluginPath}]; 84 | 85 | //skip File objects that err'd out for any reason 86 | if(nil == fileObj) 87 | { 88 | //skip 89 | continue; 90 | } 91 | 92 | //process item 93 | // ->save and report to UI 94 | [super processItem:fileObj]; 95 | } 96 | 97 | }//auth plugin directories 98 | 99 | return; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /Plugins/BTM.h: -------------------------------------------------------------------------------- 1 | // 2 | // BTM.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 6/26/23. 6 | // Copyright (c) 2023 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface BTM : PluginBase 13 | { 14 | 15 | } 16 | 17 | /* (custom) METHODS */ 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Plugins/BTM.m: -------------------------------------------------------------------------------- 1 | // 2 | // BTM.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 6/26/23. 6 | // Copyright (c) 2023 Objective-See. All rights reserved. 7 | 8 | #import "BTM.h" 9 | #import "File.h" 10 | #import "dumpBTM.h" 11 | #import "Utilities.h" 12 | 13 | //plugin name 14 | #define PLUGIN_NAME @"Background Managed Tasks" 15 | 16 | //plugin description 17 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"background agents, daemons, & login items", @"background agents, daemons, & login items") 18 | 19 | //plugin icon 20 | #define PLUGIN_ICON @"btmIcon" 21 | 22 | @implementation BTM 23 | 24 | //init 25 | // set name, description, etc 26 | -(id)init 27 | { 28 | //super 29 | self = [super init]; 30 | if(self) 31 | { 32 | //set name 33 | self.name = PLUGIN_NAME; 34 | 35 | //set description 36 | self.description = PLUGIN_DESCRIPTION; 37 | 38 | //set icon 39 | self.icon = PLUGIN_ICON; 40 | } 41 | 42 | return self; 43 | } 44 | 45 | //scan for btm items 46 | -(void)scan 47 | { 48 | //only available on macOS 13+ 49 | if(@available(macOS 13, *)) 50 | { 51 | //contents 52 | NSDictionary* contents = nil; 53 | 54 | //items 55 | NSMutableDictionary* items = nil; 56 | 57 | //items sorted 58 | NSArray* itemsSorted = nil; 59 | 60 | //paths (for dups) 61 | NSMutableSet* paths = nil; 62 | 63 | //parse BTM db 64 | contents = parseBTM(nil); 65 | if(noErr != [contents[KEY_BTM_ERROR] integerValue]) 66 | { 67 | //error 68 | goto bail; 69 | } 70 | 71 | //init 72 | items = [NSMutableDictionary dictionary]; 73 | 74 | //init 75 | paths = [NSMutableSet set]; 76 | 77 | //iterate over all items 78 | // sorted by each user uuid 79 | for(NSString* uuid in contents[KEY_BTM_ITEMS_BY_USER_ID]) 80 | { 81 | //iterate over each item 82 | for(NSDictionary* item in contents[KEY_BTM_ITEMS_BY_USER_ID][uuid]) 83 | { 84 | //File obj 85 | File* fileObj = nil; 86 | 87 | //params to init file object 88 | NSMutableDictionary* parameters = nil; 89 | 90 | //path 91 | NSString* path = nil; 92 | 93 | //plist 94 | NSString* plist = nil; 95 | 96 | //params 97 | parameters = [NSMutableDictionary dictionary]; 98 | 99 | //ignore any items that have "embeddded item ids" 100 | // these seem to be parents, and not the actual items persisted 101 | if(nil != item[KEY_BTM_ITEM_EMBEDDED_IDS]) 102 | { 103 | //skip 104 | continue; 105 | } 106 | 107 | //executable path 108 | path = item[KEY_BTM_ITEM_EXE_PATH]; 109 | if(nil == path) 110 | { 111 | //no path 112 | // skip item 113 | continue; 114 | } 115 | 116 | //(optional) plist 117 | plist = item[KEY_BTM_ITEM_PLIST_PATH]; 118 | 119 | //init params w/ self 120 | parameters[KEY_RESULT_PLUGIN] = self; 121 | 122 | //init params w/ path 123 | parameters[KEY_RESULT_PATH] = path; 124 | 125 | //got plist? 126 | if(nil != plist) 127 | { 128 | //init params w/ plist 129 | parameters[KEY_RESULT_PLIST] = plist; 130 | } 131 | 132 | //init file obj with params (path, etc) 133 | fileObj = [[File alloc] initWithParams:parameters]; 134 | if(nil == fileObj) 135 | { 136 | //error 137 | // skip item 138 | continue; 139 | } 140 | 141 | //new? 142 | // save 143 | if(YES != [paths containsObject:fileObj.path]) 144 | { 145 | //save path 146 | [paths addObject:fileObj.path]; 147 | 148 | //save 149 | items[item[KEY_BTM_ITEM_UUID]] = fileObj; 150 | } 151 | } 152 | } 153 | 154 | //sort by name 155 | itemsSorted = [[items allValues] sortedArrayUsingComparator:^NSComparisonResult(File* itemOne, File* itemTwo) { 156 | return [itemOne.name compare:itemTwo.name]; 157 | }]; 158 | 159 | //add each to UI 160 | for(File* item in itemsSorted) 161 | { 162 | //process item 163 | // save and report to UI 164 | [super processItem:item]; 165 | } 166 | 167 | bail: 168 | 169 | return; 170 | 171 | }//macOS 13+ 172 | } 173 | 174 | @end 175 | -------------------------------------------------------------------------------- /Plugins/BrowserExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // BrowserExtensions.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | 13 | 14 | @interface BrowserExtensions : PluginBase 15 | { 16 | 17 | } 18 | 19 | /* (custom) METHODS */ 20 | 21 | //get all disabled launch items 22 | // ->specified in various overrides.plist files 23 | -(NSArray*)getInstalledBrowsers; 24 | 25 | //scan for Safari extensions 26 | -(void)scanExtensionsSafari:(NSString*)browserPath; 27 | 28 | //scan for Chrome extensions 29 | -(void)scanExtensionsChrome:(NSString*)browserPath; 30 | 31 | //scan for Firefox extensions 32 | -(void)scanExtensionsFirefox:(NSString*)browserPath; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Plugins/Cronjobs.h: -------------------------------------------------------------------------------- 1 | // 2 | // Cronjobs.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/10/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface CronJobs : PluginBase 13 | { 14 | 15 | } 16 | 17 | /* (custom) METHODS */ 18 | 19 | //determines if a line is really a cronjob 20 | // ->ignores everything that doesn't start with a digit, '*', or '@' 21 | -(BOOL)isJob:(NSString*)possibleJob; 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Plugins/DirectoryServicesPlugins.h: -------------------------------------------------------------------------------- 1 | // 2 | // DirectoryServicesPlugins.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 11/09/19. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PluginBase.h" 11 | #import 12 | 13 | @interface DirectoryServicesPlugins : PluginBase 14 | { 15 | 16 | } 17 | 18 | /* (custom) METHODS */ 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Plugins/DirectoryServicesPlugins.m: -------------------------------------------------------------------------------- 1 | // 2 | // QuicklookPlugins.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 11/09/19. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "File.h" 10 | #import "Utilities.h" 11 | #import "DirectoryServicesPlugins.h" 12 | 13 | //plugin name 14 | #define PLUGIN_NAME @"Dir. Services Plugins" 15 | 16 | //plugin description 17 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"registered directory services bundles", @"registered directory services bundles") 18 | 19 | //plugin icon 20 | #define PLUGIN_ICON @"directoryServicesIcon" 21 | 22 | @implementation DirectoryServicesPlugins 23 | 24 | //plugin search directories 25 | NSString* const DIRECTORY_SERVICES_SEARCH_DIRECTORIES[] = {@"/System/Library/Frameworks/DirectoryService.framework/Versions/A/Resources/Plugins", @"/Library/DirectoryServices/PlugIns"}; 26 | 27 | //init 28 | // ->set name, description, etc 29 | -(id)init 30 | { 31 | //super 32 | self = [super init]; 33 | if(self) 34 | { 35 | //set name 36 | self.name = PLUGIN_NAME; 37 | 38 | //set description 39 | self.description = PLUGIN_DESCRIPTION; 40 | 41 | //set icon 42 | self.icon = PLUGIN_ICON; 43 | } 44 | 45 | return self; 46 | } 47 | 48 | //scan for dir services plugins 49 | -(void)scan 50 | { 51 | //all plugins 52 | NSArray* allPlugins = nil; 53 | 54 | //path to plugin 55 | NSString* pluginPath = nil; 56 | 57 | //File obj 58 | File* fileObj = nil; 59 | 60 | //iterate over all auth plugin search directories 61 | // get all authorization plugins and process each of them 62 | for(NSString* pluginDirectory in expandPaths(DIRECTORY_SERVICES_SEARCH_DIRECTORIES, sizeof(DIRECTORY_SERVICES_SEARCH_DIRECTORIES)/sizeof(DIRECTORY_SERVICES_SEARCH_DIRECTORIES[0]))) 63 | { 64 | //get all items in current directory 65 | allPlugins = directoryContents(pluginDirectory, nil); 66 | 67 | //iterate over all importers 68 | // ->perform some sanity checks and then save 69 | for(NSString* plugin in allPlugins) 70 | { 71 | //build full path to plugin 72 | pluginPath = [NSString stringWithFormat:@"%@/%@", pluginDirectory, plugin]; 73 | 74 | //make sure plugin is a '.dsplug' bundle 75 | if(YES != [pluginPath hasSuffix:@".dsplug"]) 76 | { 77 | //skip 78 | continue; 79 | } 80 | 81 | //create File object for plugin 82 | fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:pluginPath}]; 83 | 84 | //skip File objects that err'd out for any reason 85 | if(nil == fileObj) 86 | { 87 | //skip 88 | continue; 89 | } 90 | 91 | //process item 92 | // ->save and report to UI 93 | [super processItem:fileObj]; 94 | } 95 | 96 | }//dir services plugin directories 97 | 98 | return; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /Plugins/DockTiles.h: -------------------------------------------------------------------------------- 1 | // 2 | // DockTiles.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 9/29/23. 6 | // Copyright (c) 2023 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PluginBase.h" 12 | #import "ItemEnumerator.h" 13 | 14 | /* GLOBALS */ 15 | 16 | //shared enumerator 17 | extern ItemEnumerator* sharedItemEnumerator; 18 | 19 | @interface DockTiles : PluginBase 20 | { 21 | 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Plugins/DockTiles.m: -------------------------------------------------------------------------------- 1 | // 2 | // DockTiles.m 3 | // KnockKnock 4 | // 5 | // More info: https://theevilbit.github.io/beyond/beyond_0032/ 6 | 7 | #import "File.h" 8 | #import "DockTiles.h" 9 | #import "Utilities.h" 10 | #import "AppDelegate.h" 11 | 12 | //plugin name 13 | #define PLUGIN_NAME @"Dock Tiles Plugins" 14 | 15 | //plugin description 16 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"bundles hosted by a Dock XPC service", @"bundles hosted by a Dock XPC service") 17 | 18 | //plugin icon 19 | #define PLUGIN_ICON @"dockTileIcon" 20 | 21 | //dock key (in Info.plist) 22 | #define INFO_PLIST_DOCK_TILE_KEY @"NSDockTilePlugIn" 23 | 24 | @implementation DockTiles 25 | 26 | //init 27 | // set name, description, etc 28 | -(id)init 29 | { 30 | //super 31 | self = [super init]; 32 | if(self) 33 | { 34 | //set name 35 | self.name = PLUGIN_NAME; 36 | 37 | //set description 38 | self.description = PLUGIN_DESCRIPTION; 39 | 40 | //set icon 41 | self.icon = PLUGIN_ICON; 42 | } 43 | 44 | return self; 45 | } 46 | 47 | //scan installed applications 48 | // looking for app plists that contain 'NSDockTilePlugIn' 49 | -(void)scan 50 | { 51 | //installed apps 52 | NSArray* installedApps = nil; 53 | 54 | //app's bundle 55 | NSBundle* appBundle = nil; 56 | 57 | //(relative) dock plugin path 58 | NSString* relativePath = nil; 59 | 60 | //dock plugin path 61 | NSString* fullPath = nil; 62 | 63 | //dock plugin 64 | File* fileObj = nil; 65 | 66 | //wait for shared item enumerator to complete enumeration of installed apps 67 | for(NSUInteger i=0; i<(10*60)*5; i++) 68 | { 69 | //nap 70 | [NSThread sleepForTimeInterval:0.1f]; 71 | 72 | //try grab installed apps 73 | // will only !nil, when enumeration is complete 74 | installedApps = sharedItemEnumerator.applications; 75 | 76 | //exit loop once we have apps 77 | if(nil != installedApps) 78 | { 79 | //break 80 | break; 81 | } 82 | 83 | }//try up to 5 minutes? 84 | 85 | //iterate over all install apps 86 | for(NSDictionary* installedApp in installedApps) 87 | { 88 | //skip apps that don't have paths 89 | if(nil == installedApp[@"path"]) 90 | { 91 | //skip 92 | continue; 93 | } 94 | 95 | //grab app's bundle 96 | appBundle = [NSBundle bundleWithPath:installedApp[@"path"]]; 97 | if( (nil == appBundle) || 98 | (nil == appBundle.infoDictionary) ) 99 | { 100 | //skip 101 | continue; 102 | } 103 | 104 | //grab dock tile plugin path from 'NSDockTilePlugIn' 105 | // note: this path is relative (within) application's bundle 106 | relativePath = appBundle.infoDictionary[INFO_PLIST_DOCK_TILE_KEY]; 107 | if(nil == relativePath) 108 | { 109 | //skip 110 | continue; 111 | } 112 | 113 | //build full path 114 | fullPath = [NSString pathWithComponents:@[installedApp[@"path"], @"Contents", @"PlugIns", relativePath]]; 115 | 116 | //create File object from bundle 117 | // skip those that err out for any reason 118 | if(nil == (fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:fullPath}])) 119 | { 120 | //skip 121 | continue; 122 | } 123 | 124 | //process item 125 | // save & report to UI 126 | [super processItem:fileObj]; 127 | } 128 | 129 | bail: 130 | 131 | return; 132 | } 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /Plugins/DylibInserts.h: -------------------------------------------------------------------------------- 1 | // 2 | // Kexts.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PluginBase.h" 12 | 13 | /* GLOBALS */ 14 | 15 | //shared enumerator 16 | extern ItemEnumerator* sharedItemEnumerator; 17 | 18 | 19 | @interface DylibInserts : PluginBase 20 | { 21 | 22 | } 23 | 24 | /* (custom) METHODS */ 25 | 26 | //scan all launch items 27 | // ->looks in their plists for DYLD_INSERT_LIBRARYs 28 | -(void)scanLaunchItems; 29 | 30 | //scan all installed applications 31 | // ->looks in their plists for DYLD_INSERT_LIBRARYs 32 | -(void)scanApplications; 33 | 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Plugins/DylibProxies.h: -------------------------------------------------------------------------------- 1 | // 2 | // DylibProxies.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 10/9/16. 6 | // Copyright (c) 2016 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | 11 | #import 12 | #import 13 | 14 | /* DEFINES */ 15 | 16 | @interface DylibProxies : PluginBase 17 | { 18 | 19 | } 20 | 21 | /* (custom) METHODS */ 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Plugins/EventRules.h: -------------------------------------------------------------------------------- 1 | // 2 | // EventRules.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 03/25/18. 6 | // Copyright (c) 2018 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | /* DEFINES */ 13 | 14 | @interface EventRules : PluginBase 15 | { 16 | 17 | } 18 | 19 | /* (custom) METHODS */ 20 | 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Plugins/EventRules.m: -------------------------------------------------------------------------------- 1 | // 2 | // EventRules.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 03/25/18. 6 | // Copyright (c) 2018 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Command.h" 10 | #import "Utilities.h" 11 | #import "EventRules.h" 12 | 13 | //plugin name 14 | #define PLUGIN_NAME @"Event Rules" 15 | 16 | //plugin description 17 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"actions executed by emond", @"actions executed by emond") 18 | 19 | //plugin icon 20 | #define PLUGIN_ICON @"eventRulesIcon" 21 | 22 | //default rule directory 23 | #define DEFAULT_EMOND_RULES @"/etc/emond.d/rules/" 24 | 25 | //config file 26 | #define EMOND_CONFIG @"/etc/emond.d/emond.plist" 27 | 28 | @implementation EventRules 29 | 30 | //init 31 | // ->set name, description, etc 32 | -(id)init 33 | { 34 | //super 35 | self = [super init]; 36 | if(self) 37 | { 38 | //set name 39 | self.name = PLUGIN_NAME; 40 | 41 | //set description 42 | self.description = PLUGIN_DESCRIPTION; 43 | 44 | //set icon 45 | self.icon = PLUGIN_ICON; 46 | } 47 | 48 | return self; 49 | } 50 | 51 | //scan for emond commands 52 | -(void)scan 53 | { 54 | //rules directories 55 | NSMutableArray* rulesDirectories = nil; 56 | 57 | //rule plists 58 | NSArray* ruleFiles = nil; 59 | 60 | //config 61 | NSDictionary* config = nil; 62 | 63 | //additional rule directories 64 | NSMutableArray* additionalRuleDirs = nil; 65 | 66 | //commands 67 | NSMutableArray* commands = nil; 68 | 69 | //Command obj 70 | Command* commandObj = nil; 71 | 72 | //alloc 73 | rulesDirectories = [NSMutableArray array]; 74 | 75 | //load config 76 | config = [NSDictionary dictionaryWithContentsOfFile:EMOND_CONFIG][@"config"]; 77 | if(nil != config) 78 | { 79 | //grab additional rules 80 | additionalRuleDirs = config[@"additionalRulesPaths"]; 81 | } 82 | 83 | //add default 84 | [rulesDirectories addObject:DEFAULT_EMOND_RULES]; 85 | 86 | //add any additional 87 | for(NSString* additionalRuleDir in additionalRuleDirs) 88 | { 89 | //add 90 | [rulesDirectories addObject:additionalRuleDir]; 91 | } 92 | 93 | //process each rule directory 94 | for(NSString* ruleDirectory in rulesDirectories) 95 | { 96 | //get rule (plist) files 97 | ruleFiles = directoryContents(ruleDirectory, nil); 98 | 99 | //get commands for each rule file 100 | for(NSString* ruleFile in ruleFiles) 101 | { 102 | //get commands 103 | commands = [self extractCommands:[ruleDirectory stringByAppendingPathComponent:ruleFile]]; 104 | 105 | //process all commands 106 | for(NSString* command in commands) 107 | { 108 | //create Command object for job 109 | commandObj = [[Command alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_COMMAND:command, KEY_RESULT_PATH:[ruleDirectory stringByAppendingPathComponent:ruleFile]}]; 110 | if(nil == commandObj) 111 | { 112 | //skip 113 | continue; 114 | } 115 | 116 | //process item 117 | // save and report to UI 118 | [super processItem:commandObj]; 119 | } 120 | } 121 | } 122 | 123 | return; 124 | } 125 | 126 | //extract commands from a rule file 127 | -(NSMutableArray*)extractCommands:(NSString*)ruleFile 128 | { 129 | //plist contents 130 | NSMutableArray* rules = nil; 131 | 132 | //commands 133 | NSMutableArray* commands = nil; 134 | 135 | //actions 136 | NSArray* actions = nil; 137 | 138 | //alloc 139 | commands = [NSMutableArray array]; 140 | 141 | //load rule file 142 | rules = [NSMutableArray arrayWithContentsOfFile:ruleFile]; 143 | if(nil == rules) 144 | { 145 | //bail 146 | goto bail; 147 | } 148 | 149 | //process all rules 150 | for(NSDictionary* rule in rules) 151 | { 152 | actions = rule[@"actions"]; 153 | if( (nil == actions) || 154 | (YES != [actions isKindOfClass:[NSArray class]]) ) 155 | { 156 | //skip 157 | continue; 158 | } 159 | 160 | //process all actions 161 | for(NSDictionary* action in actions) 162 | { 163 | if(nil == action[@"command"]) 164 | { 165 | //skip 166 | continue; 167 | } 168 | 169 | //add 170 | [commands addObject:action[@"command"]]; 171 | } 172 | } 173 | 174 | bail: 175 | 176 | return commands; 177 | } 178 | @end 179 | -------------------------------------------------------------------------------- /Plugins/Extensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/19/16. 6 | // Copyright (c) 2016 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | /* DEFINES */ 13 | 14 | //file that contains some (more?) finder syncs 15 | #define FINDER_SYNCS @"~/Library/Preferences/com.apple.preferences.extensions.FinderSync.plist" 16 | 17 | @interface Extensions : PluginBase 18 | { 19 | 20 | } 21 | 22 | /* (custom) METHODS */ 23 | 24 | //given output from plugin kit 25 | // ->parse out all enabled extensions 26 | -(NSMutableArray*)parseExtensions:(NSString*)output; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Plugins/Kexts.h: -------------------------------------------------------------------------------- 1 | // 2 | // Kexts.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PluginBase.h" 12 | 13 | @interface Kexts : PluginBase 14 | { 15 | 16 | } 17 | 18 | /* (custom) METHODS */ 19 | 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Plugins/Kexts.m: -------------------------------------------------------------------------------- 1 | // 2 | // Kexts.m 3 | // KnockKnock 4 | // 5 | 6 | #import "File.h" 7 | #import "Kexts.h" 8 | #import "Utilities.h" 9 | 10 | //plugin name 11 | #define PLUGIN_NAME @"Kernel Extensions" 12 | 13 | //plugin description 14 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"installed kexts, likely kernel loaded", @"installed kexts, likely kernel loaded") 15 | 16 | //plugin icon 17 | #define PLUGIN_ICON @"kernelIcon" 18 | 19 | //plugin search directories 20 | NSString * const KEXT_SEARCH_DIRECTORIES[] = {@"/System/Library/Extensions/", @"/Library/Extensions/"}; 21 | 22 | @implementation Kexts 23 | 24 | //init 25 | // ->set name, description, etc 26 | -(id)init 27 | { 28 | //super 29 | self = [super init]; 30 | if(self) 31 | { 32 | //set name 33 | self.name = PLUGIN_NAME; 34 | 35 | //set description 36 | self.description = PLUGIN_DESCRIPTION; 37 | 38 | //set icon 39 | self.icon = PLUGIN_ICON; 40 | } 41 | 42 | return self; 43 | } 44 | 45 | //scan for kexts 46 | -(void)scan 47 | { 48 | //all kexts 49 | NSArray* allKexts = nil; 50 | 51 | //number of search directories 52 | NSUInteger directoryCount = 0; 53 | 54 | //full path to kext 55 | NSString* kextPath = nil; 56 | 57 | //detected kext 58 | File* fileObj = nil; 59 | 60 | //dbg msg 61 | //NSLog(@"%@: scanning", PLUGIN_NAME); 62 | 63 | //get number of search directories 64 | directoryCount = sizeof(KEXT_SEARCH_DIRECTORIES)/sizeof(KEXT_SEARCH_DIRECTORIES[0]); 65 | 66 | //iterate over all kext search directories 67 | // ->get all kexts and process 'em 68 | for(NSUInteger i=0; i < directoryCount; i++) 69 | { 70 | //get all kexts 71 | allKexts = directoryContents(KEXT_SEARCH_DIRECTORIES[i], @"self ENDSWITH '.kext'"); 72 | 73 | //process a kext 74 | // ->create File objects and report to UI 75 | for(NSString* kext in allKexts) 76 | { 77 | //build full path to kext 78 | kextPath = [NSString stringWithFormat:@"%@%@", KEXT_SEARCH_DIRECTORIES[i], kext]; 79 | 80 | //create File object for kext 81 | // ->skip those that err out for any reason 82 | if(nil == (fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:kextPath}])) 83 | { 84 | //skip 85 | continue; 86 | } 87 | 88 | //process item 89 | // ->save and report to UI 90 | [super processItem:fileObj]; 91 | } 92 | } 93 | 94 | return; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /Plugins/LaunchItems.h: -------------------------------------------------------------------------------- 1 | // 2 | // Kexts.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PluginBase.h" 12 | 13 | /* GLOBALS */ 14 | 15 | //shared enumerator 16 | extern ItemEnumerator* sharedItemEnumerator; 17 | 18 | 19 | @interface LaunchItems : PluginBase 20 | { 21 | 22 | } 23 | 24 | //PROPERTIES 25 | 26 | //overridden disabled items 27 | @property(nonatomic, retain)NSMutableArray* disabledItems; 28 | 29 | //overridden enabled items 30 | @property(nonatomic, retain)NSMutableArray* enabledItems; 31 | 32 | /* (custom) METHODS */ 33 | 34 | //get all overridden enabled/disabled launch items 35 | // ->specified in various overrides.plist files 36 | -(void)processOverrides; 37 | 38 | //checks if an item will be automatically run by the OS 39 | -(BOOL)isAutoRun:(NSDictionary*)plistContents; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Plugins/LogInOutHooks.h: -------------------------------------------------------------------------------- 1 | // 2 | // LoginOutHooks.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/18/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface LogInOutHooks : PluginBase 13 | { 14 | 15 | } 16 | 17 | /* (custom) METHODS */ 18 | 19 | //create a File obj 20 | // ->then save & report to UI 21 | -(void)processHook:(NSString*)file parentFile:(NSString*)parentFile; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Plugins/LogInOutHooks.m: -------------------------------------------------------------------------------- 1 | // 2 | // CronJobs.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/18/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | 8 | #import "File.h" 9 | #import "Command.h" 10 | #import "Utilities.h" 11 | #import "LogInOutHooks.h" 12 | 13 | //for some details/examples: 14 | // -> http://apple.stackexchange.com/questions/16825/make-a-script-app-run-on-logout 15 | 16 | 17 | //plugin name 18 | #define PLUGIN_NAME @"Login/Logout Hooks" 19 | 20 | //plugin description 21 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"items executed upon login or logout", @"items executed upon login or logout") 22 | 23 | //plugin icon 24 | #define PLUGIN_ICON @"logInOutIcon" 25 | 26 | //plugin search directories 27 | NSString* const HOOK_SEARCH_FILES[] = {@"/Library/Preferences/com.apple.loginwindow.plist", @"~/Library/Preferences/com.apple.loginwindow.plist"}; 28 | 29 | @implementation LogInOutHooks 30 | 31 | //init 32 | // ->set name, description, etc 33 | -(id)init 34 | { 35 | //super 36 | self = [super init]; 37 | if(self) 38 | { 39 | //set name 40 | self.name = PLUGIN_NAME; 41 | 42 | //set description 43 | self.description = PLUGIN_DESCRIPTION; 44 | 45 | //set icon 46 | self.icon = PLUGIN_ICON; 47 | } 48 | 49 | return self; 50 | } 51 | 52 | //scan for login items 53 | -(void)scan 54 | { 55 | //plist data 56 | NSDictionary* plistContents = nil; 57 | 58 | //iterate over all login/out file 59 | // ->get all hooks and process em 60 | for(NSString* loginWindowPlist in expandPaths(HOOK_SEARCH_FILES, sizeof(HOOK_SEARCH_FILES)/sizeof(HOOK_SEARCH_FILES[0]))) 61 | { 62 | //load plist contents 63 | plistContents = [NSDictionary dictionaryWithContentsOfFile:loginWindowPlist]; 64 | 65 | //process login hook 66 | if(nil != plistContents[@"LoginHook"]) 67 | { 68 | //process 69 | [self processHook:plistContents[@"LoginHook"] parentFile:loginWindowPlist]; 70 | } 71 | 72 | //process logout hook 73 | if(nil != plistContents[@"LogoutHook"]) 74 | { 75 | //process 76 | [self processHook:plistContents[@"LogoutHook"] parentFile:loginWindowPlist]; 77 | } 78 | } 79 | 80 | bail: 81 | 82 | return; 83 | } 84 | 85 | //create a File or Command obj 86 | // ->then save & report to UI 87 | -(void)processHook:(NSString*)payload parentFile:(NSString*)parentFile 88 | { 89 | //File or Command Obj 90 | ItemBase* item = nil; 91 | 92 | //hook payload will usually will be a file 93 | if(YES == [[NSFileManager defaultManager] fileExistsAtPath:payload]) 94 | { 95 | //create File object for hook 96 | item = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:payload, KEY_RESULT_PLIST:parentFile}]; 97 | } 98 | //otherwise 99 | // ->likely a command 100 | else 101 | { 102 | //create Command object for hook 103 | item = [[Command alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_COMMAND:payload, KEY_RESULT_PATH:parentFile}]; 104 | } 105 | 106 | //ignore items w/ errors 107 | if(nil == item) 108 | { 109 | //ignore 110 | goto bail; 111 | } 112 | 113 | //save and report to UI 114 | [super processItem:item]; 115 | 116 | //bail 117 | bail: 118 | 119 | return; 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /Plugins/LoginItems.h: -------------------------------------------------------------------------------- 1 | // 2 | // Kexts.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface LoginItems : PluginBase 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | 19 | /* (custom) METHODS */ 20 | 21 | //enumerate traditional login items 22 | // ->basically just invoke LSSharedFileListCopySnapshot(), etc to get list of items 23 | -(NSMutableArray*)enumTraditionalItems; 24 | 25 | //enumerate sandboxed login items 26 | // ->scan /Applications for 'Contents/Library/LoginItems/' and xref w/ launchd jobs 27 | -(NSMutableArray*)enumSandboxItems; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Plugins/PeriodicScrips.h: -------------------------------------------------------------------------------- 1 | // 2 | // PeriodicScripts.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 3/26/16. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface PeriodicScripts : PluginBase 13 | { 14 | 15 | } 16 | 17 | /* (custom) METHODS */ 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Plugins/PeriodicScrips.m: -------------------------------------------------------------------------------- 1 | // 2 | // PeriodicScripts.m 3 | // KnockKnock 4 | // 5 | // Notes: Authorization, or Authentication plugins can be used to customize logins, 6 | // example app (for testing, etc): http://www.rohos.com/2015/10/installing-rohos-logon-in-mac-os-10-11-el-capitan/ 7 | 8 | #import "File.h" 9 | #import "Utilities.h" 10 | #import "PeriodicScrips.h" 11 | 12 | //plugin name 13 | #define PLUGIN_NAME @"Periodic Scripts" 14 | 15 | //plugin description 16 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"scripts that are executed periodically", @"scripts that are executed periodically") 17 | 18 | //plugin icon 19 | #define PLUGIN_ICON @"periodicIcon" 20 | 21 | //plugin search directories 22 | NSString* const PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[] = {@"/etc/periodic/daily", @"/etc/periodic/weekly", @"/etc/periodic/monthly"}; 23 | 24 | //periodic config file 25 | #define PERIOD_CONFIG @"/etc/defaults/periodic.conf" 26 | 27 | @implementation PeriodicScripts 28 | 29 | //init 30 | // ->set name, description, etc 31 | -(id)init 32 | { 33 | //super 34 | self = [super init]; 35 | if(self) 36 | { 37 | //set name 38 | self.name = PLUGIN_NAME; 39 | 40 | //set description 41 | self.description = PLUGIN_DESCRIPTION; 42 | 43 | //set icon 44 | self.icon = PLUGIN_ICON; 45 | } 46 | 47 | return self; 48 | } 49 | 50 | //scan for periodic scripts 51 | -(void)scan 52 | { 53 | //number of search directories 54 | NSUInteger directoryCount = 0; 55 | 56 | //all period scripts 57 | NSArray* allPeriodicScripts = nil; 58 | 59 | //path to period script 60 | NSString* periodScriptPathPath = nil; 61 | 62 | //File obj 63 | File* fileObj = nil; 64 | 65 | //get number of search directories 66 | directoryCount = sizeof(PERIODIC_SCRIPTS_SEARCH_DIRECTORIES)/sizeof(PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[0]); 67 | 68 | //always a period script config file 69 | // its executed by each period script, so should be reported 70 | fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:PERIOD_CONFIG}]; 71 | if(nil != fileObj) 72 | { 73 | //process item 74 | // ->save and report to UI 75 | [super processItem:fileObj]; 76 | } 77 | 78 | //iterate over all script directories 79 | // get all script files and process them 80 | for(NSUInteger i=0; i < directoryCount; i++) 81 | { 82 | //get all items in current directory 83 | allPeriodicScripts = directoryContents(PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[i], nil); 84 | 85 | //iterate over all importers 86 | // ->perform some sanity checks and then save 87 | for(NSString* periodicScript in allPeriodicScripts) 88 | { 89 | //build full path to script 90 | periodScriptPathPath = [NSString stringWithFormat:@"%@/%@", PERIODIC_SCRIPTS_SEARCH_DIRECTORIES[i], periodicScript]; 91 | 92 | //create File object for script 93 | fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:periodScriptPathPath}]; 94 | 95 | //skip File objects that err'd out for any reason 96 | if(nil == fileObj) 97 | { 98 | //skip 99 | continue; 100 | } 101 | 102 | //process item 103 | // ->save and report to UI 104 | [super processItem:fileObj]; 105 | } 106 | 107 | }//periodic script directories 108 | 109 | return; 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Plugins/PluginBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // PluginBase.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 9/25/14. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import "Consts.h" 10 | #import "../Results/ItemBase.h" 11 | #import 12 | 13 | @interface PluginBase : NSObject 14 | { 15 | 16 | } 17 | 18 | //callback 19 | @property(copy, nonatomic) void (^callback)(ItemBase*); 20 | 21 | //name 22 | @property(retain, nonatomic)NSString* name; 23 | 24 | //description 25 | @property(retain, nonatomic)NSString* description; 26 | 27 | //all detected items 28 | @property(retain, nonatomic)NSMutableArray* allItems; 29 | 30 | //untrusted items 31 | @property(retain, nonatomic)NSMutableArray* untrustedItems; 32 | 33 | //unknown (VT) items 34 | @property(retain, nonatomic)NSMutableArray* unknownItems; 35 | 36 | //flagged items 37 | @property(retain, nonatomic)NSMutableArray* flaggedItems; 38 | 39 | //icon 40 | @property(retain, nonatomic)NSString* icon; 41 | 42 | /* METHODS */ 43 | 44 | //reset 45 | // ->remove all items 46 | -(void)reset; 47 | 48 | //scan 49 | -(void)scan; 50 | 51 | //process and item 52 | // ->save and report (if necessary) 53 | -(void)processItem:(ItemBase*)item; 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Plugins/PluginBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // PluginBase.m 3 | // KnockKnock 4 | 5 | #import "PluginBase.h" 6 | #import "AppDelegate.h" 7 | 8 | #define kErrFormat @"%@ not implemented in subclass %@" 9 | #define kExceptName @"KK Plugin" 10 | 11 | 12 | 13 | @implementation PluginBase 14 | 15 | @synthesize icon; 16 | @synthesize name; 17 | @synthesize allItems; 18 | @synthesize description; 19 | @synthesize flaggedItems; 20 | @synthesize unknownItems; 21 | @synthesize untrustedItems; 22 | 23 | //init method 24 | -(id)init 25 | { 26 | //super 27 | self = [super init]; 28 | if(nil != self) 29 | { 30 | //alloc 31 | allItems = [NSMutableArray array]; 32 | 33 | //alloc 34 | untrustedItems = [NSMutableArray array]; 35 | 36 | //alloc 37 | unknownItems = [NSMutableArray array]; 38 | 39 | //alloc 40 | flaggedItems = [NSMutableArray array]; 41 | } 42 | 43 | return self; 44 | } 45 | 46 | //reset plugin 47 | // ->remove all items 48 | -(void)reset 49 | { 50 | //sync 51 | // ->VT threads might still be accessing 52 | @synchronized(self.allItems) 53 | { 54 | //remove all items 55 | [self.allItems removeAllObjects]; 56 | 57 | }//sync 58 | 59 | //sync 60 | // ->VT threads might still be accessing 61 | @synchronized(self.untrustedItems) 62 | { 63 | //remove unknown items 64 | [self.untrustedItems removeAllObjects]; 65 | 66 | }//sync 67 | 68 | //sync 69 | // ->VT threads might still be accessing 70 | @synchronized(self.unknownItems) 71 | { 72 | //remove flagged items 73 | [self.unknownItems removeAllObjects]; 74 | } 75 | 76 | //sync 77 | // ->VT threads might still be accessing 78 | @synchronized(self.flaggedItems) 79 | { 80 | //remove flagged items 81 | [self.flaggedItems removeAllObjects]; 82 | } 83 | 84 | return; 85 | } 86 | 87 | 88 | //process and item 89 | // save and report (if necessary) 90 | -(void)processItem:(ItemBase*)item 91 | { 92 | //exit if scanner (self) thread was cancelled 93 | // ->will prevent UI from updating after scan is cancelled 94 | if(YES == [[NSThread currentThread] isCancelled]) 95 | { 96 | //exit 97 | [NSThread exit]; 98 | } 99 | 100 | //sync 101 | // ->just to be safe 102 | @synchronized(self.allItems) 103 | { 104 | //save item into 'allItems' 105 | [self.allItems addObject:item]; 106 | } 107 | 108 | //for unknown items 109 | // ->save seperately as well 110 | if(YES != item.isTrusted) 111 | { 112 | //sync 113 | // ->just to be safe 114 | @synchronized(self.untrustedItems) 115 | { 116 | //save 117 | [self.untrustedItems addObject:item]; 118 | } 119 | } 120 | 121 | //invoke callback 122 | if(nil != self.callback) 123 | { 124 | //invoke 125 | self.callback(item); 126 | } 127 | 128 | return; 129 | } 130 | 131 | 132 | /* OPTIONAL METHODS */ 133 | 134 | 135 | 136 | /* REQUIRED METHODS */ 137 | 138 | //scan away! 139 | -(void)scan 140 | { 141 | @throw [NSException exceptionWithName:kExceptName 142 | reason:[NSString stringWithFormat:kErrFormat, NSStringFromSelector(_cmd), [self class]] 143 | userInfo:nil]; 144 | return; 145 | } 146 | 147 | @end 148 | -------------------------------------------------------------------------------- /Plugins/QuicklookPlugins.h: -------------------------------------------------------------------------------- 1 | // 2 | // QuicklookPlugins.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 11/09/19. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PluginBase.h" 11 | #import 12 | 13 | //path to QL framework 14 | #define QUICKLOOK_FRAMEWORK @"/System/Library/Frameworks/QuickLook.framework" 15 | 16 | //function def for '_QLCopyServerStatistics' 17 | typedef id (*QLCopyServerStatistics)(NSArray* stats); 18 | 19 | //function pointer for 20 | static QLCopyServerStatistics copyServerStats = NULL; 21 | 22 | @interface QuicklookPlugins : PluginBase 23 | { 24 | 25 | } 26 | 27 | /* (custom) METHODS */ 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Plugins/QuicklookPlugins.m: -------------------------------------------------------------------------------- 1 | // 2 | // QuicklookPlugins.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 11/09/19. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "File.h" 10 | #import "Utilities.h" 11 | #import "QuicklookPlugins.h" 12 | 13 | //plugin name 14 | #define PLUGIN_NAME @"Quicklook Plugins" 15 | 16 | //plugin description 17 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"registered quicklook bundles", @"registered quicklook bundles") 18 | 19 | //plugin icon 20 | #define PLUGIN_ICON @"quicklookIcon" 21 | 22 | @implementation QuicklookPlugins 23 | 24 | //init 25 | // ->set name, description, etc 26 | -(id)init 27 | { 28 | //super 29 | self = [super init]; 30 | if(self) 31 | { 32 | //set name 33 | self.name = PLUGIN_NAME; 34 | 35 | //set description 36 | self.description = PLUGIN_DESCRIPTION; 37 | 38 | //set icon 39 | self.icon = PLUGIN_ICON; 40 | 41 | //load ql framework 42 | // and resolve '_QLCopyServerStatistics' function 43 | if(YES == [[NSBundle bundleWithPath:QUICKLOOK_FRAMEWORK] load]) 44 | { 45 | //resolve '_QLCopyServerStatistics' 46 | copyServerStats = dlsym(RTLD_NEXT, "_QLCopyServerStatistics"); 47 | } 48 | } 49 | 50 | return self; 51 | } 52 | 53 | //scan for quicklook plugins 54 | -(void)scan 55 | { 56 | //stats (from QL server) 57 | NSDictionary* stats = nil; 58 | 59 | //all ql plugins 60 | NSDictionary* plugins = nil; 61 | 62 | //unique plugins 63 | // same plugin can be registered multiple times 64 | NSMutableSet* uniquePlugins = nil; 65 | 66 | //plugin path 67 | NSString* pluginPath = nil; 68 | 69 | //range 70 | // needed for parsing plugin paths 71 | NSRange range = {0}; 72 | 73 | //File obj 74 | File* fileObj = nil; 75 | 76 | //alloc 77 | uniquePlugins = [NSMutableSet set]; 78 | 79 | //get stats (plugins) 80 | // should return a dictionary... 81 | stats = copyServerStats(@[@"plugins"]); 82 | if(YES != [stats isKindOfClass:[NSDictionary class]]) 83 | { 84 | //bail 85 | goto bail; 86 | } 87 | 88 | //process all plugins 89 | for(NSString* key in stats) 90 | { 91 | //get list for key 92 | // should be another dictionary 93 | plugins = stats[key]; 94 | if(YES != [plugins isKindOfClass:[NSDictionary class]]) 95 | { 96 | //skip 97 | continue; 98 | } 99 | 100 | //process each plugin 101 | // have to parse path a bit... 102 | for(NSString* name in plugins) 103 | { 104 | //extract path 105 | // format is path (#) 106 | pluginPath = plugins[name]; 107 | 108 | //find offset of last " ( 109 | range = [pluginPath rangeOfString:@" (" options:NSBackwardsSearch]; 110 | if(NSNotFound == range.location) 111 | { 112 | //skip 113 | continue; 114 | } 115 | 116 | //grab just path part 117 | pluginPath = [pluginPath substringWithRange:NSMakeRange(0, range.location)]; 118 | 119 | //skipping already reported plugins 120 | if(YES == [uniquePlugins containsObject:pluginPath]) 121 | { 122 | //skip 123 | continue; 124 | } 125 | 126 | //new 127 | // add plugin path 128 | [uniquePlugins addObject:pluginPath]; 129 | 130 | //create File object for plugin 131 | fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:pluginPath}]; 132 | 133 | //skip File objects that err'd out for any reason 134 | if(nil == fileObj) 135 | { 136 | //skip 137 | continue; 138 | } 139 | 140 | //process item 141 | // save & report to UI 142 | [super processItem:fileObj]; 143 | } 144 | } 145 | 146 | bail: 147 | 148 | return; 149 | } 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /Plugins/SpotlightImporters.h: -------------------------------------------------------------------------------- 1 | // 2 | // SpotlightImporters.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface SpotlightImporters : PluginBase 13 | { 14 | 15 | } 16 | 17 | /* (custom) METHODS */ 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Plugins/SpotlightImporters.m: -------------------------------------------------------------------------------- 1 | // 2 | // SpotlightImporters.m 3 | // KnockKnock 4 | // 5 | 6 | #import "File.h" 7 | #import "Utilities.h" 8 | #import "SpotlightImporters.h" 9 | 10 | //plugin name 11 | #define PLUGIN_NAME @"Spotlight Importers" 12 | 13 | //plugin description 14 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"bundles loaded by Spotlight (mdworker)", @"bundles loaded by Spotlight (mdworker)") 15 | 16 | //plugin icon 17 | #define PLUGIN_ICON @"spotlightIcon" 18 | 19 | //plugin search directories 20 | NSString * const SPOTLIGHT_SEARCH_DIRECTORIES[] = {@"/System/Library/Spotlight", @"/Library/Spotlight", @"~/Library/Spotlight"}; 21 | 22 | 23 | @implementation SpotlightImporters 24 | 25 | //init 26 | // ->set name, description, etc 27 | -(id)init 28 | { 29 | //super 30 | self = [super init]; 31 | if(self) 32 | { 33 | //set name 34 | self.name = PLUGIN_NAME; 35 | 36 | //set description 37 | self.description = PLUGIN_DESCRIPTION; 38 | 39 | //set icon 40 | self.icon = PLUGIN_ICON; 41 | } 42 | 43 | return self; 44 | } 45 | 46 | //scan for spotlight importers 47 | -(void)scan 48 | { 49 | //all spotlight importers 50 | NSArray* allImporters = nil; 51 | 52 | //path to importer 53 | NSString* importerPath = nil; 54 | 55 | //File obj 56 | File* fileObj = nil; 57 | 58 | //dbg msg 59 | //NSLog(@"%@: scanning", PLUGIN_NAME); 60 | 61 | //iterate over all spotlight importer search directories 62 | // get all spotlight importer bundles and process each of them 63 | for(NSString* importerDirectory in expandPaths(SPOTLIGHT_SEARCH_DIRECTORIES, sizeof(SPOTLIGHT_SEARCH_DIRECTORIES)/sizeof(SPOTLIGHT_SEARCH_DIRECTORIES[0]))) 64 | { 65 | //get all items in current directory 66 | allImporters = directoryContents(importerDirectory, nil); 67 | 68 | //iterate over all importers 69 | // ->perform some sanity checks and then save 70 | for(NSString* importer in allImporters) 71 | { 72 | //build full path to importer 73 | importerPath = [NSString stringWithFormat:@"%@/%@", importerDirectory, importer]; 74 | 75 | //make sure importer is a bundle 76 | // ->i.e. not just a random directory 77 | if(YES != [[NSWorkspace sharedWorkspace] isFilePackageAtPath:importerPath]) 78 | { 79 | //skip 80 | continue; 81 | } 82 | 83 | //create File object for importer 84 | fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:importerPath}]; 85 | 86 | //skip File objects that err'd out for any reason 87 | if(nil == fileObj) 88 | { 89 | //skip 90 | continue; 91 | } 92 | 93 | //process item 94 | // ->save and report to UI 95 | [super processItem:fileObj]; 96 | } 97 | 98 | }//spotlight importer directories 99 | 100 | return; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /Plugins/StartupScripts.h: -------------------------------------------------------------------------------- 1 | // 2 | // StartupScripts.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 3/26/16. 6 | // Copyright (c) 2016 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface StartupScripts : PluginBase 13 | { 14 | 15 | } 16 | 17 | /* (custom) METHODS */ 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Plugins/StartupScripts.m: -------------------------------------------------------------------------------- 1 | // 2 | // StartupScripts.m 3 | // KnockKnock 4 | // 5 | // Notes: OS scripts that are exec'd as OS X boot/starts/logs such as /etc/rc.* and /etc/launchd.conf 6 | // normally these scripts shouldn't exist, or are whitelisted - so any deviations, just show file 7 | 8 | #import "File.h" 9 | #import "Utilities.h" 10 | #import "StartupScripts.h" 11 | 12 | //plugin name 13 | #define PLUGIN_NAME @"Startup Scripts" 14 | 15 | //plugin description 16 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"scripts executed during OS startup", @"scripts executed during OS startup") 17 | 18 | //plugin icon 19 | #define PLUGIN_ICON @"startupScriptsIcon" 20 | 21 | //plugin search directories 22 | NSString* const STARTUP_SCRIPTS_SEARCH_FILES[] = {@"/etc/rc.cleanup", @"/etc/rc.common", @"/etc/rc.installer_cleanup", @"/etc/rc.server", @"/etc/launchd.conf"}; 23 | 24 | @implementation StartupScripts 25 | 26 | //init 27 | // ->set name, description, etc 28 | -(id)init 29 | { 30 | //super 31 | self = [super init]; 32 | if(self) 33 | { 34 | //set name 35 | self.name = PLUGIN_NAME; 36 | 37 | //set description 38 | self.description = PLUGIN_DESCRIPTION; 39 | 40 | //set icon 41 | self.icon = PLUGIN_ICON; 42 | } 43 | 44 | return self; 45 | } 46 | 47 | //scan for startup scripts 48 | // ->any that exist are reported (though known ones are whitelisted) 49 | -(void)scan 50 | { 51 | //File obj 52 | File* fileObj = nil; 53 | 54 | //iterate over all script directories 55 | // ->get all script files and process them 56 | for(NSUInteger i=0; inote these generally shouldn't exist (on default install) 60 | fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:STARTUP_SCRIPTS_SEARCH_FILES[i]}]; 61 | 62 | //skip File objects that err'd out for any reason 63 | if(nil == fileObj) 64 | { 65 | //skip 66 | continue; 67 | } 68 | 69 | //process item 70 | // ->save and report to UI 71 | [super processItem:fileObj]; 72 | } 73 | 74 | return; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /Plugins/SystemExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // SystemExtensions.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/19/16. 6 | // Copyright (c) 2021 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | 13 | @interface SystemExtensions : PluginBase 14 | { 15 | 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Plugins/SystemExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.m 3 | // KnockKnock 4 | // 5 | // Notes: view via these via System Preferences->Extensions, or pluginkit -vmA 6 | // only for current user, since we utilized 'pluginkit' which is "for current user" 7 | 8 | #import "File.h" 9 | #import "Utilities.h" 10 | #import "SystemExtensions.h" 11 | 12 | //plugin name 13 | #define PLUGIN_NAME @"System Extensions" 14 | 15 | //plugin description 16 | #define PLUGIN_DESCRIPTION NSLocalizedString(@"user-mode 'drivers' extending OS functionality", @"user-mode 'drivers' extending OS functionality") 17 | 18 | //plugin icon 19 | #define PLUGIN_ICON @"systemExtensionIcon" 20 | 21 | //path to 'database' 22 | #define SYSTEM_EXTENSION_DATABASE @"/Library/SystemExtensions/db.plist" 23 | 24 | @implementation SystemExtensions 25 | 26 | //init 27 | // set name, description, etc 28 | -(id)init 29 | { 30 | //super 31 | self = [super init]; 32 | if(self) 33 | { 34 | //set name 35 | self.name = PLUGIN_NAME; 36 | 37 | //set description 38 | self.description = PLUGIN_DESCRIPTION; 39 | 40 | //set icon 41 | self.icon = PLUGIN_ICON; 42 | } 43 | 44 | return self; 45 | } 46 | 47 | //get list of installed extensions 48 | // how? parses: /Library/SystemExtensions/db.plist 49 | -(NSMutableArray*)enumExtensions 50 | { 51 | //database 52 | NSDictionary* database = nil; 53 | 54 | //all extensions 55 | NSMutableArray* extensions = nil; 56 | 57 | //alloc array for extensions 58 | extensions = [NSMutableArray array]; 59 | 60 | //load from database 61 | database = [NSDictionary dictionaryWithContentsOfFile:SYSTEM_EXTENSION_DATABASE]; 62 | 63 | //parse extensions 64 | for(NSDictionary* extension in database[@"extensions"]) 65 | { 66 | //not active 67 | if(YES != [extension[@"state"] isEqualToString:@"activated_enabled"]) continue; 68 | 69 | //save path 70 | [extensions addObject:extension[@"originPath"]]; 71 | } 72 | 73 | return extensions; 74 | } 75 | 76 | //scan for extensions 77 | -(void)scan 78 | { 79 | //File obj 80 | File* fileObj = nil; 81 | 82 | //enumerate all extensions 83 | for(NSString* extension in [self enumExtensions]) 84 | { 85 | //create File object 86 | fileObj = [[File alloc] initWithParams:@{KEY_RESULT_PLUGIN:self, KEY_RESULT_PATH:extension}]; 87 | if(nil == fileObj) 88 | { 89 | //skip 90 | continue; 91 | } 92 | 93 | //process item 94 | // save and report to UI 95 | [super processItem:fileObj]; 96 | } 97 | 98 | return; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /PrefsWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PrefsWindowController.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/6/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PrefsWindowController : NSWindowController 12 | { 13 | 14 | } 15 | 16 | /* METHODS */ 17 | 18 | //register default prefs 19 | // ->only used if user hasn't set any 20 | -(void)registerDefaults; 21 | 22 | //load (persistence) preferences from file system 23 | -(void)loadPreferences; 24 | 25 | //buttons 26 | 27 | //button for filtering out OS componets 28 | @property (weak) IBOutlet NSButton* showTrustedItemsBtn; 29 | 30 | //button disabling update check 31 | @property (weak) IBOutlet NSButton *disableUpdateCheckBtn; 32 | 33 | //button for disabling talking to VT 34 | @property (weak) IBOutlet NSButton* disableVTQueriesBtn; 35 | 36 | //button for saving output 37 | @property (weak) IBOutlet NSButton* saveOutputBtn; 38 | 39 | //button for ok/close 40 | @property (weak) IBOutlet NSButton *okButton; 41 | 42 | //filter out OS/known items 43 | @property BOOL showTrustedItems; 44 | 45 | //no update checks 46 | @property BOOL disableUpdateCheck; 47 | 48 | //disable talking to VT 49 | @property BOOL disableVTQueries; 50 | 51 | //save results (at end of scan) 52 | @property BOOL saveOutput; 53 | 54 | //save results now 55 | @property BOOL shouldSaveNow; 56 | 57 | /* METHODS */ 58 | 59 | //save existing prefs 60 | -(void)captureExistingPrefs; 61 | 62 | //'OK' button handler 63 | // ->save prefs and close window 64 | -(IBAction)closeWindow:(id)sender; 65 | 66 | 67 | /* METHODS */ 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KnockKnock 2 | Enumerate persistently installed software 3 | -------------------------------------------------------------------------------- /Results/Command.h: -------------------------------------------------------------------------------- 1 | // 2 | // Command.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "ItemBase.h" 10 | #import 11 | 12 | @interface Command : ItemBase 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | @property (nonatomic, retain)NSString* command; 19 | 20 | /* METHODS */ 21 | 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Results/Command.m: -------------------------------------------------------------------------------- 1 | // 2 | // Command.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Consts.h" 10 | #import "Command.h" 11 | #import "Utilities.h" 12 | 13 | @implementation Command 14 | 15 | @synthesize command; 16 | 17 | //init method 18 | -(id)initWithParams:(NSDictionary*)params 19 | { 20 | //super 21 | self = [super initWithParams:params]; 22 | if(nil != self) 23 | { 24 | //save command 25 | self.command = params[KEY_RESULT_COMMAND]; 26 | } 27 | 28 | return self; 29 | } 30 | 31 | //convert object to JSON string 32 | -(NSString*)toJSON 33 | { 34 | //json string 35 | NSString *json = nil; 36 | 37 | //init json 38 | // ->note: command is escaped to make sure its valid JSON 39 | json = [NSString stringWithFormat:@"\"command\": \"%@\", \"file\": \"%@\"", escapeString(self.command), self.path]; 40 | 41 | return json; 42 | } 43 | 44 | 45 | //description 46 | -(NSString*)description 47 | { 48 | return [NSString stringWithFormat:@"command: %@, file: %@", self.command, self.path]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Results/Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // Extension.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "ItemBase.h" 10 | #import 11 | 12 | @interface Extension : ItemBase 13 | { 14 | 15 | } 16 | 17 | //id 18 | @property(nonatomic, retain)NSString* identifier; 19 | 20 | //description 21 | @property(nonatomic, retain)NSString* details; 22 | 23 | //(host) browser 24 | @property(nonatomic, retain)NSString* browser; 25 | 26 | 27 | /* METHODS */ 28 | 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Results/Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // Extension.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Consts.h" 10 | #import "Extension.h" 11 | #import "AppDelegate.h" 12 | 13 | @implementation Extension 14 | 15 | //init method 16 | -(id)initWithParams:(NSDictionary*)params 17 | { 18 | //super 19 | self = [super initWithParams:params]; 20 | if(nil != self) 21 | { 22 | //extract/save id 23 | self.identifier = params[KEY_EXTENSION_ID]; 24 | 25 | //extract/save description 26 | self.details = params[KEY_EXTENSION_DETAILS]; 27 | 28 | //extract/save description 29 | self.browser = params[KEY_EXTENSION_BROWSER]; 30 | 31 | //call into filter object to check if file is known 32 | // ->signed or whitelisted 33 | self.isTrusted = [itemFilter isTrustedExtension:self]; 34 | } 35 | 36 | return self; 37 | } 38 | 39 | //convert object to JSON string 40 | -(NSString*)toJSON 41 | { 42 | //json string 43 | NSString *json = nil; 44 | 45 | //name ...escaped 46 | NSString* escapedName = nil; 47 | 48 | //details ...escaped 49 | NSString* escapedDetails = nil; 50 | 51 | //escape name 52 | escapedName = [self.name stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; 53 | 54 | //escape details 55 | // remove newlines 56 | escapedDetails = [[self.details componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:@" "]; 57 | 58 | //escape details 59 | // replace " with \" 60 | escapedDetails = [escapedDetails stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; 61 | 62 | //init json 63 | json = [NSString stringWithFormat:@"\"name\": \"%@\", \"path\": \"%@\", \"identifier\": \"%@\", \"details\": \"%@\", \"browser\": \"%@\"", escapedName, self.path, self.identifier, escapedDetails, self.browser]; 64 | 65 | return json; 66 | } 67 | 68 | //description 69 | -(NSString*)description 70 | { 71 | return [NSString stringWithFormat:@"name: %@, path: %@, identifier: %@, details: %@, browser: %@", self.name, self.path, self.identifier, self.details, self.browser]; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Results/File.h: -------------------------------------------------------------------------------- 1 | // 2 | // File.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "ItemBase.h" 10 | #import 11 | #import 12 | 13 | @interface File : ItemBase 14 | { 15 | 16 | } 17 | 18 | /* PROPERTIES */ 19 | 20 | //name 21 | @property(nonatomic, retain)NSString* name; 22 | 23 | //path 24 | @property(nonatomic, retain)NSString* path; 25 | 26 | //plist 27 | @property(nonatomic, retain)NSString* plist; 28 | 29 | //bundle 30 | @property(nonatomic, retain)NSBundle* bundle; 31 | 32 | //hashes (md5, sha1) 33 | @property(nonatomic, retain)NSDictionary* hashes; 34 | 35 | //signing info 36 | @property(nonatomic, retain)NSDictionary* signingInfo; 37 | 38 | //is packed 39 | @property BOOL isPacked; 40 | 41 | //is encrypted 42 | @property BOOL isEncrypted; 43 | 44 | /* VIRUS TOTAL INFO */ 45 | 46 | //dictionary returned by VT 47 | @property (nonatomic, retain)NSDictionary* vtInfo; 48 | 49 | 50 | /* METHODS */ 51 | 52 | //init method 53 | -(id)initWithParams:(NSDictionary*)params; 54 | 55 | //determine name 56 | // ->extra logic for apps (plists), etc 57 | -(NSString*)determineName; 58 | 59 | //format the signing info dictionary 60 | -(NSString*)formatSigningInfo; 61 | 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /Results/ItemBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // PluginBase.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 9/25/14. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class PluginBase; 12 | 13 | @interface ItemBase : NSObject 14 | { 15 | 16 | } 17 | 18 | //plugin 19 | @property(nonatomic, retain)PluginBase* plugin; 20 | 21 | //name 22 | @property(retain, nonatomic)NSString* name; 23 | 24 | //path 25 | @property(retain, nonatomic)NSString* path; 26 | 27 | //file attributes 28 | @property(nonatomic, retain)NSDictionary* attributes; 29 | 30 | //flag if known 31 | // ->signed by apple and/or whitelisted 32 | @property BOOL isTrusted; 33 | 34 | 35 | /* METHODS */ 36 | 37 | //init method 38 | -(id)initWithParams:(NSDictionary*)params; 39 | 40 | //return a path that can be opened in Finder.app 41 | -(NSString*)pathForFinder; 42 | 43 | //convert object to JSON string 44 | -(NSString*)toJSON; 45 | 46 | 47 | 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Results/ItemBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // PluginBase.m 3 | // KnockKnock 4 | 5 | #import "Consts.h" 6 | #import "Command.h" 7 | #import "ItemBase.h" 8 | 9 | 10 | #define kErrFormat @"%@ not implemented in subclass %@" 11 | #define kExceptName @"KK Item" 12 | 13 | 14 | 15 | @implementation ItemBase 16 | 17 | @synthesize name; 18 | @synthesize path; 19 | @synthesize isTrusted; 20 | @synthesize attributes; 21 | 22 | //init method 23 | -(id)initWithParams:(NSDictionary*)params 24 | { 25 | //super 26 | self = [super init]; 27 | if(nil != self) 28 | { 29 | //save plugin 30 | self.plugin = params[KEY_RESULT_PLUGIN]; 31 | 32 | //extract/save name 33 | self.name = params[KEY_RESULT_NAME]; 34 | 35 | //extract/save path 36 | self.path = params[KEY_RESULT_PATH]; 37 | 38 | //for files/extensions 39 | // ->get attributes 40 | if(YES != [self isKindOfClass:[Command class]]) 41 | { 42 | //get attributes 43 | // ->based off path 44 | self.attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:self.path error:nil]; 45 | } 46 | } 47 | 48 | return self; 49 | } 50 | 51 | //return a path that can be opened in Finder.app 52 | -(NSString*)pathForFinder 53 | { 54 | return self.path; 55 | } 56 | 57 | 58 | /* OPTIONAL METHODS */ 59 | 60 | 61 | /* REQUIRED METHODS */ 62 | 63 | //stubs for inherited methods 64 | // ->all just throw exceptions as they should be implemented in sub-classes 65 | 66 | //scan 67 | -(void)scan:(NSDictionary*)scanOptions 68 | { 69 | @throw [NSException exceptionWithName:kExceptName 70 | reason:[NSString stringWithFormat:kErrFormat, NSStringFromSelector(_cmd), [self class]] 71 | userInfo:nil]; 72 | return; 73 | } 74 | 75 | //convert object to JSON string 76 | -(NSString*)toJSON 77 | { 78 | @throw [NSException exceptionWithName:kExceptName 79 | reason:[NSString stringWithFormat:kErrFormat, NSStringFromSelector(_cmd), [self class]] 80 | userInfo:nil]; 81 | return nil; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /ResultsWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ResultsWindowController.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/6/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UnknownItemsWindowController.h" 11 | 12 | @interface ResultsWindowController : NSWindowController 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | 19 | //details 20 | @property(nonatomic, retain)NSString* details; 21 | 22 | //details of results label/string 23 | @property(weak) IBOutlet NSTextField* detailsLabel; 24 | 25 | //unknown items 26 | @property(nonatomic, retain)NSMutableArray* unknownItems; 27 | 28 | //unknown itmes details 29 | @property(nonatomic, retain)NSString* vtDetails; 30 | 31 | //unknown items 32 | @property (weak) IBOutlet NSTextField *vtDetailsLabel; 33 | 34 | //submit to VT button 35 | @property (weak) IBOutlet NSButton *submitToVT; 36 | 37 | //window controller for unknown items 38 | @property(nonatomic, strong)UnknownItemsWindowController* unknownItemsWindowController; 39 | 40 | /* METHODS */ 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /ResultsWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ResultsWindowController.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/6/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import "Utilities.h" 10 | #import "AppDelegate.h" 11 | #import "ResultsWindowController.h" 12 | 13 | @implementation ResultsWindowController 14 | 15 | @synthesize details; 16 | @synthesize detailsLabel; 17 | 18 | //automatically called when nib is loaded 19 | // ->center window 20 | -(void)awakeFromNib 21 | { 22 | //center 23 | [self.window center]; 24 | } 25 | 26 | //initialize window 27 | -(void)windowDidLoad 28 | { 29 | //super 30 | [super windowDidLoad]; 31 | 32 | //not in dark mode? 33 | // make window white 34 | if(YES != isDarkMode()) 35 | { 36 | //make white 37 | self.window.backgroundColor = NSColor.whiteColor; 38 | } 39 | 40 | //set details 41 | self.detailsLabel.stringValue = self.details; 42 | 43 | //set VT results 44 | if(nil != self.vtDetails) 45 | { 46 | //set 47 | self.vtDetailsLabel.stringValue = self.vtDetails; 48 | 49 | //line spacing 50 | setLineSpacing(self.vtDetailsLabel, 5.0); 51 | 52 | //show/hide 'unknown items' button 53 | self.submitToVT.hidden = !(self.unknownItems.count); 54 | } 55 | //no VT results 56 | // disabled? something else? 57 | else 58 | { 59 | //disabled 60 | if(YES == ((AppDelegate*)[[NSApplication sharedApplication] delegate]).prefsWindowController.disableVTQueries) 61 | { 62 | self.vtDetailsLabel.stringValue = NSLocalizedString(@"VirusTotal Results: N/A (Disabled)", @"VirusTotal Results: N/A (Disabled)"); 63 | } 64 | //? 65 | else 66 | { 67 | self.vtDetailsLabel.stringValue = @"VirusTotal: Error(?)"; 68 | } 69 | } 70 | 71 | return; 72 | } 73 | 74 | //show 'unknown items' window 75 | -(IBAction)viewUnknownItems:(id)sender 76 | { 77 | //make normal 78 | [self.window setLevel:NSNormalWindowLevel]; 79 | 80 | //alloc/init unknown items 81 | self.unknownItemsWindowController = [[UnknownItemsWindowController alloc] initWithWindowNibName:@"UnknownItems"]; 82 | 83 | //set unknown items 84 | self.unknownItemsWindowController.items = self.unknownItems; 85 | 86 | //show it 87 | [self.unknownItemsWindowController showWindow:self]; 88 | 89 | //center 90 | [self.unknownItemsWindowController.window center]; 91 | 92 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{ 93 | 94 | //and make it first responder 95 | [self.unknownItemsWindowController.window makeFirstResponder:self.unknownItemsWindowController.submit]; 96 | 97 | }); 98 | 99 | return; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /Signing.h: -------------------------------------------------------------------------------- 1 | // 2 | // File: Signing.h 3 | // Project: Proc Info 4 | // 5 | // Created by: Patrick Wardle 6 | // Copyright: 2017 Objective-See 7 | // License: Creative Commons Attribution-NonCommercial 4.0 International License 8 | // 9 | 10 | #ifndef Signing_h 11 | #define Signing_h 12 | 13 | #import 14 | #import 15 | 16 | /* FUNCTIONS */ 17 | 18 | //get the signing info of a item 19 | // pid specified: extract dynamic code signing info 20 | // path specified: generate static code signing info 21 | NSMutableDictionary* extractSigningInfo(pid_t pid, NSString* path, SecCSFlags flags); 22 | 23 | //determine who signed item 24 | NSNumber* extractSigner(SecStaticCodeRef code, SecCSFlags flags, BOOL isDynamic); 25 | 26 | //validate a requirement 27 | OSStatus validateRequirement(SecStaticCodeRef code, SecRequirementRef requirement, SecCSFlags flags, BOOL isDynamic); 28 | 29 | //extract (names) of signing auths 30 | NSMutableArray* extractSigningAuths(NSDictionary* signingDetails); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /UI/en.lproj/DiffWindow.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSWindow"; title = "Differences"; ObjectID = "QvC-M9-y7g"; */ 3 | "QvC-M9-y7g.title" = "Differences"; 4 | 5 | /* Class = "NSButtonCell"; title = "Close"; ObjectID = "cvj-Jf-F5t"; */ 6 | "cvj-Jf-F5t.title" = "Close"; 7 | -------------------------------------------------------------------------------- /UI/en.lproj/UnknownItems.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "1tA-WZ-bke"; */ 3 | "1tA-WZ-bke.title" = "Text Cell"; 4 | 5 | /* Class = "NSTableColumn"; headerCell.title = "Submit?"; ObjectID = "4Yf-Xs-7Mi"; */ 6 | "4Yf-Xs-7Mi.headerCell.title" = "Submit?"; 7 | 8 | /* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "4Zg-Mt-eqA"; */ 9 | "4Zg-Mt-eqA.title" = "Table View Cell"; 10 | 11 | /* Class = "NSButtonCell"; title = "View"; ObjectID = "G1q-Ag-u0M"; */ 12 | "G1q-Ag-u0M.title" = "View"; 13 | 14 | /* Class = "NSButtonCell"; title = "Submit"; ObjectID = "ORZ-Dh-wck"; */ 15 | "ORZ-Dh-wck.title" = "Submit"; 16 | 17 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "QE4-vB-ePI"; */ 18 | "QE4-vB-ePI.title" = "Text Cell"; 19 | 20 | /* Class = "NSTableColumn"; headerCell.title = "Unknown Item"; ObjectID = "QnT-0o-QAw"; */ 21 | "QnT-0o-QAw.headerCell.title" = "Unknown Item"; 22 | 23 | /* Class = "NSTextFieldCell"; title = "Results"; ObjectID = "X4L-QK-gGw"; */ 24 | "X4L-QK-gGw.title" = "Results"; 25 | 26 | /* Class = "NSTableColumn"; headerCell.title = "Result"; ObjectID = "XoS-Yw-8k6"; */ 27 | "XoS-Yw-8k6.headerCell.title" = "Result"; 28 | 29 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "lTj-A6-MWz"; */ 30 | "lTj-A6-MWz.title" = "Text Cell"; 31 | 32 | /* Class = "NSWindow"; title = "Unknown Items"; ObjectID = "pvW-8N-g8T"; */ 33 | "pvW-8N-g8T.title" = "Unknown Items"; 34 | -------------------------------------------------------------------------------- /UI/es.lproj/UnknownItems.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "1tA-WZ-bke"; */ 3 | "1tA-WZ-bke.title" = "Text Cell"; 4 | 5 | /* Class = "NSTableColumn"; headerCell.title = "Submit?"; ObjectID = "4Yf-Xs-7Mi"; */ 6 | "4Yf-Xs-7Mi.headerCell.title" = "Submit?"; 7 | 8 | /* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "4Zg-Mt-eqA"; */ 9 | "4Zg-Mt-eqA.title" = "Table View Cell"; 10 | 11 | /* Class = "NSButtonCell"; title = "View"; ObjectID = "G1q-Ag-u0M"; */ 12 | "G1q-Ag-u0M.title" = "View"; 13 | 14 | /* Class = "NSButtonCell"; title = "Submit"; ObjectID = "ORZ-Dh-wck"; */ 15 | "ORZ-Dh-wck.title" = "Submit"; 16 | 17 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "QE4-vB-ePI"; */ 18 | "QE4-vB-ePI.title" = "Text Cell"; 19 | 20 | /* Class = "NSTableColumn"; headerCell.title = "Unknown Item"; ObjectID = "QnT-0o-QAw"; */ 21 | "QnT-0o-QAw.headerCell.title" = "Unknown Item"; 22 | 23 | /* Class = "NSTextFieldCell"; title = "Results"; ObjectID = "X4L-QK-gGw"; */ 24 | "X4L-QK-gGw.title" = "Results"; 25 | 26 | /* Class = "NSTableColumn"; headerCell.title = "Result"; ObjectID = "XoS-Yw-8k6"; */ 27 | "XoS-Yw-8k6.headerCell.title" = "Result"; 28 | 29 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "lTj-A6-MWz"; */ 30 | "lTj-A6-MWz.title" = "Text Cell"; 31 | 32 | /* Class = "NSWindow"; title = "Unknown Items"; ObjectID = "pvW-8N-g8T"; */ 33 | "pvW-8N-g8T.title" = "Unknown Items"; 34 | -------------------------------------------------------------------------------- /UI/mul.lproj/AboutWindow.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "6g3-Pg-x3P.title" : { 5 | "comment" : "Class = \"NSButtonCell\"; title = \"Support Us!\"; ObjectID = \"6g3-Pg-x3P\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "en" : { 9 | "stringUnit" : { 10 | "state" : "new", 11 | "value" : "Support Us!" 12 | } 13 | }, 14 | "es" : { 15 | "stringUnit" : { 16 | "state" : "translated", 17 | "value" : "¡Apóyanos!" 18 | } 19 | } 20 | } 21 | }, 22 | "bBK-v0-ypq.title" : { 23 | "comment" : "Class = \"NSTextFieldCell\"; title = \"Version:\"; ObjectID = \"bBK-v0-ypq\";", 24 | "extractionState" : "extracted_with_value", 25 | "localizations" : { 26 | "en" : { 27 | "stringUnit" : { 28 | "state" : "new", 29 | "value" : "Version:" 30 | } 31 | }, 32 | "es" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "Versión:" 36 | } 37 | } 38 | } 39 | }, 40 | "fJg-qw-wDf.title" : { 41 | "comment" : "Class = \"NSTextFieldCell\"; title = \"Patrons & Friends\"; ObjectID = \"fJg-qw-wDf\";", 42 | "extractionState" : "extracted_with_value", 43 | "localizations" : { 44 | "en" : { 45 | "stringUnit" : { 46 | "state" : "new", 47 | "value" : "Patrons & Friends" 48 | } 49 | }, 50 | "es" : { 51 | "stringUnit" : { 52 | "state" : "translated", 53 | "value" : "Patrons & Friends" 54 | } 55 | } 56 | } 57 | }, 58 | "J9x-sM-h9S.title" : { 59 | "comment" : "Class = \"NSButtonCell\"; title = \"More Info\"; ObjectID = \"J9x-sM-h9S\";", 60 | "extractionState" : "extracted_with_value", 61 | "localizations" : { 62 | "en" : { 63 | "stringUnit" : { 64 | "state" : "new", 65 | "value" : "More Info" 66 | } 67 | }, 68 | "es" : { 69 | "stringUnit" : { 70 | "state" : "translated", 71 | "value" : "Más Info" 72 | } 73 | } 74 | } 75 | } 76 | }, 77 | "version" : "1.0" 78 | } -------------------------------------------------------------------------------- /UI/mul.lproj/DiffWindow.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "cvj-Jf-F5t.title" : { 5 | "comment" : "Class = \"NSButtonCell\"; title = \"Close\"; ObjectID = \"cvj-Jf-F5t\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "en" : { 9 | "stringUnit" : { 10 | "state" : "new", 11 | "value" : "Close" 12 | } 13 | }, 14 | "es" : { 15 | "stringUnit" : { 16 | "state" : "translated", 17 | "value" : "Cerrar" 18 | } 19 | } 20 | } 21 | }, 22 | "QvC-M9-y7g.title" : { 23 | "comment" : "Class = \"NSWindow\"; title = \"Differences\"; ObjectID = \"QvC-M9-y7g\";", 24 | "extractionState" : "extracted_with_value", 25 | "localizations" : { 26 | "en" : { 27 | "stringUnit" : { 28 | "state" : "new", 29 | "value" : "Differences" 30 | } 31 | }, 32 | "es" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "Diferencias" 36 | } 37 | } 38 | } 39 | } 40 | }, 41 | "version" : "1.0" 42 | } -------------------------------------------------------------------------------- /UI/mul.lproj/PlistWindow.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "1Dc-km-Bwx.title" : { 5 | "comment" : "Class = \"NSButtonCell\"; title = \"Close\"; ObjectID = \"1Dc-km-Bwx\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "en" : { 9 | "stringUnit" : { 10 | "state" : "new", 11 | "value" : "Close" 12 | } 13 | }, 14 | "es" : { 15 | "stringUnit" : { 16 | "state" : "translated", 17 | "value" : "Cerrar" 18 | } 19 | } 20 | } 21 | }, 22 | "iny-wp-VI1.title" : { 23 | "comment" : "Class = \"NSTextFieldCell\"; title = \"plist\"; ObjectID = \"iny-wp-VI1\";", 24 | "extractionState" : "extracted_with_value", 25 | "localizations" : { 26 | "en" : { 27 | "stringUnit" : { 28 | "state" : "new", 29 | "value" : "plist" 30 | } 31 | }, 32 | "es" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "plist" 36 | } 37 | } 38 | } 39 | } 40 | }, 41 | "version" : "1.0" 42 | } -------------------------------------------------------------------------------- /UI/mul.lproj/PrefsWindow.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "F0z-JX-Cv5.title" : { 5 | "comment" : "Class = \"NSWindow\"; title = \"Settings\"; ObjectID = \"F0z-JX-Cv5\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "en" : { 9 | "stringUnit" : { 10 | "state" : "new", 11 | "value" : "Settings" 12 | } 13 | }, 14 | "es" : { 15 | "stringUnit" : { 16 | "state" : "translated", 17 | "value" : "Configuración" 18 | } 19 | } 20 | } 21 | }, 22 | "gXW-vY-Aj1.title" : { 23 | "comment" : "Class = \"NSButtonCell\"; title = \"Disable VirusTotal integration.\"; ObjectID = \"gXW-vY-Aj1\";", 24 | "extractionState" : "extracted_with_value", 25 | "localizations" : { 26 | "en" : { 27 | "stringUnit" : { 28 | "state" : "new", 29 | "value" : "Disable VirusTotal integration." 30 | } 31 | }, 32 | "es" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "Deshabilitar la integración con VirusTotal." 36 | } 37 | } 38 | } 39 | }, 40 | "idJ-pd-k6U.title" : { 41 | "comment" : "Class = \"NSButtonCell\"; title = \"Disable automatic update check.\"; ObjectID = \"idJ-pd-k6U\";", 42 | "extractionState" : "extracted_with_value", 43 | "localizations" : { 44 | "en" : { 45 | "stringUnit" : { 46 | "state" : "new", 47 | "value" : "Disable automatic update check." 48 | } 49 | }, 50 | "es" : { 51 | "stringUnit" : { 52 | "state" : "translated", 53 | "value" : "Deshabilitar la comprobación automática de actualizaciones." 54 | } 55 | } 56 | } 57 | }, 58 | "J9x-sM-h9S.title" : { 59 | "comment" : "Class = \"NSButtonCell\"; title = \"OK\"; ObjectID = \"J9x-sM-h9S\";", 60 | "extractionState" : "extracted_with_value", 61 | "localizations" : { 62 | "en" : { 63 | "stringUnit" : { 64 | "state" : "new", 65 | "value" : "OK" 66 | } 67 | }, 68 | "es" : { 69 | "stringUnit" : { 70 | "state" : "translated", 71 | "value" : "OK" 72 | } 73 | } 74 | } 75 | }, 76 | "WN8-cQ-8xh.title" : { 77 | "comment" : "Class = \"NSButtonCell\"; title = \"Include macOS/known items.\"; ObjectID = \"WN8-cQ-8xh\";", 78 | "extractionState" : "extracted_with_value", 79 | "localizations" : { 80 | "en" : { 81 | "stringUnit" : { 82 | "state" : "new", 83 | "value" : "Include macOS/known items." 84 | } 85 | }, 86 | "es" : { 87 | "stringUnit" : { 88 | "state" : "translated", 89 | "value" : "Incluir ítems de macOS/conocidos." 90 | } 91 | } 92 | } 93 | } 94 | }, 95 | "version" : "1.0" 96 | } -------------------------------------------------------------------------------- /UI/mul.lproj/ResultsWindow.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "71T-dO-S3a.title" : { 5 | "comment" : "Class = \"NSButtonCell\"; title = \"View/Submit Items\"; ObjectID = \"71T-dO-S3a\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "en" : { 9 | "stringUnit" : { 10 | "state" : "new", 11 | "value" : "View/Submit Items" 12 | } 13 | }, 14 | "es" : { 15 | "stringUnit" : { 16 | "state" : "translated", 17 | "value" : "Ver/Enviar ítems" 18 | } 19 | } 20 | } 21 | }, 22 | "c7T-S9-D47.title" : { 23 | "comment" : "Class = \"NSTextFieldCell\"; title = \"Results...\"; ObjectID = \"c7T-S9-D47\";", 24 | "extractionState" : "extracted_with_value", 25 | "localizations" : { 26 | "en" : { 27 | "stringUnit" : { 28 | "state" : "new", 29 | "value" : "Results..." 30 | } 31 | }, 32 | "es" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "Resultados..." 36 | } 37 | } 38 | } 39 | }, 40 | "F0z-JX-Cv5.title" : { 41 | "comment" : "Class = \"NSWindow\"; title = \"KnockKnock\"; ObjectID = \"F0z-JX-Cv5\";", 42 | "extractionState" : "extracted_with_value", 43 | "localizations" : { 44 | "en" : { 45 | "stringUnit" : { 46 | "state" : "new", 47 | "value" : "KnockKnock" 48 | } 49 | }, 50 | "es" : { 51 | "stringUnit" : { 52 | "state" : "translated", 53 | "value" : "KnockKnock" 54 | } 55 | } 56 | } 57 | }, 58 | "ivf-fv-SFp.title" : { 59 | "comment" : "Class = \"NSTextFieldCell\"; title = \"VirusTotal:\"; ObjectID = \"ivf-fv-SFp\";", 60 | "extractionState" : "extracted_with_value", 61 | "localizations" : { 62 | "en" : { 63 | "stringUnit" : { 64 | "state" : "new", 65 | "value" : "VirusTotal:" 66 | } 67 | }, 68 | "es" : { 69 | "stringUnit" : { 70 | "state" : "translated", 71 | "value" : "VirusTotal:" 72 | } 73 | } 74 | } 75 | }, 76 | "viG-9e-1Nj.title" : { 77 | "comment" : "Class = \"NSTextFieldCell\"; title = \"Scan Complete\"; ObjectID = \"viG-9e-1Nj\";", 78 | "extractionState" : "extracted_with_value", 79 | "localizations" : { 80 | "en" : { 81 | "stringUnit" : { 82 | "state" : "new", 83 | "value" : "Scan Complete" 84 | } 85 | }, 86 | "es" : { 87 | "stringUnit" : { 88 | "state" : "translated", 89 | "value" : "Escaneo Completo" 90 | } 91 | } 92 | } 93 | } 94 | }, 95 | "version" : "1.0" 96 | } -------------------------------------------------------------------------------- /UI/mul.lproj/UnknownItems.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "4Yf-Xs-7Mi.headerCell.title" : { 5 | "comment" : "Class = \"NSTableColumn\"; headerCell.title = \"Submit?\"; ObjectID = \"4Yf-Xs-7Mi\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "en" : { 9 | "stringUnit" : { 10 | "state" : "new", 11 | "value" : "Submit?" 12 | } 13 | }, 14 | "es" : { 15 | "stringUnit" : { 16 | "state" : "translated", 17 | "value" : "¿Enviar?" 18 | } 19 | } 20 | } 21 | }, 22 | "G1q-Ag-u0M.title" : { 23 | "comment" : "Class = \"NSButtonCell\"; title = \"View\"; ObjectID = \"G1q-Ag-u0M\";", 24 | "extractionState" : "extracted_with_value", 25 | "localizations" : { 26 | "en" : { 27 | "stringUnit" : { 28 | "state" : "new", 29 | "value" : "View" 30 | } 31 | }, 32 | "es" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "Ver" 36 | } 37 | } 38 | } 39 | }, 40 | "ORZ-Dh-wck.title" : { 41 | "comment" : "Class = \"NSButtonCell\"; title = \"Submit\"; ObjectID = \"ORZ-Dh-wck\";", 42 | "extractionState" : "extracted_with_value", 43 | "localizations" : { 44 | "en" : { 45 | "stringUnit" : { 46 | "state" : "new", 47 | "value" : "Submit" 48 | } 49 | }, 50 | "es" : { 51 | "stringUnit" : { 52 | "state" : "translated", 53 | "value" : "Enviar" 54 | } 55 | } 56 | } 57 | }, 58 | "pvW-8N-g8T.title" : { 59 | "comment" : "Class = \"NSWindow\"; title = \"Unknown Items\"; ObjectID = \"pvW-8N-g8T\";", 60 | "extractionState" : "extracted_with_value", 61 | "localizations" : { 62 | "en" : { 63 | "stringUnit" : { 64 | "state" : "new", 65 | "value" : "Unknown Items" 66 | } 67 | }, 68 | "es" : { 69 | "stringUnit" : { 70 | "state" : "translated", 71 | "value" : "Ítems desconocidos" 72 | } 73 | } 74 | } 75 | }, 76 | "QnT-0o-QAw.headerCell.title" : { 77 | "comment" : "Class = \"NSTableColumn\"; headerCell.title = \"Unknown Item\"; ObjectID = \"QnT-0o-QAw\";", 78 | "extractionState" : "extracted_with_value", 79 | "localizations" : { 80 | "en" : { 81 | "stringUnit" : { 82 | "state" : "new", 83 | "value" : "Unknown Item" 84 | } 85 | }, 86 | "es" : { 87 | "stringUnit" : { 88 | "state" : "translated", 89 | "value" : "Ítem desconocido" 90 | } 91 | } 92 | } 93 | }, 94 | "X4L-QK-gGw.title" : { 95 | "comment" : "Class = \"NSTextFieldCell\"; title = \"Results\"; ObjectID = \"X4L-QK-gGw\";", 96 | "extractionState" : "extracted_with_value", 97 | "localizations" : { 98 | "en" : { 99 | "stringUnit" : { 100 | "state" : "new", 101 | "value" : "Results" 102 | } 103 | }, 104 | "es" : { 105 | "stringUnit" : { 106 | "state" : "translated", 107 | "value" : "Resultados" 108 | } 109 | } 110 | } 111 | }, 112 | "XoS-Yw-8k6.headerCell.title" : { 113 | "comment" : "Class = \"NSTableColumn\"; headerCell.title = \"Result\"; ObjectID = \"XoS-Yw-8k6\";", 114 | "extractionState" : "extracted_with_value", 115 | "localizations" : { 116 | "en" : { 117 | "stringUnit" : { 118 | "state" : "new", 119 | "value" : "Result" 120 | } 121 | }, 122 | "es" : { 123 | "stringUnit" : { 124 | "state" : "translated", 125 | "value" : "Resultado" 126 | } 127 | } 128 | } 129 | } 130 | }, 131 | "version" : "1.0" 132 | } -------------------------------------------------------------------------------- /UI/mul.lproj/UpdateWindow.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | 5 | }, 6 | "version" : "1.0" 7 | } -------------------------------------------------------------------------------- /UnknownItemsWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // UnknownItemsWindowController.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 1/1/25 6 | // 7 | 8 | #import 9 | 10 | @interface UnknownItemsWindowController : NSWindowController 11 | { 12 | 13 | } 14 | 15 | /* PROPERTIES */ 16 | 17 | //unknown items 18 | @property(nonatomic, retain)NSMutableArray* items; 19 | 20 | @property(nonatomic, retain)NSMutableDictionary*results; 21 | @property(nonatomic, retain)NSMutableDictionary*selections; 22 | 23 | //table view 24 | @property(weak)IBOutlet NSTableView *tableView; 25 | 26 | //'submit' button 27 | @property(weak)IBOutlet NSButton *submit; 28 | 29 | //activity indicator 30 | @property (weak) IBOutlet NSProgressIndicator *activityIndicator; 31 | 32 | //status label 33 | @property (weak) IBOutlet NSTextField *statusLabel; 34 | 35 | /* METHODS */ 36 | 37 | //checkbox button handler 38 | -(IBAction)toggleTest:(id)sender; 39 | 40 | //submit button handler 41 | -(IBAction)submit:(id)sender; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Update.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: Update.h 3 | // project: KnockKnock 4 | // description: checks for new versions of KnockKnock (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | 11 | #ifndef Update_h 12 | #define Update_h 13 | 14 | @import Cocoa; 15 | @import Foundation; 16 | 17 | @interface Update : NSObject 18 | 19 | //check for an update 20 | // will invoke app delegate method to update UI when check completes 21 | -(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler; 22 | 23 | @end 24 | 25 | 26 | #endif /* Update_h */ 27 | -------------------------------------------------------------------------------- /Update.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: Update.m 3 | // project: KnockKnock 4 | // description: checks for new versions of KnockKnock 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "Consts.h" 11 | #import "Update.h" 12 | #import "Utilities.h" 13 | #import "AppDelegate.h" 14 | 15 | 16 | @implementation Update 17 | 18 | //check for an update 19 | // ->will invoke app delegate method to update UI when check completes 20 | -(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler 21 | { 22 | //latest version 23 | __block NSString* latestVersion = nil; 24 | 25 | //result 26 | __block NSInteger result = -1; 27 | 28 | //get latest version in background 29 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 30 | 31 | //grab latest version 32 | latestVersion = [self getLatestVersion]; 33 | if(nil != latestVersion) 34 | { 35 | //check 36 | result = (NSOrderedAscending == [getAppVersion() compare:latestVersion options:NSNumericSearch]); 37 | } 38 | 39 | //invoke app delegate method 40 | // ->will update UI/show popup if necessart 41 | dispatch_async(dispatch_get_main_queue(), 42 | ^{ 43 | completionHandler(result, latestVersion); 44 | }); 45 | 46 | }); 47 | 48 | return; 49 | } 50 | 51 | //query interwebz to get latest version 52 | -(NSString*)getLatestVersion 53 | { 54 | //product version(s) data 55 | NSData* productsVersionData = nil; 56 | 57 | //version dictionary 58 | NSDictionary* productsVersionDictionary = nil; 59 | 60 | //latest version 61 | NSString* latestVersion = nil; 62 | 63 | //get version from remote URL 64 | productsVersionData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]]; 65 | if(nil == productsVersionData) 66 | { 67 | //bail 68 | goto bail; 69 | } 70 | 71 | //convert JSON to dictionary 72 | // ->wrap as may throw exception 73 | @try 74 | { 75 | //convert 76 | productsVersionDictionary = [NSJSONSerialization JSONObjectWithData:productsVersionData options:0 error:nil]; 77 | if(nil == productsVersionDictionary) 78 | { 79 | //bail 80 | goto bail; 81 | } 82 | } 83 | @catch(NSException* exception) 84 | { 85 | //bail 86 | goto bail; 87 | } 88 | 89 | //extract latest version 90 | latestVersion = [[productsVersionDictionary objectForKey:PRODUCT_NAME] objectForKey:@"version"]; 91 | 92 | bail: 93 | 94 | return latestVersion; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /UpdateWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: UpdateWindowController.m 3 | // project: KnockKnock 4 | // description: window handler for update window/popup (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface UpdateWindowController : NSWindowController 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | 19 | //version label/string 20 | @property(weak)IBOutlet NSTextField *infoLabel; 21 | 22 | //action button 23 | @property(weak)IBOutlet NSButton *actionButton; 24 | 25 | //label string 26 | @property(nonatomic, retain)NSString* infoLabelString; 27 | 28 | //first button ('update check') 29 | @property(weak)IBOutlet NSView *firstButton; 30 | 31 | //button title 32 | @property(nonatomic, retain)NSString* actionButtonTitle; 33 | 34 | //overlay view 35 | @property(weak)IBOutlet NSView *overlayView; 36 | 37 | //spinner 38 | @property(weak)IBOutlet NSProgressIndicator *progressIndicator; 39 | 40 | /* METHODS */ 41 | 42 | //save the main label's & button title's text 43 | -(void)configure:(NSString*)label buttonTitle:(NSString*)buttonTitle; 44 | 45 | //invoked when user clicks button 46 | // ->trigger action such as opening product website, updating, etc 47 | -(IBAction)buttonHandler:(id)sender; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /UpdateWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: UpdateWindowController.m 3 | // project: KnockKnock 4 | // description: window handler for update window/popup 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "Consts.h" 11 | #import "Utilities.h" 12 | #import "AppDelegate.h" 13 | #import "UpdateWindowController.h" 14 | 15 | 16 | @implementation UpdateWindowController 17 | 18 | @synthesize infoLabel; 19 | @synthesize overlayView; 20 | @synthesize firstButton; 21 | @synthesize actionButton; 22 | @synthesize infoLabelString; 23 | @synthesize actionButtonTitle; 24 | @synthesize progressIndicator; 25 | 26 | //automatically called when nib is loaded 27 | // ->center window 28 | -(void)awakeFromNib 29 | { 30 | //center 31 | [self.window center]; 32 | 33 | return; 34 | } 35 | 36 | //automatically invoked when window is loaded 37 | // ->set to white 38 | -(void)windowDidLoad 39 | { 40 | //super 41 | [super windowDidLoad]; 42 | 43 | //not in dark mode? 44 | // make window white 45 | if(YES != isDarkMode()) 46 | { 47 | //make white 48 | self.window.backgroundColor = NSColor.whiteColor; 49 | } 50 | 51 | //indicated title bar is tranparent (too) 52 | self.window.titlebarAppearsTransparent = YES; 53 | 54 | //set main label 55 | [self.infoLabel setStringValue:self.infoLabelString]; 56 | 57 | //set button text 58 | self.actionButton.title = self.actionButtonTitle; 59 | 60 | //hide first button when action is 'update' 61 | // ->don't need update check button ;) 62 | if(YES == [self.actionButton.title isEqualToString:@"Update"]) 63 | { 64 | //hide 65 | self.firstButton.hidden = YES; 66 | 67 | //then make action button first responder 68 | [self.window makeFirstResponder:self.actionButton]; 69 | } 70 | 71 | //make it key window 72 | [self.window makeKeyAndOrderFront:self]; 73 | 74 | //make window front 75 | [NSApp activateIgnoringOtherApps:YES]; 76 | 77 | return; 78 | } 79 | 80 | //automatically invoked when window is closing 81 | // ->make ourselves unmodal 82 | -(void)windowWillClose:(NSNotification *)notification 83 | { 84 | //make un-modal 85 | [[NSApplication sharedApplication] stopModal]; 86 | 87 | return; 88 | } 89 | 90 | //save the main label's & button title's text 91 | // ->invoked before window is loaded (and thus buttons, etc are nil) 92 | -(void)configure:(NSString*)label buttonTitle:(NSString*)buttonTitle 93 | { 94 | //save label's string 95 | self.infoLabelString = label; 96 | 97 | //save button's title 98 | self.actionButtonTitle = buttonTitle; 99 | 100 | return; 101 | } 102 | 103 | //invoked when user clicks button 104 | // trigger action such as opening product website, updating, etc 105 | -(IBAction)buttonHandler:(id)sender 106 | { 107 | //handle 'update' / 'more info', etc 108 | // ->open KnockKnock's webpage, if they *didn't* click 'Close' 109 | if(YES != [((NSButton*)sender).title isEqualToString:NSLocalizedString(@"Close", @"Close")]) 110 | { 111 | //open URL 112 | // ->invokes user's default browser 113 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]]; 114 | } 115 | 116 | //always close window 117 | [[self window] close]; 118 | 119 | return; 120 | } 121 | @end 122 | -------------------------------------------------------------------------------- /Utilities.h: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 2/7/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #ifndef KnockKnock_Utilities_h 10 | #define KnockKnock_Utilities_h 11 | 12 | /* FUNCTIONS */ 13 | 14 | //get OS's major or minor version 15 | SInt32 getVersion(OSType selector); 16 | 17 | //disable std err 18 | void disableSTDERR(void); 19 | 20 | //get name of logged in user 21 | NSString* getConsoleUser(void); 22 | 23 | //get all users 24 | NSMutableDictionary* allUsers(void); 25 | 26 | //give a list of paths 27 | // convert any `~` to all or current user 28 | NSMutableArray* expandPaths(const __strong NSString* const paths[], int count); 29 | 30 | //given a path to binary 31 | // parse it back up to find app's bundle 32 | NSBundle* findAppBundle(NSString* binaryPath); 33 | 34 | //get an icon for a process 35 | // ->for apps, this will be app's icon, otherwise just a standard system one 36 | NSImage* getIconForBinary(NSString* binary, NSBundle* bundle); 37 | 38 | //given a directory and a filter predicate 39 | // ->return all matches 40 | NSArray* directoryContents(NSString* directory, NSString* predicate); 41 | 42 | //hash (sha1/md5) a file 43 | NSDictionary* hashFile(NSString* filePath); 44 | 45 | //get app's version 46 | // ->extracted from Info.plist 47 | NSString* getAppVersion(void); 48 | 49 | //convert a textview to a clickable hyperlink 50 | void makeTextViewHyperlink(NSTextField* textField, NSURL* url); 51 | 52 | //set the color of an attributed string 53 | NSMutableAttributedString* setStringColor(NSAttributedString* string, NSColor* color); 54 | 55 | //exec a process and grab it's output 56 | NSData* execTask(NSString* binaryPath, NSArray* arguments, int* exitCode); 57 | 58 | //check if computer has network connection 59 | BOOL isNetworkConnected(void); 60 | 61 | //escape \ and "s in a string 62 | NSString* escapeString(NSString* unescapedString); 63 | 64 | //find a constraint (by name) of a view 65 | NSLayoutConstraint* findConstraint(NSView* view, NSString* constraintName); 66 | 67 | //given a 'short' path or process name 68 | // ->find the full path by scanning $PATH 69 | NSString* which(NSString* processName); 70 | 71 | //get array of running procs 72 | // ->returns an array of process paths 73 | NSMutableArray* runningProcesses(void); 74 | 75 | //check if a file is a binary 76 | BOOL isBinary(NSString* file); 77 | 78 | //lookup object in dictionary 79 | // note: key can be case-insensitive 80 | id extractFromDictionary(NSDictionary* dictionary, NSString* sensitiveKey); 81 | 82 | //check if (full) dark mode 83 | // meaning, Mojave+ and dark mode enabled 84 | BOOL isDarkMode(void); 85 | 86 | //bring an app to foreground (to get an icon in the dock) or background 87 | void transformProcess(ProcessApplicationTransformState location); 88 | 89 | //set line space 90 | void setLineSpacing(NSTextField* textField, CGFloat lineSpacing); 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /VTButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // vtButton.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 3/26/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "File.h" 10 | #import 11 | 12 | //#import "ItemTableController.h" 13 | 14 | @class ItemTableController; 15 | 16 | @interface VTButton : NSButton 17 | { 18 | 19 | } 20 | 21 | //properties 22 | 23 | //parent object 24 | @property(assign)ItemTableController *delegate; 25 | 26 | //File object 27 | @property(nonatomic, retain)File* fileObj; 28 | 29 | //button's row index 30 | 31 | //flag indicating press 32 | @property BOOL mouseDown; 33 | 34 | //flag indicating exit 35 | @property BOOL mouseExit; 36 | 37 | 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /VTInfoWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // VTInfoWindow.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 3/29/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | @class File; 10 | @class HyperlinkTextField; 11 | 12 | #import 13 | 14 | @interface VTInfoWindowController : NSWindowController 15 | { 16 | 17 | } 18 | 19 | /* PROPERTIES */ 20 | 21 | //window controller 22 | @property(nonatomic, strong)VTInfoWindowController *windowController; 23 | 24 | //file object 25 | @property(nonatomic, retain)File* fileObj; 26 | 27 | 28 | //properties in window 29 | @property (weak) IBOutlet NSTextField *unknownFile; 30 | 31 | @property (weak) IBOutlet NSTextField *fileNameLabel; 32 | @property (weak) IBOutlet NSTextField *fileName; 33 | 34 | @property (weak) IBOutlet NSTextField *detectionRatioLabel; 35 | @property (weak) IBOutlet NSTextField *detectionRatio; 36 | 37 | @property (weak) IBOutlet NSTextField *analysisURLLabel; 38 | @property (weak) IBOutlet HyperlinkTextField *analysisURL; 39 | 40 | @property (weak) IBOutlet NSButton *closeButton; 41 | 42 | @property (weak) IBOutlet NSButton *submitButton; 43 | @property (weak) IBOutlet NSProgressIndicator *progressIndicator; 44 | @property (strong) IBOutlet NSView *overlayView; 45 | @property (weak) IBOutlet NSTextField *statusMsg; 46 | 47 | /* METHODS */ 48 | 49 | //init method 50 | // ->save item and load nib 51 | -(id)initWithItem:(File*)selectedItem; 52 | 53 | //'submit' button handler 54 | -(IBAction)vtButtonHandler:(id)sender; 55 | 56 | //'close' button handler 57 | -(IBAction)closeButtonHandler:(id)sender; 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /VirusTotal.h: -------------------------------------------------------------------------------- 1 | // 2 | // VirusTotal.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 3/8/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "PluginBase.h" 10 | #import 11 | 12 | @interface VirusTotal : NSObject 13 | { 14 | 15 | } 16 | 17 | /* METHODS */ 18 | 19 | //thread function 20 | // ->runs in the background to get virus total info about a plugin's items 21 | -(void)getInfo:(PluginBase*)plugin; 22 | 23 | //make the (POST)query to VT 24 | -(NSDictionary*)postRequest:(NSURL*)url parameters:(id)params; 25 | 26 | //submit a file to VT 27 | -(NSDictionary*)submit:(File*)fileObj; 28 | 29 | //submit a rescan request 30 | -(NSDictionary*)reScan:(File*)fileObj; 31 | 32 | //process results 33 | // ->updates items (found, detection ratio, etc) 34 | -(void)processResults:(NSArray*)items results:(NSDictionary*)results; 35 | 36 | //get info for a single item 37 | // will callback into AppDelegate to reload plugin 38 | -(BOOL)getInfoForItem:(File*)fileObj scanID:(NSString*)scanID; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /WhiteList/whitelistedCommands.json: -------------------------------------------------------------------------------- 1 | { 2 | "commands": 3 | [ 4 | "alias ConsoleMessage=echo", 5 | "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec:/System/Library/CoreServices; export PATH", 6 | "set -u", 7 | ". /etc/hostconfig" 8 | ] 9 | } -------------------------------------------------------------------------------- /WhiteList/whitelistedExtensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "mgndgikekgjfcpckkfioiadnlibdjbkf" : "Chrome", 3 | "nmmhkkegccagdldgiimedpiccmgmieda" : "Google Wallet", 4 | "ahfgeienlihckogmohjhadlkjgocpleb" : "Google Store", 5 | "gfdkimpbcpahaombhbimeihdjnejgicl" : "Chrome FeedBack", 6 | "pjkljhegncpnkpknbcohdijeoejaedia" : "Gmail", 7 | "nkeimhogjdpnpccoofpliimaahmaaome" : "Google Hangouts", 8 | "coobgpohoikkiipiblmjeljniedjpjpf" : "Google Search", 9 | "neajdppkdcdipfabeoofebfddakdcjhd" : "Google Network Speech", 10 | "kmendfapggjehodndflmmgagdbamhnfd" : "Chrome Crypto Token Extension", 11 | "apdfllckaahabafndbhieahigkjlhalf" : "Google Drive", 12 | "dnhpdliibojhegemfjheidglijccjfmc" : "Google Hotword Helper", 13 | "bepbmhgboaologfdajaanbcjmnhjmhfn" : "Google Voice Search Hotword", 14 | "blpcfgokakmgnkcojhhkbfbldkacnbeo" : "Google YouTube", 15 | "aohghmighlieiainnegkcijnfilokake" : "Google Docs", 16 | "eemcgdkfndhakfknompkggombfjjjeno" : "Chrome Bookmark Manager", 17 | "mfehgcgbbipciphmccgaenjidiccnmng" : "Chrome Cloud Print", 18 | "ennkphjdgehloodpbhlhldgbnhmacadg" : "Chrome Settings", 19 | "pafkbggdmjlpgkdkcbjmhmfcdpncadgh" : "Google Now", 20 | "mfffpogegjflfpflabcdkioaeobkgjik" : "GAIA Component Extension", 21 | } -------------------------------------------------------------------------------- /WhiteList/whitelistedFiles.json: -------------------------------------------------------------------------------- 1 | { 2 | "/usr/libexec/configureLocalKDC":["19f6e328d0286ad7f81ee8224e369726"], 3 | "/usr/libexec/locate.updatedb":["e8cc729ae05233c414eb0c672d836fc1"], 4 | "/usr/libexec/ntpd-wrapper":["baf0968c6df24734e079baeb01851221"], 5 | "/usr/libexec/postfix/check-aliases.sh":["ff8fb1f04e944737d2cd15e410f6de06"], 6 | "/Library/Spotlight/Microsoft Office.mdimporter/Contents/MacOS/Microsoft Office":["d9a23fc4585c30448bccf46213c26028"], 7 | "/usr/libexec/gkreport":["a9355083f340d5a1f72127f8d1f08e44", "24482cf8b7be865582ad10e0bf0b6a8e"], 8 | "/etc/periodic/daily/110.clean-tmps":["3f4a4eb220706b891260f1e22dff34d5"], 9 | "/etc/periodic/daily/130.clean-msgs":["f6367dd6876c2a06a5d6728d80ea19c3"], 10 | "/etc/periodic/daily/140.clean-rwho":["aecff6f0a6eb42bf5de8bcb6cd42276e"], 11 | "/etc/periodic/daily/199.clean-fax":["eed6196746a0163429d2e82948a6e6b9"], 12 | "/etc/periodic/daily/310.accounting":["a5a3a7fe42f1fefe8519f1b964487b15"], 13 | "/etc/periodic/daily/400.status-disks":["b1a3c1672198511b82708c90a824af07"], 14 | "/etc/periodic/daily/420.status-network":["37a7cf005e69d02bfe9f5c42ad536560"], 15 | "/etc/periodic/daily/430.status-rwho":["6f95783dafa59bab982827bdb8b865d9"], 16 | "/etc/periodic/daily/999.local":["0516c2cbf1255d9547da29cdd78a5d88"], 17 | "/etc/periodic/weekly/320.whatis":["203fb58bd70bbd788d5d05ba62f14bc3"], 18 | "/etc/periodic/weekly/999.local":["c53d2a36e6b70a5e6e22508d9b50a85a"], 19 | "/etc/periodic/monthly/199.rotate-fax":["4984ab80ac4b1d13eb5d265eb30d8193"], 20 | "/etc/periodic/monthly/200.accounting":["84b8f6b0fa02fbf8fce92f1be7912dad"], 21 | "/etc/periodic/monthly/999.local":["c63e8e9d3ac93dd923dc9555f0237d17"], 22 | "/etc/defaults/periodic.conf":["7beb8971f053949f6f1681a9d5204028", "62842e4978d878da44697ba81eac797c"], 23 | "/etc/rc.common":["5db454651210bcb920c010f8149d118c", "9c3ea0b6d054087fecd2013d875c336b", "28ce428faefe6168618867f3ff5527f9"] 24 | } 25 | -------------------------------------------------------------------------------- /WhiteList/whitelistedKexts.json: -------------------------------------------------------------------------------- 1 | { 2 | "/Library/Extensions/HighPointIOP.kext/Contents/MacOS/HighPointIOP":["Developer ID Application: HighPoint Technologies, Inc (DX6G69M9N2)"], 3 | "/Library/Extensions/PromiseSTEX.kext/Contents/MacOS/PromiseSTEX":["Developer ID Application: Promise Technology Mobile Apps (268CCUR4WN)"], 4 | "/System/Library/Extensions/PromiseSTEX.kext/Contents/MacOS/PromiseSTEX":["Developer ID Application: Promise Technology Mobile Apps (268CCUR4WN)"], 5 | "/Library/Extensions/ATTOCelerityFC8.kext/Contents/MacOS/ATTOCelerityFC8":["Developer ID Application: ATTO Technology, Inc. (FC94733TZD)"], 6 | "/Library/Extensions/HighPointRR.kext/Contents/MacOS/HighPointRR":["Developer ID Application: HighPoint Technologies, Inc (DX6G69M9N2)"], 7 | "/Library/Extensions/CalDigitHDProDrv.kext/Contents/MacOS/CalDigitHDProDrv":["Developer ID Application: CalDigit, Inc (8R7PS6VYW7)"], 8 | "/Library/Extensions/SoftRAID.kext/Contents/MacOS/SoftRAID":["Developer ID Application: SoftRAID LLC (NDGSU3WA4Y)", "Developer ID Application: Other World Computing (Q9P8K45M5C)"], 9 | "/Library/Extensions/ATTOExpressSASHBA2.kext/Contents/MacOS/ATTOExpressSASHBA2":["Developer ID Application: ATTO Technology, Inc. (FC94733TZD)"], 10 | "/Library/Extensions/ArcMSR.kext/Contents/MacOS/ArcMSR":["Developer ID Application: Areca Technology Corporation (34JN824YNC)"], 11 | "/System/Library/Extensions/ArcMSR.kext/Contents/MacOS/ArcMSR":["Developer ID Application: Areca Technology Corporation (34JN824YNC)"], 12 | "/Library/Extensions/ATTOExpressSASRAID2.kext/Contents/MacOS/ATTOExpressSASRAID2":["Developer ID Application: ATTO Technology, Inc. (FC94733TZD)"], 13 | "/Library/Extensions/ACS6x.kext/Contents/MacOS/ACS6x":["Developer ID Application: Accusys,Inc (K3TDMD9Y6B)"], 14 | "/System/Library/Extensions/Accusys6xxxx.kext/Contents/MacOS/Accusys6xxxx":["b02c769f3b6635e307b551462a48107d"], 15 | "/System/Library/Extensions/AppleBacklightExpert.kext/AppleBacklightExpert":["6501354452b48465dea904e27fe8c5f9", "8854000a050f4bbadd36db2b8118ffa1", "678c0efdde7c4a90e5e5b76855c9ee85"], 16 | "/System/Library/Extensions/ArcMSR.kext/Contents/MacOS/ArcMSR":["c57237576ff817b13246296ec786cce2"], 17 | "/System/Library/Extensions/ATTOCelerityFC.kext/Contents/MacOS/ATTOCelerityFC":["c061f1786d1e9b07846c1bfa1a906190"], 18 | "/System/Library/Extensions/ATTOCelerityFC8.kext/Contents/MacOS/ATTOCelerityFC8":["bbf4c3a42934c36d8ae804c7c7386547"], 19 | "/System/Library/Extensions/ATTOExpressPCI4.kext/Contents/MacOS/ATTOExpressPCI4":["433e4f9488d90020e480c56893c8a80f"], 20 | "/System/Library/Extensions/ATTOExpressSASHBA.kext/Contents/MacOS/ATTOExpressSASHBA":["4d5ef99ed9d52e8a0550b8a91c6a9aca"], 21 | "/System/Library/Extensions/ATTOExpressSASHBA2.kext/Contents/MacOS/ATTOExpressSASHBA2":["e440639d53144ccb09d9796e675169f9"], 22 | "/System/Library/Extensions/ATTOExpressSASHBA3.kext/Contents/MacOS/ATTOExpressSASHBA3":["864aed4dd2f45fbc39a95fec1efb47db"], 23 | "/System/Library/Extensions/ATTOExpressSASRAID.kext/Contents/MacOS/ATTOExpressSASRAID":["e68c0f60ca8e10bbd241ce1335a3dca8"], 24 | "/System/Library/Extensions/ATTOExpressSASRAID2.kext/Contents/MacOS/ATTOExpressSASRAID2":["ed974b9a9e41b01d648f64bec5959b46"], 25 | "/System/Library/Extensions/AudioAUUC.kext/AudioAUUC":["6e02093ece9dc275a30ecd3417b1b016", "a785d5ccef1991009af1d4d25a0373c2", "020e254d626ea0eb8432880314bdffda"], 26 | "/System/Library/Extensions/CalDigitHDProDrv.kext/Contents/MacOS/CalDigitHDProDrv":["a53366611eed8c2cb2cf12b79f893ee3"], 27 | "/System/Library/Extensions/CoreStorage.kext/Contents/MacOS/CoreStorage":["7ffecdf00647495170b05bb64bc0ca26"], 28 | "/System/Library/Extensions/IOGraphicsFamily.kext/IOGraphicsFamily":["e037d3730c01962ebcd4bba09d69679c", "6c16ebd149ac177978393ee98ff84c2d", "68941445971cf95576ff28831c423d04"], 29 | "/System/Library/Extensions/IONDRVSupport.kext/IONDRVSupport":["013c73074d7993cba3e230b5511cd901", "f470a6cacf052cbe469dc400973511d2", "6688610c05329bfc4909b4bc21230d6d"], 30 | "/System/Library/Extensions/IOPCIFamily.kext/IOPCIFamily":["6a9d57017a18fc470d323547d1ab86e4", "562be2c6d9d55b3ad2d8ee00e9da4ca6", "a899be1ccbe7cdc6fb54f92f7aa09dc3"], 31 | "/System/Library/Extensions/HighPointIOP.kext/Contents/MacOS/HighPointIOP":["64e3e122c1f0d24fd0b225c18f44440d"], 32 | "/System/Library/Extensions/HighPointRR.kext/Contents/MacOS/HighPointRR":["316bb5757bbe7ef70044f85717ff97df"], 33 | "/System/Library/Extensions/JMicronATA.kext/Contents/MacOS/JMicronATA":["9c8207d44446861a5b40e2ac4c6f5dba"], 34 | "/System/Library/Extensions/PromiseSTEX.kext/Contents/MacOS/PromiseSTEX":["1cd38bebacdc6ba85a86a8b65474b8b5"], 35 | "/System/Library/Extensions/SoftRAID.kext/Contents/MacOS/SoftRAID":["18bfb361ae05cff7f2a2310d685a44fc"], 36 | "/System/Library/Extensions/webdav_fs.kext/Contents/MacOS/webdav_fs":["6b9068594520afce60dcf99262d1af12"] 37 | } 38 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | KNOCKKNOCK CHANGELOG 2 | 3 | 4 | VERSION 1.6.1 (10/8/2015) 5 | updated crontab plugin, so it would ignore commented out jobs 6 | 7 | 8 | VERSION 1.6.0 (10/5/2015) 9 | made application fully resizable 10 | improved 'inserted dylibs' plugin (now checks for __XPC_DYLD_INSERT_LIBRARIES) 11 | added self verification check so malicious modifications (e.g. whitelists) may be detected 12 | updated whitelist hashes for El Capitan 13 | fixed bug where VirusTotal timeout could trigger crash 14 | 15 | 16 | VERSION 1.5.0 (7/19/2015) 17 | added Cron Job plugin 18 | added Login/Logout Hook plugin 19 | improved Launch Daemon/Agent plugin (now includes items with'OnDemand' set to False) 20 | apple-signed binaries now shown with green 'signed' icon 21 | fixed issue with copy & paste (via NSApplicationKeyEvents subclass) 22 | updated whitelist to include various Apple binaries (kexts) 23 | when saving results, user can now specify name and location of output 24 | network availability now checked before trying to connect to VirusTotal 25 | other minor UI tweaks/improvement (e.g. fixed text color issue in unselected rows, etc.) 26 | extra error checking to improve stability 27 | 28 | 29 | VERSION 1.3.1 (5/18/2015) 30 | made preferences persistence 31 | fixed logic bug where re-scans might hang 32 | added extra error checking in launch item plugin 33 | 34 | 35 | VERSION 1.3.0 (5/13/2015) 36 | added ability to enumerate login items, installed by sandboxed apps 37 | improved vertical scrollbars, so they'd always be rendered in 'modern' style 38 | other minor UI tweaks (e.g. pref window clipping) 39 | 40 | 41 | VERSION 1.2.4 (5/4/2015) 42 | added timeout to injected dylib scanning plugin 43 | improved logic for making windows modal (e.g. window checks) 44 | 45 | 46 | VERSION 1.2.3 (4/30/2015) 47 | improved VirusTotal logic (e.g. when an signed OS file was flagged) 48 | tweaked UI to be more compatible with OS X 10.9 49 | 50 | 51 | VERSION 1.2.2 (4/28/2015) 52 | browser extensions plugin now supports enumerating extensions in older versions of Safari 53 | improved JSON output & fixed bug when saving JSON when file hash or signature was nil 54 | recompiled with updated/improved (shared) MachO parser 55 | fixed issue where on multiple scans, result popup was not properly updated 56 | improved UI to display item's plist (when applicable) into the item's row 57 | listed items in item table are now selectable 58 | 59 | 60 | VERSION 1.2.1 (4/25/2015) 61 | improved DYLD_INSERT_LIBRARIES plugin to report path to applications' Info.plist as string (instead of URL) 62 | fixed issue in DYLD_INSERT_LIBRARIES plugin, where NSInvalidArgumentException would result if enviro var was string 63 | 64 | 65 | VERSION 1.2.0 (4/25/2015) 66 | added DYLD_INSERT_LIBRARIES plugin 67 | browser extensions plugin now supports enumerating Opera plugins 68 | browser extensions plugin improved to enumerate Google Chrome with multiple profiles 69 | increased timeouts for making a popups modal (to avoid NSInternalInconsistencyException issues) 70 | fixed nil dictionary insertion when processing Safari extensions with missing 'Bundle Identifier' 71 | 72 | 73 | VERSION 1.1.0 (4/24/2015) 74 | added plugin to scan for Authorization Plugins 75 | fixed NSJSONSerialization bug (parsing Google Chrome plugins) 76 | 77 | 78 | VERSION 1.0.0 (4/23/2015) 79 | initial release 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /es.lproj/KnockKnock-InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle name */ 2 | "CFBundleName" = "KnockKnock"; 3 | 4 | /* Copyright (human-readable) */ 5 | "NSHumanReadableCopyright" = "Copyright © 2019 Objective-See, LLC. Todos los derechos reservados."; 6 | 7 | -------------------------------------------------------------------------------- /icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/icon.psd -------------------------------------------------------------------------------- /images/authorizationIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/authorizationIcon.png -------------------------------------------------------------------------------- /images/binaryIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/binaryIcon.icns -------------------------------------------------------------------------------- /images/browserIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/browserIcon.png -------------------------------------------------------------------------------- /images/btmIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/btmIcon.png -------------------------------------------------------------------------------- /images/bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/bug.png -------------------------------------------------------------------------------- /images/cronIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/cronIcon.png -------------------------------------------------------------------------------- /images/directoryServicesIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/directoryServicesIcon.png -------------------------------------------------------------------------------- /images/dockTileIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/dockTileIcon.png -------------------------------------------------------------------------------- /images/dylibIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/dylibIcon.png -------------------------------------------------------------------------------- /images/eventRulesIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/eventRulesIcon.png -------------------------------------------------------------------------------- /images/extensionIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/extensionIcon.png -------------------------------------------------------------------------------- /images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/info.png -------------------------------------------------------------------------------- /images/infoBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/infoBG.png -------------------------------------------------------------------------------- /images/infoOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/infoOver.png -------------------------------------------------------------------------------- /images/kernelIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/kernelIcon.png -------------------------------------------------------------------------------- /images/kkIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/kkIcon.png -------------------------------------------------------------------------------- /images/kkText.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/kkText.ai -------------------------------------------------------------------------------- /images/kkText.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/kkText.png -------------------------------------------------------------------------------- /images/launchIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/launchIcon.png -------------------------------------------------------------------------------- /images/logInOutIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/logInOutIcon.png -------------------------------------------------------------------------------- /images/loginIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/loginIcon.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/logo.png -------------------------------------------------------------------------------- /images/logoApple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/logoApple.png -------------------------------------------------------------------------------- /images/logoAppleBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/logoAppleBG.png -------------------------------------------------------------------------------- /images/logoAppleOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/logoAppleOver.png -------------------------------------------------------------------------------- /images/mainIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/mainIcon.png -------------------------------------------------------------------------------- /images/periodicIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/periodicIcon.png -------------------------------------------------------------------------------- /images/proxyIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/proxyIcon.png -------------------------------------------------------------------------------- /images/quicklookIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/quicklookIcon.png -------------------------------------------------------------------------------- /images/scanIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/scanIcon.png -------------------------------------------------------------------------------- /images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/settings.png -------------------------------------------------------------------------------- /images/settingsBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/settingsBG.png -------------------------------------------------------------------------------- /images/settingsOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/settingsOver.png -------------------------------------------------------------------------------- /images/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/show.png -------------------------------------------------------------------------------- /images/showBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/showBG.png -------------------------------------------------------------------------------- /images/showOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/showOver.png -------------------------------------------------------------------------------- /images/signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/signed.png -------------------------------------------------------------------------------- /images/signedAppleIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/signedAppleIcon.png -------------------------------------------------------------------------------- /images/spotlightIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/spotlightIcon.png -------------------------------------------------------------------------------- /images/startScan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/startScan.png -------------------------------------------------------------------------------- /images/startScanBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/startScanBG.png -------------------------------------------------------------------------------- /images/startScanOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/startScanOver.png -------------------------------------------------------------------------------- /images/startupScriptsIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/startupScriptsIcon.png -------------------------------------------------------------------------------- /images/stopScan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/stopScan.png -------------------------------------------------------------------------------- /images/stopScanBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/stopScanBG.png -------------------------------------------------------------------------------- /images/stopScanOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/stopScanOver.png -------------------------------------------------------------------------------- /images/systemExtensionIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/systemExtensionIcon.png -------------------------------------------------------------------------------- /images/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/unknown.png -------------------------------------------------------------------------------- /images/unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/unsigned.png -------------------------------------------------------------------------------- /images/virus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/virus.png -------------------------------------------------------------------------------- /images/virusTotal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/virusTotal.png -------------------------------------------------------------------------------- /images/virusTotalBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/virusTotalBG.png -------------------------------------------------------------------------------- /images/vtLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KnockKnock/a72b1b2d448310328a3c74a663a4a75f9b2807a7/images/vtLogo.png -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | // 2 | // main.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 11/12/18. 6 | // Copyright © 2018 Objective-See. All rights reserved. 7 | // 8 | 9 | #ifndef main_h 10 | #define main_h 11 | 12 | #import "Consts.h" 13 | #import "Filter.h" 14 | #import "Utilities.h" 15 | #import "VirusTotal.h" 16 | #import "AppDelegate.h" 17 | #import "ItemEnumerator.h" 18 | 19 | #import 20 | 21 | /* GLOBALS */ 22 | 23 | //filter object 24 | Filter* itemFilter = nil; 25 | 26 | //shared item enumerator object 27 | ItemEnumerator* sharedItemEnumerator = nil; 28 | 29 | //cmdline scan 30 | BOOL cmdlineMode = NO; 31 | 32 | //cmdline flag 33 | BOOL isVerbose = NO; 34 | 35 | /* FUNCTIONS */ 36 | 37 | //print usage 38 | void usage(void); 39 | 40 | //perform a cmdline scan 41 | void cmdlineScan(void); 42 | 43 | //pretty print JSON 44 | void prettyPrintJSON(NSString* output); 45 | 46 | #endif /* main_h */ 47 | -------------------------------------------------------------------------------- /mul.lproj/DiffWindow.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "cvj-Jf-F5t.title" : { 5 | "comment" : "Class = \"NSButtonCell\"; title = \"Close\"; ObjectID = \"cvj-Jf-F5t\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "en" : { 9 | "stringUnit" : { 10 | "state" : "new", 11 | "value" : "Close" 12 | } 13 | } 14 | } 15 | }, 16 | "QvC-M9-y7g.title" : { 17 | "comment" : "Class = \"NSWindow\"; title = \"Differences\"; ObjectID = \"QvC-M9-y7g\";", 18 | "extractionState" : "extracted_with_value", 19 | "localizations" : { 20 | "en" : { 21 | "stringUnit" : { 22 | "state" : "new", 23 | "value" : "Differences" 24 | } 25 | } 26 | } 27 | } 28 | }, 29 | "version" : "1.0" 30 | } -------------------------------------------------------------------------------- /patrons.txt: -------------------------------------------------------------------------------- 1 | Patrons (2^6+): 2 | Jan Koum, Matt Mullenweg, Christian Blümlein, Shain Singh, Andreas Fink, Nuno, Rabi Rob Thomas, Mikhail S. 3 | 4 | Friends of Objective-See: 5 | Kandji, Jamf, Moonlock (by MacPaw), Palo Alto Networks, 1Password, iVerify, MalwareBytes, SmugMug, Guardian Mobile Firewall, Halo Privacy, The Mitten Mac 6 | --------------------------------------------------------------------------------