├── .gitignore ├── KextViewr.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ ├── IDEWorkspaceChecks.plist │ ├── KnockKnock.xccheckout │ └── TaskExplorer.xccheckout │ └── xcuserdata │ ├── patrick.xcuserdatad │ └── WorkspaceSettings.xcsettings │ └── patrickw.xcuserdatad │ ├── UserInterfaceState.xcuserstate │ └── WorkspaceSettings.xcsettings └── KextViewr ├── 3rdParty ├── OrderedDictionary.h └── OrderedDictionary.m ├── AboutWindow.xib ├── AboutWindowController.h ├── AboutWindowController.m ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets ├── Refresh.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png ├── RefreshAlternate.imageset │ ├── Contents.json │ └── alternate.png ├── Save.imageset │ ├── Contents.json │ ├── darkMode.png │ └── lightMode.png └── SaveAlternate.imageset │ ├── Contents.json │ └── alternate.png ├── CustomTextField.h ├── CustomTextField.m ├── Filter.h ├── Filter.m ├── Info.plist ├── KKRow.h ├── KKRow.m ├── Kext.h ├── Kext.m ├── KextEnumerator.h ├── KextEnumerator.m ├── KextTableController.h ├── KextTableController.m ├── NSApplicationKeyEvents.h ├── NSApplicationKeyEvents.m ├── NSMutableArray+QueueAdditions.h ├── NSMutableArray+QueueAdditions.m ├── changelog.txt ├── consts.h ├── en.lproj ├── InfoPlist.strings └── MainMenu.xib ├── images ├── icon.iconset │ ├── 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 ├── kvText.png ├── logo.png ├── logoApple.png ├── logoAppleBG.png ├── logoAppleOver.png ├── refreshIcon.png ├── refreshIconBG.png ├── refreshIconOver.png ├── signed.png ├── signedAppleIcon.png └── unknown.png ├── kkRowCell.h ├── kkRowCell.m ├── kvText.ai ├── main.m ├── patrons.txt ├── utilities.h └── utilities.m /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Carthage/* 3 | DerivedData/* 4 | *.xcscheme 5 | *.xcuserstate 6 | KextViewr.xcodeproj/xcuserdata/* 7 | KextViewr.xcodeproj/project.xcworkspace/xcuserdata/* 8 | 9 | -------------------------------------------------------------------------------- /KextViewr.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D21BC4F172AF43D009D1CFD /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D21BC4E172AF43D009D1CFD /* Cocoa.framework */; }; 11 | 7D1222761CCB517000CD38C1 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D1222751CCB517000CD38C1 /* IOKit.framework */; }; 12 | 7DAA78091B903BF1004840B9 /* CustomTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DAA78081B903BF1004840B9 /* CustomTextField.m */; }; 13 | CD001B381AB903040089014A /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = CD001B351AB903040089014A /* logo.png */; }; 14 | CD001B391AB903040089014A /* logoApple.png in Resources */ = {isa = PBXBuildFile; fileRef = CD001B361AB903040089014A /* logoApple.png */; }; 15 | CD02194F1AD34D8B005148A2 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD02194D1AD34D8B005148A2 /* AboutWindow.xib */; }; 16 | CD0219531AD34D9A005148A2 /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD0219521AD34D9A005148A2 /* AboutWindowController.m */; }; 17 | CD02195C1AD38823005148A2 /* kkRowCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CD02195B1AD38823005148A2 /* kkRowCell.m */; }; 18 | CD3F4CE81AF5CF68002A2647 /* KextEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = CD3F4CE61AF5CF68002A2647 /* KextEnumerator.m */; }; 19 | CD3F4CEB1AF6D948002A2647 /* OrderedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = CD3F4CEA1AF6D948002A2647 /* OrderedDictionary.m */; }; 20 | CD4D53CA1B20296E00008030 /* unknown.png in Resources */ = {isa = PBXBuildFile; fileRef = CD4D53C91B20296E00008030 /* unknown.png */; }; 21 | CD4D54221B2CE6F200008030 /* NSMutableArray+QueueAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CD4D54211B2CE6F200008030 /* NSMutableArray+QueueAdditions.m */; }; 22 | CD4D543F1B2FF32C00008030 /* signedAppleIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD4D543E1B2FF32C00008030 /* signedAppleIcon.png */; }; 23 | CD5813DE299F20A800DEBE46 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD5813DD299F20A800DEBE46 /* Assets.xcassets */; }; 24 | CD5813E029A06ACB00DEBE46 /* patrons.txt in Resources */ = {isa = PBXBuildFile; fileRef = CD5813DF29A06ACB00DEBE46 /* patrons.txt */; }; 25 | CD5813E129A07BCD00DEBE46 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D561A95B4B4009790E2 /* MainMenu.xib */; }; 26 | CD5813E329A07CE000DEBE46 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = CD5813E229A07CE000DEBE46 /* Info.plist */; }; 27 | CD5813E529A07DFD00DEBE46 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CD5813E429A07DFD00DEBE46 /* main.m */; }; 28 | CD6095731A87067D00E091CD /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD6095721A87067D00E091CD /* Security.framework */; }; 29 | CD6AFB831B4BAA2100D42C34 /* refreshIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB821B4BAA2100D42C34 /* refreshIcon.png */; }; 30 | CD6AFB861B4BABB200D42C34 /* refreshIconBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB841B4BABB200D42C34 /* refreshIconBG.png */; }; 31 | CD6AFB871B4BABB200D42C34 /* refreshIconOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6AFB851B4BABB200D42C34 /* refreshIconOver.png */; }; 32 | CD74522E1BCCAE50006EE37A /* Kext.m in Sources */ = {isa = PBXBuildFile; fileRef = CD74522D1BCCAE50006EE37A /* Kext.m */; }; 33 | CD7B9F4D1ACB959200DF3C71 /* logoAppleOver.png in Resources */ = {isa = PBXBuildFile; fileRef = CD7B9F4C1ACB959200DF3C71 /* logoAppleOver.png */; }; 34 | CD7B9FAB1AD08FA100DF3C71 /* KKRow.m in Sources */ = {isa = PBXBuildFile; fileRef = CD7B9FAA1AD08FA100DF3C71 /* KKRow.m */; }; 35 | CD8C73B71BDB2171001B5A7D /* kvText.png in Resources */ = {isa = PBXBuildFile; fileRef = CD8C73B61BDB2171001B5A7D /* kvText.png */; }; 36 | CD8C73B91BDDDCC4001B5A7D /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD8C73B81BDDDCC4001B5A7D /* SystemConfiguration.framework */; }; 37 | CDA81D4F1A95B492009790E2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA81D451A95B492009790E2 /* AppDelegate.m */; }; 38 | CDA81D531A95B492009790E2 /* utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA81D4E1A95B492009790E2 /* utilities.m */; }; 39 | CDA81D741A95B4FB009790E2 /* icon.iconset in Resources */ = {isa = PBXBuildFile; fileRef = CDA81D731A95B4FB009790E2 /* icon.iconset */; }; 40 | CDA81D7B1A95D29B009790E2 /* KextTableController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA81D7A1A95D29B009790E2 /* KextTableController.m */; }; 41 | CDA81DD31A9970A0009790E2 /* signed.png in Resources */ = {isa = PBXBuildFile; fileRef = CDA81DD11A9970A0009790E2 /* signed.png */; }; 42 | CDA81DEE1A99B5F8009790E2 /* Filter.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA81DED1A99B5F8009790E2 /* Filter.m */; }; 43 | CDBE49181B58DC9B0031FC22 /* NSApplicationKeyEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = CDBE49171B58DC9B0031FC22 /* NSApplicationKeyEvents.m */; }; 44 | CDF08CBF1AC3DE25009B3423 /* logoAppleBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CDF08CBE1AC3DE25009B3423 /* logoAppleBG.png */; }; 45 | CDF08CEA1AC8D97B009B3423 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDF08CE91AC8D97B009B3423 /* Quartz.framework */; }; 46 | /* End PBXBuildFile section */ 47 | 48 | /* Begin PBXCopyFilesBuildPhase section */ 49 | CDA5F6B91B16D805003CE340 /* Embed XPC Services */ = { 50 | isa = PBXCopyFilesBuildPhase; 51 | buildActionMask = 2147483647; 52 | dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices"; 53 | dstSubfolderSpec = 16; 54 | files = ( 55 | ); 56 | name = "Embed XPC Services"; 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXCopyFilesBuildPhase section */ 60 | 61 | /* Begin PBXFileReference section */ 62 | 1D21BC4B172AF43D009D1CFD /* KextViewr.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KextViewr.app; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 1D21BC4E172AF43D009D1CFD /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 64 | 1D21BC51172AF43D009D1CFD /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 65 | 1D21BC52172AF43D009D1CFD /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 66 | 1D21BC53172AF43D009D1CFD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 67 | 7D1222751CCB517000CD38C1 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 68 | 7DAA78071B903BF1004840B9 /* CustomTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomTextField.h; path = KextViewr/CustomTextField.h; sourceTree = ""; }; 69 | 7DAA78081B903BF1004840B9 /* CustomTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CustomTextField.m; path = KextViewr/CustomTextField.m; sourceTree = ""; }; 70 | CD001B351AB903040089014A /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = KextViewr/images/logo.png; sourceTree = SOURCE_ROOT; }; 71 | CD001B361AB903040089014A /* logoApple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoApple.png; path = KextViewr/images/logoApple.png; sourceTree = SOURCE_ROOT; }; 72 | CD02194D1AD34D8B005148A2 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AboutWindow.xib; path = KextViewr/AboutWindow.xib; sourceTree = ""; }; 73 | CD0219511AD34D9A005148A2 /* AboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AboutWindowController.h; path = KextViewr/AboutWindowController.h; sourceTree = ""; }; 74 | CD0219521AD34D9A005148A2 /* AboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AboutWindowController.m; path = KextViewr/AboutWindowController.m; sourceTree = ""; }; 75 | CD02195A1AD38823005148A2 /* kkRowCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = kkRowCell.h; path = KextViewr/kkRowCell.h; sourceTree = ""; }; 76 | CD02195B1AD38823005148A2 /* kkRowCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = kkRowCell.m; path = KextViewr/kkRowCell.m; sourceTree = ""; }; 77 | CD3F4CE61AF5CF68002A2647 /* KextEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KextEnumerator.m; path = KextViewr/KextEnumerator.m; sourceTree = SOURCE_ROOT; }; 78 | CD3F4CE71AF5CF68002A2647 /* KextEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KextEnumerator.h; path = KextViewr/KextEnumerator.h; sourceTree = SOURCE_ROOT; }; 79 | CD3F4CE91AF6D948002A2647 /* OrderedDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OrderedDictionary.h; path = KextViewr/3rdParty/OrderedDictionary.h; sourceTree = ""; }; 80 | CD3F4CEA1AF6D948002A2647 /* OrderedDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OrderedDictionary.m; path = KextViewr/3rdParty/OrderedDictionary.m; sourceTree = ""; }; 81 | CD4D53C91B20296E00008030 /* unknown.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = unknown.png; path = KextViewr/images/unknown.png; sourceTree = SOURCE_ROOT; }; 82 | CD4D54201B2CE6F200008030 /* NSMutableArray+QueueAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSMutableArray+QueueAdditions.h"; path = "KextViewr/NSMutableArray+QueueAdditions.h"; sourceTree = ""; }; 83 | CD4D54211B2CE6F200008030 /* NSMutableArray+QueueAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSMutableArray+QueueAdditions.m"; path = "KextViewr/NSMutableArray+QueueAdditions.m"; sourceTree = ""; }; 84 | CD4D543E1B2FF32C00008030 /* signedAppleIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = signedAppleIcon.png; path = KextViewr/images/signedAppleIcon.png; sourceTree = SOURCE_ROOT; }; 85 | CD5813DD299F20A800DEBE46 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = KextViewr/Assets.xcassets; sourceTree = SOURCE_ROOT; }; 86 | CD5813DF29A06ACB00DEBE46 /* patrons.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = patrons.txt; path = KextViewr/patrons.txt; sourceTree = SOURCE_ROOT; }; 87 | CD5813E229A07CE000DEBE46 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = KextViewr/Info.plist; sourceTree = ""; }; 88 | CD5813E429A07DFD00DEBE46 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = KextViewr/main.m; sourceTree = ""; }; 89 | CD6095721A87067D00E091CD /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 90 | CD6AFB821B4BAA2100D42C34 /* refreshIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = refreshIcon.png; path = KextViewr/images/refreshIcon.png; sourceTree = SOURCE_ROOT; }; 91 | CD6AFB841B4BABB200D42C34 /* refreshIconBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = refreshIconBG.png; path = KextViewr/images/refreshIconBG.png; sourceTree = SOURCE_ROOT; }; 92 | CD6AFB851B4BABB200D42C34 /* refreshIconOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = refreshIconOver.png; path = KextViewr/images/refreshIconOver.png; sourceTree = SOURCE_ROOT; }; 93 | CD74522C1BCCAE50006EE37A /* Kext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Kext.h; path = KextViewr/Kext.h; sourceTree = ""; }; 94 | CD74522D1BCCAE50006EE37A /* Kext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Kext.m; path = KextViewr/Kext.m; sourceTree = ""; }; 95 | CD7B9F4C1ACB959200DF3C71 /* logoAppleOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoAppleOver.png; path = KextViewr/images/logoAppleOver.png; sourceTree = SOURCE_ROOT; }; 96 | CD7B9FA91AD08FA100DF3C71 /* KKRow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KKRow.h; path = KextViewr/KKRow.h; sourceTree = ""; }; 97 | CD7B9FAA1AD08FA100DF3C71 /* KKRow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KKRow.m; path = KextViewr/KKRow.m; sourceTree = ""; }; 98 | CD8C73B61BDB2171001B5A7D /* kvText.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = kvText.png; path = KextViewr/images/kvText.png; sourceTree = SOURCE_ROOT; }; 99 | CD8C73B81BDDDCC4001B5A7D /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 100 | CDA81D441A95B492009790E2 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = KextViewr/AppDelegate.h; sourceTree = SOURCE_ROOT; }; 101 | CDA81D451A95B492009790E2 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = KextViewr/AppDelegate.m; sourceTree = SOURCE_ROOT; }; 102 | CDA81D481A95B492009790E2 /* consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = consts.h; path = KextViewr/consts.h; sourceTree = SOURCE_ROOT; }; 103 | CDA81D4D1A95B492009790E2 /* utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utilities.h; path = KextViewr/utilities.h; sourceTree = SOURCE_ROOT; }; 104 | CDA81D4E1A95B492009790E2 /* utilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = utilities.m; path = KextViewr/utilities.m; sourceTree = SOURCE_ROOT; }; 105 | CDA81D571A95B4B4009790E2 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = KextViewr/en.lproj/MainMenu.xib; sourceTree = SOURCE_ROOT; }; 106 | CDA81D731A95B4FB009790E2 /* icon.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = icon.iconset; path = KextViewr/images/icon.iconset; sourceTree = SOURCE_ROOT; }; 107 | CDA81D791A95D29B009790E2 /* KextTableController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KextTableController.h; path = KextViewr/KextTableController.h; sourceTree = ""; }; 108 | CDA81D7A1A95D29B009790E2 /* KextTableController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KextTableController.m; path = KextViewr/KextTableController.m; sourceTree = ""; }; 109 | CDA81DD11A9970A0009790E2 /* signed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = signed.png; path = KextViewr/images/signed.png; sourceTree = SOURCE_ROOT; }; 110 | CDA81DEC1A99B5F8009790E2 /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Filter.h; path = KextViewr/Filter.h; sourceTree = ""; }; 111 | CDA81DED1A99B5F8009790E2 /* Filter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Filter.m; path = KextViewr/Filter.m; sourceTree = ""; }; 112 | CDBE49161B58DC9B0031FC22 /* NSApplicationKeyEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSApplicationKeyEvents.h; path = KextViewr/NSApplicationKeyEvents.h; sourceTree = ""; }; 113 | CDBE49171B58DC9B0031FC22 /* NSApplicationKeyEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSApplicationKeyEvents.m; path = KextViewr/NSApplicationKeyEvents.m; sourceTree = ""; }; 114 | CDF08CBE1AC3DE25009B3423 /* logoAppleBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoAppleBG.png; path = KextViewr/images/logoAppleBG.png; sourceTree = SOURCE_ROOT; }; 115 | CDF08CE91AC8D97B009B3423 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; 116 | /* End PBXFileReference section */ 117 | 118 | /* Begin PBXFrameworksBuildPhase section */ 119 | 1D21BC48172AF43D009D1CFD /* Frameworks */ = { 120 | isa = PBXFrameworksBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | 7D1222761CCB517000CD38C1 /* IOKit.framework in Frameworks */, 124 | CD8C73B91BDDDCC4001B5A7D /* SystemConfiguration.framework in Frameworks */, 125 | CDF08CEA1AC8D97B009B3423 /* Quartz.framework in Frameworks */, 126 | CD6095731A87067D00E091CD /* Security.framework in Frameworks */, 127 | 1D21BC4F172AF43D009D1CFD /* Cocoa.framework in Frameworks */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | /* End PBXFrameworksBuildPhase section */ 132 | 133 | /* Begin PBXGroup section */ 134 | 1D21BC42172AF43D009D1CFD = { 135 | isa = PBXGroup; 136 | children = ( 137 | CDF08CE31AC89FD4009B3423 /* 3rdParty */, 138 | 1D21BC4D172AF43D009D1CFD /* Frameworks */, 139 | 1D21BC54172AF43D009D1CFD /* KextViewr */, 140 | 1D21BC4C172AF43D009D1CFD /* Products */, 141 | CDA81D781A95B939009790E2 /* UIControllers */, 142 | ); 143 | sourceTree = ""; 144 | }; 145 | 1D21BC4C172AF43D009D1CFD /* Products */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 1D21BC4B172AF43D009D1CFD /* KextViewr.app */, 149 | ); 150 | name = Products; 151 | sourceTree = ""; 152 | }; 153 | 1D21BC4D172AF43D009D1CFD /* Frameworks */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 7D1222751CCB517000CD38C1 /* IOKit.framework */, 157 | CD8C73B81BDDDCC4001B5A7D /* SystemConfiguration.framework */, 158 | CDF08CE91AC8D97B009B3423 /* Quartz.framework */, 159 | CD6095721A87067D00E091CD /* Security.framework */, 160 | 1D21BC4E172AF43D009D1CFD /* Cocoa.framework */, 161 | 1D21BC50172AF43D009D1CFD /* Other Frameworks */, 162 | ); 163 | name = Frameworks; 164 | sourceTree = ""; 165 | }; 166 | 1D21BC50172AF43D009D1CFD /* Other Frameworks */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 1D21BC51172AF43D009D1CFD /* AppKit.framework */, 170 | 1D21BC52172AF43D009D1CFD /* CoreData.framework */, 171 | 1D21BC53172AF43D009D1CFD /* Foundation.framework */, 172 | ); 173 | name = "Other Frameworks"; 174 | sourceTree = ""; 175 | }; 176 | 1D21BC54172AF43D009D1CFD /* KextViewr */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | CD02194D1AD34D8B005148A2 /* AboutWindow.xib */, 180 | CDA81D441A95B492009790E2 /* AppDelegate.h */, 181 | CDA81D451A95B492009790E2 /* AppDelegate.m */, 182 | CD5813DD299F20A800DEBE46 /* Assets.xcassets */, 183 | CDA81D481A95B492009790E2 /* consts.h */, 184 | 7DAA78071B903BF1004840B9 /* CustomTextField.h */, 185 | 7DAA78081B903BF1004840B9 /* CustomTextField.m */, 186 | CDA81DEC1A99B5F8009790E2 /* Filter.h */, 187 | CD5813E229A07CE000DEBE46 /* Info.plist */, 188 | CDA81DED1A99B5F8009790E2 /* Filter.m */, 189 | CD6095501A8329FA00E091CD /* images */, 190 | CD74522C1BCCAE50006EE37A /* Kext.h */, 191 | CD74522D1BCCAE50006EE37A /* Kext.m */, 192 | CD3F4CE71AF5CF68002A2647 /* KextEnumerator.h */, 193 | CD3F4CE61AF5CF68002A2647 /* KextEnumerator.m */, 194 | CD7B9FA91AD08FA100DF3C71 /* KKRow.h */, 195 | CD7B9FAA1AD08FA100DF3C71 /* KKRow.m */, 196 | CD02195A1AD38823005148A2 /* kkRowCell.h */, 197 | CD02195B1AD38823005148A2 /* kkRowCell.m */, 198 | CDA81D561A95B4B4009790E2 /* MainMenu.xib */, 199 | CDBE49161B58DC9B0031FC22 /* NSApplicationKeyEvents.h */, 200 | CDBE49171B58DC9B0031FC22 /* NSApplicationKeyEvents.m */, 201 | CD5813E429A07DFD00DEBE46 /* main.m */, 202 | CD4D54201B2CE6F200008030 /* NSMutableArray+QueueAdditions.h */, 203 | CD4D54211B2CE6F200008030 /* NSMutableArray+QueueAdditions.m */, 204 | CD5813DF29A06ACB00DEBE46 /* patrons.txt */, 205 | CDA81D4D1A95B492009790E2 /* utilities.h */, 206 | CDA81D4E1A95B492009790E2 /* utilities.m */, 207 | ); 208 | name = KextViewr; 209 | sourceTree = ""; 210 | }; 211 | CD6095501A8329FA00E091CD /* images */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | CDA81D731A95B4FB009790E2 /* icon.iconset */, 215 | CD8C73B61BDB2171001B5A7D /* kvText.png */, 216 | CD6AFB841B4BABB200D42C34 /* refreshIconBG.png */, 217 | CD6AFB851B4BABB200D42C34 /* refreshIconOver.png */, 218 | CD6AFB821B4BAA2100D42C34 /* refreshIcon.png */, 219 | CD4D543E1B2FF32C00008030 /* signedAppleIcon.png */, 220 | CD4D53C91B20296E00008030 /* unknown.png */, 221 | CD7B9F4C1ACB959200DF3C71 /* logoAppleOver.png */, 222 | CDF08CBE1AC3DE25009B3423 /* logoAppleBG.png */, 223 | CD001B351AB903040089014A /* logo.png */, 224 | CD001B361AB903040089014A /* logoApple.png */, 225 | CDA81DD11A9970A0009790E2 /* signed.png */, 226 | ); 227 | name = images; 228 | path = KextViewr/images; 229 | sourceTree = ""; 230 | }; 231 | CDA81D781A95B939009790E2 /* UIControllers */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | CD0219511AD34D9A005148A2 /* AboutWindowController.h */, 235 | CD0219521AD34D9A005148A2 /* AboutWindowController.m */, 236 | CDA81D791A95D29B009790E2 /* KextTableController.h */, 237 | CDA81D7A1A95D29B009790E2 /* KextTableController.m */, 238 | ); 239 | name = UIControllers; 240 | sourceTree = ""; 241 | }; 242 | CDF08CE31AC89FD4009B3423 /* 3rdParty */ = { 243 | isa = PBXGroup; 244 | children = ( 245 | CD3F4CE91AF6D948002A2647 /* OrderedDictionary.h */, 246 | CD3F4CEA1AF6D948002A2647 /* OrderedDictionary.m */, 247 | ); 248 | name = 3rdParty; 249 | sourceTree = ""; 250 | }; 251 | /* End PBXGroup section */ 252 | 253 | /* Begin PBXNativeTarget section */ 254 | 1D21BC4A172AF43D009D1CFD /* KextViewr */ = { 255 | isa = PBXNativeTarget; 256 | buildConfigurationList = 1D21BC68172AF43D009D1CFD /* Build configuration list for PBXNativeTarget "KextViewr" */; 257 | buildPhases = ( 258 | 1D21BC47172AF43D009D1CFD /* Sources */, 259 | 1D21BC48172AF43D009D1CFD /* Frameworks */, 260 | 1D21BC49172AF43D009D1CFD /* Resources */, 261 | CDA5F6B91B16D805003CE340 /* Embed XPC Services */, 262 | ); 263 | buildRules = ( 264 | ); 265 | dependencies = ( 266 | ); 267 | name = KextViewr; 268 | productName = KextViewr; 269 | productReference = 1D21BC4B172AF43D009D1CFD /* KextViewr.app */; 270 | productType = "com.apple.product-type.application"; 271 | }; 272 | /* End PBXNativeTarget section */ 273 | 274 | /* Begin PBXProject section */ 275 | 1D21BC43172AF43D009D1CFD /* Project object */ = { 276 | isa = PBXProject; 277 | attributes = { 278 | LastUpgradeCheck = 1420; 279 | ORGANIZATIONNAME = "Lucas Derraugh"; 280 | TargetAttributes = { 281 | 1D21BC4A172AF43D009D1CFD = { 282 | DevelopmentTeam = VBG97UB4TA; 283 | }; 284 | }; 285 | }; 286 | buildConfigurationList = 1D21BC46172AF43D009D1CFD /* Build configuration list for PBXProject "KextViewr" */; 287 | compatibilityVersion = "Xcode 3.2"; 288 | developmentRegion = English; 289 | hasScannedForEncodings = 0; 290 | knownRegions = ( 291 | English, 292 | en, 293 | ); 294 | mainGroup = 1D21BC42172AF43D009D1CFD; 295 | productRefGroup = 1D21BC4C172AF43D009D1CFD /* Products */; 296 | projectDirPath = ""; 297 | projectRoot = ""; 298 | targets = ( 299 | 1D21BC4A172AF43D009D1CFD /* KextViewr */, 300 | ); 301 | }; 302 | /* End PBXProject section */ 303 | 304 | /* Begin PBXResourcesBuildPhase section */ 305 | 1D21BC49172AF43D009D1CFD /* Resources */ = { 306 | isa = PBXResourcesBuildPhase; 307 | buildActionMask = 2147483647; 308 | files = ( 309 | CD8C73B71BDB2171001B5A7D /* kvText.png in Resources */, 310 | CD6AFB861B4BABB200D42C34 /* refreshIconBG.png in Resources */, 311 | CD4D53CA1B20296E00008030 /* unknown.png in Resources */, 312 | CD6AFB871B4BABB200D42C34 /* refreshIconOver.png in Resources */, 313 | CD001B391AB903040089014A /* logoApple.png in Resources */, 314 | CD5813E329A07CE000DEBE46 /* Info.plist in Resources */, 315 | CD5813E129A07BCD00DEBE46 /* MainMenu.xib in Resources */, 316 | CD7B9F4D1ACB959200DF3C71 /* logoAppleOver.png in Resources */, 317 | CD001B381AB903040089014A /* logo.png in Resources */, 318 | CD4D543F1B2FF32C00008030 /* signedAppleIcon.png in Resources */, 319 | CD5813DE299F20A800DEBE46 /* Assets.xcassets in Resources */, 320 | CD5813E029A06ACB00DEBE46 /* patrons.txt in Resources */, 321 | CDF08CBF1AC3DE25009B3423 /* logoAppleBG.png in Resources */, 322 | CD6AFB831B4BAA2100D42C34 /* refreshIcon.png in Resources */, 323 | CDA81D741A95B4FB009790E2 /* icon.iconset in Resources */, 324 | CD02194F1AD34D8B005148A2 /* AboutWindow.xib in Resources */, 325 | CDA81DD31A9970A0009790E2 /* signed.png in Resources */, 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | }; 329 | /* End PBXResourcesBuildPhase section */ 330 | 331 | /* Begin PBXSourcesBuildPhase section */ 332 | 1D21BC47172AF43D009D1CFD /* Sources */ = { 333 | isa = PBXSourcesBuildPhase; 334 | buildActionMask = 2147483647; 335 | files = ( 336 | CD3F4CE81AF5CF68002A2647 /* KextEnumerator.m in Sources */, 337 | CD4D54221B2CE6F200008030 /* NSMutableArray+QueueAdditions.m in Sources */, 338 | CD3F4CEB1AF6D948002A2647 /* OrderedDictionary.m in Sources */, 339 | CDA81DEE1A99B5F8009790E2 /* Filter.m in Sources */, 340 | 7DAA78091B903BF1004840B9 /* CustomTextField.m in Sources */, 341 | CDA81D7B1A95D29B009790E2 /* KextTableController.m in Sources */, 342 | CD74522E1BCCAE50006EE37A /* Kext.m in Sources */, 343 | CD02195C1AD38823005148A2 /* kkRowCell.m in Sources */, 344 | CDA81D4F1A95B492009790E2 /* AppDelegate.m in Sources */, 345 | CD0219531AD34D9A005148A2 /* AboutWindowController.m in Sources */, 346 | CDBE49181B58DC9B0031FC22 /* NSApplicationKeyEvents.m in Sources */, 347 | CDA81D531A95B492009790E2 /* utilities.m in Sources */, 348 | CD5813E529A07DFD00DEBE46 /* main.m in Sources */, 349 | CD7B9FAB1AD08FA100DF3C71 /* KKRow.m in Sources */, 350 | ); 351 | runOnlyForDeploymentPostprocessing = 0; 352 | }; 353 | /* End PBXSourcesBuildPhase section */ 354 | 355 | /* Begin PBXVariantGroup section */ 356 | CDA81D561A95B4B4009790E2 /* MainMenu.xib */ = { 357 | isa = PBXVariantGroup; 358 | children = ( 359 | CDA81D571A95B4B4009790E2 /* en */, 360 | ); 361 | name = MainMenu.xib; 362 | path = KextViewr; 363 | sourceTree = ""; 364 | }; 365 | /* End PBXVariantGroup section */ 366 | 367 | /* Begin XCBuildConfiguration section */ 368 | 1D21BC66172AF43D009D1CFD /* Debug */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 373 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 374 | CLANG_CXX_LIBRARY = "libc++"; 375 | CLANG_ENABLE_OBJC_ARC = YES; 376 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 377 | CLANG_WARN_BOOL_CONVERSION = YES; 378 | CLANG_WARN_COMMA = YES; 379 | CLANG_WARN_CONSTANT_CONVERSION = YES; 380 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 381 | CLANG_WARN_EMPTY_BODY = YES; 382 | CLANG_WARN_ENUM_CONVERSION = YES; 383 | CLANG_WARN_INFINITE_RECURSION = YES; 384 | CLANG_WARN_INT_CONVERSION = YES; 385 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 386 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 387 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 388 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 389 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 390 | CLANG_WARN_STRICT_PROTOTYPES = YES; 391 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 392 | CLANG_WARN_UNREACHABLE_CODE = YES; 393 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 394 | CODE_SIGN_IDENTITY = "Apple Development"; 395 | COPY_PHASE_STRIP = NO; 396 | DEAD_CODE_STRIPPING = YES; 397 | ENABLE_STRICT_OBJC_MSGSEND = YES; 398 | ENABLE_TESTABILITY = YES; 399 | GCC_C_LANGUAGE_STANDARD = gnu99; 400 | GCC_DYNAMIC_NO_PIC = NO; 401 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 402 | GCC_NO_COMMON_BLOCKS = YES; 403 | GCC_OPTIMIZATION_LEVEL = 0; 404 | GCC_PREPROCESSOR_DEFINITIONS = ( 405 | "DEBUG=1", 406 | "$(inherited)", 407 | ); 408 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 409 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 410 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; 411 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 412 | GCC_WARN_UNDECLARED_SELECTOR = YES; 413 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 414 | GCC_WARN_UNUSED_FUNCTION = YES; 415 | GCC_WARN_UNUSED_LABEL = YES; 416 | GCC_WARN_UNUSED_PARAMETER = NO; 417 | GCC_WARN_UNUSED_VARIABLE = YES; 418 | INFOPLIST_FILE = "KextViewr-Info.plist"; 419 | MACOSX_DEPLOYMENT_TARGET = 11.0; 420 | ONLY_ACTIVE_ARCH = YES; 421 | PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.$(PRODUCT_NAME:rfc1034identifier)"; 422 | PRODUCT_NAME = KextViewr; 423 | SDKROOT = macosx; 424 | }; 425 | name = Debug; 426 | }; 427 | 1D21BC67172AF43D009D1CFD /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ALWAYS_SEARCH_USER_PATHS = NO; 431 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 432 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 433 | CLANG_CXX_LIBRARY = "libc++"; 434 | CLANG_ENABLE_OBJC_ARC = YES; 435 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 436 | CLANG_WARN_BOOL_CONVERSION = YES; 437 | CLANG_WARN_COMMA = YES; 438 | CLANG_WARN_CONSTANT_CONVERSION = YES; 439 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 440 | CLANG_WARN_EMPTY_BODY = YES; 441 | CLANG_WARN_ENUM_CONVERSION = YES; 442 | CLANG_WARN_INFINITE_RECURSION = YES; 443 | CLANG_WARN_INT_CONVERSION = YES; 444 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 445 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 446 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 447 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 448 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 449 | CLANG_WARN_STRICT_PROTOTYPES = YES; 450 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 451 | CLANG_WARN_UNREACHABLE_CODE = YES; 452 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 453 | CODE_SIGN_IDENTITY = "Apple Development"; 454 | COPY_PHASE_STRIP = YES; 455 | DEAD_CODE_STRIPPING = YES; 456 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 457 | ENABLE_STRICT_OBJC_MSGSEND = YES; 458 | GCC_C_LANGUAGE_STANDARD = gnu99; 459 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 460 | GCC_NO_COMMON_BLOCKS = YES; 461 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 462 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; 463 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 464 | GCC_WARN_UNDECLARED_SELECTOR = YES; 465 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 466 | GCC_WARN_UNUSED_FUNCTION = YES; 467 | GCC_WARN_UNUSED_LABEL = YES; 468 | GCC_WARN_UNUSED_PARAMETER = NO; 469 | GCC_WARN_UNUSED_VARIABLE = YES; 470 | INFOPLIST_FILE = "KextViewr-Info.plist"; 471 | MACOSX_DEPLOYMENT_TARGET = 11.0; 472 | ONLY_ACTIVE_ARCH = YES; 473 | PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.$(PRODUCT_NAME:rfc1034identifier)"; 474 | PRODUCT_NAME = KextViewr; 475 | SDKROOT = macosx; 476 | }; 477 | name = Release; 478 | }; 479 | 1D21BC69172AF43D009D1CFD /* Debug */ = { 480 | isa = XCBuildConfiguration; 481 | buildSettings = { 482 | CODE_SIGN_IDENTITY = "Apple Development"; 483 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; 484 | COMBINE_HIDPI_IMAGES = YES; 485 | CURRENT_PROJECT_VERSION = 2.0.0; 486 | DEAD_CODE_STRIPPING = YES; 487 | ENABLE_HARDENED_RUNTIME = YES; 488 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 489 | GCC_PREFIX_HEADER = ""; 490 | INFOPLIST_FILE = KextViewr/Info.plist; 491 | INFOPLIST_KEY_CFBundleDisplayName = KextViewr; 492 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; 493 | INFOPLIST_KEY_NSMainNibFile = MainMenu; 494 | MACOSX_DEPLOYMENT_TARGET = 11.0; 495 | MARKETING_VERSION = 2.0.0; 496 | PRODUCT_NAME = KextViewr; 497 | PROVISIONING_PROFILE = ""; 498 | WRAPPER_EXTENSION = app; 499 | }; 500 | name = Debug; 501 | }; 502 | 1D21BC6A172AF43D009D1CFD /* Release */ = { 503 | isa = XCBuildConfiguration; 504 | buildSettings = { 505 | CODE_SIGN_IDENTITY = "Apple Development"; 506 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; 507 | COMBINE_HIDPI_IMAGES = YES; 508 | CURRENT_PROJECT_VERSION = 2.0.0; 509 | DEAD_CODE_STRIPPING = YES; 510 | ENABLE_HARDENED_RUNTIME = YES; 511 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 512 | GCC_PREFIX_HEADER = ""; 513 | INFOPLIST_FILE = KextViewr/Info.plist; 514 | INFOPLIST_KEY_CFBundleDisplayName = KextViewr; 515 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; 516 | INFOPLIST_KEY_NSMainNibFile = MainMenu; 517 | MACOSX_DEPLOYMENT_TARGET = 11.0; 518 | MARKETING_VERSION = 2.0.0; 519 | PRODUCT_NAME = KextViewr; 520 | PROVISIONING_PROFILE = ""; 521 | WRAPPER_EXTENSION = app; 522 | }; 523 | name = Release; 524 | }; 525 | /* End XCBuildConfiguration section */ 526 | 527 | /* Begin XCConfigurationList section */ 528 | 1D21BC46172AF43D009D1CFD /* Build configuration list for PBXProject "KextViewr" */ = { 529 | isa = XCConfigurationList; 530 | buildConfigurations = ( 531 | 1D21BC66172AF43D009D1CFD /* Debug */, 532 | 1D21BC67172AF43D009D1CFD /* Release */, 533 | ); 534 | defaultConfigurationIsVisible = 0; 535 | defaultConfigurationName = Release; 536 | }; 537 | 1D21BC68172AF43D009D1CFD /* Build configuration list for PBXNativeTarget "KextViewr" */ = { 538 | isa = XCConfigurationList; 539 | buildConfigurations = ( 540 | 1D21BC69172AF43D009D1CFD /* Debug */, 541 | 1D21BC6A172AF43D009D1CFD /* Release */, 542 | ); 543 | defaultConfigurationIsVisible = 0; 544 | defaultConfigurationName = Release; 545 | }; 546 | /* End XCConfigurationList section */ 547 | }; 548 | rootObject = 1D21BC43172AF43D009D1CFD /* Project object */; 549 | } 550 | -------------------------------------------------------------------------------- /KextViewr.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /KextViewr.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /KextViewr.xcodeproj/project.xcworkspace/xcshareddata/KnockKnock.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 1ECDBF86-1DFC-4002-A5BE-41FC31ACB68B 9 | IDESourceControlProjectName 10 | project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D 14 | https://bitbucket.org/objective-see/knockknock.git 15 | 16 | IDESourceControlProjectPath 17 | KnockKnock.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://bitbucket.org/objective-see/knockknock.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | A9FFC1B124E25027A0E10FB456DBA9E2803FAE9D 36 | IDESourceControlWCCName 37 | KnockKnock 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /KextViewr.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | FE4103FE-6F26-4639-8C9F-D8D32C76D6A9 9 | IDESourceControlProjectName 10 | TaskExplorer 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 61F07AFB33748EF0C810BEEF6126283DAC63A899 14 | https://bitbucket.org/objective-see/taskexplorer.git 15 | 16 | IDESourceControlProjectPath 17 | TaskExplorer.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 61F07AFB33748EF0C810BEEF6126283DAC63A899 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://bitbucket.org/objective-see/taskexplorer.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 61F07AFB33748EF0C810BEEF6126283DAC63A899 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 61F07AFB33748EF0C810BEEF6126283DAC63A899 36 | IDESourceControlWCCName 37 | TaskExplorer 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /KextViewr.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /KextViewr.xcodeproj/project.xcworkspace/xcuserdata/patrickw.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr.xcodeproj/project.xcworkspace/xcuserdata/patrickw.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /KextViewr.xcodeproj/project.xcworkspace/xcuserdata/patrickw.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /KextViewr/3rdParty/OrderedDictionary.h: -------------------------------------------------------------------------------- 1 | // 2 | // OrderedDictionary.h 3 | // OrderedDictionary 4 | // 5 | // Created by Matt Gallagher on 19/12/08. 6 | // Copyright 2008 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | #import 25 | 26 | @interface OrderedDictionary : NSMutableDictionary 27 | { 28 | NSMutableDictionary *dictionary; 29 | NSMutableArray *array; 30 | } 31 | 32 | //add an object 33 | // ->either (but only) start/end 34 | -(void)addObject:(id)anObject forKey:(id)aKey atStart:(BOOL)atStart; 35 | 36 | //key at index 37 | -(id)keyAtIndex:(NSUInteger)anIndex; 38 | 39 | //index of key 40 | -(NSUInteger)indexOfKey:(id)aKey; 41 | 42 | //reverse key enumerator 43 | -(NSEnumerator *)reverseKeyEnumerator; 44 | 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /KextViewr/3rdParty/OrderedDictionary.m: -------------------------------------------------------------------------------- 1 | // 2 | // OrderedDictionary.m 3 | // OrderedDictionary 4 | // 5 | // Created by Matt Gallagher on 19/12/08. 6 | // Copyright 2008 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | #import "OrderedDictionary.h" 25 | 26 | @implementation OrderedDictionary 27 | 28 | -(id)init 29 | { 30 | self = [super init]; 31 | if (self != nil) 32 | { 33 | dictionary = [NSMutableDictionary dictionary]; 34 | array = [NSMutableArray array]; 35 | } 36 | return self; 37 | 38 | } 39 | 40 | //copy 41 | -(id)copy 42 | { 43 | return [self mutableCopy]; 44 | } 45 | 46 | //description 47 | -(NSString*)description 48 | { 49 | return dictionary.description; 50 | } 51 | 52 | //remove 53 | -(void)removeObjectForKey:(id)aKey 54 | { 55 | [dictionary removeObjectForKey:aKey]; 56 | [array removeObject:aKey]; 57 | } 58 | 59 | //count 60 | -(NSUInteger)count 61 | { 62 | return [dictionary count]; 63 | } 64 | 65 | //object for key 66 | -(id)objectForKey:(id)aKey 67 | { 68 | return [dictionary objectForKey:aKey]; 69 | } 70 | 71 | //reverse key enumerator 72 | -(NSEnumerator *)reverseKeyEnumerator 73 | { 74 | return [array reverseObjectEnumerator]; 75 | } 76 | 77 | //key at index 78 | -(id)keyAtIndex:(NSUInteger)anIndex 79 | { 80 | return [array objectAtIndex:anIndex]; 81 | } 82 | 83 | //index of key 84 | -(NSUInteger)indexOfKey:(id)aKey 85 | { 86 | return [array indexOfObject:aKey]; 87 | } 88 | 89 | -(NSEnumerator *)keyEnumerator 90 | { 91 | return [array objectEnumerator]; 92 | } 93 | 94 | //add an object 95 | // ->either (but only) start or end 96 | -(void)addObject:(id)anObject forKey:(id)aKey atStart:(BOOL)atStart 97 | { 98 | //if object already exists 99 | // ->remove from both dictionary *and* array 100 | if(nil != [dictionary objectForKey:aKey]) 101 | { 102 | //remove 103 | [self removeObjectForKey:aKey]; 104 | } 105 | 106 | //at start? 107 | // ->insert into beginning of array 108 | if(YES == atStart) 109 | { 110 | //insert 111 | [array insertObject:aKey atIndex:0]; 112 | } 113 | //otherwise at end 114 | // ->just add into array 115 | else 116 | { 117 | //add 118 | [array addObject:aKey]; 119 | } 120 | 121 | //add to dictionary 122 | [dictionary setObject:anObject forKey:aKey]; 123 | 124 | return; 125 | } 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /KextViewr/AboutWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 100 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /KextViewr/AboutWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PrefsWindowController.h 3 | // DHS 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 | //support us button tag 12 | #define BUTTON_SUPPORT_US 100 13 | 14 | //more info button tag 15 | #define BUTTON_MORE_INFO 101 16 | 17 | @interface AboutWindowController : NSWindowController 18 | { 19 | 20 | } 21 | 22 | /* PROPERTIES */ 23 | 24 | //version label/string 25 | @property (weak) IBOutlet NSTextField *versionLabel; 26 | 27 | //patrons 28 | @property (unsafe_unretained) IBOutlet NSTextView *patrons; 29 | 30 | /* METHODS */ 31 | 32 | //automatically invoked when user clicks any of the buttons 33 | // perform actions, such as loading patreon or products URL 34 | -(IBAction)buttonHandler:(id)sender; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /KextViewr/AboutWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PrefsWindowController.m 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 2/6/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | 10 | #import "consts.h" 11 | #import "utilities.h" 12 | #import "AboutWindowController.h" 13 | 14 | @implementation AboutWindowController 15 | 16 | @synthesize patrons; 17 | @synthesize versionLabel; 18 | 19 | //automatically called when nib is loaded 20 | // ->center window 21 | -(void)awakeFromNib 22 | { 23 | //center 24 | [self.window center]; 25 | 26 | return; 27 | } 28 | 29 | //automatically invoked when window is loaded 30 | // set to window to white, set app version, patrons, etc 31 | -(void)windowDidLoad 32 | { 33 | //version 34 | NSString* version = nil; 35 | 36 | //super 37 | [super windowDidLoad]; 38 | 39 | //not in dark mode? 40 | // make window white 41 | if(YES != isDarkMode()) 42 | { 43 | //make white 44 | self.window.backgroundColor = NSColor.whiteColor; 45 | } 46 | 47 | //grab app version 48 | version = getAppVersion(); 49 | if(nil == version) 50 | { 51 | //default 52 | version = @"unknown"; 53 | } 54 | 55 | //set version sting 56 | self.versionLabel.stringValue = [NSString stringWithFormat:@"Version: %@", version]; 57 | 58 | //load patrons 59 | // <3 you guys & girls 60 | self.patrons.string = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"patrons" ofType:@"txt"] encoding:NSUTF8StringEncoding error:NULL]; 61 | if(nil == self.patrons.string) 62 | { 63 | //default 64 | self.patrons.string = @"error: failed to load patrons :/"; 65 | } 66 | 67 | //make 'Support Us' button first responder 68 | [self.window makeFirstResponder:[self.window.contentView viewWithTag:BUTTON_SUPPORT_US]]; 69 | 70 | return; 71 | } 72 | 73 | //automatically invoked when window is closing 74 | // ->make window unmodal 75 | -(void)windowWillClose:(NSNotification *)notification 76 | { 77 | //make un-modal 78 | [NSApplication.sharedApplication stopModal]; 79 | 80 | return; 81 | } 82 | 83 | //automatically invoked when user clicks any of the buttons 84 | // ->perform actions, such as loading patreon or products URL 85 | -(IBAction)buttonHandler:(id)sender 86 | { 87 | //support us button 88 | if(((NSButton*)sender).tag == BUTTON_SUPPORT_US) 89 | { 90 | //open URL 91 | // ->invokes user's default browser 92 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]]; 93 | } 94 | 95 | //more info button 96 | else if(((NSButton*)sender).tag == BUTTON_MORE_INFO) 97 | { 98 | //open URL 99 | // ->invokes user's default browser 100 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]]; 101 | } 102 | 103 | return; 104 | } 105 | @end 106 | -------------------------------------------------------------------------------- /KextViewr/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | #import "Filter.h" 9 | #import "KextEnumerator.h" 10 | #import "CustomTextField.h" 11 | #import "KextTableController.h" 12 | #import "AboutWindowController.h" 13 | 14 | #import 15 | 16 | @interface AppDelegate : NSObject 17 | { 18 | 19 | } 20 | 21 | //start time 22 | @property NSTimeInterval startTime; 23 | 24 | //connection flag 25 | @property BOOL isConnected; 26 | 27 | //'filter kext' search box 28 | // ->top pane 29 | @property (weak) IBOutlet NSSearchField *filterKextsBox; 30 | 31 | //kext enumerator object 32 | @property(nonatomic, retain)KextEnumerator* kextEnumerator; 33 | 34 | //kext table controller object 35 | @property (weak) IBOutlet KextTableController *kextTableController; 36 | 37 | //button to toggle on/off showing OS kexts 38 | @property (weak) IBOutlet NSButton *showOSKexts; 39 | 40 | //main window 41 | @property (assign) IBOutlet NSWindow *window; 42 | 43 | //logo button 44 | @property (weak) IBOutlet NSButton *logoButton; 45 | 46 | //filter object 47 | @property(nonatomic, retain)Filter* filterObj; 48 | 49 | //about window controller 50 | @property(nonatomic, retain)AboutWindowController* aboutWindowController; 51 | 52 | //refresh button 53 | @property (weak) IBOutlet NSButton *refreshButton; 54 | 55 | //save button 56 | @property (weak) IBOutlet NSButton *saveButton; 57 | 58 | //flag for filter field (autocomplete) 59 | @property BOOL completePosting; 60 | 61 | //flag for filter field (autocomplete) 62 | @property BOOL commandHandling; 63 | 64 | //custom search field for kexts 65 | @property(nonatomic, retain)CustomTextField* kextFilterView; 66 | 67 | //enumerator thread 68 | @property(nonatomic, retain)NSThread *kextEnumThread; 69 | 70 | /* METHODS */ 71 | 72 | 73 | //action for 'refresh' button 74 | // ->query OS to refresh/reload all kexts 75 | -(IBAction)refreshKexts:(id)sender; 76 | 77 | //button handler for logo 78 | -(IBAction)logoButtonHandler:(id)sender; 79 | 80 | //action for 'about' in menu/logo in UI 81 | -(IBAction)about:(id)sender; 82 | 83 | //reload (to re-draw) a specific row in table 84 | -(void)reloadRow:(id)item; 85 | 86 | //reload kext table 87 | -(void)reloadKextTable; 88 | 89 | //filter for excluding OS kexts checkbox 90 | -(void)filterAppleKexts; 91 | 92 | //save button handler 93 | -(IBAction)saveResults:(id)sender; 94 | 95 | //callback for custom search fields 96 | // ->handle auto-complete filterings 97 | -(void)filterAutoComplete:(NSTextView*)textField; 98 | 99 | //code to complete filtering/search 100 | // ->reload table/scroll to top etc 101 | -(void)finalizeFiltration; 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /KextViewr/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // KextViewr 4 | // 5 | 6 | #import "consts.h" 7 | #import "utilities.h" 8 | #import "AppDelegate.h" 9 | #import "KextTableController.h" 10 | 11 | @implementation AppDelegate 12 | 13 | @synthesize filterObj; 14 | @synthesize startTime; 15 | @synthesize saveButton; 16 | @synthesize isConnected; 17 | @synthesize refreshButton; 18 | @synthesize kextEnumerator; 19 | @synthesize kextEnumThread; 20 | @synthesize commandHandling; 21 | @synthesize completePosting; 22 | @synthesize kextFilterView; 23 | @synthesize kextTableController; 24 | @synthesize aboutWindowController; 25 | 26 | //center window 27 | // ->also make front 28 | -(void)awakeFromNib 29 | { 30 | //center 31 | [self.window center]; 32 | 33 | //make it key window 34 | [self.window makeKeyAndOrderFront:self]; 35 | 36 | //make window front 37 | [NSApp activateIgnoringOtherApps:YES]; 38 | 39 | return; 40 | } 41 | 42 | //automatically invoked by OS 43 | // ->main entry point 44 | -(void)applicationDidFinishLaunching:(NSNotification *)notification 45 | { 46 | //init filter obj 47 | filterObj = [[Filter alloc] init]; 48 | 49 | //alloc/init custom search field for items 50 | kextFilterView = [[CustomTextField alloc] init]; 51 | 52 | //set owner 53 | self.kextFilterView.owner = self; 54 | 55 | //set field editor for items 56 | [self.kextFilterView setFieldEditor:YES]; 57 | 58 | //center 59 | [self.window center]; 60 | 61 | //no need to have a first responder 62 | [self.window makeFirstResponder:nil]; 63 | 64 | //register for hotkey presses 65 | [self registerKeypressHandler]; 66 | 67 | //start enuming kexts 68 | [self enumKexts]; 69 | 70 | //set delegate 71 | // ->ensures our 'windowWillClose' method, which has logic to fully exit app 72 | self.window.delegate = self; 73 | 74 | return; 75 | } 76 | 77 | //register handler for hot keys 78 | -(void)registerKeypressHandler 79 | { 80 | //event 81 | NSEvent * (^keypressHandler)(NSEvent *); 82 | 83 | //keypress handler 84 | keypressHandler = ^NSEvent * (NSEvent * theEvent){ 85 | 86 | return [self handleKeypress:theEvent]; 87 | 88 | }; 89 | 90 | //register for key-down events 91 | [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask handler:keypressHandler]; 92 | 93 | return; 94 | } 95 | 96 | //invoked for any (but only) key-down events 97 | -(NSEvent*)handleKeypress:(NSEvent*)event 98 | { 99 | //flag indicating event was handled 100 | BOOL wasHandled = NO; 101 | 102 | //only care about 'cmd' + something 103 | if(NSCommandKeyMask != (event.modifierFlags & NSCommandKeyMask)) 104 | { 105 | //bail 106 | goto bail; 107 | } 108 | 109 | //handle key-code 110 | // refresh (cmd+r) 111 | // save (cmd+s) 112 | // close window (cmd+w) 113 | switch ([event keyCode]) 114 | { 115 | //'r' (refresh) 116 | case KEYCODE_R: 117 | 118 | //refresh 119 | [self refreshKexts:nil]; 120 | 121 | //set flag 122 | wasHandled = YES; 123 | 124 | break; 125 | 126 | //'s' (save) 127 | case KEYCODE_S: 128 | 129 | //save 130 | [self saveResults:nil]; 131 | 132 | //set flag 133 | wasHandled = YES; 134 | 135 | break; 136 | 137 | //'w' (close window) 138 | case KEYCODE_W: 139 | 140 | //close 141 | // ->if not main window 142 | if(self.window != [[NSApplication sharedApplication] keyWindow]) 143 | { 144 | //close window 145 | [[[NSApplication sharedApplication] keyWindow] close]; 146 | 147 | //set flag 148 | wasHandled = YES; 149 | } 150 | 151 | break; 152 | 153 | 154 | default: 155 | break; 156 | } 157 | 158 | //bail 159 | bail: 160 | 161 | //nil out event if it was handled 162 | if(YES == wasHandled) 163 | { 164 | event = nil; 165 | } 166 | 167 | //return the event, a new event, or, to stop 168 | // the event from being dispatched, nil 169 | return event; 170 | } 171 | 172 | //begin kext enumeration 173 | -(void)enumKexts 174 | { 175 | //refresh button disabled? 176 | // already enumerating, so bail 177 | if(YES != self.refreshButton.enabled) 178 | { 179 | return; 180 | } 181 | 182 | //disable refresh button 183 | self.refreshButton.enabled = NO; 184 | 185 | //alloc kext enumerator 186 | if(nil == self.kextEnumerator) 187 | { 188 | //alloc 189 | kextEnumerator = [[KextEnumerator alloc] init]; 190 | } 191 | 192 | //cancel (previous) enumerator thread 193 | if(nil != self.kextEnumThread) 194 | { 195 | //cancel 196 | [self.kextEnumThread cancel]; 197 | } 198 | 199 | //fade-out overlay 200 | // start kext enumeration 201 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 202 | 203 | //hide overlay 204 | [self.kextTableController hideOverlay]; 205 | 206 | //alloc enumerator thread 207 | self.kextEnumThread = [[NSThread alloc] initWithTarget:self.kextEnumerator selector:@selector(enumerateKexts) object:nil]; 208 | 209 | //kick off thread to enum kext 210 | // will update table as results come in 211 | [self.kextEnumThread start]; 212 | 213 | }); 214 | 215 | return; 216 | } 217 | 218 | //smartly reload a specific row in table 219 | // ->arg determines pane (top/bottom) and for bottom pane, the active view the item belongs to 220 | -(void)reloadRow:(Kext*)item; 221 | { 222 | //table view 223 | __block NSTableView* tableView = nil; 224 | 225 | //row 226 | __block NSUInteger row = 0; 227 | 228 | //run everything on main thread 229 | // ->ensures table view isn't changed out from under us.... 230 | dispatch_async(dispatch_get_main_queue(), ^{ 231 | 232 | //top table view 233 | tableView = [((id)self.kextTableController) itemView]; 234 | 235 | //no filtering 236 | // ->grab row from all kexts 237 | if(YES != self.kextTableController.isFiltered) 238 | { 239 | //get row 240 | row = [self.kextEnumerator.kexts indexOfKey:item.name]; 241 | } 242 | //filtering 243 | // ->grab row from filtered kexts 244 | else 245 | { 246 | //get row 247 | row = [self.kextTableController.filteredItems indexOfObject:item]; 248 | } 249 | 250 | //sanity check 251 | if(NSNotFound == row) 252 | { 253 | //bail 254 | goto bail; 255 | } 256 | 257 | //begin updates 258 | [tableView beginUpdates]; 259 | 260 | //reload row 261 | [tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:(row)] columnIndexes:[NSIndexSet indexSetWithIndex:0]]; 262 | 263 | //end updates 264 | [tableView endUpdates]; 265 | 266 | //bail 267 | bail: 268 | ; 269 | 270 | }); //dispatch on main thread 271 | 272 | return; 273 | } 274 | 275 | //display alert about OS not being supported 276 | -(void)showUnsupportedAlert 277 | { 278 | //alert box 279 | NSAlert* fullScanAlert = nil; 280 | 281 | //alloc/init alert 282 | fullScanAlert = [NSAlert alertWithMessageText:[NSString stringWithFormat:@"OS X %@ is not supported", [[NSProcessInfo processInfo] operatingSystemVersionString]] defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"sorry for the inconvenience!"]; 283 | 284 | //and show it 285 | [fullScanAlert runModal]; 286 | 287 | return; 288 | } 289 | 290 | //automatically invoked when user clicks logo 291 | // ->load objective-see's html page 292 | -(IBAction)logoButtonHandler:(id)sender 293 | { 294 | //open URL 295 | // ->invokes user's default browser 296 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://objective-see.com"]]; 297 | 298 | return; 299 | } 300 | 301 | //reload kext table 302 | // invoke custom refresh method on main thread 303 | -(void)reloadKextTable 304 | { 305 | //refresh on main thread 306 | dispatch_async(dispatch_get_main_queue(), ^{ 307 | 308 | //refresh 309 | [(id)self.kextTableController refresh]; 310 | 311 | }); 312 | 313 | return; 314 | } 315 | 316 | //automatically invoked when window is closing 317 | // ->terminate app 318 | -(void)windowWillClose:(NSNotification *)notification 319 | { 320 | //exit 321 | [NSApp terminate:self]; 322 | 323 | return; 324 | } 325 | 326 | 327 | //invoked when user clicks 'save' icon 328 | // ->show popup that allows user to save results 329 | -(IBAction)saveResults:(id)sender 330 | { 331 | //save panel 332 | NSSavePanel *panel = nil; 333 | 334 | //save results popup 335 | __block NSAlert* saveResultPopup = nil; 336 | 337 | //output 338 | // ->json of all kexts 339 | __block NSMutableString* output = nil; 340 | 341 | //error 342 | __block NSError* error = nil; 343 | 344 | //create panel 345 | panel = [NSSavePanel savePanel]; 346 | 347 | //suggest file name 348 | [panel setNameFieldStringValue:@"Kexts.json"]; 349 | 350 | //show panel 351 | // ->completion handler will invoked when user clicks 'ok' 352 | [panel beginWithCompletionHandler:^(NSInteger result) 353 | { 354 | //only need to handle 'ok' 355 | if(NSFileHandlingPanelOKButton == result) 356 | { 357 | //alloc output JSON 358 | output = [NSMutableString string]; 359 | 360 | //start JSON 361 | [output appendString:@"{\"kexts:\":["]; 362 | 363 | //sync 364 | @synchronized(self.kextEnumerator.kexts) 365 | { 366 | 367 | //get kexts 368 | for(NSString* name in self.kextEnumerator.kexts) 369 | { 370 | //append kext JSON 371 | [output appendFormat:@"{%@},", [self.kextEnumerator.kexts[name] toJSON]]; 372 | } 373 | 374 | }//sync 375 | 376 | //remove last ',' 377 | if(YES == [output hasSuffix:@","]) 378 | { 379 | //remove 380 | [output deleteCharactersInRange:NSMakeRange([output length]-1, 1)]; 381 | } 382 | 383 | //terminate list/output 384 | [output appendString:@"]}"]; 385 | 386 | //save JSON to disk 387 | // ->on error will show err msg in popup 388 | if(YES != [output writeToURL:[panel URL] atomically:NO encoding:NSUTF8StringEncoding error:&error]) 389 | { 390 | //init popup w/ error msg 391 | saveResultPopup = [NSAlert alertWithMessageText:@"ERROR: failed to save output" defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"details: %@", error]; 392 | 393 | } 394 | //happy 395 | // ->set result msg 396 | else 397 | { 398 | //init popup w/ msg 399 | saveResultPopup = [NSAlert alertWithMessageText:@"Succesfully saved output" defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"file: %@", [[panel URL] path]]; 400 | } 401 | 402 | //show popup 403 | [saveResultPopup runModal]; 404 | } 405 | 406 | }]; 407 | 408 | return; 409 | } 410 | 411 | 412 | 413 | #pragma mark Menu Handler(s) #pragma mark - 414 | 415 | //automatically invoked when user clicks 'About/Info' 416 | // ->show about window 417 | -(IBAction)about:(id)sender 418 | { 419 | //alloc/init settings window 420 | if(nil == self.aboutWindowController) 421 | { 422 | //alloc/init 423 | aboutWindowController = [[AboutWindowController alloc] initWithWindowNibName:@"AboutWindow"]; 424 | } 425 | 426 | //center window 427 | [[self.aboutWindowController window] center]; 428 | 429 | //show it 430 | [self.aboutWindowController showWindow:self]; 431 | 432 | return; 433 | } 434 | 435 | //automatically invoked when user enters text in filter search boxes 436 | // ->filter kexts 437 | -(void)controlTextDidChange:(NSNotification *)aNotification 438 | { 439 | //search text 440 | NSTextView* search = nil; 441 | 442 | //extract search (text) view 443 | search = aNotification.userInfo[@"NSFieldEditor"]; 444 | 445 | //sanity check 446 | if(nil == search) 447 | { 448 | //bail 449 | goto bail; 450 | } 451 | 452 | //prevent calling "complete" too often 453 | if( (YES != self.completePosting) && 454 | (YES != self.commandHandling) ) 455 | { 456 | //set flag 457 | self.completePosting = YES; 458 | 459 | //invoke complete 460 | [aNotification.userInfo[@"NSFieldEditor"] complete:nil]; 461 | 462 | //unset flag 463 | self.completePosting = NO; 464 | } 465 | 466 | //when text is reset 467 | // ->just reset flag 468 | if(0 == search.string.length) 469 | { 470 | //set flag 471 | self.kextTableController.isFiltered = NO; 472 | 473 | //check 'show os kexts' box 474 | self.showOSKexts.state = STATE_ON; 475 | } 476 | //filter kexts 477 | else 478 | { 479 | //'#' indicates a keyword search 480 | // ->this is handled by customized auto-complete logic, so ignore 481 | if(YES == [search.string hasPrefix:@"#"]) 482 | { 483 | //ignore 484 | goto bail; 485 | } 486 | 487 | //sync 488 | @synchronized(self.kextTableController.filteredItems) 489 | { 490 | //normal filter 491 | [self.filterObj filterKexts:search.string items:self.kextEnumerator.kexts results:self.kextTableController.filteredItems]; 492 | } 493 | 494 | //set flag 495 | self.kextTableController.isFiltered = YES; 496 | } 497 | 498 | //finalize filtering/search 499 | // ->updates UI, etc 500 | [self finalizeFiltration]; 501 | 502 | //bail 503 | bail: 504 | 505 | 506 | return; 507 | } 508 | 509 | //code to complete filtering/search 510 | // ->reload table/scroll to top etc 511 | -(void)finalizeFiltration 512 | { 513 | //always reload table 514 | [self.kextTableController.itemView reloadData]; 515 | 516 | //scroll to top 517 | [self.kextTableController scrollToTop]; 518 | 519 | return; 520 | } 521 | 522 | //action for 'refresh' button/cmd+r hotkey 523 | -(IBAction)refreshKexts:(id)sender 524 | { 525 | //unset filter flag 526 | self.kextTableController.isFiltered = NO; 527 | 528 | //sync 529 | @synchronized(self.kextTableController.filteredItems) 530 | { 531 | //remove all filtered items 532 | [self.kextTableController.filteredItems removeAllObjects]; 533 | } 534 | 535 | //reset filter box 536 | self.filterKextsBox.stringValue = @""; 537 | 538 | //reset 'show os kexts' button 539 | self.showOSKexts.state = STATE_ON; 540 | 541 | //remove all kexts 542 | [self.kextEnumerator.kexts removeAllObjects]; 543 | 544 | //refresh 545 | [self.kextTableController refresh]; 546 | 547 | //scroll to top 548 | [self.kextTableController scrollToTop]; 549 | 550 | //select top row 551 | [self.kextTableController.itemView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; 552 | 553 | //show overlay 554 | [self.kextTableController showOverlay]; 555 | 556 | //get kexts 557 | // background thread will enum kexts, update table, etc 558 | [self enumKexts]; 559 | 560 | return; 561 | } 562 | 563 | //delegate method, automatically called 564 | // ->generate list of matches to return for drop-down 565 | -(NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index 566 | { 567 | //matches 568 | NSMutableArray *matches = nil; 569 | 570 | //range options 571 | NSUInteger rangeOptions = {0}; 572 | 573 | //init array for matches 574 | matches = [[NSMutableArray alloc] init]; 575 | 576 | //init range options 577 | rangeOptions = NSAnchoredSearch | NSCaseInsensitiveSearch; 578 | 579 | //ignore all text's views that aren't kext filter view 580 | if(textView != self.kextFilterView) 581 | { 582 | //bail 583 | goto bail; 584 | } 585 | 586 | //check all filters 587 | for(NSString* filter in self.filterObj.filterKeywords) 588 | { 589 | //check if found 590 | // ->add to match when found 591 | if([filter rangeOfString:textView.string options:rangeOptions range:NSMakeRange(0, filter.length)].location != NSNotFound) 592 | { 593 | //add 594 | [matches addObject:filter]; 595 | } 596 | } 597 | 598 | //sort matches 599 | [matches sortUsingComparator:^(NSString *a, NSString *b) 600 | { 601 | //sort 602 | return [a localizedStandardCompare:b]; 603 | }]; 604 | 605 | //bail 606 | bail: 607 | 608 | return matches; 609 | } 610 | 611 | //delegate method, automatically invoked 612 | // ->handle invocations for text view 613 | -(BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector 614 | { 615 | //flag 616 | BOOL didPerformRequestedSelectorOnTextView = NO; 617 | 618 | //invocation 619 | NSInvocation *textViewInvocationForSelector = nil; 620 | 621 | //check if text view can handle selector 622 | if(YES != [textView respondsToSelector:commandSelector]) 623 | { 624 | //bail 625 | goto bail; 626 | } 627 | 628 | //set iVar flag 629 | self.commandHandling = YES; 630 | 631 | //init invocation 632 | textViewInvocationForSelector = [NSInvocation invocationWithMethodSignature:[textView methodSignatureForSelector:commandSelector]]; 633 | 634 | //set target 635 | [textViewInvocationForSelector setTarget:textView]; 636 | 637 | //set selector 638 | [textViewInvocationForSelector setSelector:commandSelector]; 639 | 640 | //invoke selector 641 | [textViewInvocationForSelector invoke]; 642 | 643 | //unset iVar 644 | self.commandHandling = NO; 645 | 646 | //indicate that selector was performed 647 | didPerformRequestedSelectorOnTextView = YES; 648 | 649 | 650 | //bail 651 | bail: 652 | 653 | return didPerformRequestedSelectorOnTextView; 654 | } 655 | 656 | 657 | //callback for custom search fields 658 | // ->handle auto-complete filterings 659 | -(void)filterAutoComplete:(NSTextView*)textView 660 | { 661 | //filter string 662 | NSString* filterString = nil; 663 | 664 | //extract filter 665 | filterString = textView.textStorage.string; 666 | 667 | //sync 668 | @synchronized(self.kextTableController.filteredItems) 669 | { 670 | //filter 671 | [self.filterObj filterKexts:filterString items:self.kextEnumerator.kexts results:self.kextTableController.filteredItems]; 672 | } 673 | 674 | //set flag 675 | self.kextTableController.isFiltered = YES; 676 | 677 | //finalize filtering 678 | [self finalizeFiltration]; 679 | 680 | //when filter is '#apple' 681 | // ->make sure 'show os kexts' is checked 682 | if(YES == [textView.textStorage.string isEqualToString:@"#apple"]) 683 | { 684 | //check 685 | self.showOSKexts.state = STATE_ON; 686 | } 687 | 688 | //when filter is '#nonapple' 689 | // ->make sure 'show os kexts' is unchecked 690 | else if(YES == [textView.textStorage.string isEqualToString:@"#nonapple"]) 691 | { 692 | //uncheck 693 | self.showOSKexts.state = STATE_OFF; 694 | } 695 | 696 | return; 697 | } 698 | 699 | //include or exclude OS kexts 700 | -(IBAction)toggleOSFilter:(id)sender 701 | { 702 | //when off 703 | // ->hide OS kexts 704 | if(STATE_OFF == ((NSButton*)sender).state) 705 | { 706 | //set kext filter 707 | [self.filterKextsBox setStringValue:@"#nonapple"]; 708 | 709 | //filter out 710 | [self filterAppleKexts]; 711 | } 712 | //reset filter 713 | else 714 | { 715 | //reset kext filter 716 | [self.filterKextsBox setStringValue:@""]; 717 | 718 | //not filtered 719 | self.kextTableController.isFiltered = NO; 720 | 721 | //finalize non-filter 722 | [self finalizeFiltration]; 723 | } 724 | 725 | return; 726 | } 727 | 728 | //filter for excluding OS kexts checkbox 729 | -(void)filterAppleKexts 730 | { 731 | //sync 732 | @synchronized(self.kextTableController.filteredItems) 733 | { 734 | //filter 735 | // ->logically same as '#nonapple' 736 | [self.filterObj filterKexts:@"#nonapple" items:self.kextEnumerator.kexts results:self.kextTableController.filteredItems]; 737 | } 738 | 739 | //set flag 740 | self.kextTableController.isFiltered = YES; 741 | 742 | //finalize filtering 743 | [self finalizeFiltration]; 744 | 745 | return; 746 | } 747 | 748 | //automatically invoked 749 | // ->set all NSSearchFields to be instances of our custom NSTextView 750 | -(id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client 751 | { 752 | //field editor 753 | id fieldEditor = nil; 754 | 755 | //ignore non-NSSearchField classes 756 | if(YES != [client isKindOfClass:[NSSearchField class]]) 757 | { 758 | //ingnore 759 | goto bail; 760 | } 761 | 762 | //set kext's filter search field 763 | if(client == self.filterKextsBox) 764 | { 765 | //assign for return 766 | fieldEditor = self.kextFilterView; 767 | } 768 | 769 | //bail 770 | bail: 771 | 772 | return fieldEditor; 773 | } 774 | 775 | 776 | 777 | @end 778 | -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/Refresh.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 | -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/Refresh.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/Assets.xcassets/Refresh.imageset/darkMode.png -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/Refresh.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/Assets.xcassets/Refresh.imageset/lightMode.png -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/RefreshAlternate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "alternate.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/RefreshAlternate.imageset/alternate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/Assets.xcassets/RefreshAlternate.imageset/alternate.png -------------------------------------------------------------------------------- /KextViewr/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 | -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/Save.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/Assets.xcassets/Save.imageset/darkMode.png -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/Save.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/Assets.xcassets/Save.imageset/lightMode.png -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/SaveAlternate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "alternate.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /KextViewr/Assets.xcassets/SaveAlternate.imageset/alternate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/Assets.xcassets/SaveAlternate.imageset/alternate.png -------------------------------------------------------------------------------- /KextViewr/CustomTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomTextField.h 3 | // SearchField 4 | // 5 | // Created by Patrick Wardle on 8/27/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | //NSTextView subclass 12 | // 1) fixes issue with non-alphanumeric characters in keyword matches 13 | // 2) triggers action when user hits enter (1x) 14 | @interface CustomTextField : NSTextView 15 | { 16 | 17 | } 18 | 19 | //'owner' 20 | @property (nonatomic, retain)id owner; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /KextViewr/CustomTextField.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomTextField.m 3 | // SearchField 4 | // 5 | // Created by Patrick Wardle on 8/27/15. 6 | // 7 | // 8 | 9 | #import "CustomTextField.h" 10 | #import "AppDelegate.h" 11 | 12 | @implementation CustomTextField 13 | 14 | @synthesize owner; 15 | 16 | //subclass override 17 | // ->see: http://stackoverflow.com/questions/5163646/how-to-make-nssearchfield-send-action-upon-autocompletion/5360535#5360535 18 | -(void)insertCompletion:(NSString *)word forPartialWordRange:(NSRange)charRange movement:(NSInteger)movement isFinal:(BOOL)flag 19 | { 20 | //suppress completion if user types a space 21 | if(movement == NSRightTextMovement) 22 | { 23 | //bail 24 | goto bail; 25 | } 26 | 27 | //show full replacements 28 | if(0 != charRange.location) 29 | { 30 | //update length 31 | charRange.length += charRange.location; 32 | 33 | //reset location 34 | charRange.location = 0; 35 | } 36 | 37 | //insert completion 38 | // ->will use updated char range! 39 | [super insertCompletion:word forPartialWordRange:charRange movement:movement isFinal:flag]; 40 | 41 | //on enter 42 | // ->call up into app delegate to process (filter) 43 | if(movement == NSReturnTextMovement) 44 | { 45 | //call up into owner to process 46 | [owner filterAutoComplete:self]; 47 | } 48 | 49 | //bail 50 | bail: 51 | 52 | return; 53 | } 54 | 55 | @end -------------------------------------------------------------------------------- /KextViewr/Filter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Filter.h 3 | // KextViewer 4 | // 5 | // Created by Patrick Wardle on 2/21/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Kext.h" 10 | 11 | 12 | #import 13 | 14 | @interface Filter : NSObject 15 | { 16 | 17 | } 18 | 19 | /* METHODS */ 20 | 21 | //determine if search string is #keyword 22 | -(BOOL)isKeyword:(NSString*)searchString; 23 | 24 | //check if a kext fulfills a keyword 25 | -(BOOL)kextFulfillsKeyword:(NSString*)keyword kext:(Kext*)kext; 26 | 27 | //keyword filter '#apple' 28 | // ->determine if kext is signed by apple 29 | -(BOOL)isApple:(Kext*)item; 30 | 31 | //filter kexts 32 | // ->name/path/#keyword 33 | -(void)filterKexts:(NSString*)filterText items:(NSMutableDictionary*)items results:(NSMutableArray*)results; 34 | 35 | 36 | /* PROPERTIES */ 37 | 38 | //filter keywords 39 | @property(nonatomic, retain)NSMutableArray* filterKeywords; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /KextViewr/Filter.m: -------------------------------------------------------------------------------- 1 | // 2 | // Filter.m 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 2/21/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | #import "Kext.h" 9 | #import "consts.h" 10 | #import "Filter.h" 11 | #import "utilities.h" 12 | 13 | 14 | //binary filter keywords 15 | NSString * const BINARY_KEYWORDS[] = {@"#apple", @"#nonapple"}; 16 | 17 | @implementation Filter 18 | 19 | @synthesize filterKeywords; 20 | 21 | //init 22 | -(id)init 23 | { 24 | //init super 25 | self = [super init]; 26 | if(nil != self) 27 | { 28 | //alloc binary filter keywords 29 | filterKeywords = [NSMutableArray array]; 30 | 31 | //init binary filters 32 | for(NSUInteger i=0; i < sizeof(BINARY_KEYWORDS)/sizeof(BINARY_KEYWORDS[0]); i++) 33 | { 34 | //add 35 | [self.filterKeywords addObject:BINARY_KEYWORDS[i]]; 36 | } 37 | } 38 | 39 | return self; 40 | } 41 | 42 | //determine if search string is #keyword 43 | -(BOOL)isKeyword:(NSString*)searchString 44 | { 45 | //for now just check in binary keywords 46 | return [self.filterKeywords containsObject:searchString]; 47 | } 48 | 49 | //filter kexts 50 | // ->name, path, & bundle id 51 | -(void)filterKexts:(NSString*)filterText items:(NSMutableDictionary*)items results:(NSMutableArray*)results 52 | { 53 | //kext 54 | Kext* kext = nil; 55 | 56 | //flag for keyword filter 57 | BOOL isKeyword = NO; 58 | 59 | //first reset filter'd items 60 | [results removeAllObjects]; 61 | 62 | //set keyword flag 63 | // ->note: already checked its a full/matching keyword 64 | isKeyword = [filterText hasPrefix:@"#"]; 65 | 66 | //sync 67 | @synchronized(items) 68 | { 69 | 70 | //iterate over all kexts 71 | for(NSString* key in items) 72 | { 73 | //extract kext 74 | kext = items[key]; 75 | 76 | //handle keyword filtering 77 | if( (YES == isKeyword) && 78 | (YES == [self kextFulfillsKeyword:filterText kext:kext]) ) 79 | { 80 | //add 81 | [results addObject:kext]; 82 | 83 | }//keywords 84 | 85 | //no keyword search 86 | else 87 | { 88 | //check path first 89 | // mostly likely to match 90 | if( (nil != kext.path) && 91 | (NSNotFound != [kext.path rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) 92 | { 93 | //save match 94 | [results addObject:kext]; 95 | 96 | //next 97 | continue; 98 | } 99 | 100 | //check name 101 | if( (nil != kext.name) && 102 | (NSNotFound != [kext.name rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) 103 | { 104 | //save match 105 | [results addObject:kext]; 106 | 107 | //next 108 | continue; 109 | } 110 | 111 | //check bundle id 112 | if( (nil != kext.bundle.bundleIdentifier) && 113 | (NSNotFound != [kext.bundle.bundleIdentifier rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) 114 | { 115 | //save match 116 | [results addObject:kext]; 117 | 118 | //next 119 | continue; 120 | } 121 | 122 | //check collection name 123 | if((NSNotFound != [kext.collectionName rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) 124 | { 125 | //save match 126 | [results addObject:kext]; 127 | 128 | //next 129 | continue; 130 | } 131 | 132 | //check address 133 | if((NSNotFound != [kext.address rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) 134 | { 135 | //save match 136 | [results addObject:kext]; 137 | 138 | //next 139 | continue; 140 | } 141 | 142 | //check size 143 | if((NSNotFound != [kext.size rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) 144 | { 145 | //save match 146 | [results addObject:kext]; 147 | 148 | //next 149 | continue; 150 | } 151 | 152 | //check architecture 153 | if((NSNotFound != [kext.architecture rangeOfString:filterText options:NSCaseInsensitiveSearch].location) ) 154 | { 155 | //save match 156 | [results addObject:kext]; 157 | 158 | //next 159 | continue; 160 | } 161 | 162 | } 163 | 164 | }//all kexts 165 | 166 | }//sync 167 | 168 | return; 169 | } 170 | 171 | //check if a binary fulfills a keyword 172 | -(BOOL)kextFulfillsKeyword:(NSString*)keyword kext:(Kext*)kext 173 | { 174 | //flag 175 | BOOL fulfills = NO; 176 | 177 | //handle '#apple' 178 | if( (YES == [keyword isEqualToString:@"#apple"]) && 179 | (YES == [self isApple:kext]) ) 180 | { 181 | //happy 182 | fulfills = YES; 183 | 184 | //bail 185 | goto bail; 186 | } 187 | 188 | //handle '#nonapple' 189 | else if( (YES == [keyword isEqualToString:@"#nonapple"]) && 190 | (YES != [self isApple:kext]) ) 191 | { 192 | //happy 193 | fulfills = YES; 194 | 195 | //bail 196 | goto bail; 197 | } 198 | 199 | bail: 200 | 201 | return fulfills; 202 | } 203 | 204 | //keyword filter '#apple' (and indirectly #nonapple) 205 | -(BOOL)isApple:(Kext*)item 206 | { 207 | //flag 208 | BOOL isApple = NO; 209 | 210 | //boot and system kexts are apple kexts 211 | if( (item.collection == BootCollection) || 212 | (item.collection == SystemCollection) ) 213 | { 214 | //set flag 215 | isApple = YES; 216 | } 217 | 218 | return isApple; 219 | } 220 | 221 | @end 222 | -------------------------------------------------------------------------------- /KextViewr/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSApplicationCategoryType 24 | public.app-category.utilities 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright (c) 2023 Objective-See. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplicationKeyEvents 33 | 34 | 35 | -------------------------------------------------------------------------------- /KextViewr/KKRow.h: -------------------------------------------------------------------------------- 1 | // 2 | // CategoryRow.h 3 | // KextViewr 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 | 14 | @end 15 | -------------------------------------------------------------------------------- /KextViewr/KKRow.m: -------------------------------------------------------------------------------- 1 | // 2 | // CategoryRow.m 3 | // KextViewr 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, 2.5, 2.5); 28 | 29 | //dark mode highlight 30 | if(YES == isDarkMode()) 31 | { 32 | //set stroke 33 | [[NSColor colorWithCalibratedWhite:1.0 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 | @end 62 | -------------------------------------------------------------------------------- /KextViewr/Kext.h: -------------------------------------------------------------------------------- 1 | // 2 | // File.h 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | 12 | //signers 13 | enum Collection{BootCollection, SystemCollection, AuxiliaryCollection}; 14 | 15 | 16 | @interface Kext : NSObject 17 | { 18 | 19 | } 20 | 21 | /* PROPERTIES */ 22 | 23 | //name 24 | @property(retain, nonatomic)NSString* name; 25 | 26 | //path 27 | @property(retain, nonatomic)NSString* path; 28 | 29 | //bundle 30 | @property(nonatomic, retain)NSBundle* bundle; 31 | 32 | //address 33 | @property(nonatomic, retain)NSString* address; 34 | 35 | //size 36 | @property(nonatomic, retain)NSString* size; 37 | 38 | //code signing icon 39 | @property(nonatomic, retain)NSImage* csIcon; 40 | 41 | //architecture 42 | @property(nonatomic, retain)NSString* architecture; 43 | 44 | //collection (type) 45 | @property NSUInteger collection; 46 | 47 | //collection name 48 | @property(nonatomic, retain)NSString* collectionName; 49 | 50 | 51 | /* METHODS */ 52 | 53 | //init 54 | -(id)init:(NSArray *)info collection:(NSUInteger)collection; 55 | 56 | //get name 57 | -(NSString*)getName; 58 | 59 | //convert self to JSON string 60 | -(NSString*)toJSON; 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /KextViewr/Kext.m: -------------------------------------------------------------------------------- 1 | // 2 | // File.m 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 2/19/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Kext.h" 10 | #import "consts.h" 11 | #import "utilities.h" 12 | #import "AppDelegate.h" 13 | 14 | #import 15 | #import 16 | 17 | @implementation Kext 18 | 19 | @synthesize name; 20 | @synthesize path; 21 | @synthesize bundle; 22 | 23 | //init method 24 | -(id)init:(NSArray *)info collection:(NSUInteger)collection 25 | { 26 | //bundle ID 27 | NSString* bundleID = nil; 28 | 29 | //bundle url 30 | CFURLRef bundleURL = nil; 31 | 32 | //super 33 | self = [super init]; 34 | if(self) 35 | { 36 | //bundle id 37 | bundleID = info[6]; 38 | 39 | //get url to bundle 40 | bundleURL = KextManagerCreateURLForBundleIdentifier(NULL, (__bridge CFStringRef)bundleID); 41 | if(nil == bundleURL) 42 | { 43 | //err msg 44 | syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: could find bundle URL for %s", bundleID.UTF8String); 45 | 46 | //unset object 47 | self = nil; 48 | 49 | //bail 50 | goto bail; 51 | } 52 | 53 | //load bundle 54 | self.bundle = [NSBundle bundleWithURL:(__bridge NSURL * _Nonnull)(bundleURL)]; 55 | if(nil == self.bundle) 56 | { 57 | //err msg 58 | syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: could not load bundle for %s", bundleID.UTF8String); 59 | 60 | //unset object 61 | self = nil; 62 | 63 | //bail 64 | goto bail; 65 | } 66 | 67 | //extract bundle path 68 | self.path = self.bundle.bundlePath; 69 | if(nil == self.path) 70 | { 71 | //err msg 72 | syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: could not get path for %s", self.bundle.description.UTF8String); 73 | 74 | //unset object 75 | self = nil; 76 | 77 | //bail 78 | goto bail; 79 | } 80 | 81 | //get name 82 | self.name = [self getName]; 83 | 84 | //addr 85 | self.address = info[2]; 86 | 87 | //size 88 | self.size = info[3]; 89 | 90 | //arch 91 | self.architecture = info[5]; 92 | 93 | //unknown? default to system 94 | if(YES == [self.architecture hasPrefix:@"????"]) 95 | { 96 | //set to native 97 | self.architecture = getNativeArch(); 98 | } 99 | 100 | //collection 101 | self.collection = collection; 102 | 103 | //collection name 104 | switch(self.collection) 105 | { 106 | //boot 107 | case BootCollection: 108 | self.collectionName = @"Boot"; 109 | break; 110 | 111 | //system 112 | case SystemCollection: 113 | self.collectionName = @"System"; 114 | break; 115 | 116 | //auxiliary 117 | case AuxiliaryCollection: 118 | self.collectionName = @"Auxiliary"; 119 | break; 120 | 121 | default: 122 | self.collectionName = @"Unknown"; 123 | break; 124 | } 125 | 126 | //cs icon 127 | switch(self.collection) 128 | { 129 | case BootCollection: 130 | case SystemCollection: 131 | { 132 | self.csIcon = [NSImage imageNamed:@"signedAppleIcon"]; 133 | break; 134 | } 135 | 136 | case AuxiliaryCollection: 137 | { 138 | self.csIcon = [NSImage imageNamed:@"signed"]; 139 | break; 140 | } 141 | 142 | default: 143 | self.csIcon = [NSImage imageNamed:@"unknown"]; 144 | break; 145 | } 146 | 147 | } 148 | 149 | //bail 150 | bail: 151 | 152 | //release bundle URL 153 | if(nil != bundleURL) 154 | { 155 | //release 156 | CFRelease((CFStringRef)bundleURL); 157 | } 158 | 159 | return self; 160 | } 161 | 162 | 163 | 164 | //get kext's name 165 | // either from 'CFBundleName', 'CFBundleExecutable', or path 166 | -(NSString*)getName 167 | { 168 | //name 169 | NSString* kextName = nil; 170 | 171 | //save name 172 | // ->first check 'CFBundleName' 173 | if(nil != self.bundle.infoDictionary[@"CFBundleName"]) 174 | { 175 | //save 176 | kextName = self.bundle.infoDictionary[@"CFBundleName"]; 177 | } 178 | 179 | //some info dictionaries don't have 'CFBundleName' 180 | // ->use 'CFBundleExecutable' 181 | if(nil == kextName) 182 | { 183 | //save 184 | // ->but just file name 185 | kextName = [[self.bundle.infoDictionary[@"CFBundleExecutable"] lastPathComponent] stringByDeletingPathExtension]; 186 | } 187 | 188 | //when still nil 189 | // ->derive from path 190 | if(nil == kextName) 191 | { 192 | //save 193 | // ->but just file name 194 | kextName = [[self.path lastPathComponent] stringByDeletingPathExtension]; 195 | } 196 | 197 | return kextName; 198 | } 199 | 200 | //convert self to JSON string 201 | -(NSString*)toJSON 202 | { 203 | //init json 204 | return [NSString stringWithFormat:@"\"name\": \"%@\", \"path\": \"%@\", \"collection\": \"%@\", \"address\": \"%@\", \"size\": \"%@\", \"architecture\": \"%@\"", self.name, self.path, self.collectionName, self.address, self.size, self.architecture]; 205 | } 206 | 207 | 208 | @end 209 | -------------------------------------------------------------------------------- /KextViewr/KextEnumerator.h: -------------------------------------------------------------------------------- 1 | // 2 | // KextEnumerator.h 3 | // 4 | // 5 | // Created by Patrick Wardle on 5/2/15. 6 | // 7 | // 8 | 9 | #import "3rdParty/OrderedDictionary.h" 10 | 11 | #import 12 | 13 | 14 | @interface KextEnumerator : NSObject 15 | { 16 | 17 | } 18 | 19 | /* PROPERTIES */ 20 | 21 | //all kext objects 22 | @property(nonatomic, retain)OrderedDictionary* kexts; 23 | 24 | /* METHODS */ 25 | 26 | //enumerate all kext 27 | // calls back into app delegate to update table 28 | -(void)enumerateKexts; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /KextViewr/KextEnumerator.m: -------------------------------------------------------------------------------- 1 | // 2 | // KextEnumerator.m 3 | // 4 | // 5 | // Created by Patrick Wardle on 5/2/15. 6 | // 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #import "Kext.h" 13 | #import "consts.h" 14 | #import "utilities.h" 15 | #import "AppDelegate.h" 16 | #import "KextEnumerator.h" 17 | 18 | #import 19 | #import 20 | #import 21 | 22 | @implementation KextEnumerator 23 | 24 | @synthesize kexts; 25 | 26 | //init 27 | -(id)init 28 | { 29 | //init super 30 | self = [super init]; 31 | if(nil != self) 32 | { 33 | //init kexts dictionary/list 34 | kexts = [[OrderedDictionary alloc] init]; 35 | } 36 | 37 | return self; 38 | } 39 | 40 | 41 | //enumerate all kexts 42 | // calls back into app delegate to update table 43 | -(void)enumerateKexts 44 | { 45 | //results from 'kextstat' cmd 46 | NSString* output = nil; 47 | 48 | //base args 49 | NSArray* baseArgs = @[@"showloaded", @"--show-kernel", @"--list-only", @"--arch-info", @"-V", @"release", @"--collection"]; 50 | 51 | //sync & reset 52 | @synchronized(self.kexts) 53 | { 54 | //reset 55 | [self.kexts removeAllObjects]; 56 | } 57 | 58 | //get each kext collection 59 | for (enum Collection collection = BootCollection; collection <= AuxiliaryCollection; collection++) 60 | { 61 | //collection 62 | NSString* collectionName = 0; 63 | 64 | //boot? 65 | switch(collection) 66 | { 67 | case BootCollection: 68 | collectionName = @"boot"; 69 | break; 70 | 71 | case SystemCollection: 72 | collectionName = @"sys"; 73 | break; 74 | 75 | case AuxiliaryCollection: 76 | collectionName = @"aux"; 77 | break; 78 | } 79 | 80 | //exec 'kmutil' to get loaded kexts 81 | // has the entitlement to enumerate kexts 82 | output = [[NSString alloc] initWithData:execTask(KM_UTIL, [baseArgs arrayByAddingObject:collectionName]) encoding:NSUTF8StringEncoding]; 83 | if(nil == output) 84 | { 85 | //next 86 | continue; 87 | } 88 | 89 | //parse 90 | [self parse:output collection:collection]; 91 | } 92 | 93 | //reload kext table 94 | // ensures all kexts are displayed 95 | dispatch_sync(dispatch_get_main_queue(), ^{ 96 | 97 | //reload 98 | [(AppDelegate*)NSApplication.sharedApplication.delegate reloadKextTable]; 99 | 100 | //renable refresh button 101 | ((AppDelegate*)NSApplication.sharedApplication.delegate).refreshButton.enabled = YES; 102 | 103 | 104 | }); 105 | 106 | return; 107 | } 108 | 109 | //parse output 110 | // ...and init kext objects for each kext 111 | -(void)parse:(NSString*)output collection:(NSUInteger)collection 112 | { 113 | //iterate over all kexts 114 | // instantiate an object for each 115 | for(NSString* line in [output componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\n"]]) 116 | { 117 | //kext object 118 | Kext* kext = nil; 119 | 120 | //kext components 121 | NSArray* kextComponents = nil; 122 | 123 | //sanity check 124 | if(0 == line.length) 125 | { 126 | //skip 127 | continue; 128 | } 129 | 130 | //split on white spaces into array 131 | kextComponents = [[line componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]]; 132 | 133 | //sanity check 134 | if(kextComponents.count < 6) 135 | { 136 | //err msg 137 | NSLog(@"OBJECTIVE-SEE ERROR: %@ -> %@, could not be parsed", line, kextComponents); 138 | 139 | //skip 140 | continue; 141 | } 142 | 143 | //create kext 144 | kext = [[Kext alloc] init:kextComponents collection:collection]; 145 | if(nil == kext) 146 | { 147 | //skip 148 | continue; 149 | } 150 | 151 | //save it 152 | // key is kext name 153 | [self.kexts addObject:kext forKey:kext.name atStart:NO]; 154 | 155 | //reload table every 5 kexts 156 | if(0 == self.kexts.count % 5) 157 | { 158 | //on main thread 159 | dispatch_sync(dispatch_get_main_queue(), ^{ 160 | 161 | //reload kext table 162 | [((AppDelegate*)[[NSApplication sharedApplication] delegate]) reloadKextTable]; 163 | 164 | }); 165 | } 166 | 167 | }//all kexts 168 | 169 | 170 | return; 171 | } 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /KextViewr/KextTableController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ItemTableController.h 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 2/18/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "Kext.h" 10 | #import "3rdParty/OrderedDictionary.h" 11 | 12 | 13 | 14 | #import 15 | 16 | @interface KextTableController : NSViewController 17 | { 18 | 19 | } 20 | 21 | //overlay 22 | @property (weak) IBOutlet NSView *overlay; 23 | @property (weak) IBOutlet NSProgressIndicator *activityIndicator; 24 | 25 | //flag for ignoring automated row selections 26 | @property BOOL ignoreSelection; 27 | 28 | //flag for filtering 29 | @property BOOL isFiltered; 30 | 31 | //all table items 32 | @property(nonatomic, retain)NSMutableArray* tableItems; 33 | 34 | //filtered table items 35 | @property(nonatomic, retain)NSMutableArray* filteredItems; 36 | 37 | //category table view 38 | @property(weak) IBOutlet NSTableView *itemView; 39 | 40 | 41 | //currently selected row 42 | // can help determine if newly selected row is really new 43 | @property NSUInteger selectedRow; 44 | 45 | //flag to differentiate between top/bottom view 46 | @property BOOL isBottomPane; 47 | 48 | /* METHODS */ 49 | 50 | //reload table 51 | -(void)reloadTable; 52 | 53 | //show overlay 54 | -(void)showOverlay; 55 | 56 | //hide overlay 57 | -(void)hideOverlay; 58 | 59 | //custom reload 60 | // ->ensures selected row remains selected 61 | -(void)refresh; 62 | 63 | //grab a kext at a row 64 | -(Kext*)kextForRow:(id)sender; 65 | 66 | //scroll back up to top of table 67 | -(void)scrollToTop; 68 | 69 | 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /KextViewr/KextTableController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ItemTableController.m 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 2/18/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | #import "Kext.h" 9 | #import "consts.h" 10 | 11 | #import "utilities.h" 12 | #import "AppDelegate.h" 13 | #import "KextTableController.h" 14 | 15 | #import "KKRow.h" 16 | #import "kkRowCell.h" 17 | 18 | #import 19 | 20 | @implementation KextTableController 21 | 22 | @synthesize itemView; 23 | @synthesize isFiltered; 24 | @synthesize tableItems; 25 | @synthesize selectedRow; 26 | @synthesize isBottomPane; 27 | @synthesize filteredItems; 28 | @synthesize ignoreSelection; 29 | 30 | -(void)awakeFromNib 31 | { 32 | //once 33 | static dispatch_once_t once = 0; 34 | 35 | dispatch_once (&once, ^{ 36 | 37 | //init selected row 38 | self.selectedRow = 0; 39 | 40 | //alloc array for filtered items 41 | self.filteredItems = [NSMutableArray array]; 42 | 43 | //pre-req for color of overlay 44 | self.overlay.wantsLayer = YES; 45 | 46 | //round overlay's corners 47 | self.overlay.layer.cornerRadius = 20.0; 48 | 49 | //mask overlay 50 | self.overlay.layer.masksToBounds = YES; 51 | 52 | //set overlay's view color to gray 53 | self.overlay.layer.backgroundColor = NSColor.lightGrayColor.CGColor; 54 | 55 | //show/activate 56 | [self showOverlay]; 57 | 58 | //table resizing settings 59 | [self.itemView sizeLastColumnToFit]; 60 | 61 | }); 62 | 63 | return; 64 | } 65 | 66 | //show overlay 67 | -(void)showOverlay 68 | { 69 | //(re)set alpha 70 | self.overlay.alphaValue = 1.0f; 71 | 72 | //show overlay 73 | self.overlay.hidden = NO; 74 | 75 | //show activity indicator 76 | self.activityIndicator.hidden = NO; 77 | 78 | //start activity indicator 79 | [self.activityIndicator startAnimation:nil]; 80 | 81 | return; 82 | 83 | } 84 | 85 | //hide overlay 86 | -(void)hideOverlay 87 | { 88 | //begin grouping 89 | [NSAnimationContext beginGrouping]; 90 | 91 | //set duration 92 | [[NSAnimationContext currentContext] setDuration:1.0]; 93 | 94 | //fade out 95 | [[self.overlay animator] setAlphaValue:0.0]; 96 | 97 | //end grouping 98 | [NSAnimationContext endGrouping]; 99 | } 100 | 101 | //table delegate 102 | // ->return number of rows, which is just number of items in the currently selected plugin 103 | -(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView 104 | { 105 | //rows 106 | NSUInteger rows = 0; 107 | 108 | //kexts 109 | OrderedDictionary* kexts = nil; 110 | 111 | //when not filtered 112 | // ->use all kexts 113 | if(YES != isFiltered) 114 | { 115 | //get kexts 116 | kexts = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).kextEnumerator.kexts; 117 | 118 | //set count 119 | rows = kexts.count; 120 | } 121 | //when filtered 122 | // ->use filtered kexts 123 | else 124 | { 125 | //set count 126 | rows = self.filteredItems.count; 127 | } 128 | 129 | return rows; 130 | 131 | } 132 | 133 | //table delegate method 134 | // ->return cell for row 135 | -(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row 136 | { 137 | //kexts 138 | OrderedDictionary* kexts = nil; 139 | 140 | //item obj 141 | // ->contains data for view 142 | id item = nil; 143 | 144 | //row view 145 | NSView* rowView = nil; 146 | 147 | //when not filtered 148 | // ->use kexts 149 | if(YES != isFiltered) 150 | { 151 | //grab kexts 152 | kexts = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).kextEnumerator.kexts; 153 | 154 | //sanity check 155 | // ->make sure there is table item for row 156 | if(kexts.count <= row) 157 | { 158 | //bail 159 | goto bail; 160 | } 161 | 162 | //get kext object 163 | // ->by index to get key, then by key 164 | item = kexts[[kexts keyAtIndex:row]]; 165 | } 166 | 167 | //when filtered 168 | // ->use filtered items 169 | else 170 | { 171 | //sanity check 172 | // ->make sure there is table item for row 173 | if(self.filteredItems.count <= row) 174 | { 175 | //bail 176 | goto bail; 177 | } 178 | 179 | //get kext object 180 | item = self.filteredItems[row]; 181 | } 182 | 183 | //create custom item view 184 | if(nil != item) 185 | { 186 | //create 187 | rowView = [self createRow:tableView column:tableColumn kext:item]; 188 | } 189 | 190 | return rowView; 191 | 192 | 193 | bail: 194 | 195 | return nil; 196 | } 197 | 198 | 199 | //create/config row view 200 | -(NSTableCellView*)createRow:(NSTableView*)tableView column:(NSTableColumn*)column kext:(Kext*)kext 201 | { 202 | //row cell 203 | NSTableCellView* cell = nil; 204 | 205 | //create detailed cell 206 | if(column == tableView.tableColumns[0]) 207 | { 208 | //init 209 | cell = [tableView makeViewWithIdentifier:@"kextCell" owner:self]; 210 | 211 | //set code signing icon 212 | ((NSImageView*)[cell viewWithTag:TABLE_ROW_SIGNATURE_ICON]).image = kext.csIcon; 213 | 214 | //set main text (name) 215 | cell.textField.stringValue = [NSString stringWithFormat:@"%@ (%@)", kext.name, kext.bundle.bundleIdentifier]; 216 | 217 | //set path 218 | [[cell viewWithTag:TABLE_ROW_SUB_TEXT_TAG] setStringValue:kext.path]; 219 | 220 | //set kext 221 | // allows lookup later... 222 | ((kkRowCell*)cell).item = kext; 223 | } 224 | else 225 | { 226 | //init 227 | cell = [tableView makeViewWithIdentifier:@"simpleCell" owner:self]; 228 | 229 | //TODO: nil check! 230 | 231 | //collection 232 | if(column == tableView.tableColumns[1]) 233 | { 234 | //set 235 | ((NSTableCellView*)cell).textField.stringValue = kext.collectionName; 236 | } 237 | 238 | //address 239 | if(column == tableView.tableColumns[2]) 240 | { 241 | //kernel proper? (addr: 0) 242 | if(YES == [kext.address isEqualToString:@"0"]) 243 | { 244 | ((NSTableCellView*)cell).textField.stringValue = @"0 (Kernel)"; 245 | } 246 | else 247 | { 248 | ((NSTableCellView*)cell).textField.stringValue = kext.address; 249 | } 250 | } 251 | 252 | //size 253 | else if(column == tableView.tableColumns[3]) 254 | { 255 | //kernel proper? (size: 0) 256 | if(YES == [kext.size isEqualToString:@"0"]) 257 | { 258 | ((NSTableCellView*)cell).textField.stringValue = @"0 (Kernel)"; 259 | } 260 | else 261 | { 262 | ((NSTableCellView*)cell).textField.stringValue = kext.size; 263 | } 264 | 265 | } 266 | 267 | //architecture 268 | else if(column == tableView.tableColumns[4]) 269 | { 270 | ((NSTableCellView*)cell).textField.stringValue = kext.architecture; 271 | } 272 | 273 | } 274 | 275 | return cell; 276 | } 277 | 278 | //automatically invoked 279 | // ->create custom (sub-classed) NSTableRowView 280 | -(NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row 281 | { 282 | //row view 283 | KKRow* rowView = nil; 284 | 285 | //row ID 286 | static NSString* const kRowIdentifier = @"TableRowView"; 287 | 288 | //try grab existing row view 289 | rowView = [tableView makeViewWithIdentifier:kRowIdentifier owner:self]; 290 | 291 | //make new if needed 292 | if(nil == rowView) 293 | { 294 | //create new 295 | // ->size doesn't matter 296 | rowView = [[KKRow alloc] initWithFrame:NSZeroRect]; 297 | 298 | //set row ID 299 | rowView.identifier = kRowIdentifier; 300 | } 301 | 302 | return rowView; 303 | } 304 | 305 | 306 | 307 | 308 | //scroll back up to top of table 309 | -(void)scrollToTop 310 | { 311 | //scroll if more than 1 row 312 | if([self.itemView numberOfRows] > 0) 313 | { 314 | //top 315 | [self.itemView scrollRowToVisible:0]; 316 | } 317 | } 318 | 319 | //reload table 320 | -(void)reloadTable 321 | { 322 | //reload table 323 | [self.itemView reloadData]; 324 | 325 | //scroll to top 326 | [self scrollToTop]; 327 | 328 | return; 329 | } 330 | 331 | //custom reload 332 | // ensures selected row remains selected 333 | -(void)refresh 334 | { 335 | //kexts 336 | OrderedDictionary* kexts = nil; 337 | 338 | //selected kext 339 | Kext* selectedKext = nil; 340 | 341 | //filter string 342 | NSString* filterString = nil; 343 | 344 | //kext index after reload 345 | NSUInteger kextIndex = 0; 346 | 347 | //grab kexts 348 | kexts = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).kextEnumerator.kexts; 349 | 350 | //make sure filter is updated 351 | if(YES == self.isFiltered) 352 | { 353 | //extract filter 354 | filterString = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).filterKextsBox.stringValue; 355 | 356 | //sync 357 | @synchronized(self.filteredItems) 358 | { 359 | //filter 360 | [((AppDelegate*)[[NSApplication sharedApplication] delegate]).filterObj filterKexts:filterString items:kexts results:self.filteredItems]; 361 | } 362 | } 363 | 364 | //get kext 365 | selectedKext = [self kextForRow:nil]; 366 | 367 | //ignore selection change though 368 | self.ignoreSelection = YES; 369 | 370 | //always reload 371 | [self.itemView reloadData]; 372 | 373 | //don't ignore selection 374 | self.ignoreSelection = NO; 375 | 376 | //when an item was selected 377 | // get its index and make sure that's still selected 378 | if(nil != selectedKext) 379 | { 380 | //get kext's index 381 | kextIndex = [kexts indexOfKey:selectedKext.name]; 382 | 383 | //(re)select kext's row 384 | if(NSNotFound != kextIndex) 385 | { 386 | //begin updates 387 | [self.itemView beginUpdates]; 388 | 389 | //(re)select 390 | [self.itemView selectRowIndexes:[NSIndexSet indexSetWithIndex:kextIndex] byExtendingSelection:NO]; 391 | 392 | //end updates 393 | [self.itemView endUpdates]; 394 | } 395 | } 396 | 397 | return; 398 | } 399 | 400 | //grab a kext at a row 401 | -(Kext*)kextForRow:(id)sender 402 | { 403 | //index of row 404 | NSInteger kextRow = 0; 405 | 406 | //selected row cell 407 | NSTableCellView* rowView = nil; 408 | 409 | //kexts 410 | OrderedDictionary* kexts = nil; 411 | 412 | //kext 413 | Kext* kext = nil; 414 | 415 | //grab kexts 416 | kexts = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).kextEnumerator.kexts; 417 | 418 | //use sender if provided 419 | if(nil != sender) 420 | { 421 | //grab row 422 | kextRow = [self.itemView rowForView:sender]; 423 | } 424 | //otherwise use selected row 425 | else 426 | { 427 | //grab row 428 | kextRow = [self.itemView selectedRow]; 429 | } 430 | 431 | //sanity check(s) 432 | // ->make sure row is decent 433 | if( (-1 == kextRow) || 434 | ((YES != self.isFiltered) && (kexts.count < kextRow)) || 435 | ((YES == self.isFiltered) && (self.filteredItems.count < kextRow)) ) 436 | { 437 | //bail 438 | goto bail; 439 | } 440 | 441 | //get row that's about to be selected 442 | rowView = [self.itemView viewAtColumn:0 row:kextRow makeIfNecessary:YES]; 443 | 444 | //extract kext 445 | kext = ((kkRowCell*)rowView).item; 446 | 447 | //bail 448 | bail: 449 | 450 | return kext; 451 | } 452 | 453 | //automatically invoked when user clicks the 'show in finder' icon 454 | // ->open Finder to show kext 455 | -(IBAction)showInFinder:(id)sender 456 | { 457 | //kext 458 | Kext* kext = nil; 459 | 460 | //file open error alert 461 | NSAlert* errorAlert = nil; 462 | 463 | //get kext 464 | kext = [self kextForRow:sender]; 465 | 466 | //open item in Finder 467 | // ->error alert shown if file open fails 468 | if(YES != [[NSWorkspace sharedWorkspace] selectFile:kext.path inFileViewerRootedAtPath:@""]) 469 | { 470 | //alloc/init alert 471 | errorAlert = [NSAlert alertWithMessageText:[NSString stringWithFormat:@"ERROR: failed to open %@", kext.path] defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"errno value: %d", errno]; 472 | 473 | //show it 474 | [errorAlert runModal]; 475 | } 476 | 477 | return; 478 | } 479 | 480 | 481 | @end 482 | -------------------------------------------------------------------------------- /KextViewr/NSApplicationKeyEvents.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSApplicationKeyEvents.h 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 7/11/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSApplicationKeyEvents : NSApplication 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /KextViewr/NSApplicationKeyEvents.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSApplicationKeyEvents.m 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 7/11/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "NSApplicationKeyEvents.h" 11 | 12 | @implementation NSApplicationKeyEvents 13 | 14 | //to enable copy/paste etc even though we don't have an 'Edit' menu 15 | // details: http://stackoverflow.com/questions/970707/cocoa-keyboard-shortcuts-in-dialog-without-an-edit-menu 16 | -(void)sendEvent:(NSEvent *)event 17 | { 18 | //only care about key down + command 19 | if( (NSEventTypeKeyDown != event.type) || 20 | (NSEventModifierFlagCommand != (event.modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask)) ) 21 | { 22 | //bail 23 | goto bail; 24 | } 25 | 26 | //+c (copy) 27 | if(YES == [[event charactersIgnoringModifiers] isEqualToString:@"c"]) 28 | { 29 | //copy 30 | if(YES == [self sendAction:@selector(copy:) to:nil from:self]) 31 | { 32 | return; 33 | } 34 | } 35 | 36 | //+v (paste) 37 | else if ([[event charactersIgnoringModifiers] isEqualToString:@"v"]) 38 | { 39 | //paste 40 | if(YES == [self sendAction:@selector(paste:) to:nil from:self]) 41 | { 42 | return; 43 | } 44 | } 45 | 46 | //+x (cut) 47 | else if ([[event charactersIgnoringModifiers] isEqualToString:@"x"]) 48 | { 49 | //cut 50 | if(YES == [self sendAction:@selector(cut:) to:nil from:self]) 51 | { 52 | return; 53 | } 54 | } 55 | 56 | //+a (select all) 57 | else if([[event charactersIgnoringModifiers] isEqualToString:@"a"]) 58 | { 59 | //select 60 | if(YES == [self sendAction:@selector(selectAll:) to:nil from:self]) 61 | { 62 | return; 63 | } 64 | } 65 | 66 | //+h (hide window) 67 | else if([[event charactersIgnoringModifiers] isEqualToString:@"h"]) 68 | { 69 | //hide 70 | if(YES == [self sendAction:@selector(hide:) to:nil from:self]) 71 | { 72 | return; 73 | } 74 | } 75 | 76 | //+m (minimize window) 77 | else if([[event charactersIgnoringModifiers] isEqualToString:@"m"]) 78 | { 79 | //minimize 80 | [NSApplication.sharedApplication.keyWindow miniaturize:nil]; 81 | return; 82 | } 83 | 84 | //+w (close window) 85 | else if([[event charactersIgnoringModifiers] isEqualToString:@"w"]) 86 | { 87 | //close 88 | [NSApplication.sharedApplication.keyWindow close]; 89 | return; 90 | } 91 | 92 | //+f 93 | else if([[event charactersIgnoringModifiers] isEqualToString:@"f"]) 94 | { 95 | //iterate over all toolbar items 96 | // ...find search field, and select 97 | for(NSToolbarItem* item in NSApplication.sharedApplication.keyWindow.toolbar.items) 98 | { 99 | //not search field? skip 100 | if(0x1 != item.tag) continue; 101 | 102 | //and make it first responder 103 | [NSApplication.sharedApplication.keyWindow makeFirstResponder:item.view]; 104 | 105 | //done 106 | return; 107 | } 108 | } 109 | 110 | //+r (refresh) 111 | else if([[event charactersIgnoringModifiers] isEqualToString:@"r"]) 112 | { 113 | //refresh 114 | [((AppDelegate*)NSApplication.sharedApplication.delegate) refreshKexts:nil]; 115 | } 116 | 117 | bail: 118 | 119 | //super 120 | [super sendEvent:event]; 121 | 122 | return; 123 | } 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /KextViewr/NSMutableArray+QueueAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableArray+QueueAdditions.h 3 | // BlockBlock 4 | // 5 | // Created by Patrick Wardle on 9/26/14. 6 | // Copyright (c) 2014 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSMutableArray (QueueAdditions) 12 | { 13 | 14 | } 15 | 16 | //METHODS 17 | 18 | //remove first object 19 | -(id)dequeue; 20 | 21 | //add to end 22 | -(void)enqueue:(id)obj; 23 | 24 | //check if empty 25 | -(BOOL)empty; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /KextViewr/NSMutableArray+QueueAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableArray+QueueAdditions.m 3 | // BlockBlock 4 | // 5 | // Created by Patrick Wardle on 9/26/14. 6 | // Copyright (c) 2014 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "NSMutableArray+QueueAdditions.h" 10 | 11 | @implementation NSMutableArray (QueueAdditions) 12 | 13 | //add object to tail (end) of queue 14 | -(void)enqueue:(id)anObject 15 | { 16 | //sync 17 | @synchronized(self) 18 | { 19 | //add object 20 | [self addObject: anObject]; 21 | } 22 | } 23 | 24 | //grab next item in queue 25 | -(id)dequeue 26 | { 27 | //extract object 28 | id queueObject = nil; 29 | 30 | //sync 31 | @synchronized(self) 32 | { 33 | //check to make sure there are some items 34 | if(YES != [self empty]) 35 | { 36 | //extract first one 37 | queueObject = [self objectAtIndex: 0]; 38 | 39 | //delete it from queue 40 | [self removeObjectAtIndex: 0]; 41 | } 42 | 43 | }//sync 44 | 45 | return queueObject; 46 | } 47 | 48 | // Checks if the queue is empty 49 | -(BOOL)empty 50 | { 51 | return ([self lastObject] == nil); 52 | } 53 | 54 | @end -------------------------------------------------------------------------------- /KextViewr/changelog.txt: -------------------------------------------------------------------------------- 1 | TASKEXPLORER CHANGELOG 2 | 3 | 4 | VERSION 1.2.0 (10/11/2015) 5 | el capitan/rootless compatibility 6 | autocomplete search/filter 7 | keyboard shortcuts (cmd+s, cmd+r, cmd+f, cmd+w) 8 | network results included in global search results 9 | xpc-comms refactor (major speed improvement!) 10 | ui fixes/improvements 11 | 12 | 13 | VERSION 1.1.0 (8/23/2015) 14 | added a global search window (tasks, dylibs, files) 15 | added a flagged items window for any flagged tasks or dylibs 16 | xpc-helper's security improved by allowing only Objective-See binary to connect 17 | ui fixes/improvements 18 | 19 | 20 | VERSION 1.0.1 (8/5/2015) 21 | fixed crash on Mavericks (NSSearchField/setPlaceholderString:) 22 | 23 | 24 | VERSION 1.0.0 (8/5/2015) 25 | initial release -------------------------------------------------------------------------------- /KextViewr/consts.h: -------------------------------------------------------------------------------- 1 | // 2 | // Consts.h 3 | // DHS 4 | // 5 | // Created by Patrick Wardle on 2/4/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #ifndef KK_Consts_h 10 | #define KK_Consts_h 11 | 12 | //success 13 | #define STATUS_SUCCESS 0 14 | 15 | //keys for signing stuff 16 | #define KEY_SIGNATURE_STATUS @"signatureStatus" 17 | #define KEY_SIGNING_AUTHORITIES @"signingAuthorities" 18 | #define KEY_SIGNING_IS_APPLE @"signedByApple" 19 | 20 | //patreon url 21 | #define PATREON_URL @"https://www.patreon.com/bePatron?c=701171" 22 | 23 | //product url 24 | #define PRODUCT_URL @"https://objective-see.org/products/kextviewr.html" 25 | 26 | //OS version x 27 | #define OS_MAJOR_VERSION_X 10 28 | 29 | //OS minor version lion 30 | #define OS_MINOR_VERSION_LION 8 31 | 32 | //OS minor version mavericks 33 | #define OS_MINOR_VERSION_MAVERICKS 9 34 | 35 | //OS minor version yosemite 36 | #define OS_MINOR_VERSION_YOSEMITE 10 37 | 38 | //OS minor version el capitan 39 | #define OS_MINOR_VERSION_EL_CAPITAN 11 40 | 41 | //path to kmutil 42 | #define KM_UTIL @"/usr/bin/kmutil" 43 | 44 | //hash key, SHA1 45 | #define KEY_HASH_SHA1 @"sha1" 46 | 47 | //hash key, MD5 48 | #define KEY_HASH_MD5 @"md5" 49 | 50 | //refresh button 51 | #define REFRESH_BUTTON_TAG 10001 52 | 53 | //logo button 54 | #define SAVE_BUTTON_TAG 10003 55 | 56 | //logo button 57 | #define LOGO_BUTTON_TAG 10004 58 | 59 | //id (tag) for detailed text in category table 60 | #define TABLE_ROW_NAME_TAG 100 61 | 62 | //id (tag) for detailed text in category table 63 | #define TABLE_ROW_SUB_TEXT_TAG 101 64 | 65 | //id (tag) for signed icon 66 | #define TABLE_ROW_SIGNATURE_ICON 100 67 | 68 | //id (tag) for path 69 | #define TABLE_ROW_PATH_LABEL 101 70 | 71 | //id (tag) for plist 72 | #define TABLE_ROW_PID_LABEL 102 73 | 74 | //id (tag) for 'virus total' button 75 | #define TABLE_ROW_VT_BUTTON 103 76 | 77 | //id (tag) for 'info' button 78 | #define TABLE_ROW_INFO_BUTTON 105 79 | 80 | //id (tag) for 'show' button 81 | #define TABLE_ROW_SHOW_BUTTON 107 82 | 83 | //scanner option key 84 | // ->filter apple signed/known items 85 | #define KEY_SCANNER_FILTER @"filterItems" 86 | 87 | //name key 88 | #define KEY_RESULT_NAME @"name" 89 | 90 | //path key 91 | #define KEY_RESULT_PATH @"path" 92 | 93 | //extension id key 94 | #define KEY_EXTENSION_ID @"id" 95 | 96 | /* VIRUS TOTAL */ 97 | 98 | //query url 99 | #define VT_QUERY_URL @"https://www.virustotal.com/partners/sysinternals/file-reports?apikey=" 100 | 101 | //requery url 102 | #define VT_REQUERY_URL @"https://www.virustotal.com/vtapi/v2/file/report" 103 | 104 | //rescan url 105 | #define VT_RESCAN_URL @"https://www.virustotal.com/vtapi/v2/file/rescan" 106 | 107 | //submit url 108 | #define VT_SUBMIT_URL @"https://www.virustotal.com/vtapi/v2/file/scan" 109 | 110 | //api key 111 | #define VT_API_KEY @"233f22e200ca5822bd91103043ccac138b910db79f29af5616a9afe8b6f215ad" 112 | 113 | //user agent 114 | #define VT_USER_AGENT @"VirusTotal" 115 | 116 | //query count 117 | #define VT_MAX_QUERY_COUNT 25 118 | 119 | //results 120 | #define VT_RESULTS @"data" 121 | 122 | //results response code 123 | #define VT_RESULTS_RESPONSE @"response_code" 124 | 125 | //result url 126 | #define VT_RESULTS_URL @"permalink" 127 | 128 | //result hash 129 | #define VT_RESULT_HASH @"hash" 130 | 131 | //results positives 132 | #define VT_RESULTS_POSITIVES @"positives" 133 | 134 | //results total 135 | #define VT_RESULTS_TOTAL @"total" 136 | 137 | //results scan id 138 | #define VT_RESULTS_SCANID @"scan_id" 139 | 140 | //button state off 141 | #define STATE_OFF 0x0 142 | 143 | //button state on 144 | #define STATE_ON 0x1 145 | 146 | //hotkey 's' 147 | #define KEYCODE_S 0x1 148 | 149 | //hotkey 'f' 150 | #define KEYCODE_F 0x3 151 | 152 | //hotkey 'w' 153 | #define KEYCODE_W 0xD 154 | 155 | //hotkey 'r' 156 | #define KEYCODE_R 0xF 157 | 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /KextViewr/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /KextViewr/en.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 74 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 296 | 300 | 301 | 302 | 303 | 304 | 305 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_128x128.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_16x16.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_256x256.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_32x32.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_512x512.png -------------------------------------------------------------------------------- /KextViewr/images/icon.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/icon.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /KextViewr/images/kvText.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/kvText.png -------------------------------------------------------------------------------- /KextViewr/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/logo.png -------------------------------------------------------------------------------- /KextViewr/images/logoApple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/logoApple.png -------------------------------------------------------------------------------- /KextViewr/images/logoAppleBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/logoAppleBG.png -------------------------------------------------------------------------------- /KextViewr/images/logoAppleOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/logoAppleOver.png -------------------------------------------------------------------------------- /KextViewr/images/refreshIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/refreshIcon.png -------------------------------------------------------------------------------- /KextViewr/images/refreshIconBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/refreshIconBG.png -------------------------------------------------------------------------------- /KextViewr/images/refreshIconOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/refreshIconOver.png -------------------------------------------------------------------------------- /KextViewr/images/signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/signed.png -------------------------------------------------------------------------------- /KextViewr/images/signedAppleIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/signedAppleIcon.png -------------------------------------------------------------------------------- /KextViewr/images/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/images/unknown.png -------------------------------------------------------------------------------- /KextViewr/kkRowCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // kkRowCell.h 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 4/6/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface kkRowCell : NSTableCellView 12 | { 13 | 14 | } 15 | 16 | /* PROPERTIES */ 17 | 18 | //tag 19 | @property id item; 20 | 21 | //color 22 | @property(nonatomic, retain)NSColor* color; 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /KextViewr/kkRowCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // kkRowCell.m 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle on 4/6/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "kkRowCell.h" 10 | 11 | @implementation kkRowCell 12 | 13 | @synthesize item; 14 | 15 | 16 | //draw method 17 | - (void)drawRect:(NSRect)dirtyRect 18 | { 19 | //draw custom color 20 | if(nil != self.color) 21 | { 22 | //set color 23 | [self.color set]; 24 | 25 | //fill 26 | NSRectFill([self bounds]); 27 | } 28 | } 29 | 30 | //set background color 31 | // ->always light! 32 | - (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle 33 | { 34 | [super setBackgroundStyle: NSBackgroundStyleLight]; 35 | } 36 | 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /KextViewr/kvText.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/KextViewr/8eed712b70ebf65d0d1049b406af9a2ffd8a2e29/KextViewr/kvText.ai -------------------------------------------------------------------------------- /KextViewr/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // KextViewr 4 | // 5 | // Created by Patrick Wardle 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | return NSApplicationMain(argc, (const char **)argv); 15 | } 16 | -------------------------------------------------------------------------------- /KextViewr/patrons.txt: -------------------------------------------------------------------------------- 1 | Patrons (2^6+): 2 | Jan Koum, Nick, Cane Juice, Christian Blümlein, M S, Shain Singh, Nuno, Rabbi Rob Thomas 3 | 4 | Friends of Objective-See: 5 | Kandji, Jamf, Mosyle, CleanMyMac X, Kolide, Fleet, Palo Alto Networks, Sophos, SmugMug, Guardian Mobile Firewall, iVerify, Halo Privacy 6 | -------------------------------------------------------------------------------- /KextViewr/utilities.h: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.h 3 | // DHS 4 | // 5 | // Created by Patrick Wardle on 2/7/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #ifndef DHS_Utilities_h 10 | #define DHS_Utilities_h 11 | 12 | #import 13 | #import 14 | 15 | /* METHODS */ 16 | 17 | //get host architecture (as string) 18 | NSString* getNativeArch(void); 19 | 20 | //get app's version 21 | // ->extracted from Info.plist 22 | NSString* getAppVersion(void); 23 | 24 | //determine if a file is signed by Apple proper 25 | BOOL isApple(NSString* path); 26 | 27 | //exec a process and grab it's output 28 | NSData* execTask(NSString* binaryPath, NSArray* arguments); 29 | 30 | //wait until a window is non nil 31 | // ->then make it modal 32 | void makeModal(NSWindowController* windowController); 33 | 34 | //check if (full) dark mode 35 | BOOL isDarkMode(void); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /KextViewr/utilities.m: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.m 3 | // DHS 4 | // 5 | // Created by Patrick Wardle on 2/7/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "consts.h" 10 | #import "utilities.h" 11 | 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | 22 | //get host architecture (as string) 23 | NSString* getNativeArch(void) 24 | { 25 | int mib[2] = {0}; 26 | size_t length = 0; 27 | char* output = NULL; 28 | 29 | NSString* nativeArchitecture = nil; 30 | 31 | //init 32 | mib[0] = CTL_HW; 33 | mib[1] = HW_MACHINE; 34 | 35 | //get buffer size 36 | sysctl(mib, 2, NULL, &length, NULL, 0); 37 | 38 | //alloc 39 | output = malloc(length); 40 | 41 | //(re)invoke to get native arch 42 | sysctl(mib, 2, output, &length, NULL, 0); 43 | 44 | //convert 45 | nativeArchitecture = [NSString stringWithUTF8String:output]; 46 | 47 | //cleanup 48 | if(NULL != output) 49 | { 50 | //free 51 | free(output); 52 | output = NULL; 53 | } 54 | 55 | return nativeArchitecture; 56 | } 57 | 58 | //get app's version 59 | NSString* getAppVersion(void) 60 | { 61 | //read and return 'CFBundleVersion' from bundle 62 | return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; 63 | } 64 | 65 | 66 | //exec a process and grab it's output 67 | NSData* execTask(NSString* binaryPath, NSArray* arguments) 68 | { 69 | //task 70 | NSTask *task = nil; 71 | 72 | //output pipe 73 | NSPipe *outPipe = nil; 74 | 75 | //read handle 76 | NSFileHandle* readHandle = nil; 77 | 78 | //output 79 | NSMutableData *output = nil; 80 | 81 | //init task 82 | task = [NSTask new]; 83 | 84 | //init output pipe 85 | outPipe = [NSPipe pipe]; 86 | 87 | //init read handle 88 | readHandle = [outPipe fileHandleForReading]; 89 | 90 | //init output buffer 91 | output = [NSMutableData data]; 92 | 93 | //set task's path 94 | [task setLaunchPath:binaryPath]; 95 | 96 | //set task's args 97 | [task setArguments:arguments]; 98 | 99 | //set task's output 100 | [task setStandardOutput:outPipe]; 101 | 102 | //wrap task launch 103 | @try { 104 | 105 | //launch 106 | [task launch]; 107 | } 108 | @catch(NSException *exception) 109 | { 110 | //err msg 111 | //syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: taskExec(%s) failed with %s", [binaryPath UTF8String], [[exception description] UTF8String]); 112 | 113 | //bail 114 | goto bail; 115 | } 116 | 117 | //read in output 118 | while(YES == [task isRunning]) 119 | { 120 | //accumulate output 121 | [output appendData:[readHandle readDataToEndOfFile]]; 122 | } 123 | 124 | //grab any left over data 125 | [output appendData:[readHandle readDataToEndOfFile]]; 126 | 127 | //bail 128 | bail: 129 | 130 | return output; 131 | } 132 | 133 | //wait until a window is non nil 134 | // ->then make it modal 135 | void makeModal(NSWindowController* windowController) 136 | { 137 | //wait up to 1 second window to be non-nil 138 | // ->then make modal 139 | for(int i=0; i<20; i++) 140 | { 141 | //can make it modal once we have a window 142 | if(nil != windowController.window) 143 | { 144 | //make modal on main thread 145 | dispatch_sync(dispatch_get_main_queue(), ^{ 146 | 147 | //modal 148 | [[NSApplication sharedApplication] runModalForWindow:windowController.window]; 149 | 150 | }); 151 | 152 | //all done 153 | break; 154 | } 155 | 156 | //nap 157 | [NSThread sleepForTimeInterval:0.05f]; 158 | 159 | }//until 1 second 160 | 161 | return; 162 | } 163 | 164 | 165 | //set or unset button's highlight 166 | void buttonAppearance(NSTableView* table, NSEvent* event, BOOL shouldReset) 167 | { 168 | //mouse point 169 | NSPoint mousePoint = {0}; 170 | 171 | //row index 172 | NSUInteger rowIndex = -1; 173 | 174 | //current row 175 | NSTableCellView* currentRow = nil; 176 | 177 | //tag 178 | NSUInteger tag = 0; 179 | 180 | //button 181 | NSButton* button = nil; 182 | 183 | //image name 184 | NSString* imageName = nil; 185 | 186 | //extract tag 187 | tag = [((NSDictionary*)event.userData)[@"tag"] unsignedIntegerValue]; 188 | 189 | //restore button back to default (visual) state 190 | if(YES == shouldReset) 191 | { 192 | //set image name 193 | // ->'info' 194 | if(TABLE_ROW_INFO_BUTTON == tag) 195 | { 196 | //set 197 | imageName = @"info"; 198 | } 199 | //set image name 200 | // ->'info' 201 | else if(TABLE_ROW_SHOW_BUTTON == tag) 202 | { 203 | //set 204 | imageName = @"show"; 205 | } 206 | } 207 | //highlight button 208 | else 209 | { 210 | //set image name 211 | // ->'info' 212 | if(TABLE_ROW_INFO_BUTTON == tag) 213 | { 214 | //set 215 | imageName = @"infoOver"; 216 | } 217 | //set image name 218 | // ->'info' 219 | else if(TABLE_ROW_SHOW_BUTTON == tag) 220 | { 221 | //set 222 | imageName = @"showOver"; 223 | } 224 | } 225 | 226 | //grab mouse point 227 | mousePoint = [table convertPoint:[event locationInWindow] fromView:nil]; 228 | 229 | //compute row indow 230 | rowIndex = [table rowAtPoint:mousePoint]; 231 | 232 | //sanity check 233 | if(-1 == rowIndex) 234 | { 235 | //bail 236 | goto bail; 237 | } 238 | 239 | //get row that's about to be selected 240 | currentRow = [table viewAtColumn:0 row:rowIndex makeIfNecessary:YES]; 241 | 242 | //get button 243 | // ->tag id of button, passed in userData var 244 | button = [currentRow viewWithTag:[((NSDictionary*)event.userData)[@"tag"] unsignedIntegerValue]]; 245 | 246 | //restore default button image 247 | // ->for 'info' and 'show' buttons 248 | if(nil != imageName) 249 | { 250 | //set image 251 | [button setImage:[NSImage imageNamed:imageName]]; 252 | } 253 | 254 | bail: 255 | 256 | return; 257 | } 258 | 259 | //check if (full) dark mode 260 | BOOL isDarkMode(void) 261 | { 262 | //flag 263 | BOOL darkMode = NO; 264 | 265 | //not mojave? 266 | // bail, since not true dark mode 267 | if(YES != [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 14, 0}]) 268 | { 269 | //bail 270 | goto bail; 271 | } 272 | 273 | //not dark mode? 274 | if(YES != [[NSUserDefaults.standardUserDefaults stringForKey:@"AppleInterfaceStyle"] isEqualToString:@"Dark"]) 275 | { 276 | //bail 277 | goto bail; 278 | } 279 | 280 | //ok, mojave dark mode it is! 281 | darkMode = YES; 282 | 283 | bail: 284 | 285 | return darkMode; 286 | } 287 | 288 | 289 | --------------------------------------------------------------------------------