├── .gitignore ├── DHS.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── DHS.xccheckout │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ ├── patrick.xcuserdatad │ │ └── WorkspaceSettings.xcsettings │ │ └── patrickw.xcuserdatad │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ ├── patrick.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── DHS.xcscheme │ │ └── xcschememanagement.plist │ └── patrickw.xcuserdatad │ └── xcschemes │ ├── DHS.xcscheme │ └── xcschememanagement.plist ├── DHS ├── AboutWindow.xib ├── AboutWindowController.h ├── AboutWindowController.m ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ └── MainMenu.xib ├── Binary.h ├── Binary.m ├── Consts.h ├── DHS-Info.plist ├── DHS-Prefix.pch ├── MachO │ ├── MachO.h │ └── MachO.m ├── NSApplicationKeyEvents.h ├── NSApplicationKeyEvents.m ├── PrefsWindow.xib ├── PrefsWindowController.h ├── PrefsWindowController.m ├── Scanner.h ├── Scanner.m ├── Utilities.h ├── Utilities.m ├── en.lproj │ └── InfoPlist.strings ├── images │ ├── Assets.xcassets │ │ ├── .DS_Store │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon_128x128.png │ │ │ ├── icon_128x128@2x.png │ │ │ ├── icon_16x16.png │ │ │ ├── icon_16x16@2x.png │ │ │ ├── icon_256x256.png │ │ │ ├── icon_256x256@2x.png │ │ │ ├── icon_32x32.png │ │ │ ├── icon_32x32@2x.png │ │ │ └── icon_512x512.png │ │ ├── Contents.json │ │ ├── FriendsFleet.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsJamf.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsKandji.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsKolide.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsMacPaw.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsMosyle.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsPANW.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ └── FriendsSophos.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ ├── bug.png │ ├── dhsText.ai │ ├── dhsText.png │ ├── icon.png │ ├── logo.png │ ├── logoApple.png │ ├── logoAppleBG.png │ ├── logoAppleOver.png │ ├── settings.png │ ├── settingsBG.png │ ├── settingsOver.png │ ├── show.png │ ├── showOff.png │ ├── showOver.png │ ├── startScan.png │ ├── startScanBG.png │ ├── startScanOver.png │ ├── stopScan.png │ ├── stopScanBG.png │ ├── stopScanOver.png │ └── virus.png ├── main.m └── patrons.txt └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | ## macOS 2 | .DS_Store 3 | 4 | ## Build generated 5 | build/ 6 | DerivedData/ 7 | 8 | ## Various settings 9 | *.pbxuser 10 | !default.pbxuser 11 | *.mode1v3 12 | !default.mode1v3 13 | *.mode2v3 14 | !default.mode2v3 15 | *.perspectivev3 16 | !default.perspectivev3 17 | xcuserdata/ 18 | -------------------------------------------------------------------------------- /DHS.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 | 1D21BC59172AF43D009D1CFD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1D21BC57172AF43D009D1CFD /* InfoPlist.strings */; }; 12 | 1D21BC5B172AF43D009D1CFD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D21BC5A172AF43D009D1CFD /* main.m */; }; 13 | 1D21BC62172AF43D009D1CFD /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D21BC61172AF43D009D1CFD /* AppDelegate.m */; }; 14 | 1D21BC65172AF43D009D1CFD /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1D21BC63172AF43D009D1CFD /* MainMenu.xib */; }; 15 | 7D3E40A11CE6EC38002B0997 /* NSApplicationKeyEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D3E40A01CE6EC38002B0997 /* NSApplicationKeyEvents.m */; }; 16 | 7D3E40A51CE6EFC2002B0997 /* show.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3E40A21CE6EFC2002B0997 /* show.png */; }; 17 | 7D3E40A61CE6EFC2002B0997 /* showOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3E40A31CE6EFC2002B0997 /* showOff.png */; }; 18 | 7D3E40A71CE6EFC2002B0997 /* showOver.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3E40A41CE6EFC2002B0997 /* showOver.png */; }; 19 | 7D3E40AB1CE6F38F002B0997 /* logoAppleOver.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3E40A81CE6F38F002B0997 /* logoAppleOver.png */; }; 20 | 7D3E40AC1CE6F38F002B0997 /* startScanOver.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3E40A91CE6F38F002B0997 /* startScanOver.png */; }; 21 | 7D3E40AD1CE6F38F002B0997 /* stopScanOver.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3E40AA1CE6F38F002B0997 /* stopScanOver.png */; }; 22 | 7D3E40AF1CE6F4E8002B0997 /* settingsOver.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D3E40AE1CE6F4E8002B0997 /* settingsOver.png */; }; 23 | CD0869131ABFD0C100307871 /* settings.png in Resources */ = {isa = PBXBuildFile; fileRef = CD0869111ABFD0C100307871 /* settings.png */; }; 24 | CD0869141ABFD0C100307871 /* settingsBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CD0869121ABFD0C100307871 /* settingsBG.png */; }; 25 | CD08691A1ABFD9BA00307871 /* PrefsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD0869181ABFD9BA00307871 /* PrefsWindowController.m */; }; 26 | CD08691B1ABFD9BA00307871 /* PrefsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD0869191ABFD9BA00307871 /* PrefsWindow.xib */; }; 27 | CD08691D1ABFDF1900307871 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD08691C1ABFDF1900307871 /* Quartz.framework */; }; 28 | CD08691F1AC137FF00307871 /* logoAppleBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CD08691E1AC137FF00307871 /* logoAppleBG.png */; }; 29 | CD39BF84226D550D007E9D67 /* patrons.txt in Resources */ = {isa = PBXBuildFile; fileRef = CD39BF83226D550D007E9D67 /* patrons.txt */; }; 30 | CD39BF86226D58B0007E9D67 /* Collaboration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD39BF85226D58B0007E9D67 /* Collaboration.framework */; }; 31 | CD39BF88226D6A9C007E9D67 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD39BF87226D6A9C007E9D67 /* Assets.xcassets */; }; 32 | CD6095591A832E8800E091CD /* startScanBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6095551A832E8800E091CD /* startScanBG.png */; }; 33 | CD60955A1A832E8800E091CD /* stopScanBG.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6095561A832E8800E091CD /* stopScanBG.png */; }; 34 | CD60955B1A832E8800E091CD /* stopScan.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6095571A832E8800E091CD /* stopScan.png */; }; 35 | CD60955C1A832E8800E091CD /* startScan.png in Resources */ = {isa = PBXBuildFile; fileRef = CD6095581A832E8800E091CD /* startScan.png */; }; 36 | CD6095601A8342A200E091CD /* Scanner.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60955F1A8342A200E091CD /* Scanner.m */; }; 37 | CD60956E1A85F81F00E091CD /* Binary.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60956D1A85F81F00E091CD /* Binary.m */; }; 38 | CD6095701A87027300E091CD /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60956F1A87027300E091CD /* Utilities.m */; }; 39 | CD6095731A87067D00E091CD /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD6095721A87067D00E091CD /* Security.framework */; }; 40 | CD76209D1AEE0A0E00CFCB68 /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD76209B1AEE0A0E00CFCB68 /* AboutWindowController.m */; }; 41 | CD76209E1AEE0A0E00CFCB68 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD76209C1AEE0A0E00CFCB68 /* AboutWindow.xib */; }; 42 | CD7620A01AEE0A3800CFCB68 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD76209F1AEE0A3800CFCB68 /* icon.png */; }; 43 | CD94D2BA29E9DAF8007BD8BF /* MachO.m in Sources */ = {isa = PBXBuildFile; fileRef = CD94D2B829E9DAF8007BD8BF /* MachO.m */; }; 44 | CDB4266C1A8C8CCA00749E80 /* bug.png in Resources */ = {isa = PBXBuildFile; fileRef = CDB4266A1A8C8CCA00749E80 /* bug.png */; }; 45 | CDB4266D1A8C8CCA00749E80 /* virus.png in Resources */ = {isa = PBXBuildFile; fileRef = CDB4266B1A8C8CCA00749E80 /* virus.png */; }; 46 | CDFB64411AA6E51C00D998E1 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = CDFB64401AA6E51C00D998E1 /* logo.png */; }; 47 | CDFB64431AA6EA8B00D998E1 /* dhsText.png in Resources */ = {isa = PBXBuildFile; fileRef = CDFB64421AA6EA8B00D998E1 /* dhsText.png */; }; 48 | CDFB64601AA8313B00D998E1 /* logoApple.png in Resources */ = {isa = PBXBuildFile; fileRef = CDFB645F1AA8313B00D998E1 /* logoApple.png */; }; 49 | /* End PBXBuildFile section */ 50 | 51 | /* Begin PBXFileReference section */ 52 | 1D21BC4B172AF43D009D1CFD /* DHS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DHS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 1D21BC4E172AF43D009D1CFD /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 54 | 1D21BC51172AF43D009D1CFD /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 55 | 1D21BC52172AF43D009D1CFD /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 56 | 1D21BC53172AF43D009D1CFD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 57 | 1D21BC56172AF43D009D1CFD /* DHS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DHS-Info.plist"; sourceTree = ""; }; 58 | 1D21BC58172AF43D009D1CFD /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 59 | 1D21BC5A172AF43D009D1CFD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 60 | 1D21BC5C172AF43D009D1CFD /* DHS-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DHS-Prefix.pch"; sourceTree = ""; }; 61 | 1D21BC60172AF43D009D1CFD /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 62 | 1D21BC61172AF43D009D1CFD /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 63 | 7D3E409F1CE6EC38002B0997 /* NSApplicationKeyEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSApplicationKeyEvents.h; sourceTree = ""; }; 64 | 7D3E40A01CE6EC38002B0997 /* NSApplicationKeyEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSApplicationKeyEvents.m; sourceTree = ""; }; 65 | 7D3E40A21CE6EFC2002B0997 /* show.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = show.png; path = images/show.png; sourceTree = ""; }; 66 | 7D3E40A31CE6EFC2002B0997 /* showOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = showOff.png; path = images/showOff.png; sourceTree = ""; }; 67 | 7D3E40A41CE6EFC2002B0997 /* showOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = showOver.png; path = images/showOver.png; sourceTree = ""; }; 68 | 7D3E40A81CE6F38F002B0997 /* logoAppleOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoAppleOver.png; path = images/logoAppleOver.png; sourceTree = ""; }; 69 | 7D3E40A91CE6F38F002B0997 /* startScanOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = startScanOver.png; path = images/startScanOver.png; sourceTree = ""; }; 70 | 7D3E40AA1CE6F38F002B0997 /* stopScanOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopScanOver.png; path = images/stopScanOver.png; sourceTree = ""; }; 71 | 7D3E40AE1CE6F4E8002B0997 /* settingsOver.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = settingsOver.png; path = images/settingsOver.png; sourceTree = ""; }; 72 | CD0869111ABFD0C100307871 /* settings.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = settings.png; path = images/settings.png; sourceTree = ""; }; 73 | CD0869121ABFD0C100307871 /* settingsBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = settingsBG.png; path = images/settingsBG.png; sourceTree = ""; }; 74 | CD0869171ABFD9BA00307871 /* PrefsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrefsWindowController.h; sourceTree = ""; }; 75 | CD0869181ABFD9BA00307871 /* PrefsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrefsWindowController.m; sourceTree = ""; }; 76 | CD0869191ABFD9BA00307871 /* PrefsWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PrefsWindow.xib; sourceTree = ""; }; 77 | CD08691C1ABFDF1900307871 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; 78 | CD08691E1AC137FF00307871 /* logoAppleBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoAppleBG.png; path = images/logoAppleBG.png; sourceTree = ""; }; 79 | CD39BF82226D5415007E9D67 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 80 | CD39BF83226D550D007E9D67 /* patrons.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = patrons.txt; sourceTree = ""; }; 81 | CD39BF85226D58B0007E9D67 /* Collaboration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Collaboration.framework; path = System/Library/Frameworks/Collaboration.framework; sourceTree = SDKROOT; }; 82 | CD39BF87226D6A9C007E9D67 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = images/Assets.xcassets; sourceTree = ""; }; 83 | CD6095551A832E8800E091CD /* startScanBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = startScanBG.png; path = images/startScanBG.png; sourceTree = ""; }; 84 | CD6095561A832E8800E091CD /* stopScanBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopScanBG.png; path = images/stopScanBG.png; sourceTree = ""; }; 85 | CD6095571A832E8800E091CD /* stopScan.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopScan.png; path = images/stopScan.png; sourceTree = ""; }; 86 | CD6095581A832E8800E091CD /* startScan.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = startScan.png; path = images/startScan.png; sourceTree = ""; }; 87 | CD60955D1A83355900E091CD /* Consts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Consts.h; sourceTree = ""; }; 88 | CD60955E1A8342A200E091CD /* Scanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Scanner.h; sourceTree = ""; }; 89 | CD60955F1A8342A200E091CD /* Scanner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Scanner.m; sourceTree = ""; }; 90 | CD60956C1A85F81F00E091CD /* Binary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Binary.h; sourceTree = ""; }; 91 | CD60956D1A85F81F00E091CD /* Binary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Binary.m; sourceTree = ""; }; 92 | CD60956F1A87027300E091CD /* Utilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Utilities.m; sourceTree = ""; }; 93 | CD6095711A87028600E091CD /* Utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Utilities.h; sourceTree = ""; }; 94 | CD6095721A87067D00E091CD /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 95 | CD76209A1AEE0A0E00CFCB68 /* AboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutWindowController.h; sourceTree = ""; }; 96 | CD76209B1AEE0A0E00CFCB68 /* AboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboutWindowController.m; sourceTree = ""; }; 97 | CD76209C1AEE0A0E00CFCB68 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AboutWindow.xib; sourceTree = ""; }; 98 | CD76209F1AEE0A3800CFCB68 /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon.png; path = images/icon.png; sourceTree = ""; }; 99 | CD94D2B829E9DAF8007BD8BF /* MachO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MachO.m; sourceTree = ""; }; 100 | CD94D2B929E9DAF8007BD8BF /* MachO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachO.h; sourceTree = ""; }; 101 | CDB4266A1A8C8CCA00749E80 /* bug.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = bug.png; path = images/bug.png; sourceTree = ""; }; 102 | CDB4266B1A8C8CCA00749E80 /* virus.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = virus.png; path = images/virus.png; sourceTree = ""; }; 103 | CDFB64401AA6E51C00D998E1 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = images/logo.png; sourceTree = ""; }; 104 | CDFB64421AA6EA8B00D998E1 /* dhsText.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dhsText.png; path = images/dhsText.png; sourceTree = ""; }; 105 | CDFB645F1AA8313B00D998E1 /* logoApple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoApple.png; path = images/logoApple.png; sourceTree = ""; }; 106 | /* End PBXFileReference section */ 107 | 108 | /* Begin PBXFrameworksBuildPhase section */ 109 | 1D21BC48172AF43D009D1CFD /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | CD39BF86226D58B0007E9D67 /* Collaboration.framework in Frameworks */, 114 | CD08691D1ABFDF1900307871 /* Quartz.framework in Frameworks */, 115 | CD6095731A87067D00E091CD /* Security.framework in Frameworks */, 116 | 1D21BC4F172AF43D009D1CFD /* Cocoa.framework in Frameworks */, 117 | ); 118 | runOnlyForDeploymentPostprocessing = 0; 119 | }; 120 | /* End PBXFrameworksBuildPhase section */ 121 | 122 | /* Begin PBXGroup section */ 123 | 1D21BC42172AF43D009D1CFD = { 124 | isa = PBXGroup; 125 | children = ( 126 | 1D21BC54172AF43D009D1CFD /* DHS */, 127 | 1D21BC4D172AF43D009D1CFD /* Frameworks */, 128 | 1D21BC4C172AF43D009D1CFD /* Products */, 129 | ); 130 | sourceTree = ""; 131 | }; 132 | 1D21BC4C172AF43D009D1CFD /* Products */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 1D21BC4B172AF43D009D1CFD /* DHS.app */, 136 | ); 137 | name = Products; 138 | sourceTree = ""; 139 | }; 140 | 1D21BC4D172AF43D009D1CFD /* Frameworks */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | CD39BF85226D58B0007E9D67 /* Collaboration.framework */, 144 | CD08691C1ABFDF1900307871 /* Quartz.framework */, 145 | CD6095721A87067D00E091CD /* Security.framework */, 146 | 1D21BC4E172AF43D009D1CFD /* Cocoa.framework */, 147 | 1D21BC50172AF43D009D1CFD /* Other Frameworks */, 148 | ); 149 | name = Frameworks; 150 | sourceTree = ""; 151 | }; 152 | 1D21BC50172AF43D009D1CFD /* Other Frameworks */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 1D21BC51172AF43D009D1CFD /* AppKit.framework */, 156 | 1D21BC52172AF43D009D1CFD /* CoreData.framework */, 157 | 1D21BC53172AF43D009D1CFD /* Foundation.framework */, 158 | ); 159 | name = "Other Frameworks"; 160 | sourceTree = ""; 161 | }; 162 | 1D21BC54172AF43D009D1CFD /* DHS */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 7D3E409F1CE6EC38002B0997 /* NSApplicationKeyEvents.h */, 166 | 7D3E40A01CE6EC38002B0997 /* NSApplicationKeyEvents.m */, 167 | CD76209A1AEE0A0E00CFCB68 /* AboutWindowController.h */, 168 | CD76209B1AEE0A0E00CFCB68 /* AboutWindowController.m */, 169 | CD76209C1AEE0A0E00CFCB68 /* AboutWindow.xib */, 170 | CD6095501A8329FA00E091CD /* images */, 171 | 1D21BC60172AF43D009D1CFD /* AppDelegate.h */, 172 | 1D21BC61172AF43D009D1CFD /* AppDelegate.m */, 173 | CD94D2BB29E9DAFD007BD8BF /* MachO */, 174 | 1D21BC63172AF43D009D1CFD /* MainMenu.xib */, 175 | CD60956F1A87027300E091CD /* Utilities.m */, 176 | CD6095711A87028600E091CD /* Utilities.h */, 177 | 1D21BC55172AF43D009D1CFD /* Supporting Files */, 178 | CD60955D1A83355900E091CD /* Consts.h */, 179 | CD60955E1A8342A200E091CD /* Scanner.h */, 180 | CD60955F1A8342A200E091CD /* Scanner.m */, 181 | CD60956C1A85F81F00E091CD /* Binary.h */, 182 | CD60956D1A85F81F00E091CD /* Binary.m */, 183 | CD0869171ABFD9BA00307871 /* PrefsWindowController.h */, 184 | CD0869181ABFD9BA00307871 /* PrefsWindowController.m */, 185 | CD0869191ABFD9BA00307871 /* PrefsWindow.xib */, 186 | ); 187 | path = DHS; 188 | sourceTree = ""; 189 | }; 190 | 1D21BC55172AF43D009D1CFD /* Supporting Files */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | CD39BF87226D6A9C007E9D67 /* Assets.xcassets */, 194 | CD39BF83226D550D007E9D67 /* patrons.txt */, 195 | 1D21BC56172AF43D009D1CFD /* DHS-Info.plist */, 196 | 1D21BC57172AF43D009D1CFD /* InfoPlist.strings */, 197 | 1D21BC5A172AF43D009D1CFD /* main.m */, 198 | 1D21BC5C172AF43D009D1CFD /* DHS-Prefix.pch */, 199 | ); 200 | name = "Supporting Files"; 201 | sourceTree = ""; 202 | }; 203 | CD6095501A8329FA00E091CD /* images */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | 7D3E40AE1CE6F4E8002B0997 /* settingsOver.png */, 207 | 7D3E40A81CE6F38F002B0997 /* logoAppleOver.png */, 208 | 7D3E40A91CE6F38F002B0997 /* startScanOver.png */, 209 | 7D3E40AA1CE6F38F002B0997 /* stopScanOver.png */, 210 | 7D3E40A21CE6EFC2002B0997 /* show.png */, 211 | 7D3E40A31CE6EFC2002B0997 /* showOff.png */, 212 | 7D3E40A41CE6EFC2002B0997 /* showOver.png */, 213 | CD76209F1AEE0A3800CFCB68 /* icon.png */, 214 | CD08691E1AC137FF00307871 /* logoAppleBG.png */, 215 | CD0869111ABFD0C100307871 /* settings.png */, 216 | CD0869121ABFD0C100307871 /* settingsBG.png */, 217 | CDFB645F1AA8313B00D998E1 /* logoApple.png */, 218 | CDFB64421AA6EA8B00D998E1 /* dhsText.png */, 219 | CDFB64401AA6E51C00D998E1 /* logo.png */, 220 | CDB4266A1A8C8CCA00749E80 /* bug.png */, 221 | CDB4266B1A8C8CCA00749E80 /* virus.png */, 222 | CD6095551A832E8800E091CD /* startScanBG.png */, 223 | CD6095561A832E8800E091CD /* stopScanBG.png */, 224 | CD6095571A832E8800E091CD /* stopScan.png */, 225 | CD6095581A832E8800E091CD /* startScan.png */, 226 | ); 227 | name = images; 228 | sourceTree = ""; 229 | }; 230 | CD94D2BB29E9DAFD007BD8BF /* MachO */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | CD94D2B929E9DAF8007BD8BF /* MachO.h */, 234 | CD94D2B829E9DAF8007BD8BF /* MachO.m */, 235 | ); 236 | path = MachO; 237 | sourceTree = ""; 238 | }; 239 | /* End PBXGroup section */ 240 | 241 | /* Begin PBXNativeTarget section */ 242 | 1D21BC4A172AF43D009D1CFD /* DHS */ = { 243 | isa = PBXNativeTarget; 244 | buildConfigurationList = 1D21BC68172AF43D009D1CFD /* Build configuration list for PBXNativeTarget "DHS" */; 245 | buildPhases = ( 246 | 1D21BC47172AF43D009D1CFD /* Sources */, 247 | 1D21BC48172AF43D009D1CFD /* Frameworks */, 248 | 1D21BC49172AF43D009D1CFD /* Resources */, 249 | ); 250 | buildRules = ( 251 | ); 252 | dependencies = ( 253 | ); 254 | name = DHS; 255 | productName = "Lesson 53"; 256 | productReference = 1D21BC4B172AF43D009D1CFD /* DHS.app */; 257 | productType = "com.apple.product-type.application"; 258 | }; 259 | /* End PBXNativeTarget section */ 260 | 261 | /* Begin PBXProject section */ 262 | 1D21BC43172AF43D009D1CFD /* Project object */ = { 263 | isa = PBXProject; 264 | attributes = { 265 | LastUpgradeCheck = 1020; 266 | ORGANIZATIONNAME = "Lucas Derraugh"; 267 | TargetAttributes = { 268 | 1D21BC4A172AF43D009D1CFD = { 269 | DevelopmentTeam = VBG97UB4TA; 270 | ProvisioningStyle = Manual; 271 | }; 272 | }; 273 | }; 274 | buildConfigurationList = 1D21BC46172AF43D009D1CFD /* Build configuration list for PBXProject "DHS" */; 275 | compatibilityVersion = "Xcode 3.2"; 276 | developmentRegion = en; 277 | hasScannedForEncodings = 0; 278 | knownRegions = ( 279 | en, 280 | Base, 281 | ); 282 | mainGroup = 1D21BC42172AF43D009D1CFD; 283 | productRefGroup = 1D21BC4C172AF43D009D1CFD /* Products */; 284 | projectDirPath = ""; 285 | projectRoot = ""; 286 | targets = ( 287 | 1D21BC4A172AF43D009D1CFD /* DHS */, 288 | ); 289 | }; 290 | /* End PBXProject section */ 291 | 292 | /* Begin PBXResourcesBuildPhase section */ 293 | 1D21BC49172AF43D009D1CFD /* Resources */ = { 294 | isa = PBXResourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | 7D3E40AF1CE6F4E8002B0997 /* settingsOver.png in Resources */, 298 | CDFB64411AA6E51C00D998E1 /* logo.png in Resources */, 299 | CD39BF84226D550D007E9D67 /* patrons.txt in Resources */, 300 | CDFB64601AA8313B00D998E1 /* logoApple.png in Resources */, 301 | CDB4266C1A8C8CCA00749E80 /* bug.png in Resources */, 302 | CD0869131ABFD0C100307871 /* settings.png in Resources */, 303 | CD39BF88226D6A9C007E9D67 /* Assets.xcassets in Resources */, 304 | 7D3E40A61CE6EFC2002B0997 /* showOff.png in Resources */, 305 | 1D21BC59172AF43D009D1CFD /* InfoPlist.strings in Resources */, 306 | CD08691F1AC137FF00307871 /* logoAppleBG.png in Resources */, 307 | CD0869141ABFD0C100307871 /* settingsBG.png in Resources */, 308 | CD60955C1A832E8800E091CD /* startScan.png in Resources */, 309 | CDB4266D1A8C8CCA00749E80 /* virus.png in Resources */, 310 | 7D3E40AD1CE6F38F002B0997 /* stopScanOver.png in Resources */, 311 | 7D3E40AB1CE6F38F002B0997 /* logoAppleOver.png in Resources */, 312 | CD60955A1A832E8800E091CD /* stopScanBG.png in Resources */, 313 | CD7620A01AEE0A3800CFCB68 /* icon.png in Resources */, 314 | CD6095591A832E8800E091CD /* startScanBG.png in Resources */, 315 | 7D3E40A51CE6EFC2002B0997 /* show.png in Resources */, 316 | CDFB64431AA6EA8B00D998E1 /* dhsText.png in Resources */, 317 | CD76209E1AEE0A0E00CFCB68 /* AboutWindow.xib in Resources */, 318 | 7D3E40AC1CE6F38F002B0997 /* startScanOver.png in Resources */, 319 | 7D3E40A71CE6EFC2002B0997 /* showOver.png in Resources */, 320 | 1D21BC65172AF43D009D1CFD /* MainMenu.xib in Resources */, 321 | CD60955B1A832E8800E091CD /* stopScan.png in Resources */, 322 | CD08691B1ABFD9BA00307871 /* PrefsWindow.xib in Resources */, 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | /* End PBXResourcesBuildPhase section */ 327 | 328 | /* Begin PBXSourcesBuildPhase section */ 329 | 1D21BC47172AF43D009D1CFD /* Sources */ = { 330 | isa = PBXSourcesBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | CD94D2BA29E9DAF8007BD8BF /* MachO.m in Sources */, 334 | 1D21BC5B172AF43D009D1CFD /* main.m in Sources */, 335 | 1D21BC62172AF43D009D1CFD /* AppDelegate.m in Sources */, 336 | CD6095601A8342A200E091CD /* Scanner.m in Sources */, 337 | CD60956E1A85F81F00E091CD /* Binary.m in Sources */, 338 | 7D3E40A11CE6EC38002B0997 /* NSApplicationKeyEvents.m in Sources */, 339 | CD08691A1ABFD9BA00307871 /* PrefsWindowController.m in Sources */, 340 | CD6095701A87027300E091CD /* Utilities.m in Sources */, 341 | CD76209D1AEE0A0E00CFCB68 /* AboutWindowController.m in Sources */, 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | }; 345 | /* End PBXSourcesBuildPhase section */ 346 | 347 | /* Begin PBXVariantGroup section */ 348 | 1D21BC57172AF43D009D1CFD /* InfoPlist.strings */ = { 349 | isa = PBXVariantGroup; 350 | children = ( 351 | 1D21BC58172AF43D009D1CFD /* en */, 352 | ); 353 | name = InfoPlist.strings; 354 | sourceTree = ""; 355 | }; 356 | 1D21BC63172AF43D009D1CFD /* MainMenu.xib */ = { 357 | isa = PBXVariantGroup; 358 | children = ( 359 | CD39BF82226D5415007E9D67 /* Base */, 360 | ); 361 | name = MainMenu.xib; 362 | sourceTree = ""; 363 | }; 364 | /* End PBXVariantGroup section */ 365 | 366 | /* Begin XCBuildConfiguration section */ 367 | 1D21BC66172AF43D009D1CFD /* Debug */ = { 368 | isa = XCBuildConfiguration; 369 | buildSettings = { 370 | ALWAYS_SEARCH_USER_PATHS = NO; 371 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 372 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 373 | CLANG_CXX_LIBRARY = "libc++"; 374 | CLANG_ENABLE_OBJC_ARC = YES; 375 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 376 | CLANG_WARN_BOOL_CONVERSION = YES; 377 | CLANG_WARN_COMMA = YES; 378 | CLANG_WARN_CONSTANT_CONVERSION = YES; 379 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 380 | CLANG_WARN_EMPTY_BODY = YES; 381 | CLANG_WARN_ENUM_CONVERSION = YES; 382 | CLANG_WARN_INFINITE_RECURSION = YES; 383 | CLANG_WARN_INT_CONVERSION = YES; 384 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 385 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 386 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 387 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 388 | CLANG_WARN_STRICT_PROTOTYPES = YES; 389 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 390 | CLANG_WARN_UNREACHABLE_CODE = YES; 391 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 392 | CODE_SIGN_IDENTITY = "Mac Developer"; 393 | COPY_PHASE_STRIP = NO; 394 | ENABLE_STRICT_OBJC_MSGSEND = YES; 395 | ENABLE_TESTABILITY = YES; 396 | GCC_C_LANGUAGE_STANDARD = gnu99; 397 | GCC_DYNAMIC_NO_PIC = NO; 398 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 399 | GCC_NO_COMMON_BLOCKS = YES; 400 | GCC_OPTIMIZATION_LEVEL = 0; 401 | GCC_PREPROCESSOR_DEFINITIONS = ( 402 | "DEBUG=1", 403 | "$(inherited)", 404 | ); 405 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 406 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 407 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 408 | GCC_WARN_UNDECLARED_SELECTOR = YES; 409 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 410 | GCC_WARN_UNUSED_FUNCTION = YES; 411 | GCC_WARN_UNUSED_VARIABLE = YES; 412 | MACOSX_DEPLOYMENT_TARGET = 11.0; 413 | ONLY_ACTIVE_ARCH = YES; 414 | SDKROOT = macosx; 415 | }; 416 | name = Debug; 417 | }; 418 | 1D21BC67172AF43D009D1CFD /* Release */ = { 419 | isa = XCBuildConfiguration; 420 | buildSettings = { 421 | ALWAYS_SEARCH_USER_PATHS = NO; 422 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 423 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 424 | CLANG_CXX_LIBRARY = "libc++"; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 427 | CLANG_WARN_BOOL_CONVERSION = YES; 428 | CLANG_WARN_COMMA = YES; 429 | CLANG_WARN_CONSTANT_CONVERSION = YES; 430 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 431 | CLANG_WARN_EMPTY_BODY = YES; 432 | CLANG_WARN_ENUM_CONVERSION = YES; 433 | CLANG_WARN_INFINITE_RECURSION = YES; 434 | CLANG_WARN_INT_CONVERSION = YES; 435 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 436 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 437 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 438 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 439 | CLANG_WARN_STRICT_PROTOTYPES = YES; 440 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 441 | CLANG_WARN_UNREACHABLE_CODE = YES; 442 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 443 | CODE_SIGN_IDENTITY = "Mac Developer"; 444 | COPY_PHASE_STRIP = YES; 445 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 446 | ENABLE_STRICT_OBJC_MSGSEND = YES; 447 | GCC_C_LANGUAGE_STANDARD = gnu99; 448 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 449 | GCC_NO_COMMON_BLOCKS = YES; 450 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 451 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 452 | GCC_WARN_UNDECLARED_SELECTOR = YES; 453 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 454 | GCC_WARN_UNUSED_FUNCTION = YES; 455 | GCC_WARN_UNUSED_VARIABLE = YES; 456 | MACOSX_DEPLOYMENT_TARGET = 11.0; 457 | ONLY_ACTIVE_ARCH = YES; 458 | SDKROOT = macosx; 459 | }; 460 | name = Release; 461 | }; 462 | 1D21BC69172AF43D009D1CFD /* Debug */ = { 463 | isa = XCBuildConfiguration; 464 | buildSettings = { 465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 466 | CODE_SIGN_IDENTITY = "Developer ID Application"; 467 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; 468 | CODE_SIGN_STYLE = Manual; 469 | COMBINE_HIDPI_IMAGES = YES; 470 | DEVELOPMENT_TEAM = VBG97UB4TA; 471 | ENABLE_HARDENED_RUNTIME = YES; 472 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 473 | GCC_PREFIX_HEADER = "DHS/DHS-Prefix.pch"; 474 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; 475 | INFOPLIST_FILE = "DHS/DHS-Info.plist"; 476 | MACOSX_DEPLOYMENT_TARGET = 11.0; 477 | ONLY_ACTIVE_ARCH = NO; 478 | PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.$(PRODUCT_NAME:rfc1034identifier)"; 479 | PRODUCT_NAME = DHS; 480 | PROVISIONING_PROFILE = ""; 481 | PROVISIONING_PROFILE_SPECIFIER = ""; 482 | WRAPPER_EXTENSION = app; 483 | }; 484 | name = Debug; 485 | }; 486 | 1D21BC6A172AF43D009D1CFD /* Release */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 490 | CODE_SIGN_IDENTITY = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; 491 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)"; 492 | CODE_SIGN_STYLE = Manual; 493 | COMBINE_HIDPI_IMAGES = YES; 494 | DEVELOPMENT_TEAM = VBG97UB4TA; 495 | ENABLE_HARDENED_RUNTIME = YES; 496 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 497 | GCC_PREFIX_HEADER = "DHS/DHS-Prefix.pch"; 498 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; 499 | INFOPLIST_FILE = "DHS/DHS-Info.plist"; 500 | MACOSX_DEPLOYMENT_TARGET = 11.0; 501 | ONLY_ACTIVE_ARCH = NO; 502 | PRODUCT_BUNDLE_IDENTIFIER = "com.objective-see.$(PRODUCT_NAME:rfc1034identifier)"; 503 | PRODUCT_NAME = DHS; 504 | PROVISIONING_PROFILE = ""; 505 | PROVISIONING_PROFILE_SPECIFIER = ""; 506 | WRAPPER_EXTENSION = app; 507 | }; 508 | name = Release; 509 | }; 510 | /* End XCBuildConfiguration section */ 511 | 512 | /* Begin XCConfigurationList section */ 513 | 1D21BC46172AF43D009D1CFD /* Build configuration list for PBXProject "DHS" */ = { 514 | isa = XCConfigurationList; 515 | buildConfigurations = ( 516 | 1D21BC66172AF43D009D1CFD /* Debug */, 517 | 1D21BC67172AF43D009D1CFD /* Release */, 518 | ); 519 | defaultConfigurationIsVisible = 0; 520 | defaultConfigurationName = Release; 521 | }; 522 | 1D21BC68172AF43D009D1CFD /* Build configuration list for PBXNativeTarget "DHS" */ = { 523 | isa = XCConfigurationList; 524 | buildConfigurations = ( 525 | 1D21BC69172AF43D009D1CFD /* Debug */, 526 | 1D21BC6A172AF43D009D1CFD /* Release */, 527 | ); 528 | defaultConfigurationIsVisible = 0; 529 | defaultConfigurationName = Release; 530 | }; 531 | /* End XCConfigurationList section */ 532 | }; 533 | rootObject = 1D21BC43172AF43D009D1CFD /* Project object */; 534 | } 535 | -------------------------------------------------------------------------------- /DHS.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DHS.xcodeproj/project.xcworkspace/xcshareddata/DHS.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | AC0BCBBC-7C12-4672-A1BE-E4EF0105B209 9 | IDESourceControlProjectName 10 | DHS 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 7564E3FECD3AE625755C217749E31B3EE2B69E20 14 | https://bitbucket.org/objective-see/macho.git 15 | 761C0DB3C039BC5B2D73FEB80F04373AFE2CE412 16 | https://bitbucket.org/objective-see/dhs.git 17 | 18 | IDESourceControlProjectPath 19 | DHS.xcodeproj 20 | IDESourceControlProjectRelativeInstallPathDictionary 21 | 22 | 7564E3FECD3AE625755C217749E31B3EE2B69E20 23 | ../../../MachO 24 | 761C0DB3C039BC5B2D73FEB80F04373AFE2CE412 25 | ../.. 26 | 27 | IDESourceControlProjectURL 28 | https://bitbucket.org/objective-see/dhs.git 29 | IDESourceControlProjectVersion 30 | 111 31 | IDESourceControlProjectWCCIdentifier 32 | 761C0DB3C039BC5B2D73FEB80F04373AFE2CE412 33 | IDESourceControlProjectWCConfigurations 34 | 35 | 36 | IDESourceControlRepositoryExtensionIdentifierKey 37 | public.vcs.git 38 | IDESourceControlWCCIdentifierKey 39 | 761C0DB3C039BC5B2D73FEB80F04373AFE2CE412 40 | IDESourceControlWCCName 41 | dylibHijackScanner 42 | 43 | 44 | IDESourceControlRepositoryExtensionIdentifierKey 45 | public.vcs.git 46 | IDESourceControlWCCIdentifierKey 47 | 7564E3FECD3AE625755C217749E31B3EE2B69E20 48 | IDESourceControlWCCName 49 | MachO 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /DHS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DHS.xcodeproj/project.xcworkspace/xcuserdata/patrick.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /DHS.xcodeproj/project.xcworkspace/xcuserdata/patrickw.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /DHS.xcodeproj/xcuserdata/patrick.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /DHS.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/DHS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /DHS.xcodeproj/xcuserdata/patrick.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DHS.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1D21BC4A172AF43D009D1CFD 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /DHS.xcodeproj/xcuserdata/patrickw.xcuserdatad/xcschemes/DHS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /DHS.xcodeproj/xcuserdata/patrickw.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DHS.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1D21BC4A172AF43D009D1CFD 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /DHS/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 | 63 | 64 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 102 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /DHS/AboutWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: AboutWindowController.h 3 | // project: lulu (config) 4 | // description: about window display/controller (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | #import 11 | 12 | @interface AboutWindowController : NSWindowController 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | 19 | //version label/string 20 | @property (weak, atomic) IBOutlet NSTextField *versionLabel; 21 | 22 | //patrons 23 | @property (unsafe_unretained, atomic) IBOutlet NSTextView *patrons; 24 | 25 | //'support us' button 26 | @property (weak, atomic) IBOutlet NSButton *supportUs; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /DHS/AboutWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: AboutWindowController.m 3 | // project: lulu (config) 4 | // description: about window display/controller 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "Consts.h" 11 | #import "Utilities.h" 12 | #import "AboutWindowController.h" 13 | 14 | @implementation AboutWindowController 15 | 16 | @synthesize patrons; 17 | @synthesize supportUs; 18 | @synthesize versionLabel; 19 | 20 | //automatically called when nib is loaded 21 | // center window 22 | -(void)awakeFromNib 23 | { 24 | //center 25 | [self.window center]; 26 | } 27 | 28 | //automatically invoked when window is loaded 29 | // set to white 30 | -(void)windowDidLoad 31 | { 32 | //super 33 | [super windowDidLoad]; 34 | 35 | //not in dark mode? 36 | // make window white 37 | if(YES != isDarkMode()) 38 | { 39 | //make white 40 | self.window.backgroundColor = NSColor.whiteColor; 41 | } 42 | 43 | //set version sting 44 | self.versionLabel.stringValue = [NSString stringWithFormat:@"Version: %@", getAppVersion()]; 45 | 46 | //load patrons 47 | self.patrons.string = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"patrons" ofType:@"txt"] encoding:NSUTF8StringEncoding error:NULL]; 48 | 49 | //make 'support us' default 50 | [self.supportUs setKeyEquivalent:@"\r"]; 51 | 52 | //make first responder 53 | // calling this without a timeout sometimes fails :/ 54 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{ 55 | 56 | //and make it first responder 57 | [self.window makeFirstResponder:self.supportUs]; 58 | 59 | }); 60 | 61 | return; 62 | } 63 | 64 | //automatically invoked when window is closing 65 | // make ourselves unmodal 66 | -(void)windowWillClose:(NSNotification *)notification 67 | { 68 | #pragma unused(notification) 69 | 70 | //make un-modal 71 | [[NSApplication sharedApplication] stopModal]; 72 | 73 | return; 74 | } 75 | 76 | //automatically invoked when user clicks any of the buttons 77 | // load patreon or products webpage in user's default browser 78 | -(IBAction)buttonHandler:(id)sender 79 | { 80 | //support us button 81 | if(((NSButton*)sender).tag == BUTTON_SUPPORT_US) 82 | { 83 | //open URL 84 | // invokes user's default browser 85 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]]; 86 | } 87 | 88 | //more info button 89 | else if(((NSButton*)sender).tag == BUTTON_MORE_INFO) 90 | { 91 | //open URL 92 | // invokes user's default browser 93 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]]; 94 | } 95 | 96 | return; 97 | } 98 | @end 99 | -------------------------------------------------------------------------------- /DHS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // 4 | // Created by Patrick Wardle on 2/6/15. 5 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 6 | // 7 | 8 | #import "Binary.h" 9 | #import "AboutWindowController.h" 10 | #import 11 | 12 | @class PrefsWindowController; 13 | 14 | @interface AppDelegate : NSObject 15 | { 16 | 17 | 18 | } 19 | 20 | //initialized flag 21 | @property BOOL initialized; 22 | 23 | //array to hold binary objects that are in array 24 | @property (nonatomic, retain)NSMutableArray *tableContents; 25 | 26 | //index of 'Vulnerable Applications' header row 27 | @property NSUInteger vulnerableAppHeaderIndex; 28 | 29 | @property (assign) IBOutlet NSWindow *window; 30 | 31 | //version string 32 | @property (weak) IBOutlet NSTextField *versionString; 33 | 34 | @property (weak) IBOutlet NSWindow *friends; 35 | 36 | //main table view 37 | @property (weak) IBOutlet NSTableView *resultsTableView; 38 | 39 | @property (weak) IBOutlet NSButton *showPreferencesButton; 40 | 41 | @property (weak) IBOutlet NSButton *logoButton; 42 | 43 | @property (weak) IBOutlet NSButton *scanButton; 44 | @property (weak) IBOutlet NSTextField *scanButtonLabel; 45 | 46 | 47 | //spinner 48 | @property (weak) IBOutlet NSProgressIndicator *progressIndicator; 49 | @property (weak) IBOutlet NSTextField *statusText; 50 | 51 | 52 | //gear (show prefs) button 53 | @property (weak) IBOutlet NSButton *showPreferences; 54 | 55 | //button handler for when settings icon (gear) is clicked 56 | -(IBAction)showPreferences:(id)sender; 57 | 58 | //settings window controller 59 | @property (nonatomic, retain) PrefsWindowController* prefsWindowController; 60 | 61 | //non-UI thread that performs actual scan 62 | @property (nonatomic, strong) NSThread *scannerThread; 63 | 64 | //number of hijacked binaries 65 | @property NSUInteger hijackCount; 66 | 67 | //number of vulnerable binaries 68 | @property NSUInteger vulnerableCount; 69 | 70 | //about window controller 71 | @property(nonatomic, retain)AboutWindowController* aboutWindowController; 72 | 73 | //constraint for status text 74 | @property (weak) IBOutlet NSLayoutConstraint *statusTextConstraint; 75 | 76 | /* METHODS */ 77 | 78 | //handler for scan button 79 | -(IBAction)scanButtonHandler:(id)sender; 80 | 81 | //display error alert 82 | -(void)showUnsupportedAlert; 83 | 84 | //callback method 85 | // ->adds a hijacked/vulnerable binary to the table 86 | -(void)addToTable:(Binary*)binary; 87 | 88 | //shows alert stating that that scan is complete (w/ stats) 89 | -(void)displayScanStats; 90 | 91 | //handler for 'about' menu item and logo (bottom) 92 | // ->go to objective-see's website 93 | -(IBAction)about:(id)sender; 94 | 95 | //automatically invoked when user clicks logo 96 | // ->load objective-see's html page 97 | -(IBAction)logoButtonHandler:(id)sender; 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /DHS/Binary.h: -------------------------------------------------------------------------------- 1 | // 2 | // Binary.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 "MachO/MachO.h" 10 | #import 11 | 12 | @interface Binary : NSObject 13 | { 14 | 15 | } 16 | 17 | //path (on disk) 18 | @property(nonatomic, retain)NSString* path; 19 | 20 | //instance of mach-O parser 21 | @property(nonatomic, retain)MachO* parserInstance; 22 | 23 | //run paths 24 | @property(nonatomic, retain)NSMutableArray* lcRPATHS; 25 | 26 | 27 | 28 | 29 | //vulnerable 30 | @property BOOL isVulnerable; 31 | 32 | //hijacked 33 | @property BOOL isHijacked; 34 | 35 | //type of vulnerable/hijack 36 | // ->either rpath or weak 37 | @property NSUInteger issueType; 38 | 39 | //path to dylib that could or is causing the issue 40 | @property NSString* issueItem; 41 | 42 | /* METHODS */ 43 | 44 | //init with a path 45 | -(id)initWithPath:(NSString*)binaryPath; 46 | 47 | //get the machO type from the machO parser instance 48 | // ->just grab from first header (should all by the same) 49 | -(uint32_t)getType; 50 | 51 | //convert object to JSON string 52 | -(NSString*)toJSON; 53 | 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /DHS/Binary.m: -------------------------------------------------------------------------------- 1 | // 2 | // Binary.m 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 "Consts.h" 10 | #import "Binary.h" 11 | 12 | @implementation Binary 13 | 14 | @synthesize path; 15 | @synthesize lcRPATHS; 16 | @synthesize issueType; 17 | @synthesize issueItem; 18 | @synthesize isHijacked; 19 | @synthesize isVulnerable; 20 | @synthesize parserInstance; 21 | 22 | //init with a path 23 | -(id)initWithPath:(NSString*)binaryPath 24 | { 25 | //init super 26 | self = [super init]; 27 | if(nil != self) 28 | { 29 | //save path 30 | self.path = binaryPath; 31 | 32 | //alloc array for run-path search directories 33 | // ->needed since we resolve these manually 34 | lcRPATHS = [NSMutableArray array]; 35 | } 36 | 37 | return self; 38 | } 39 | 40 | //get the machO type from the machO parser instance 41 | // ->just grab from first header (should all by the same) 42 | -(uint32_t)getType 43 | { 44 | //type 45 | uint32_t type = 0; 46 | 47 | //extract type 48 | if(nil != self.parserInstance) 49 | { 50 | //extract 51 | type = [[[self.parserInstance.binaryInfo[KEY_MACHO_HEADERS] firstObject] objectForKey:KEY_HEADER_BINARY_TYPE] unsignedIntValue]; 52 | } 53 | 54 | return type; 55 | } 56 | 57 | //convert object to JSON string 58 | -(NSString*)toJSON 59 | { 60 | //json string 61 | NSString *json = nil; 62 | 63 | //issue 64 | NSString* issue = nil; 65 | 66 | //init issue 67 | // ->rpath 68 | if(ISSUE_TYPE_RPATH == self.issueType) 69 | { 70 | issue = @"rpath"; 71 | } 72 | //init issue 73 | // ->weak 74 | else 75 | { 76 | issue = @"weak"; 77 | } 78 | 79 | //init json 80 | json = [NSString stringWithFormat:@"\"binary path\": \"%@\", \"issue\": \"%@\", \"dylib path\": \"%@\"", self.path, issue, self.issueItem]; 81 | 82 | return json; 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /DHS/Consts.h: -------------------------------------------------------------------------------- 1 | // 2 | // Consts.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 | #ifndef DHS_Consts_h 10 | #define DHS_Consts_h 11 | 12 | //not first run 13 | #define NOT_FIRST_TIME @"notFirstTime" 14 | 15 | //button text, start scan 16 | #define START_SCAN @"Start Scan" 17 | 18 | //button text, stop scan 19 | #define STOP_SCAN @"Stop Scan" 20 | 21 | //status msg 22 | #define SCAN_MSG_PARTIAL @"Scanning running processes" 23 | 24 | //status msg 25 | #define SCAN_MSG_FULL @"Scanning entire system" 26 | 27 | //status msg 28 | #define SCAN_MSG_STOPPED @"Scan stopped" 29 | 30 | //status msg 31 | #define SCAN_MSG_COMPLETE @"Scan complete!" 32 | 33 | //success 34 | #define STATUS_SUCCESS 0 35 | 36 | //keys for scanner options 37 | #define KEY_SCANNER_FULL @"scanFull" 38 | #define KEY_SCANNER_WEAK_HIJACKERS @"scan4WeakHijackers" 39 | 40 | //keys for signing stuff 41 | #define KEY_IS_APPLE @"isApple" 42 | #define KEY_SIGNATURE_STATUS @"signatureStatus" 43 | #define KEY_HARDENED_RUNTIME @"hardenedRuntime" 44 | #define KEY_SIGNING_ENTITLEMENTS @"entitlements" 45 | #define KEY_LIBRARY_VALIDATION @"libraryValidation" 46 | #define KEY_SIGNING_AUTHORITIES @"signingAuthorities" 47 | 48 | //executable path 49 | #define EXECUTABLE_PATH @"@executable_path" 50 | 51 | //loader path 52 | #define LOADER_PATH @"@loader_path" 53 | 54 | //rpath 55 | #define RUN_SEARCH_PATH @"@rpath" 56 | 57 | //hardened runtime flags 58 | #define FLAG_HARDENED_RUNTIME 0x10000 59 | 60 | //library validation flags 61 | #define FLAGS_LIBRARY_VALIDATION 0x2000 62 | 63 | //type 64 | // ->rpath 65 | #define ISSUE_TYPE_RPATH 1 66 | 67 | //type 68 | // ->weak 69 | #define ISSUE_TYPE_WEAK 2 70 | 71 | //path to LSOF 72 | #define LSOF @"/usr/sbin/lsof" 73 | 74 | //header for table 75 | // ->hijacked apps 76 | #define TABLE_HEADER_HIJACK @"Hijacked Applications" 77 | 78 | //header for table 79 | // ->vulnerable apps 80 | #define TABLE_HEADER_VULNERABLE @"Vulnerable Applications" 81 | 82 | //id (tag) for total's msg 83 | #define TABLE_HEADER_TOTAL_TAG 101 84 | 85 | //id (tag) for detailed text in rows 86 | #define TABLE_ROW_SUB_TEXT_TAG 2 87 | 88 | //id (tag) for 'find in finder' button 89 | #define TABLE_ROW_FINDER_BUTTON 3 90 | 91 | //disabled state 92 | #define STATE_DISABLED 0 93 | 94 | //enabled state 95 | #define STATE_ENABLED 1 96 | 97 | //prefs 98 | // ->full system scan 99 | #define PREF_FULL_SYSTEM_SCAN @"fullSystemScan" 100 | 101 | //prefs 102 | // ->weak hijacker detection 103 | #define PREF_WEAK_HIJACKER_DETECTION @"weakHijackerDetection" 104 | 105 | //prefs 106 | // ->save output 107 | #define PREF_SAVE_OUTPUT @"saveOutput" 108 | 109 | 110 | //key for JSON output 111 | #define KEY_ITEM @"item" 112 | 113 | //output file 114 | #define OUTPUT_FILE @"dhsFindings.txt" 115 | 116 | //hotkey 'w' 117 | #define KEYCODE_W 0xD 118 | 119 | //hotkey 'q' 120 | #define KEYCODE_Q 0xC 121 | 122 | //scan button 123 | #define SCAN_BUTTON_TAG 1000 124 | 125 | //pref button 126 | #define PREF_BUTTON_TAG 1001 127 | 128 | //logo button 129 | #define LOGO_BUTTON_TAG 1002 130 | 131 | //support us button tag 132 | #define BUTTON_SUPPORT_US 100 133 | 134 | //more info button tag 135 | #define BUTTON_MORE_INFO 101 136 | 137 | //patreon url 138 | #define PATREON_URL @"https://www.patreon.com/objective_see" 139 | 140 | //product url 141 | #define PRODUCT_URL @"https://objective-see.org/products/dhs.html" 142 | 143 | //user name 144 | #define USER_NAME @"userName" 145 | 146 | //user (home) directory 147 | #define USER_DIRECTORY @"userDirectory" 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /DHS/DHS-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.5.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.5.1 23 | LSMinimumSystemVersion 24 | ${MACOSX_DEPLOYMENT_TARGET} 25 | NSHumanReadableCopyright 26 | Copyright © 2023 Objective-See, LLC. All rights reserved. 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplicationKeyEvents 31 | 32 | 33 | -------------------------------------------------------------------------------- /DHS/DHS-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'DHS' target in the 'DHS' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /DHS/MachO/MachO.h: -------------------------------------------------------------------------------- 1 | // 2 | // MachO.h 3 | // MachOParser 4 | // 5 | // Created by Patrick Wardle on 2/6/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /* CONSTS */ 12 | 13 | //dictionary keys 14 | #define KEY_BINARY_PATH @"binaryPath" 15 | #define KEY_MACHO_HEADERS @"machoHeaders" 16 | #define KEY_LOAD_COMMANDS @"loadCommands" 17 | 18 | #define KEY_HEADER_OFFSET @"headerOffset" 19 | #define KEY_HEADER_SIZE @"headerSize" 20 | #define KEY_HEADER_BINARY_TYPE @"headerType" 21 | #define KEY_HEADER_BYTE_ORDER @"headerByteOrder" 22 | #define KEY_IS_PACKED @"isPacked" 23 | #define KEY_IS_ENCRYPTED @"isEncryted" 24 | 25 | #define KEY_LC_RPATHS @"lcRpath" 26 | #define KEY_LC_REEXPORT_DYLIBS @"lcRexports" 27 | #define KEY_LC_LOAD_DYLIBS @"lcLoadDylib" 28 | #define KEY_LC_LOAD_WEAK_DYLIBS @"lcLoadWeakDylib" 29 | 30 | 31 | @interface MachO : NSObject 32 | { 33 | 34 | } 35 | 36 | //info dictionary 37 | // ->contains everything parsed out of the file 38 | @property(nonatomic, retain)NSMutableDictionary* binaryInfo; 39 | 40 | //binary's data 41 | @property(nonatomic, retain)NSData* binaryData; 42 | 43 | //segment names found in various packers 44 | @property(nonatomic, retain)NSSet* packerSegmentNames; 45 | 46 | 47 | /* METHODS */ 48 | 49 | //parse a binary 50 | // ->extract all required/interesting stuff 51 | -(BOOL)parse:(NSString*)binaryPath classify:(BOOL)shouldClassify; 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /DHS/MachO/MachO.m: -------------------------------------------------------------------------------- 1 | // 2 | // MachO.m 3 | // MachOParser 4 | // 5 | // Created by Patrick Wardle on 2/6/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | 9 | #import "MachO.h" 10 | 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | 17 | @implementation MachO 18 | 19 | @synthesize binaryInfo; 20 | @synthesize binaryData; 21 | @synthesize packerSegmentNames; 22 | 23 | //init 24 | -(id)init 25 | { 26 | //init super 27 | self = [super init]; 28 | if(nil != self) 29 | { 30 | //alloc info dictionary 31 | // ->contains everything collected about the file 32 | binaryInfo = [NSMutableDictionary dictionary]; 33 | 34 | //init array for machO headers 35 | self.binaryInfo[KEY_MACHO_HEADERS] = [NSMutableArray array]; 36 | 37 | //init array for LC_RPATHS 38 | self.binaryInfo[KEY_LC_RPATHS] = [NSMutableArray array]; 39 | 40 | //init array for LC_REEXPORT_DYLIBs 41 | self.binaryInfo[KEY_LC_REEXPORT_DYLIBS] = [NSMutableArray array]; 42 | 43 | //init array for LC_LOAD_DYLIBs 44 | self.binaryInfo[KEY_LC_LOAD_DYLIBS] = [NSMutableArray array]; 45 | 46 | //init array for LC_LOAD_WEAK_DYLIBs 47 | self.binaryInfo[KEY_LC_LOAD_WEAK_DYLIBS] = [NSMutableArray array]; 48 | 49 | //init packer seg names 50 | // upx: __XHDR 51 | // mpress: __MPRESS__* 52 | packerSegmentNames = [NSSet setWithObjects:@"__XHDR", @"__MPRESS__", nil]; 53 | } 54 | 55 | return self; 56 | } 57 | 58 | //parse a binary 59 | // ->extract all required/interesting stuff 60 | -(BOOL)parse:(NSString*)binaryPath classify:(BOOL)shouldClassify 61 | { 62 | //ret var 63 | BOOL wasParsed = NO; 64 | 65 | //dbg msg 66 | //NSLog(@"parsing %@", binaryPath); 67 | 68 | //save path 69 | self.binaryInfo[KEY_BINARY_PATH] = binaryPath; 70 | 71 | //load binary into memory 72 | self.binaryData = [NSData dataWithContentsOfFile:binaryPath]; 73 | if( (nil == self.binaryData) || 74 | (NULL == [self.binaryData bytes]) ) 75 | { 76 | //err msg 77 | //NSLog(@"OBJECTIVE-SEE ERROR: failed to load %@ into memory", binaryPath); 78 | 79 | //bail 80 | goto bail; 81 | } 82 | 83 | //parse headers 84 | // ->populates 'KEY_MACHO_HEADERS' array in 'binaryInfo' iVar 85 | if(YES != [self parseHeaders]) 86 | { 87 | //err msg 88 | //NSLog(@"OBJECTIVE-SEE ERROR: failed to find any machO headers"); 89 | 90 | //bail 91 | goto bail; 92 | } 93 | 94 | //parse headers 95 | // ->populates 'KEY_MACHO_HEADERS' array in 'binaryInfo' iVar 96 | if(YES != [self parseLoadCmds]) 97 | { 98 | //err msg 99 | //NSLog(@"OBJECTIVE-SEE ERROR: failed to parse load commands"); 100 | 101 | //bail 102 | goto bail; 103 | } 104 | 105 | //dbg msg 106 | //NSLog(@"parsed load commands"); 107 | 108 | //only do packer/encryption checks if specified 109 | if(YES == shouldClassify) 110 | { 111 | //first determine if binary is encrypted 112 | self.binaryInfo[KEY_IS_ENCRYPTED] = [NSNumber numberWithBool:[self isEncrypted]]; 113 | 114 | //all encrypted binaries will also appear packed 115 | // ->so only check if unencrypted binaries are unpacked 116 | if(YES != [self.binaryInfo[KEY_IS_ENCRYPTED] boolValue]) 117 | { 118 | //determine if packed 119 | self.binaryInfo[KEY_IS_PACKED] = [NSNumber numberWithBool:[self isPacked]]; 120 | } 121 | } 122 | 123 | //happy 124 | wasParsed = YES; 125 | 126 | //bail 127 | bail: 128 | 129 | return wasParsed; 130 | } 131 | 132 | //parse all machO headers 133 | -(BOOL)parseHeaders 134 | { 135 | //return var 136 | BOOL wasParsed = NO; 137 | 138 | //start of macho header 139 | const uint32_t *headerStart = NULL; 140 | 141 | //swapped flag 142 | BOOL shouldSwap = NO; 143 | 144 | //header dictionary 145 | NSDictionary* header = nil; 146 | 147 | //number of machO headers 148 | uint32_t headerCount = 0; 149 | 150 | //header offsets 151 | NSMutableArray* headerOffsets = nil; 152 | 153 | //per-architecture header 154 | struct fat_arch *arch = NULL; 155 | 156 | //pointer to binary's data 157 | const void* binaryBytes = NULL; 158 | 159 | //alloc array 160 | headerOffsets = [NSMutableArray array]; 161 | 162 | //grab binary's bytes 163 | binaryBytes = [self.binaryData bytes]; 164 | if(NULL == binaryBytes) 165 | { 166 | //bail 167 | goto bail; 168 | } 169 | 170 | //init start of header 171 | headerStart = binaryBytes; 172 | 173 | //handle universal (fat) case 174 | if( (FAT_MAGIC == *headerStart) || 175 | (FAT_CIGAM == *headerStart) ) 176 | { 177 | //dbg msg 178 | //NSLog(@"parsing universal binary"); 179 | 180 | //swap if needed 181 | if(FAT_CIGAM == *headerStart) 182 | { 183 | //set flag 184 | shouldSwap = YES; 185 | 186 | //swap 187 | swap_fat_header((struct fat_header*)headerStart, 0); 188 | } 189 | 190 | //get number of fat_arch structs 191 | // ->one per each architecture 192 | headerCount = ((struct fat_header*)binaryBytes)->nfat_arch; 193 | 194 | //get offsets of all headers 195 | for(uint32_t i = 0; i < headerCount; i++) 196 | { 197 | //get current struct fat_arch * 198 | // ->base + size of fat_header + size of fat_archs 199 | arch = (struct fat_arch*)((unsigned char*)binaryBytes + sizeof(struct fat_header) + i * sizeof(struct fat_arch)); 200 | 201 | //swap if needed 202 | if(YES == shouldSwap) 203 | { 204 | //swap 205 | swap_fat_arch(arch, 0x01, 0); 206 | } 207 | 208 | //sanity check 209 | // ->make sure arch is something 'within' binary 210 | if( ((unsigned char*)arch < (unsigned char*)binaryBytes) || 211 | ((unsigned char*)(binaryBytes + self.binaryData.length) < (unsigned char*)((unsigned char*)arch + sizeof(struct fat_arch))) ) 212 | { 213 | //err 214 | goto bail; 215 | } 216 | 217 | //save into header offset array 218 | [headerOffsets addObject:[NSNumber numberWithUnsignedInt:arch->offset]]; 219 | } 220 | } 221 | 222 | //not fat 223 | // ->just add start as (only) header offset 224 | else 225 | { 226 | //dbg msg 227 | //NSLog(@"parsing non-universal binary"); 228 | 229 | //add start 230 | [headerOffsets addObject:@0x0]; 231 | } 232 | 233 | //classify all headers 234 | for(NSNumber* headerOffset in headerOffsets) 235 | { 236 | //skip invalid header offsets 237 | if(headerOffset.unsignedIntValue > [self.binaryData length]) 238 | { 239 | //skip 240 | continue; 241 | } 242 | 243 | //grab start of header 244 | headerStart = binaryBytes + headerOffset.unsignedIntValue; 245 | 246 | //classify header 247 | switch(*headerStart) 248 | { 249 | //32bit mach-O 250 | // ->little-endian version 251 | case MH_CIGAM: 252 | 253 | //swap 254 | swap_mach_header((struct mach_header*)headerStart, 0); 255 | 256 | //init header dictionary 257 | header = @{ 258 | KEY_HEADER_OFFSET:headerOffset, 259 | KEY_HEADER_SIZE:@(sizeof(struct mach_header)), 260 | KEY_HEADER_BINARY_TYPE:[NSNumber numberWithInt:((struct mach_header*)headerStart)->filetype], 261 | KEY_HEADER_BYTE_ORDER: [NSNumber numberWithInt:LITTLE_ENDIAN], 262 | KEY_LOAD_COMMANDS: [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsOpaqueMemory] 263 | }; 264 | 265 | //add header 266 | [self.binaryInfo[KEY_MACHO_HEADERS] addObject:header]; 267 | 268 | //next 269 | break; 270 | 271 | //32-bit mach-O 272 | // ->big-endian version 273 | case MH_MAGIC: 274 | 275 | //init header dictionary 276 | header = @{ 277 | KEY_HEADER_OFFSET:headerOffset, 278 | KEY_HEADER_SIZE:@(sizeof(struct mach_header)), 279 | KEY_HEADER_BINARY_TYPE:[NSNumber numberWithInt:((struct mach_header*)headerStart)->filetype], 280 | KEY_HEADER_BYTE_ORDER: [NSNumber numberWithInt:BIG_ENDIAN], 281 | KEY_LOAD_COMMANDS: [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsOpaqueMemory] 282 | }; 283 | 284 | //add header 285 | [self.binaryInfo[KEY_MACHO_HEADERS] addObject:header]; 286 | 287 | //next 288 | break; 289 | 290 | //64-bit mach-O 291 | // ->little-endian version 292 | case MH_CIGAM_64: 293 | 294 | //swap 295 | swap_mach_header_64((struct mach_header_64*)headerStart, 0); 296 | 297 | //init header dictionary 298 | header = @{ 299 | KEY_HEADER_OFFSET:headerOffset, 300 | KEY_HEADER_SIZE:@(sizeof(struct mach_header_64)), 301 | KEY_HEADER_BINARY_TYPE:[NSNumber numberWithInt:((struct mach_header_64*)headerStart)->filetype], 302 | KEY_HEADER_BYTE_ORDER: [NSNumber numberWithInt:LITTLE_ENDIAN], 303 | KEY_LOAD_COMMANDS: [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsOpaqueMemory] 304 | }; 305 | 306 | //add header 307 | [self.binaryInfo[KEY_MACHO_HEADERS] addObject:header]; 308 | 309 | //next 310 | break; 311 | 312 | //64-bit mach-O 313 | // ->big-endian version 314 | case MH_MAGIC_64: 315 | 316 | //init header dictionary 317 | header = @{ 318 | KEY_HEADER_OFFSET:headerOffset, 319 | KEY_HEADER_SIZE:@(sizeof(struct mach_header_64)), 320 | KEY_HEADER_BINARY_TYPE:[NSNumber numberWithInt:((struct mach_header_64*)headerStart)->filetype], 321 | KEY_HEADER_BYTE_ORDER: [NSNumber numberWithInt:BIG_ENDIAN], 322 | KEY_LOAD_COMMANDS: [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsOpaqueMemory] 323 | }; 324 | 325 | //add header 326 | [self.binaryInfo[KEY_MACHO_HEADERS] addObject:header]; 327 | 328 | //next 329 | break; 330 | 331 | default: 332 | 333 | //err msg 334 | //NSLog(@"OBJECTIVE-SEE ERROR: unknown machO magic: %#x", *headerStart); 335 | 336 | //next 337 | break; 338 | 339 | }//switch, classifying headers 340 | 341 | }//for all headers 342 | 343 | //sanity check 344 | // ->make sure parser found at least one header 345 | if(0 != [self.binaryInfo[KEY_MACHO_HEADERS] count]) 346 | { 347 | //happy 348 | wasParsed = YES; 349 | } 350 | 351 | //bail 352 | bail: 353 | 354 | return wasParsed; 355 | } 356 | 357 | //parse the load commands 358 | // ->for now just save LC_RPATH, LC_LOAD_DYLIB, and LC_LOAD_WEAK_DYLIB 359 | -(BOOL)parseLoadCmds 360 | { 361 | //ret var 362 | BOOL wasParsed = NO; 363 | 364 | //pointer to load command structure 365 | struct load_command *loadCommand = NULL; 366 | 367 | //path in load commands such as LC_LOAD_DYLIB 368 | NSString* path = nil; 369 | 370 | //pointer to binary's data 371 | const void* binaryBytes = NULL; 372 | 373 | //current macho header 374 | struct mach_header* currentHeader = NULL; 375 | 376 | //grab binary's bytes 377 | binaryBytes = [self.binaryData bytes]; 378 | if(NULL == binaryBytes) 379 | { 380 | //bail 381 | goto bail; 382 | } 383 | 384 | //iterate over all machO headers 385 | for(NSDictionary* machoHeader in self.binaryInfo[KEY_MACHO_HEADERS]) 386 | { 387 | //get pointer to current machO header 388 | currentHeader = (struct mach_header*)(unsigned char*)(binaryBytes + [machoHeader[KEY_HEADER_OFFSET] unsignedIntegerValue]); 389 | 390 | //get first load command 391 | // ->immediately follows header 392 | loadCommand = (struct load_command*)(unsigned char*)(binaryBytes + [machoHeader[KEY_HEADER_OFFSET] unsignedIntegerValue] + [machoHeader[KEY_HEADER_SIZE] unsignedIntValue]); 393 | 394 | //iterate over all load commands 395 | // ->number of commands is in 'ncmds' member of (current) header struct 396 | for(uint32_t i = 0; i < currentHeader->ncmds; i++) 397 | { 398 | //sanity check load command 399 | if((unsigned char*)loadCommand > (unsigned char*)((unsigned char*)currentHeader + [machoHeader[KEY_HEADER_SIZE] unsignedIntegerValue] + currentHeader->sizeofcmds)) 400 | { 401 | //bail 402 | goto bail; 403 | } 404 | 405 | //swap if needed 406 | if(LITTLE_ENDIAN == [machoHeader[KEY_HEADER_BYTE_ORDER] unsignedIntegerValue]) 407 | { 408 | //swap 409 | // ->manually swap, cuz don't won't to affect in memory values 410 | switch (OSSwapBigToHostInt32(loadCommand->cmd)) 411 | { 412 | case LC_SEGMENT: 413 | 414 | //swap 415 | swap_segment_command((struct segment_command *)loadCommand, 0x0); 416 | break; 417 | 418 | case LC_SEGMENT_64: 419 | 420 | //swap 421 | swap_segment_command_64((struct segment_command_64 *)loadCommand, 0x0); 422 | break; 423 | 424 | default: 425 | 426 | //swap 427 | swap_load_command(loadCommand, 0x0); 428 | break; 429 | 430 | }//switch 431 | 432 | }//need to swap 433 | 434 | //save load command 435 | [machoHeader[KEY_LOAD_COMMANDS] addPointer:loadCommand]; 436 | 437 | //handle load commands of interest 438 | switch(loadCommand->cmd) 439 | { 440 | //LC_RPATHs 441 | // ->extract and save path 442 | case LC_RPATH: 443 | 444 | //extract name 445 | path = [self extractPath:loadCommand byteOrder:machoHeader[KEY_HEADER_BYTE_ORDER]]; 446 | 447 | //save if new 448 | if(YES != [self.binaryInfo[KEY_LC_RPATHS] containsObject:path]) 449 | { 450 | //save 451 | [self.binaryInfo[KEY_LC_RPATHS] addObject:path]; 452 | } 453 | 454 | break; 455 | 456 | //LC_REEXPORT_DYLIB 457 | // ->extract and save path 458 | case LC_REEXPORT_DYLIB: 459 | 460 | //extract name 461 | path = [self extractPath:loadCommand byteOrder:machoHeader[KEY_HEADER_BYTE_ORDER]]; 462 | 463 | //save if new 464 | if(YES != [self.binaryInfo[KEY_LC_REEXPORT_DYLIBS] containsObject:path]) 465 | { 466 | //save 467 | [self.binaryInfo[KEY_LC_REEXPORT_DYLIBS] addObject:path]; 468 | } 469 | 470 | break; 471 | 472 | //LC_LOAD_DYLIB and LC_LOAD_WEAK_DYLIB 473 | // ->extract and save path 474 | case LC_LOAD_DYLIB: 475 | case LC_LOAD_WEAK_DYLIB: 476 | 477 | //extract name 478 | path = [self extractPath:loadCommand byteOrder:machoHeader[KEY_HEADER_BYTE_ORDER]]; 479 | 480 | //save if new dylib 481 | if( (LC_LOAD_DYLIB == loadCommand->cmd) && 482 | (YES != [self.binaryInfo[KEY_LC_LOAD_DYLIBS] containsObject:path]) ) 483 | { 484 | //save 485 | [self.binaryInfo[KEY_LC_LOAD_DYLIBS] addObject:path]; 486 | } 487 | 488 | //save if new weak dylib 489 | else if( (LC_LOAD_WEAK_DYLIB == loadCommand->cmd) && 490 | (YES != [self.binaryInfo[KEY_LC_LOAD_WEAK_DYLIBS] containsObject:path]) ) 491 | { 492 | //save 493 | [self.binaryInfo[KEY_LC_LOAD_WEAK_DYLIBS] addObject:path]; 494 | } 495 | 496 | break; 497 | 498 | default: 499 | 500 | break; 501 | } 502 | 503 | //got to next load command 504 | // ->immediately follows current one 505 | loadCommand = (struct load_command *)(((unsigned char*)((unsigned char*)loadCommand + loadCommand->cmdsize))); 506 | 507 | }//all load commands 508 | 509 | }//all machO headers 510 | 511 | //happy 512 | wasParsed = YES; 513 | 514 | //bail 515 | bail: 516 | 517 | return wasParsed; 518 | } 519 | 520 | //determine if binary is encrypted 521 | // with OS X's native encryption scheme 522 | // see: http://osxbook.com/book/bonus/chapter7/tpmdrmmyth/ 523 | -(BOOL)isEncrypted 524 | { 525 | //flag 526 | BOOL encrypted = NO; 527 | 528 | //load command 529 | struct load_command* loadCommand = NULL; 530 | 531 | //flags 532 | uint32_t segmentFlags = 0; 533 | 534 | //check text segments 535 | // ->any marked encrypted; set flag 536 | for(NSMutableDictionary* machoHeader in self.binaryInfo[KEY_MACHO_HEADERS]) 537 | { 538 | //check all load commands 539 | for(NSUInteger i = 0; i< [machoHeader[KEY_LOAD_COMMANDS] count]; i++) 540 | { 541 | //grab load command 542 | loadCommand = [machoHeader[KEY_LOAD_COMMANDS] pointerAtIndex:i]; 543 | 544 | //ignore non-segments 545 | if( (loadCommand->cmd != LC_SEGMENT) && 546 | (loadCommand->cmd != LC_SEGMENT_64) ) 547 | { 548 | //skip 549 | continue; 550 | } 551 | 552 | //ignore everything that is not a text segment 553 | // ->for name check, segment_command & segment_command_64 are same 554 | if(0 != strncmp(((struct segment_command *)loadCommand)->segname, SEG_TEXT, sizeof(((struct segment_command *)loadCommand)->segname))) 555 | { 556 | //skip 557 | continue; 558 | } 559 | 560 | //grab flags 561 | // ->32bit 562 | if(sizeof(struct mach_header) == [machoHeader[KEY_HEADER_SIZE] integerValue]) 563 | { 564 | //flags 565 | segmentFlags = ((struct segment_command *)loadCommand)->flags; 566 | 567 | } 568 | //grab flags 569 | // ->64bit 570 | else if(sizeof(struct mach_header_64) == [machoHeader[KEY_HEADER_SIZE] integerValue]) 571 | { 572 | //flags 573 | segmentFlags = ((struct segment_command_64 *)loadCommand)->flags; 574 | 575 | } 576 | 577 | //check if segment is protected 578 | if(SG_PROTECTED_VERSION_1 == (segmentFlags & SG_PROTECTED_VERSION_1)) 579 | { 580 | //set flag 581 | encrypted = YES; 582 | 583 | //bail 584 | // ->any marked encrypted; set flag for all 585 | goto bail; 586 | } 587 | 588 | }//all load commands 589 | 590 | }//all macho headers (e.g. fat file) 591 | 592 | //bail 593 | bail: 594 | 595 | return encrypted; 596 | } 597 | 598 | //determine if packed 599 | // segment names and/or entropy 600 | // see: https://github.com/hiddenillusion/AnalyzePE/blob/master/peutils.py 601 | -(BOOL)isPacked 602 | { 603 | //flag 604 | BOOL packed = NO; 605 | 606 | //file's data 607 | NSData* fileData = nil; 608 | 609 | //file's data, as bytes 610 | char* fileBytes = NULL; 611 | 612 | //load command 613 | struct load_command* loadCommand = NULL; 614 | 615 | //segment offset 616 | u_int64_t segmentOffset = 0; 617 | 618 | //segment size 619 | u_int64_t segmentSize = 0; 620 | 621 | //segment entropy 622 | float segmentEntropy = 0.0f; 623 | 624 | //total 625 | float totalCompressedData = 0.0f; 626 | 627 | //segment name 628 | NSString* segmentName = nil; 629 | 630 | //segment name length 631 | NSUInteger segmentNameLength = 0; 632 | 633 | //open/read into file 634 | fileData = [NSData dataWithContentsOfFile:self.binaryInfo[KEY_BINARY_PATH]]; 635 | if(nil == fileData) 636 | { 637 | //bail 638 | goto bail; 639 | } 640 | 641 | //get raw bytes 642 | fileBytes = (char*)[fileData bytes]; 643 | 644 | //check text segments 645 | // ->any marked encrypted; set flag 646 | for(NSMutableDictionary* machoHeader in self.binaryInfo[KEY_MACHO_HEADERS]) 647 | { 648 | //check all load commands 649 | for(NSUInteger i = 0; i<[machoHeader[KEY_LOAD_COMMANDS] count]; i++) 650 | { 651 | //grab load command 652 | loadCommand = [machoHeader[KEY_LOAD_COMMANDS] pointerAtIndex:i]; 653 | 654 | //ignore non-segments 655 | if( (loadCommand->cmd != LC_SEGMENT) && 656 | (loadCommand->cmd != LC_SEGMENT_64) ) 657 | { 658 | //skip 659 | continue; 660 | } 661 | 662 | //init segment name length 663 | segmentNameLength = MIN(strlen(((struct segment_command *)loadCommand)->segname), sizeof(((struct segment_command *)loadCommand)->segname)); 664 | 665 | //sanity check 666 | if(0 == segmentNameLength) 667 | { 668 | //skip 669 | continue; 670 | } 671 | 672 | //init segment name 673 | segmentName = [[NSString alloc] initWithBytes:((struct segment_command *)loadCommand)->segname length:segmentNameLength encoding:NSUTF8StringEncoding]; 674 | 675 | //check if segment name matches known packer 676 | // ->upx, mpress etc have unique segment names 677 | if(YES == [self.packerSegmentNames containsObject:segmentName]) 678 | { 679 | //dbg msg 680 | //NSLog(@"found match w/ packed section: %@", segmentName); 681 | 682 | //got match 683 | packed = YES; 684 | 685 | //bail 686 | // ->its packed 687 | goto bail; 688 | 689 | } 690 | 691 | //32bit 692 | // ->get offset/size of segment 693 | if(sizeof(struct mach_header) == [machoHeader[KEY_HEADER_SIZE] integerValue]) 694 | { 695 | //offset 696 | segmentOffset = ((struct segment_command *)loadCommand)->fileoff; 697 | 698 | //size 699 | segmentSize = ((struct segment_command *)loadCommand)->filesize; 700 | 701 | } 702 | //64bit 703 | // ->get offset/size of segment 704 | else if(sizeof(struct mach_header_64) == [machoHeader[KEY_HEADER_SIZE] integerValue]) 705 | { 706 | //offset 707 | segmentOffset = ((struct segment_command_64 *)loadCommand)->fileoff; 708 | 709 | //size 710 | segmentSize = ((struct segment_command_64 *)loadCommand)->filesize; 711 | } 712 | 713 | //calc entropy 714 | // ->does entire segment... 715 | segmentEntropy = [self calcEntropy:&fileBytes[segmentOffset] length:segmentSize]; 716 | 717 | //dbg msg 718 | //NSLog(@"%s's entropy: %f", ((struct segment_command *)loadCommand)->segname, segmentEntropy); 719 | 720 | //TODO: test more! 721 | if(segmentEntropy > 7.2f) 722 | { 723 | //inc total 724 | totalCompressedData += segmentSize; 725 | } 726 | 727 | }//all load commands 728 | 729 | //dbg msg 730 | //NSLog(@"final calc: %f\n", (1.0 * totalCompressedData)/fileData.length); 731 | 732 | //final calculation for architecture 733 | if( ((1.0 * totalCompressedData)/fileData.length) > .2) 734 | { 735 | //set 736 | packed = YES; 737 | 738 | //bail 739 | // ->its packed 740 | goto bail; 741 | 742 | } 743 | 744 | }//for all macho headers (e.g. fat file) 745 | 746 | //bail 747 | bail: 748 | 749 | return packed; 750 | } 751 | 752 | //based on https://github.com/erocarrera/pefile/blob/master/pefile.py 753 | -(float)calcEntropy:(char*)data length:(NSUInteger)length 754 | { 755 | //entropy 756 | float entropy = 0.0f; 757 | 758 | //occurances array 759 | unsigned int occurrences[256] = {0}; 760 | 761 | //intermediate var 762 | float pX = 0.0f; 763 | 764 | //sanity check 765 | if(0 == length) 766 | { 767 | //bail 768 | goto bail; 769 | } 770 | 771 | //count all occurances 772 | for(NSUInteger i = 0; iis a little tricky due to offsets and lengths of strings (null paddings, etc) 803 | -(NSString*)extractPath:(struct load_command *)loadCommand byteOrder:(NSNumber*)byteOrder 804 | { 805 | //offset 806 | size_t pathOffset = 0; 807 | 808 | //path bytes 809 | char* pathBytes = NULL; 810 | 811 | //length of path 812 | size_t pathLength = 0; 813 | 814 | //path 815 | NSString* path = nil; 816 | 817 | //set path offset 818 | // ->different based on load command type 819 | switch(loadCommand->cmd) 820 | { 821 | //LC_RPATHs 822 | case LC_RPATH: 823 | 824 | //set offset 825 | pathOffset = sizeof(struct rpath_command); 826 | 827 | break; 828 | 829 | //LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIBS 830 | case LC_LOAD_DYLIB: 831 | case LC_REEXPORT_DYLIB: 832 | case LC_LOAD_WEAK_DYLIB: 833 | 834 | //set offset 835 | pathOffset = sizeof(struct dylib_command); 836 | 837 | break; 838 | 839 | default: 840 | break; 841 | } 842 | 843 | //init pointer to path's bytes 844 | pathBytes = (char*)loadCommand + pathOffset; 845 | 846 | //set path's length 847 | // ->min of strlen/value calculated from load command size 848 | pathLength = MIN(strlen(pathBytes), (loadCommand->cmdsize - pathOffset)); 849 | 850 | //create nstring version of path 851 | path = [[NSString alloc] initWithBytes:pathBytes length:pathLength encoding:NSUTF8StringEncoding]; 852 | 853 | return path; 854 | } 855 | 856 | 857 | @end 858 | -------------------------------------------------------------------------------- /DHS/NSApplicationKeyEvents.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSApplicationKeyEvents.h 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/11/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSApplicationKeyEvents : NSApplication 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DHS/NSApplicationKeyEvents.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSApplicationKeyEvents.m 3 | // KnockKnock 4 | // 5 | // Created by Patrick Wardle on 7/11/15. 6 | // Copyright (c) 2015 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "NSApplicationKeyEvents.h" 10 | 11 | @implementation NSApplicationKeyEvents 12 | 13 | //to enable copy/paste etc even though we don't have an 'Edit' menu 14 | // details: http://stackoverflow.com/questions/970707/cocoa-keyboard-shortcuts-in-dialog-without-an-edit-menu 15 | -(void) sendEvent:(NSEvent *)event { 16 | if ([event type] == NSKeyDown) { 17 | if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask) { 18 | if ([[event charactersIgnoringModifiers] isEqualToString:@"x"]) { 19 | if ([self sendAction:@selector(cut:) to:nil from:self]) 20 | return; 21 | } 22 | else if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) { 23 | if ([self sendAction:@selector(copy:) to:nil from:self]) 24 | return; 25 | } 26 | else if ([[event charactersIgnoringModifiers] isEqualToString:@"v"]) { 27 | if ([self sendAction:@selector(paste:) to:nil from:self]) 28 | return; 29 | } 30 | else if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) { 31 | if ([self sendAction:@selector(selectAll:) to:nil from:self]) 32 | return; 33 | } 34 | } 35 | } 36 | [super sendEvent:event]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /DHS/PrefsWindow.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 | 41 | 52 | 60 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /DHS/PrefsWindowController.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 | @interface PrefsWindowController : NSWindowController 12 | { 13 | 14 | } 15 | 16 | //buttons 17 | @property (weak) IBOutlet NSButton *fullScanButton; 18 | @property (weak) IBOutlet NSButton *weakHijackerButton; 19 | @property (weak) IBOutlet NSButton *saveOutputButton; 20 | 21 | //full scan 22 | @property BOOL fullScan; 23 | 24 | //weak hijackers 25 | @property BOOL weakHijackers; 26 | 27 | //save output 28 | @property BOOL saveOutput; 29 | 30 | /* METHODS */ 31 | 32 | //register default prefs 33 | // ->only used if user hasn't set any 34 | -(void)registerDefaults; 35 | 36 | //load (persistence) preferences from file system 37 | -(void)loadPreferences; 38 | 39 | //'OK' button handler 40 | // ->save prefs and close window 41 | -(IBAction)closeWindow:(id)sender; 42 | 43 | //button handler 44 | // ->invoked when user checks/unchecks 'weak hijack detection' checkbox 45 | -(IBAction)hijackDetectionOptions:(id)sender; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /DHS/PrefsWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PrefsWindowController.m 3 | // DHS 4 | // 5 | // Created by Patrick Wardle on 2/6/15. 6 | // Copyright (c) 2015 Objective-See, LLC. All rights reserved. 7 | // 8 | #import "Consts.h" 9 | #import "Utilities.h" 10 | #import 11 | #import "PrefsWindowController.h" 12 | 13 | 14 | @implementation PrefsWindowController 15 | 16 | @synthesize fullScan; 17 | @synthesize saveOutput; 18 | @synthesize weakHijackers; 19 | 20 | //automatically called when nib is loaded 21 | // ->center window 22 | -(void)awakeFromNib 23 | { 24 | //center 25 | [self.window center]; 26 | } 27 | 28 | //automatically invoked when window is loaded 29 | // ->center it 30 | -(void)windowDidLoad 31 | { 32 | //super 33 | [super windowDidLoad]; 34 | 35 | //no dark mode? 36 | // make window white 37 | if(YES != isDarkMode()) 38 | { 39 | //make white 40 | self.window.backgroundColor = NSColor.whiteColor; 41 | } 42 | 43 | //check if 'full scan' button should be selected 44 | if(YES == self.fullScan) 45 | { 46 | //set 47 | self.fullScanButton.state = STATE_ENABLED; 48 | } 49 | 50 | //check if 'weak hijack detection' button should be selected 51 | if(YES == self.weakHijackers) 52 | { 53 | //set 54 | self.weakHijackerButton.state = STATE_ENABLED; 55 | } 56 | 57 | //check if 'save output' button should be selected 58 | if(YES == self.saveOutput) 59 | { 60 | //set 61 | self.saveOutputButton.state = STATE_ENABLED; 62 | } 63 | 64 | return; 65 | } 66 | 67 | //register default prefs 68 | // ->only used if user hasn't set any 69 | -(void)registerDefaults 70 | { 71 | //set defaults 72 | [[NSUserDefaults standardUserDefaults] registerDefaults:@{PREF_FULL_SYSTEM_SCAN:@NO, PREF_WEAK_HIJACKER_DETECTION:@NO, PREF_SAVE_OUTPUT:@NO}]; 73 | 74 | return; 75 | } 76 | 77 | //load (persistence) preferences from file system 78 | -(void)loadPreferences 79 | { 80 | //user defaults 81 | NSUserDefaults* defaults = nil; 82 | 83 | //init 84 | defaults = [NSUserDefaults standardUserDefaults]; 85 | 86 | //load prefs 87 | // ->won't be any until user set some... 88 | if(nil != defaults) 89 | { 90 | //load 'full system scan' 91 | if(nil != [defaults objectForKey:PREF_FULL_SYSTEM_SCAN]) 92 | { 93 | //save 94 | self.fullScan = [defaults boolForKey:PREF_FULL_SYSTEM_SCAN]; 95 | } 96 | 97 | //load 'weak hijacker detection' 98 | if(nil != [defaults objectForKey:PREF_WEAK_HIJACKER_DETECTION]) 99 | { 100 | //save 101 | self.weakHijackers = [defaults boolForKey:PREF_WEAK_HIJACKER_DETECTION]; 102 | } 103 | 104 | //load 'save output' 105 | if(nil != [defaults objectForKey:PREF_SAVE_OUTPUT]) 106 | { 107 | //save 108 | self.saveOutput = [defaults boolForKey:PREF_SAVE_OUTPUT]; 109 | } 110 | } 111 | 112 | return; 113 | } 114 | 115 | //'weak hijacker detection' checkbox handler 116 | // ->invoked when user checks/unchecks 'weak hijack detection' checkbox 117 | -(IBAction)hijackDetectionOptions:(id)sender 118 | { 119 | //alert 120 | NSAlert* detectionAlert = nil; 121 | 122 | //check if user clicked (on) 123 | if(NSOnState == ((NSButton*)sender).state) 124 | { 125 | //alloc/init alert 126 | detectionAlert = [NSAlert alertWithMessageText:@"This might produce false positives" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"...please consult an expert if any results are found!"]; 127 | 128 | //show it 129 | [detectionAlert runModal]; 130 | } 131 | 132 | return; 133 | } 134 | 135 | //'OK' button handler 136 | // ->save prefs and close window 137 | -(IBAction)closeWindow:(id)sender 138 | { 139 | //save prefs 140 | [self savePrefs]; 141 | 142 | //close 143 | [self.window close]; 144 | 145 | //make un-modal 146 | [[NSApplication sharedApplication] stopModal]; 147 | 148 | return; 149 | } 150 | 151 | //save preferences 152 | -(void)savePrefs 153 | { 154 | //user defaults 155 | NSUserDefaults* defaults = nil; 156 | 157 | //init 158 | defaults = [NSUserDefaults standardUserDefaults]; 159 | 160 | //save full scan flag 161 | self.fullScan = self.fullScanButton.state; 162 | 163 | //save weak hijacker flag 164 | self.weakHijackers = self.weakHijackerButton.state; 165 | 166 | //save save output flag 167 | self.saveOutput = self.saveOutputButton.state; 168 | 169 | //save 'show trusted items' 170 | [defaults setBool:self.fullScan forKey:PREF_FULL_SYSTEM_SCAN]; 171 | 172 | //save 'disable vt queries' 173 | [defaults setBool:self.weakHijackers forKey:PREF_WEAK_HIJACKER_DETECTION]; 174 | 175 | //save 'save output' 176 | [defaults setBool:self.saveOutput forKey:PREF_SAVE_OUTPUT]; 177 | 178 | //flush/save 179 | [defaults synchronize]; 180 | 181 | return; 182 | } 183 | 184 | @end 185 | -------------------------------------------------------------------------------- /DHS/Scanner.h: -------------------------------------------------------------------------------- 1 | // 2 | // Scanner.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 "Binary.h" 10 | #import "MachO/MachO.h" 11 | #import 12 | 13 | @interface Scanner : NSObject 14 | { 15 | 16 | } 17 | 18 | //binaries 19 | @property(nonatomic, retain)NSMutableArray* scannedBinaries; 20 | 21 | //instance of machO parser 22 | @property(nonatomic, retain)MachO* machoParser; 23 | 24 | //flag for full scan 25 | @property BOOL doFullScan; 26 | 27 | //flag for detecting weak hijackers 28 | @property BOOL scan4WeakHijackers; 29 | 30 | //known false positives 31 | // ->for now, by path 32 | @property(nonatomic, retain) NSMutableSet* knownFPs; 33 | 34 | //(privacy) protected directories 35 | @property(nonatomic, retain)NSArray* protectedDirectories; 36 | 37 | /* METHODS */ 38 | 39 | //init 40 | // ->sets scanner options 41 | -(id)initWithOptions:(NSDictionary*)options; 42 | 43 | //begin/do scan 44 | -(void)scan; 45 | 46 | //get/scan all binaries on file system 47 | -(void)scanBinariesFileSys; 48 | 49 | //get/scan binaries from process list 50 | -(void)scanBinariesProcList; 51 | 52 | //parse a binary 53 | -(BOOL)parseBinary:(Binary*)binary; 54 | 55 | //scan a binary 56 | // ->determine if its hijacked or vulnerable 57 | -(void)scanBinary:(Binary*)binary; 58 | 59 | //check if a binary is hijacked 60 | -(void)scan4Hijack:(Binary*)binary; 61 | 62 | //check if a binary is vulnerable 63 | // ->either to weak or rpath hijack 64 | -(void)scan4Vulnerable:(Binary*)binary; 65 | 66 | //resolve an array of paths 67 | // ->any that start with w/ '@loader_path' or '@executable_path' will be resolved 68 | -(NSMutableArray*)resolvePaths:(Binary*)binary paths:(NSMutableArray*)paths; 69 | 70 | //resolve a path that start w/ '@loader_path' or '@executable_path' 71 | -(NSString*)resolvePath:(Binary*)binary path:(NSString*)unresolvedPath; 72 | 73 | //check if a found weakly imported dylib is suspicious 74 | -(BOOL)isWeakImportSuspicious:(Binary*)binary weakDylib:(NSString*)weakImport; 75 | 76 | //check if the digital signatures of a binary and an dylib match 77 | -(BOOL)doSignaturesMatch:(Binary*)binary dylib:(NSString*)dylib; 78 | 79 | //determine if a binary is a false positive 80 | // ->for now, just check path 81 | -(BOOL)isFalsePositive:(Binary*)binary; 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /DHS/Scanner.m: -------------------------------------------------------------------------------- 1 | // 2 | // Scanner.m 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 | #import 11 | #import 12 | 13 | #import "Consts.h" 14 | #import "Binary.h" 15 | #import "Scanner.h" 16 | #import "Utilities.h" 17 | #import "AppDelegate.h" 18 | 19 | //known false positives 20 | NSString* const KNOWN_FPS[] = { 21 | @"/Applications/Microsoft Messenger.app/Contents/Frameworks/mbukernel.framework/Versions/14/mbukernel", 22 | @"/Applications/Microsoft Office 2011/Office/mbuinstrument.framework/Versions/14/mbuinstrument", 23 | @"/Applications/MATLAB_R2014b.app/cefclient/bin/maci64/cefclient.app/Contents/MacOS/libcef.dylib", 24 | @"/Library/Frameworks/OSXFUSE.framework/Versions/A/OSXFUSE", 25 | @"/Applications/SmartConverter.app/Contents/Frameworks/Sparkle.framework/Versions/A/Sparkle" 26 | }; 27 | 28 | //(privacy) protected directories 29 | NSString * const PROTECTED_DIRECTORIES[] = {@"~/Library/Application Support/AddressBook", @"~/Library/Calendars", @"~/Pictures", @"~/Library/Mail", @"~/Library/Messages", @"~/Library/Safari", @"~/Library/Cookies", @"~/Library/HomeKit", @"~/Library/IdentityServices", @"~/Library/Metadata/CoreSpotlight", @"~/Library/PersonalizationPortrait", @"~/Library/Suggestions"}; 30 | 31 | 32 | @implementation Scanner 33 | 34 | @synthesize knownFPs; 35 | @synthesize doFullScan; 36 | @synthesize machoParser; 37 | @synthesize scannedBinaries; 38 | @synthesize scan4WeakHijackers; 39 | @synthesize protectedDirectories; 40 | 41 | //init 42 | // do any initializations and sets scanner options 43 | -(id)initWithOptions:(NSDictionary*)options 44 | { 45 | //init super 46 | self = [super init]; 47 | if(nil != self) 48 | { 49 | //init set 50 | knownFPs = [NSMutableSet set]; 51 | 52 | //init set of (privacy) protected directories 53 | // these will be skipped, as otherwise we will generate a privacy prompt 54 | self.protectedDirectories = expandPaths(PROTECTED_DIRECTORIES, sizeof(PROTECTED_DIRECTORIES)/sizeof(PROTECTED_DIRECTORIES[0])); 55 | 56 | //init fps 57 | // ->add each to set 58 | for(NSUInteger i=0; i < sizeof(KNOWN_FPS)/sizeof(KNOWN_FPS[0]); i++) 59 | { 60 | //add 61 | [self.knownFPs addObject:KNOWN_FPS[i]]; 62 | } 63 | 64 | //alloc list for all scanned binaries 65 | scannedBinaries = [NSMutableArray array]; 66 | 67 | //extract flag for full scan 68 | self.doFullScan = [options[KEY_SCANNER_FULL] boolValue]; 69 | 70 | //extract flag for hijack scanner options 71 | self.scan4WeakHijackers = [options[KEY_SCANNER_WEAK_HIJACKERS] boolValue]; 72 | } 73 | 74 | return self; 75 | } 76 | 77 | //do scan! 78 | -(void)scan 79 | { 80 | //full scan? 81 | // ->yes: get all binaries on file system 82 | if(YES == self.doFullScan) 83 | { 84 | //dbg msg 85 | //NSLog(@"OBJECTIVE-SEE INFO: scanning *all* binaries on file system"); 86 | 87 | //get all binaries on file system 88 | [self scanBinariesFileSys]; 89 | } 90 | 91 | //full scan? 92 | // ->no: get binaries from process list 93 | else 94 | { 95 | //dbg msg 96 | //NSLog(@"OBJECTIVE-SEE INFO: getting binaries from process list"); 97 | 98 | //get binaries from process list 99 | [self scanBinariesProcList]; 100 | } 101 | 102 | return; 103 | } 104 | 105 | //get/scan all binaries on file system 106 | -(void)scanBinariesFileSys 107 | { 108 | //directory enumerator 109 | NSDirectoryEnumerator *enumerator = nil; 110 | 111 | //directory flag 112 | BOOL isDirectory = NO; 113 | 114 | //init enumerator 115 | enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL URLWithString:@"/"] 116 | includingPropertiesForKeys:@[NSURLNameKey, NSURLIsDirectoryKey] options:0 117 | errorHandler:^BOOL(NSURL *url, NSError *error) 118 | { 119 | //ignore errors 120 | return YES; 121 | }]; 122 | 123 | //iterate over all files 124 | // save all executable binaries 125 | for(NSURL* fileURL in enumerator) 126 | { 127 | //ensure that memory cleanup happens after each binary 128 | @autoreleasepool { 129 | 130 | //check if scanner thread was cancelled 131 | // ->should exit if so 132 | if(YES == [[NSThread currentThread] isCancelled]) 133 | { 134 | //dbg msg 135 | //NSLog(@"thread is cancelled, killing it!"); 136 | 137 | //bail 138 | [NSThread exit]; 139 | } 140 | 141 | //skip protected files/directories 142 | if(YES == [self isProtected:fileURL.URLByResolvingSymlinksInPath.path]) 143 | { 144 | //skip 145 | continue; 146 | } 147 | 148 | //skip non-existent files and directories 149 | if( (YES != [[NSFileManager defaultManager] fileExistsAtPath:fileURL.URLByResolvingSymlinksInPath.path isDirectory:&isDirectory]) || 150 | (YES == isDirectory) ) 151 | { 152 | //skip 153 | continue; 154 | } 155 | 156 | //skip non-executable files 157 | // ->that is, non i386/x86_64 158 | if(YES != isURLExecutable(fileURL.URLByResolvingSymlinksInPath)) 159 | { 160 | //skip 161 | continue; 162 | } 163 | 164 | //save it 165 | [self.scannedBinaries addObject:fileURL.URLByResolvingSymlinksInPath.path]; 166 | 167 | //scan it 168 | [self scanBinary:[[Binary alloc] initWithPath:fileURL.URLByResolvingSymlinksInPath.path]]; 169 | 170 | }//autorelease 171 | } 172 | 173 | return; 174 | } 175 | 176 | //get/scan binaries from process list 177 | -(void)scanBinariesProcList 178 | { 179 | //# of procs 180 | int numberOfProcesses = 0; 181 | 182 | //array of pids 183 | pid_t* pids = NULL; 184 | 185 | //buffer for process path 186 | char pathBuffer[PROC_PIDPATHINFO_MAXSIZE] = {0}; 187 | 188 | //status 189 | int status = -1; 190 | 191 | //process name 192 | NSString* processName = nil; 193 | 194 | //get # of procs 195 | numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); 196 | 197 | //alloc buffer for pids 198 | pids = calloc(numberOfProcesses, sizeof(pid_t)); 199 | 200 | //get list of pids 201 | status = proc_listpids(PROC_ALL_PIDS, 0, pids, numberOfProcesses * sizeof(pid_t)); 202 | if(status < 0) 203 | { 204 | //err 205 | NSLog(@"OBJECTIVE-SEE ERROR: proc_listpids() failed with %d", status); 206 | 207 | //bail 208 | goto bail; 209 | } 210 | 211 | //iterate over all pids 212 | // ->get name for each 213 | for(int i = 0; i < numberOfProcesses; ++i) 214 | { 215 | //skip blank pids 216 | if(0 == pids[i]) 217 | { 218 | //skip 219 | continue; 220 | } 221 | 222 | //check if scan thread was cancelled 223 | if(YES == [[NSThread currentThread] isCancelled]) 224 | { 225 | //dbg msg 226 | //NSLog(@"thread is cancelled, killing it!"); 227 | 228 | //bail 229 | [NSThread exit]; 230 | } 231 | 232 | //reset buffer 233 | bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE); 234 | 235 | //get path 236 | status = proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer)); 237 | 238 | //sanity check 239 | // ->this generally just fails if process has exited.... 240 | if( (status < 0) || 241 | (0 == strlen(pathBuffer)) ) 242 | { 243 | //skip 244 | continue; 245 | } 246 | 247 | //init process name 248 | processName = [NSString stringWithUTF8String:pathBuffer]; 249 | 250 | //ignore dupes 251 | if(YES ==[self.scannedBinaries containsObject:processName]) 252 | { 253 | //skip 254 | continue; 255 | } 256 | 257 | //save it 258 | [self.scannedBinaries addObject:processName]; 259 | 260 | //scan it 261 | [self scanBinary:[[Binary alloc] initWithPath:processName.stringByResolvingSymlinksInPath]]; 262 | } 263 | 264 | //bail 265 | bail: 266 | 267 | //free buffer 268 | if(NULL != pids) 269 | { 270 | //free 271 | free(pids); 272 | 273 | //unset 274 | pids = NULL; 275 | } 276 | 277 | //dbg msg 278 | //NSLog(@"OBJECTIVE-SEE INFO: done scanning running processes/dylibs"); 279 | 280 | return; 281 | } 282 | 283 | //check if file is protected 284 | // on mojave+, need to avoid prompts 285 | -(BOOL)isProtected:(NSString*) path 286 | { 287 | //flag 288 | BOOL protected = NO; 289 | 290 | //skip any files in (privacy) protected directories 291 | // as otherwise we will generate a privacy prompt (on Mojave) 292 | for(NSString* directory in protectedDirectories) 293 | { 294 | //check 295 | if(YES == [path hasPrefix:directory]) 296 | { 297 | //set flag 298 | protected = YES; 299 | 300 | //done 301 | break; 302 | } 303 | } 304 | 305 | return protected; 306 | } 307 | 308 | //parse a binary 309 | -(BOOL)parseBinary:(Binary*)binary 310 | { 311 | //flag 312 | BOOL wasParsed = NO; 313 | 314 | //dbg msg 315 | //NSLog(@"parsing %@", binary); 316 | 317 | //alloc macho parser iVar 318 | // ->new instance for each file! 319 | machoParser = [[MachO alloc] init]; 320 | 321 | //parse 322 | // ->but don't do packed/encryption checks 323 | if(YES != [machoParser parse:binary.path classify:NO]) 324 | { 325 | //bail 326 | goto bail; 327 | } 328 | 329 | //happy 330 | wasParsed = YES; 331 | 332 | //save instance of parser into binary object 333 | binary.parserInstance = machoParser; 334 | 335 | bail: 336 | 337 | return wasParsed; 338 | } 339 | 340 | //scan a binary 341 | // ->determine if its hijacked or vulnerable 342 | -(void)scanBinary:(Binary*)binary 343 | { 344 | //dbg msg 345 | //NSLog(@"scanning %@", binary.path); 346 | 347 | //flag 348 | BOOL disabledLibValidation = NO; 349 | 350 | //signing dictionary for binary 351 | NSDictionary* binarySigningInfo = nil; 352 | 353 | //first gotta parse it 354 | if(YES != [self parseBinary:binary]) 355 | { 356 | //err msg 357 | //NSLog(@"OBJECTIVE-SEE ERROR: failed to parse %@", binary.path); 358 | 359 | //bail 360 | goto bail; 361 | } 362 | 363 | //skip dylibs! 364 | if(MH_EXECUTE != [binary getType]) 365 | { 366 | //skip 367 | goto bail; 368 | } 369 | 370 | //generate signing information 371 | binarySigningInfo = signingInfo(binary.path); 372 | 373 | //set flag 374 | disabledLibValidation = [binarySigningInfo[KEY_SIGNING_ENTITLEMENTS][@"com.apple.security.cs.disable-library-validation"] boolValue]; 375 | 376 | //signed ok? 377 | if(STATUS_SUCCESS == [binarySigningInfo[KEY_SIGNATURE_STATUS] unsignedIntValue]) 378 | { 379 | //skip platform binaries 380 | // this are now tacitly protected w/ lib validation 381 | if( (YES != disabledLibValidation) && 382 | (YES == [binarySigningInfo[KEY_IS_APPLE] boolValue]) ) 383 | { 384 | //NSLog(@"skipping %@, as its an apple binary", binary.path); 385 | 386 | //done 387 | goto bail; 388 | } 389 | 390 | //skip binaries with hardened runtime 391 | if( (YES != disabledLibValidation) && 392 | (YES == [binarySigningInfo[KEY_HARDENED_RUNTIME] boolValue]) ) 393 | { 394 | //skip 395 | goto bail; 396 | } 397 | 398 | //skip binaries with "libary validation) 399 | if( (YES != disabledLibValidation) && 400 | (YES == [binarySigningInfo[KEY_LIBRARY_VALIDATION] boolValue]) ) 401 | { 402 | //skip 403 | goto bail; 404 | } 405 | } 406 | 407 | //resolve LC_LOAD_WEAK_DYLIB imports 408 | // need to do this, since we check to see if they exist 409 | binary.parserInstance.binaryInfo[KEY_LC_LOAD_WEAK_DYLIBS] = [self resolvePaths:binary paths:binary.parserInstance.binaryInfo[KEY_LC_LOAD_WEAK_DYLIBS]]; 410 | 411 | //resolve LC_RPATHS imports 412 | // need to do this, since we check to see if they exist, etc 413 | binary.parserInstance.binaryInfo[KEY_LC_RPATHS] = [self resolvePaths:binary paths:binary.parserInstance.binaryInfo[KEY_LC_RPATHS]]; 414 | 415 | //check if its hijacked 416 | // set iVar within binary object 417 | [self scan4Hijack:binary]; 418 | 419 | //check if its vulnerable 420 | // note, no need to scan hijacked binaries 421 | if(YES != binary.isHijacked) 422 | { 423 | //scan 424 | // sets iVar within binary obj 425 | [self scan4Vulnerable:binary]; 426 | } 427 | 428 | //report any results 429 | // ->hiijacked/vulnerable 430 | if( (YES == binary.isHijacked) || 431 | (YES == binary.isVulnerable) ) 432 | { 433 | //dbg msg 434 | //NSLog(@"OBJECTIVE-SEE INFO: binary %@ has issue (type: %lu)!", binary.path, (unsigned long)binary.issueType); 435 | 436 | //only report non-false positive 437 | if(YES != [self isFalsePositive:binary]) 438 | { 439 | //call back up to UI in main thread to update 440 | dispatch_sync(dispatch_get_main_queue(), ^{ 441 | 442 | //call back 443 | [((AppDelegate*)[[NSApplication sharedApplication] delegate]) addToTable:binary]; 444 | 445 | }); 446 | } 447 | } 448 | 449 | bail: 450 | 451 | return; 452 | } 453 | 454 | //check if a binary is hijacked 455 | -(void)scan4Hijack:(Binary*)binary 456 | { 457 | //first check for rpath hijack 458 | // is more conclusive (less false positives) 459 | [self scan4HijackRPath:binary]; 460 | 461 | //if not rpath hijacked 462 | // check for weak hijack 463 | if( (YES == self.scan4WeakHijackers) && 464 | (YES != binary.isHijacked) ) 465 | { 466 | //scan 467 | [self scan4HijackWeak:binary]; 468 | } 469 | 470 | return; 471 | } 472 | 473 | //check if a binary is hijacked by a weak dylib 474 | // ->scan all LC_LOAD_WEAK_DYLIBS, look for existing lib that isn't signed? 475 | -(void)scan4HijackWeak:(Binary*)binary 476 | { 477 | //resolved path 478 | NSString* resolvedWeakDylib = nil; 479 | 480 | //build list of all LC_LOAD_WEAK_DYLIBS 481 | // ->@rpath'd ones have to be resolved 482 | for(NSString* weakDylib in binary.parserInstance.binaryInfo[KEY_LC_LOAD_WEAK_DYLIBS]) 483 | { 484 | //resolve @rpath'd imports 485 | // ->just need first to check 486 | if(YES == [weakDylib hasPrefix:RUN_SEARCH_PATH]) 487 | { 488 | //resolve 489 | resolvedWeakDylib = [[binary.parserInstance.binaryInfo[KEY_LC_RPATHS] firstObject] stringByAppendingPathComponent:[weakDylib substringFromIndex:[RUN_SEARCH_PATH length]]]; 490 | } 491 | //no need to resolve 492 | else 493 | { 494 | //use as is 495 | resolvedWeakDylib = weakDylib; 496 | } 497 | 498 | //skip ones that aren't found 499 | if(YES != [[NSFileManager defaultManager] fileExistsAtPath:resolvedWeakDylib]) 500 | { 501 | //skip 502 | continue; 503 | } 504 | 505 | //check if its suspicious 506 | if(YES == [self isWeakImportSuspicious:binary weakDylib:resolvedWeakDylib]) 507 | { 508 | //dbg msg 509 | //NSLog(@"OBJECTIVE-SEE INFO: %@ appears to be a weak hijack", resolvedWeakDylib); 510 | 511 | //set hijack flag 512 | binary.isHijacked = YES; 513 | 514 | //set type flag 515 | binary.issueType = ISSUE_TYPE_WEAK; 516 | 517 | //set issue item 518 | binary.issueItem = resolvedWeakDylib; 519 | 520 | //bail 521 | // ->don't need to scan for more instances, since this binary is hijacked! 522 | break; 523 | } 524 | 525 | } 526 | 527 | return; 528 | } 529 | 530 | //check if a binary is hijacked by abusing rpath seach order 531 | // ->scan all @rpath'd LC_LOAD_DYLIBS to see if there are doubles... 532 | -(void)scan4HijackRPath:(Binary*)binary 533 | { 534 | //number of occurances of dylib 535 | NSUInteger dylibCount = 0; 536 | 537 | //rpath resolved path 538 | NSString* resolvedPath = nil; 539 | 540 | //initial resolved path 541 | // ->this is the one that could be hijacked 542 | NSString* initialResolvedPath = nil; 543 | 544 | //binary's signing info 545 | NSDictionary* binarySigningInfo = nil; 546 | 547 | //scan all LC_LOAD_DYLIBS 548 | for(NSString* importedDylib in binary.parserInstance.binaryInfo[KEY_LC_LOAD_DYLIBS]) 549 | { 550 | //reset count 551 | dylibCount = 0; 552 | 553 | //reset initial resolved path 554 | initialResolvedPath = nil; 555 | 556 | //skip dylibs that are imported normally (e.g. without '@rpath') 557 | if(YES != [importedDylib hasPrefix:RUN_SEARCH_PATH]) 558 | { 559 | //skip 560 | continue; 561 | } 562 | 563 | //scan all run paths 564 | // ->get count/save of each dylib 565 | for(NSString* runPath in binary.parserInstance.binaryInfo[KEY_LC_RPATHS]) 566 | { 567 | //init rpath resolved path 568 | // ->current run path + path to dylib (with '@rpath') removed 569 | resolvedPath = [runPath stringByAppendingPathComponent:[importedDylib substringFromIndex:[RUN_SEARCH_PATH length]]]; 570 | 571 | //dbg msg 572 | //NSLog(@"checking if %@ exists", resolvedPath); 573 | 574 | //check if it exists 575 | // ->save if first and inc count 576 | if(YES == [[NSFileManager defaultManager] fileExistsAtPath:resolvedPath]) 577 | { 578 | //dbg msg 579 | //NSLog(@"found %@ in %@", resolvedPath, runPath); 580 | 581 | //want to save first instance 582 | if(nil == initialResolvedPath) 583 | { 584 | //save 585 | initialResolvedPath = resolvedPath; 586 | } 587 | 588 | //inc 589 | dylibCount++; 590 | } 591 | } 592 | 593 | //should only be one instance 594 | if(dylibCount < 2) 595 | { 596 | //ok 597 | continue; 598 | } 599 | 600 | //(possible) HIJACK DETECTED! 601 | // ->multiple instance of same named dylib in run-search paths 602 | 603 | //dbg msg 604 | //NSLog(@"OBJECTIVE-SEE INFO: found %lu instance of %@ in run-path search dir", (unsigned long)dylibCount, importedDylib); 605 | 606 | //always ignore apple signed dylibs 607 | // note: only set if validly signed, and signed by apple 608 | if(YES == [signingInfo(initialResolvedPath)[KEY_IS_APPLE] boolValue]) 609 | { 610 | //skip 611 | continue; 612 | } 613 | 614 | //get binary's signing info 615 | binarySigningInfo = signingInfo(binary.path); 616 | 617 | //if binary is signed 618 | // note: a 'hijacker' dylib with the same signature is fine 619 | if( (nil != binarySigningInfo) && 620 | (errSecCSUnsigned != [binarySigningInfo[KEY_SIGNATURE_STATUS] integerValue]) ) 621 | { 622 | //not a real hijacker if binary and dylib are both signed by the same signing auths 623 | if(YES == [self doSignaturesMatch:binary dylib:initialResolvedPath]) 624 | { 625 | //dbg msg 626 | //NSLog(@"skipping since binary and dylib are both same-signed"); 627 | 628 | //skip 629 | continue; 630 | } 631 | } 632 | 633 | //set hijack flag 634 | binary.isHijacked = YES; 635 | 636 | //set type flag 637 | binary.issueType = ISSUE_TYPE_RPATH; 638 | 639 | //set issue item 640 | // the first dylib (of 2+) found in the @rpath directories 641 | binary.issueItem = initialResolvedPath; 642 | 643 | //bail 644 | // don't need to scan for more instances, since this binary is hijacked! 645 | break; 646 | } 647 | 648 | return; 649 | } 650 | 651 | 652 | //check if a binary is vulnerable 653 | // ->either to weak or rpath hijack 654 | // note: results set in binary object 655 | -(void)scan4Vulnerable:(Binary*)binary 656 | { 657 | //check if its vulnerable to a rpath hijack 658 | [self hasVulnerableRPath:binary]; 659 | 660 | //check if its vulnerable to a weak import hijack 661 | [self hasVulnerableWeakImport:binary]; 662 | 663 | return; 664 | } 665 | 666 | //check if a binary vulnerable to a weak import hijack 667 | // ->scan all weak imports to see if any don't exist! 668 | -(void)hasVulnerableWeakImport:(Binary*)binary 669 | { 670 | //resolved path 671 | NSString* absoluteDylib = nil; 672 | 673 | //build list of all LC_LOAD_WEAK_DYLIBS 674 | // ->@rpath'd ones have to be resolved 675 | for(NSString* weakDylib in binary.parserInstance.binaryInfo[KEY_LC_LOAD_WEAK_DYLIBS]) 676 | { 677 | //resolve @rpath'd imports 678 | // ->just need first to check 679 | if(YES == [weakDylib hasPrefix:RUN_SEARCH_PATH]) 680 | { 681 | //make sure app has list of run paths 682 | // ->'GPG Keychain' has "@rpath/Libmacgpg.framework...", but no run path search paths 683 | // could look at dyld src code and see how this is handled, to see if this is vulnerable 684 | if(0 == [binary.parserInstance.binaryInfo[KEY_LC_RPATHS] count]) 685 | { 686 | //skip 687 | continue; 688 | } 689 | 690 | //resolve 691 | absoluteDylib = [[binary.parserInstance.binaryInfo[KEY_LC_RPATHS] firstObject] stringByAppendingPathComponent:[weakDylib substringFromIndex:[RUN_SEARCH_PATH length]]]; 692 | } 693 | //no need to resolve 694 | else 695 | { 696 | //use as is 697 | absoluteDylib = weakDylib; 698 | } 699 | 700 | //is candidate (not found, not SIP'd etc) 701 | if(YES == [self isCandidate:absoluteDylib]) 702 | { 703 | //dbg msg 704 | //NSLog(@"OBJECTIVE-SEE INFO: %@ is vulnerable to a weak hijack", absoluteDylib); 705 | 706 | //set vulnerable flag 707 | binary.isVulnerable = YES; 708 | 709 | //set type flag 710 | binary.issueType = ISSUE_TYPE_WEAK; 711 | 712 | //set issue item 713 | binary.issueItem = absoluteDylib; 714 | 715 | //bail 716 | // ->don't need to scan for more instances, since this binary is vulnerable! 717 | break; 718 | } 719 | } 720 | 721 | return; 722 | } 723 | 724 | //check if a binary vulnerable to a rpath hijack 725 | // ->are any @rpath'd imports not found in primary LC_RPATH directory? 726 | -(void)hasVulnerableRPath:(Binary*)binary 727 | { 728 | //rpath resolved path 729 | NSString* absoluteDylib = nil; 730 | 731 | //first run-path search directory 732 | NSString* firstRPathDirectory = nil; 733 | 734 | //skip binaries that don't have any LC_RPATHs 735 | // ->cuz obvs these can't be vulnerable to @rpath hijack 736 | if(0 == [binary.parserInstance.binaryInfo[KEY_LC_RPATHS] count]) 737 | { 738 | //bail 739 | goto bail; 740 | } 741 | 742 | //scan all LC_LOAD_DYLIBS 743 | for(NSString* loadDylib in binary.parserInstance.binaryInfo[KEY_LC_LOAD_DYLIBS]) 744 | { 745 | //skip dylibs that are imported normally (e.g. without '@rpath') 746 | if(YES != [loadDylib hasPrefix:RUN_SEARCH_PATH]) 747 | { 748 | //skip 749 | continue; 750 | } 751 | 752 | //grab first run-path search directory 753 | // ->this is the only one we need to check 754 | firstRPathDirectory = [binary.parserInstance.binaryInfo[KEY_LC_RPATHS] firstObject]; 755 | 756 | //init rpath resolved path 757 | // ->first run path + path to dylib (with '@rpath') removed 758 | absoluteDylib = [firstRPathDirectory stringByAppendingPathComponent:[loadDylib substringFromIndex:[RUN_SEARCH_PATH length]]]; 759 | 760 | //is candidate (not found, not SIP'd etc) 761 | if(YES == [self isCandidate:absoluteDylib]) 762 | { 763 | //VULNERABILITY DETECTED! 764 | // ->dylib isn't found in first run-path search directory 765 | 766 | //dbg msg 767 | //NSLog(@"OBJECTIVE-SEE INFO: %@ isn't in first run-path search directory %@", absoluteDylib, firstRPathDirectory); 768 | 769 | //set vulnerable flag 770 | binary.isVulnerable = YES; 771 | 772 | //set type flag 773 | binary.issueType = ISSUE_TYPE_RPATH; 774 | 775 | //set issue item 776 | binary.issueItem = absoluteDylib; 777 | 778 | //bail 779 | // ->don't need to scan for more instances, since this binary is vulnerable! 780 | break; 781 | } 782 | 783 | } 784 | 785 | //bail 786 | bail: 787 | 788 | return; 789 | } 790 | 791 | //resolve an array of paths 792 | // ->any that start with w/ '@loader_path' or '@executable_path' will be resolved 793 | -(NSMutableArray*)resolvePaths:(Binary*)binary paths:(NSMutableArray*)paths 794 | { 795 | //resolved paths 796 | NSMutableArray* resolvedPaths = nil; 797 | 798 | //resolved path 799 | NSString* resolvedPath = nil; 800 | 801 | //alloc/init 802 | resolvedPaths = [NSMutableArray array]; 803 | 804 | for(NSString* runPathDirectory in paths) 805 | { 806 | //only need to resolve paths with '@executable_path' or '@loader_path' 807 | if( (YES == [runPathDirectory hasPrefix:EXECUTABLE_PATH]) || 808 | (YES == [runPathDirectory hasPrefix:LOADER_PATH]) ) 809 | { 810 | //resolve it 811 | resolvedPath = [self resolvePath:binary path:runPathDirectory]; 812 | 813 | //save it 814 | // ->only if its unique 815 | if(NO == [resolvedPaths containsObject:resolvedPath]) 816 | { 817 | //save 818 | [resolvedPaths addObject:resolvedPath]; 819 | } 820 | } 821 | 822 | //didn't need to resolve 823 | // ->just save as is 824 | else 825 | { 826 | //check if its unique 827 | if(YES != [resolvedPaths containsObject:runPathDirectory]) 828 | { 829 | //save 830 | [resolvedPaths addObject:runPathDirectory]; 831 | } 832 | } 833 | } 834 | 835 | return resolvedPaths; 836 | } 837 | 838 | 839 | //resolve a path that start w/ '@loader_path' or '@executable_path' 840 | // ->since we aren't scanning modules, both are the same 841 | // see: https://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html 842 | -(NSString*)resolvePath:(Binary*)binary path:(NSString*)unresolvedPath 843 | { 844 | //resolved path 845 | NSString* resolvedPath = nil; 846 | 847 | //prefix to remove 848 | NSString* prefix = nil; 849 | 850 | //get prefix 851 | // ->'@executable_path' 852 | if(YES == [unresolvedPath hasPrefix:EXECUTABLE_PATH]) 853 | { 854 | //executable path 855 | prefix = EXECUTABLE_PATH; 856 | } 857 | 858 | //get prefix 859 | // ->'@loader_path' 860 | else if(YES == [unresolvedPath hasPrefix:LOADER_PATH]) 861 | { 862 | //loader path 863 | prefix = LOADER_PATH; 864 | } 865 | 866 | //build resolved path 867 | // 1: binary's directory + 868 | // 2: the unresolved path with '@executable_path' or '@loader_path' remove 869 | // 3: standardized to make it an absolute path 870 | resolvedPath = [[[binary.path stringByDeletingLastPathComponent] stringByAppendingPathComponent:[unresolvedPath substringFromIndex:[prefix length]]] stringByStandardizingPath]; 871 | 872 | //dbg msg 873 | //NSLog(@"resolved %@ to %@", unresolvedPath, resolvedPath); 874 | 875 | return resolvedPath; 876 | } 877 | 878 | //check if a found weakly imported dylib is suspicious 879 | // ->for now just make sure if parent is signed, so import... 880 | -(BOOL)isWeakImportSuspicious:(Binary*)binary weakDylib:(NSString*)weakImport 881 | { 882 | //return 883 | BOOL isSuspicious = NO; 884 | 885 | //signing dictionary for binary 886 | NSDictionary* binarySigningInfo = nil; 887 | 888 | //signing dictionary for weak import 889 | NSDictionary* importSigningInfo = nil; 890 | 891 | //get signing info for binary 892 | binarySigningInfo = signingInfo(binary.path); 893 | 894 | //get signing info for weak import 895 | importSigningInfo = signingInfo(weakImport); 896 | 897 | //always ignore apple signed dylibs 898 | // note: only set if validly signed, and signed by apple 899 | if(YES == [importSigningInfo[KEY_IS_APPLE] boolValue]) 900 | { 901 | //bail 902 | goto bail; 903 | } 904 | 905 | //check if parent is signed 906 | if( (nil != binarySigningInfo) && 907 | (STATUS_SUCCESS == ((NSNumber*)binarySigningInfo[KEY_SIGNATURE_STATUS]).intValue) ) 908 | { 909 | //weak import better be signed to y0 910 | if( (nil == importSigningInfo) || 911 | (STATUS_SUCCESS != ((NSNumber*)importSigningInfo[KEY_SIGNATURE_STATUS]).intValue) ) 912 | { 913 | //shady! 914 | isSuspicious = YES; 915 | } 916 | } 917 | 918 | bail: 919 | 920 | return isSuspicious; 921 | } 922 | 923 | 924 | //check if the digital signatures of a binary and an dylib match 925 | -(BOOL)doSignaturesMatch:(Binary*)binary dylib:(NSString*)dylib 926 | { 927 | //return var 928 | BOOL doMatch = NO; 929 | 930 | //signing dictionary for binary 931 | NSDictionary* binarySigningInfo = nil; 932 | 933 | //signing authorities array for binary 934 | NSArray* binarySigningAuths = nil; 935 | 936 | //signing dictionary for weak import 937 | NSDictionary* dylibSigningInfo = nil; 938 | 939 | //signing authorities array for dylib 940 | NSArray* dylibSigningAuths = nil; 941 | 942 | //index var 943 | NSUInteger index = 0; 944 | 945 | //get signing info for binary 946 | binarySigningInfo = signingInfo(binary.path); 947 | 948 | //get signin info for weak import 949 | dylibSigningInfo = signingInfo(dylib); 950 | 951 | //both need to be signed 952 | if( (nil == binarySigningInfo) || 953 | (nil == dylibSigningInfo) ) 954 | { 955 | //bail 956 | goto bail; 957 | } 958 | 959 | //extract signing auths for binary 960 | binarySigningAuths = binarySigningInfo[KEY_SIGNING_AUTHORITIES]; 961 | 962 | //extract signing auths for dylib 963 | dylibSigningAuths = dylibSigningInfo[KEY_SIGNING_AUTHORITIES]; 964 | 965 | //NSLog(@"binary signing auths: %@", binarySigningAuths); 966 | //NSLog(@"dylib signing auths: %@", dylibSigningAuths); 967 | 968 | //make sure both have same non-zero number of signed authorities 969 | if( (0 == binarySigningAuths.count) || 970 | (binarySigningAuths.count != dylibSigningAuths.count) ) 971 | { 972 | //bail 973 | goto bail; 974 | } 975 | 976 | //check all signing auths 977 | // ->all gotta match! 978 | for(index = 0; index < binarySigningAuths.count; index++) 979 | { 980 | //check 981 | if(YES != [binarySigningAuths[index] isEqualToString:dylibSigningAuths[index]]) 982 | { 983 | //no match 984 | // ->bail 985 | goto bail; 986 | } 987 | } 988 | 989 | //happy 990 | doMatch = YES; 991 | 992 | 993 | bail: 994 | 995 | return doMatch; 996 | } 997 | 998 | //check the following 999 | // a. not found 1000 | // b. not in cache 1001 | // c. not in SIP directory 1002 | -(BOOL)isCandidate:(NSString*)dylib 1003 | { 1004 | BOOL isCandidate = NO; 1005 | 1006 | //exists? 1007 | if(YES == [[NSFileManager defaultManager] fileExistsAtPath:dylib]) 1008 | { 1009 | //exists 1010 | goto bail; 1011 | 1012 | } 1013 | //is in dyld cache? 1014 | if(YES == isInCache(dylib)) 1015 | { 1016 | //in cache 1017 | goto bail; 1018 | } 1019 | 1020 | //directory is SIP'd 1021 | if(YES == isSIPDirectory([dylib stringByDeletingLastPathComponent])) 1022 | { 1023 | //is SIP'd 1024 | goto bail; 1025 | } 1026 | 1027 | //candidate! 1028 | isCandidate = YES; 1029 | 1030 | bail: 1031 | 1032 | return isCandidate; 1033 | } 1034 | 1035 | //determine if a binary is a false positive 1036 | // ->for now, just check path 1037 | -(BOOL)isFalsePositive:(Binary*)binary 1038 | { 1039 | //flag 1040 | BOOL isFalsePositive = NO; 1041 | 1042 | //check is just path 1043 | if(YES == [self.knownFPs containsObject:binary.issueItem]) 1044 | { 1045 | //set 1046 | isFalsePositive = YES; 1047 | } 1048 | 1049 | return isFalsePositive; 1050 | } 1051 | 1052 | @end 1053 | -------------------------------------------------------------------------------- /DHS/Utilities.h: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.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 | #ifndef DHS_Utilities_h 10 | #define DHS_Utilities_h 11 | 12 | //check if file is in cache 13 | BOOL isInCache(NSString* path); 14 | 15 | //check if a file is an executable 16 | BOOL isURLExecutable(NSURL* appURL); 17 | 18 | //get the signing info of a file 19 | NSDictionary* signingInfo(NSString* path); 20 | 21 | //check if directory is SIP'd 22 | BOOL isSIPDirectory(NSString* path); 23 | 24 | //get an icon for a process 25 | // ->for apps, this will be app's icon, otherwise just a standard system one 26 | NSImage* getIconForBinary(NSString* binary); 27 | 28 | //given a path to binary 29 | // parse it back up to find app's bundle 30 | NSBundle* findAppBundle(NSString* binaryPath); 31 | 32 | //get app's version 33 | // ->extracted from Info.plist 34 | NSString* getAppVersion(void); 35 | 36 | //check if (full) dark mode 37 | // meaning, Mojave+ and dark mode enabled 38 | BOOL isDarkMode(void); 39 | 40 | //get all user 41 | // includes name/home directory 42 | NSMutableDictionary* allUsers(void); 43 | 44 | //give a list of paths 45 | // convert any `~` to all or current user 46 | NSMutableArray* expandPaths(const __strong NSString* const paths[], int count); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /DHS/Utilities.m: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.m 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 "Consts.h" 10 | #import "Utilities.h" 11 | 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | 18 | //check if file is in cache 19 | BOOL isInCache(NSString* path) 20 | { 21 | return _dyld_shared_cache_contains_path(path.UTF8String); 22 | } 23 | 24 | //check if a file is an executable 25 | BOOL isURLExecutable(NSURL* appURL) 26 | { 27 | //return 28 | BOOL isExecutable = NO; 29 | 30 | //bundle url 31 | CFURLRef bundleURL = NULL; 32 | 33 | //architecture ref 34 | CFArrayRef archArrayRef = NULL; 35 | 36 | //create bundle 37 | bundleURL = CFURLCreateFromFileSystemRepresentation(NULL, (uint8_t*)[[appURL path] UTF8String], strlen((const char *)(uint8_t*)[[appURL path] UTF8String]), true); 38 | 39 | //get executable arch's 40 | archArrayRef = CFBundleCopyExecutableArchitecturesForURL(bundleURL); 41 | 42 | //check arch for i386/x6_64 43 | if(NULL != archArrayRef) 44 | { 45 | //set flag 46 | isExecutable = [(__bridge NSArray*)archArrayRef containsObject:[NSNumber numberWithInt:kCFBundleExecutableArchitectureX86_64]] || [(__bridge NSArray*)archArrayRef containsObject:[NSNumber numberWithInt:kCFBundleExecutableArchitectureI386]]; 47 | } 48 | 49 | //free bundle url 50 | if(NULL != bundleURL) 51 | { 52 | //free 53 | CFRelease(bundleURL); 54 | } 55 | 56 | //free arch ref 57 | if(NULL != archArrayRef) 58 | { 59 | //free 60 | CFRelease(archArrayRef); 61 | } 62 | 63 | return isExecutable; 64 | } 65 | 66 | //get the signing info of a file 67 | NSDictionary* signingInfo(NSString* path) 68 | { 69 | //info dictionary 70 | NSMutableDictionary* signingInfo = nil; 71 | 72 | //code 73 | SecStaticCodeRef staticCode = NULL; 74 | 75 | //"anchor apple" 76 | static SecRequirementRef isApple = nil; 77 | 78 | //token 79 | static dispatch_once_t onceToken = 0; 80 | 81 | //status 82 | OSStatus status = !STATUS_SUCCESS; 83 | 84 | //signing information 85 | CFDictionaryRef signingInformation = NULL; 86 | 87 | //cert chain 88 | NSArray* certificateChain = nil; 89 | 90 | //index 91 | NSUInteger index = 0; 92 | 93 | //cert 94 | SecCertificateRef certificate = NULL; 95 | 96 | //common name on chert 97 | CFStringRef commonName = NULL; 98 | 99 | //init signing info 100 | signingInfo = [NSMutableDictionary dictionary]; 101 | 102 | //only once 103 | // init requirements 104 | dispatch_once(&onceToken, ^{ 105 | 106 | //init apple signing requirement 107 | SecRequirementCreateWithString(CFSTR("anchor apple"), kSecCSDefaultFlags, &isApple); 108 | 109 | }); 110 | 111 | //create static code 112 | status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &staticCode); 113 | if(STATUS_SUCCESS != status) 114 | { 115 | //bail 116 | goto bail; 117 | } 118 | 119 | //check signature 120 | status = SecStaticCodeCheckValidity(staticCode, kSecCSDoNotValidateResources, NULL); 121 | 122 | //save signature status 123 | signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status]; 124 | 125 | //if file is signed 126 | // check if signed by apple, library validation, and grab signing authorities 127 | if(STATUS_SUCCESS == status) 128 | { 129 | //grab signing information 130 | status = SecCodeCopySigningInformation(staticCode, kSecCSSigningInformation, &signingInformation); 131 | if(STATUS_SUCCESS != status) 132 | { 133 | //bail 134 | goto bail; 135 | } 136 | 137 | //signed by apple? 138 | if(STATUS_SUCCESS == SecStaticCodeCheckValidity(staticCode, kSecCSDefaultFlags, isApple)) 139 | { 140 | //signed by apple 141 | signingInfo[KEY_IS_APPLE] = [NSNumber numberWithInt:YES]; 142 | } 143 | 144 | //library validation enabled? 145 | if(FLAGS_LIBRARY_VALIDATION == ([[(__bridge NSDictionary*)signingInformation objectForKey:(__bridge NSString*)kSecCodeInfoFlags] unsignedIntegerValue] & FLAGS_LIBRARY_VALIDATION)) 146 | { 147 | //library validation 148 | signingInfo[KEY_LIBRARY_VALIDATION] = [NSNumber numberWithInt:YES]; 149 | } 150 | 151 | //hardened runtime enabled? 152 | if(FLAG_HARDENED_RUNTIME == ([[(__bridge NSDictionary*)signingInformation objectForKey:(__bridge NSString*)kSecCodeInfoFlags] unsignedIntegerValue] & FLAG_HARDENED_RUNTIME)) 153 | { 154 | //library validation 155 | signingInfo[KEY_HARDENED_RUNTIME] = [NSNumber numberWithInt:YES]; 156 | } 157 | 158 | //grab entitlements 159 | if(nil != [(__bridge NSDictionary*)signingInformation objectForKey:(__bridge NSString*)kSecCodeInfoEntitlementsDict]) 160 | { 161 | //extract/save 162 | signingInfo[KEY_SIGNING_ENTITLEMENTS] = [(__bridge NSDictionary*)signingInformation objectForKey:(__bridge NSString*)kSecCodeInfoEntitlementsDict]; 163 | } 164 | } 165 | 166 | //init array for certificate names 167 | signingInfo[KEY_SIGNING_AUTHORITIES] = [NSMutableArray array]; 168 | 169 | //get cert chain 170 | certificateChain = [(__bridge NSDictionary*)signingInformation objectForKey:(__bridge NSString*)kSecCodeInfoCertificates]; 171 | 172 | //get name of all certs 173 | for(index = 0; index < certificateChain.count; index++) 174 | { 175 | //extract cert 176 | certificate = (__bridge SecCertificateRef)([certificateChain objectAtIndex:index]); 177 | 178 | //get common name 179 | status = SecCertificateCopyCommonName(certificate, &commonName); 180 | 181 | //skip ones that error out 182 | if( (STATUS_SUCCESS != status) || 183 | (NULL == commonName)) 184 | { 185 | //skip 186 | continue; 187 | } 188 | 189 | //save 190 | [signingInfo[KEY_SIGNING_AUTHORITIES] addObject:(__bridge NSString*)commonName]; 191 | 192 | //release name 193 | CFRelease(commonName); 194 | } 195 | 196 | bail: 197 | 198 | //free signing info 199 | if(NULL != signingInformation) 200 | { 201 | //free 202 | CFRelease(signingInformation); 203 | } 204 | 205 | //free static code 206 | if(NULL != staticCode) 207 | { 208 | //free 209 | CFRelease(staticCode); 210 | } 211 | 212 | return signingInfo; 213 | } 214 | 215 | //get an icon for a process 216 | // for apps, this will be app's icon, otherwise just a standard system one 217 | NSImage* getIconForBinary(NSString* path) 218 | { 219 | //icon's file name 220 | NSString* iconFile = nil; 221 | 222 | //icon's path 223 | NSString* iconPath = nil; 224 | 225 | //icon's path extension 226 | NSString* iconExtension = nil; 227 | 228 | //icon 229 | NSImage* icon = nil; 230 | 231 | //system's document icon 232 | static NSImage* documentIcon = nil; 233 | 234 | //bundle 235 | NSBundle* appBundle = nil; 236 | 237 | //invalid path? 238 | // grab a default icon and bail 239 | if(YES != [[NSFileManager defaultManager] fileExistsAtPath:path]) 240 | { 241 | //set icon to system 'application' icon 242 | icon = [[NSWorkspace sharedWorkspace] 243 | iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)]; 244 | 245 | //set size to 64 @2x 246 | [icon setSize:NSMakeSize(128, 128)]; 247 | 248 | //bail 249 | goto bail; 250 | } 251 | 252 | //first try grab bundle 253 | // ->then extact icon from this 254 | appBundle = findAppBundle(path); 255 | if(nil != appBundle) 256 | { 257 | //get file 258 | iconFile = appBundle.infoDictionary[@"CFBundleIconFile"]; 259 | 260 | //get path extension 261 | iconExtension = [iconFile pathExtension]; 262 | 263 | //if its blank (i.e. not specified) 264 | // go with 'icns' 265 | if(YES == [iconExtension isEqualTo:@""]) 266 | { 267 | //set type 268 | iconExtension = @"icns"; 269 | } 270 | 271 | //set full path 272 | iconPath = [appBundle pathForResource:[iconFile stringByDeletingPathExtension] ofType:iconExtension]; 273 | 274 | //load it 275 | icon = [[NSImage alloc] initWithContentsOfFile:iconPath]; 276 | } 277 | 278 | //process is not an app or couldn't get icon 279 | // try to get it via shared workspace 280 | if( (nil == appBundle) || 281 | (nil == icon) ) 282 | { 283 | //extract icon 284 | icon = [[NSWorkspace sharedWorkspace] iconForFile:path]; 285 | 286 | //load system document icon 287 | // static var, so only load once 288 | if(nil == documentIcon) 289 | { 290 | //load 291 | documentIcon = [[NSWorkspace sharedWorkspace] iconForFileType: 292 | NSFileTypeForHFSTypeCode(kGenericDocumentIcon)]; 293 | } 294 | 295 | //if 'iconForFile' method doesn't find and icon, it returns the system 'document' icon 296 | // the system 'application' icon seems more applicable, so use that here... 297 | if(YES == [icon isEqual:documentIcon]) 298 | { 299 | //set icon to system 'application' icon 300 | icon = [[NSWorkspace sharedWorkspace] 301 | iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)]; 302 | } 303 | 304 | //'iconForFileType' returns small icons 305 | // so set size to 64 @2x 306 | [icon setSize:NSMakeSize(128, 128)]; 307 | } 308 | 309 | bail: 310 | 311 | return icon; 312 | } 313 | 314 | //given a path to binary 315 | // parse it back up to find app's bundle 316 | NSBundle* findAppBundle(NSString* binaryPath) 317 | { 318 | //app's bundle 319 | NSBundle* appBundle = nil; 320 | 321 | //app's path 322 | NSString* appPath = nil; 323 | 324 | //first just try full path 325 | appPath = binaryPath; 326 | 327 | //try to find the app's bundle/info dictionary 328 | do 329 | { 330 | //try to load app's bundle 331 | appBundle = [NSBundle bundleWithPath:appPath]; 332 | 333 | //check for match 334 | // ->binary path's match 335 | if( (nil != appBundle) && 336 | (YES == [appBundle.executablePath isEqualToString:binaryPath])) 337 | { 338 | //all done 339 | break; 340 | } 341 | 342 | //always unset bundle var since it's being returned 343 | // ->and at this point, its not a match 344 | appBundle = nil; 345 | 346 | //remove last part 347 | // ->will try this next 348 | appPath = [appPath stringByDeletingLastPathComponent]; 349 | 350 | //scan until we get to root 351 | // ->of course, loop will be exited if app info dictionary is found/loaded 352 | } while( (nil != appPath) && 353 | (YES != [appPath isEqualToString:@"/"]) && 354 | (YES != [appPath isEqualToString:@""]) ); 355 | 356 | return appBundle; 357 | } 358 | 359 | //get app's version 360 | // ->extracted from Info.plist 361 | NSString* getAppVersion() 362 | { 363 | //read and return 'CFBundleVersion' from bundle 364 | return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; 365 | } 366 | 367 | //check if (full) dark mode 368 | // meaning, Mojave+ and dark mode enabled 369 | BOOL isDarkMode() 370 | { 371 | //flag 372 | BOOL darkMode = NO; 373 | 374 | //prior to mojave? 375 | // bail, since not true dark mode 376 | if( (YES != [NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)]) || 377 | (YES != [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 14, 0}]) ) 378 | { 379 | //bail 380 | goto bail; 381 | } 382 | 383 | //not dark mode? 384 | if(YES != [[[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"] isEqualToString:@"Dark"]) 385 | { 386 | //bail 387 | goto bail; 388 | } 389 | 390 | //ok, mojave dark mode it is! 391 | darkMode = YES; 392 | 393 | bail: 394 | 395 | return darkMode; 396 | } 397 | 398 | //get all user 399 | // includes name/home directory 400 | NSMutableDictionary* allUsers() 401 | { 402 | //users 403 | NSMutableDictionary* users = nil; 404 | 405 | //query 406 | CSIdentityQueryRef query = nil; 407 | 408 | //query results 409 | CFArrayRef results = NULL; 410 | 411 | //error 412 | CFErrorRef error = NULL; 413 | 414 | //identiry 415 | CBIdentity* identity = NULL; 416 | 417 | //alloc dictionary 418 | users = [NSMutableDictionary dictionary]; 419 | 420 | //init query 421 | query = CSIdentityQueryCreate(NULL, kCSIdentityClassUser, CSGetLocalIdentityAuthority()); 422 | 423 | //exec query 424 | if(true != CSIdentityQueryExecute(query, 0, &error)) 425 | { 426 | //bail 427 | goto bail; 428 | } 429 | 430 | //grab results 431 | results = CSIdentityQueryCopyResults(query); 432 | 433 | //process all results 434 | // add user and home directory 435 | for (int i = 0; i < CFArrayGetCount(results); ++i) 436 | { 437 | //grab identity 438 | identity = [CBIdentity identityWithCSIdentity:(CSIdentityRef)CFArrayGetValueAtIndex(results, i)]; 439 | 440 | //add user 441 | users[identity.UUIDString] = @{USER_NAME:identity.posixName, USER_DIRECTORY:NSHomeDirectoryForUser(identity.posixName)}; 442 | } 443 | 444 | bail: 445 | 446 | //release results 447 | if(NULL != results) 448 | { 449 | //release 450 | CFRelease(results); 451 | } 452 | 453 | //release query 454 | if(NULL != query) 455 | { 456 | //release 457 | CFRelease(query); 458 | } 459 | 460 | return users; 461 | } 462 | 463 | //give a list of paths 464 | // convert any `~` to all or current user 465 | NSMutableArray* expandPaths(const __strong NSString* const paths[], int count) 466 | { 467 | //expanded paths 468 | NSMutableArray* expandedPaths = nil; 469 | 470 | //(current) path 471 | const NSString* path = nil; 472 | 473 | //all users 474 | NSMutableDictionary* users = nil; 475 | 476 | //grab all users 477 | users = allUsers(); 478 | 479 | //alloc list 480 | expandedPaths = [NSMutableArray array]; 481 | 482 | //iterate/expand 483 | for(NSInteger i = 0; i < count; i++) 484 | { 485 | //grab path 486 | path = paths[i]; 487 | 488 | //no `~`? 489 | // just add and continue 490 | if(YES != [path hasPrefix:@"~"]) 491 | { 492 | //add as is 493 | [expandedPaths addObject:path]; 494 | 495 | //next 496 | continue; 497 | } 498 | 499 | //handle '~' case 500 | // root? add each user 501 | if(0 == geteuid()) 502 | { 503 | //add each user 504 | for(NSString* user in users) 505 | { 506 | [expandedPaths addObject:[users[user][USER_DIRECTORY] stringByAppendingPathComponent:[path substringFromIndex:1]]]; 507 | } 508 | } 509 | //otherwise 510 | // just convert to current user 511 | else 512 | { 513 | [expandedPaths addObject:[path stringByExpandingTildeInPath]]; 514 | } 515 | } 516 | 517 | return expandedPaths; 518 | } 519 | 520 | //check if directory is SIP'd 521 | BOOL isSIPDirectory(NSString* path) 522 | { 523 | //flag 524 | BOOL isRestricted = YES; 525 | 526 | //attributes 527 | NSDictionary* attributes = nil; 528 | 529 | //get attributes 530 | attributes = [NSFileManager.defaultManager attributesOfItemAtPath:path error:nil]; 531 | if(attributes != nil) { 532 | 533 | //check rootless 534 | isRestricted = 535 | [attributes[NSFileImmutable] boolValue] || 536 | [attributes[@"com.apple.rootless"] boolValue] || 537 | [attributes[@"com.apple.rootless.restricted"] boolValue]; 538 | } 539 | 540 | return isRestricted; 541 | } 542 | -------------------------------------------------------------------------------- /DHS/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/.DS_Store -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon_16x16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon_16x16@2x.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon_32x32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon_32x32@2x.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon_128x128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon_128x128@2x.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon_256x256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon_256x256@2x.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon_512x512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "idiom" : "mac", 59 | "scale" : "2x", 60 | "size" : "512x512" 61 | } 62 | ], 63 | "info" : { 64 | "author" : "xcode", 65 | "version" : 1 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsFleet.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsFleet.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsFleet.imageset/darkMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsFleet.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsFleet.imageset/lightMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsJamf.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsJamf.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsJamf.imageset/darkMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsJamf.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsJamf.imageset/lightMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsKandji.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsKandji.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsKandji.imageset/darkMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsKandji.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsKandji.imageset/lightMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsKolide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsKolide.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsKolide.imageset/darkMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsKolide.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsKolide.imageset/lightMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsMacPaw.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsMacPaw.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsMacPaw.imageset/darkMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsMacPaw.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsMacPaw.imageset/lightMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsMosyle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsMosyle.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsMosyle.imageset/darkMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsMosyle.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsMosyle.imageset/lightMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsPANW.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsPANW.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsPANW.imageset/darkMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsPANW.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsPANW.imageset/lightMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsSophos.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsSophos.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsSophos.imageset/darkMode.png -------------------------------------------------------------------------------- /DHS/images/Assets.xcassets/FriendsSophos.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/Assets.xcassets/FriendsSophos.imageset/lightMode.png -------------------------------------------------------------------------------- /DHS/images/bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/bug.png -------------------------------------------------------------------------------- /DHS/images/dhsText.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/dhsText.ai -------------------------------------------------------------------------------- /DHS/images/dhsText.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/dhsText.png -------------------------------------------------------------------------------- /DHS/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/icon.png -------------------------------------------------------------------------------- /DHS/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/logo.png -------------------------------------------------------------------------------- /DHS/images/logoApple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/logoApple.png -------------------------------------------------------------------------------- /DHS/images/logoAppleBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/logoAppleBG.png -------------------------------------------------------------------------------- /DHS/images/logoAppleOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/logoAppleOver.png -------------------------------------------------------------------------------- /DHS/images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/settings.png -------------------------------------------------------------------------------- /DHS/images/settingsBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/settingsBG.png -------------------------------------------------------------------------------- /DHS/images/settingsOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/settingsOver.png -------------------------------------------------------------------------------- /DHS/images/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/show.png -------------------------------------------------------------------------------- /DHS/images/showOff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/showOff.png -------------------------------------------------------------------------------- /DHS/images/showOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/showOver.png -------------------------------------------------------------------------------- /DHS/images/startScan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/startScan.png -------------------------------------------------------------------------------- /DHS/images/startScanBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/startScanBG.png -------------------------------------------------------------------------------- /DHS/images/startScanOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/startScanOver.png -------------------------------------------------------------------------------- /DHS/images/stopScan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/stopScan.png -------------------------------------------------------------------------------- /DHS/images/stopScanBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/stopScanBG.png -------------------------------------------------------------------------------- /DHS/images/stopScanOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/stopScanOver.png -------------------------------------------------------------------------------- /DHS/images/virus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/DylibHijackScanner/fd6d6157db9f0a91217f0929ec62dcb8138d78e8/DHS/images/virus.png -------------------------------------------------------------------------------- /DHS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // 4 | 5 | /* 6 | DHS: dynamic hijack scanner 7 | signing: set 'Code Signing Indentify' to 'Developer ID: *' 8 | build an archive, then export as a 'Developer ID Signed Application' 9 | test via, $codesign -dvvv DHS.app (confirm 'Objective-See LLC) 10 | $spctl -vat execute DHS.app 11 | */ 12 | 13 | #import 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | return NSApplicationMain(argc, (const char **)argv); 18 | } 19 | -------------------------------------------------------------------------------- /DHS/patrons.txt: -------------------------------------------------------------------------------- 1 | Patrons (2^6+): 2 | Jan Koum, Nick, Shain Singh, Christian Blümlein, Rocky Zadok, Cane Juice, M S 3 | 4 | Friends of Objective-See: 5 | Kandji, Jamf, Mosyle, CleanMyMac X, Kolide, Palo Alto Networks, Sophos, SmugMug, Guardian Mobile Firewall, iVerify, Halo Privacy 6 | --------------------------------------------------------------------------------