project cleanup, improved packer detection, UI / cmdline scan improvements

This commit is contained in:
Patrick Wardle
2025-12-07 11:30:53 -10:00
parent d5b8c515d9
commit ab53c92638
15 changed files with 251 additions and 89 deletions
-3
View File
@@ -44,9 +44,6 @@ extern Filter* itemFilter;
//welcome view controller
@property(nonatomic, retain)WelcomeWindowController* welcomeWindowController;
//friends
@property (weak) IBOutlet NSWindow* friends;
//close button
@property (weak) IBOutlet NSButton* closeButton;
+15 -37
View File
@@ -13,9 +13,12 @@
//TODO: support delete items
//TODO: search in UI
/* GLOBALS */
NSString* scanID = nil;
@implementation AppDelegate
@synthesize friends;
@synthesize plugins;
@synthesize scanButton;
@synthesize isConnected;
@@ -35,6 +38,7 @@
@synthesize resultsWindowController;
@synthesize welcomeWindowController;
//exception handler
// show alert and log error
void uncaughtExceptionHandler(NSException* exception) {
@@ -124,13 +128,11 @@ void uncaughtExceptionHandler(NSException* exception) {
//alloc shared item enumerator
sharedItemEnumerator = [[ItemEnumerator alloc] init];
//request access
//check/request for FDA
// delay, so UI completes rendering
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 100 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
//request access
[self requestFDA];
//request access
[self requestFDA];
});
//check for update
@@ -199,35 +201,6 @@ void uncaughtExceptionHandler(NSException* exception) {
}
//close 'friends' window
-(IBAction)closeFriendsWindow:(id)sender
{
//close to hide
[self.friends close];
return;
}
//window close handler
-(void)windowWillClose:(NSNotification *)notification {
//closing friends window?
// request full disk access
if(self.friends == notification.object)
{
//request access
// delay ensures (friends) window will close
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
//request access
[self requestFDA];
});
}
return;
}
//automatically close when user closes last window
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{
@@ -419,6 +392,9 @@ void uncaughtExceptionHandler(NSException* exception) {
// ->also shared enumerator thread (if needed)
-(void)startScan
{
//scan ID
scanID = [[NSUUID UUID] UUIDString];
//alloc scanner thread
scannerThread = [[NSThread alloc] initWithTarget:self selector:@selector(scan) object:nil];
@@ -800,6 +776,9 @@ void uncaughtExceptionHandler(NSException* exception) {
// ->ensures various threads are terminated, etc
-(void)completeScan
{
//reset scan ID
scanID = nil;
//tell enumerator to stop
[sharedItemEnumerator stop];
@@ -1165,7 +1144,6 @@ void uncaughtExceptionHandler(NSException* exception) {
}
//show 'save file' popup
// ->user clicks ok, save results (JSON) to disk
-(IBAction)saveResults:(id)sender
@@ -1215,7 +1193,7 @@ void uncaughtExceptionHandler(NSException* exception) {
else
{
//err msg
NSLog(@"ERROR: saving output to %@ failed with %@", [panel URL], error);
//NSLog(@"ERROR: saving output to %@ failed with %@", panel.URL, error);
//init alert
alert = [[NSAlert alloc] init];
+7 -7
View File
@@ -52,7 +52,7 @@
<window title="KnockKnock" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="371" userLabel="Main Window">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="0.0" y="0.0" width="1295" height="671"/>
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="769"/>
<rect key="screenRect" x="0.0" y="0.0" width="3440" height="1409"/>
<value key="minSize" type="size" width="1000" height="597"/>
<value key="maxSize" type="size" width="2500" height="1000"/>
<view key="contentView" id="372">
@@ -202,7 +202,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView translatesAutoresizingMaskIntoConstraints="NO" id="577">
<rect key="frame" x="5" y="-2" width="50" height="61"/>
<rect key="frame" x="5" y="-2" width="50" height="60"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="kB1-L8-KFN"/>
<constraint firstAttribute="width" constant="50" id="wxT-p0-paD"/>
@@ -452,14 +452,14 @@
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="kkText" id="r1Z-Hx-M6T"/>
</imageView>
<progressIndicator hidden="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" bezeled="NO" indeterminate="YES" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="839">
<rect key="frame" x="1255" y="10" width="32" height="32"/>
<rect key="frame" x="1255" y="8" width="32" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="5xq-yG-SSJ"/>
<constraint firstAttribute="height" constant="32" id="aeM-9z-lBy"/>
</constraints>
</progressIndicator>
<textField hidden="YES" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="745">
<rect key="frame" x="1160" y="16" width="75" height="18"/>
<rect key="frame" x="1160" y="13" width="75" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="1aa-3i-5H9"/>
</constraints>
@@ -672,11 +672,11 @@
<constraint firstItem="3Vf-uL-OZX" firstAttribute="leading" secondItem="372" secondAttribute="leading" constant="107" id="YFa-JP-po1"/>
<constraint firstAttribute="bottom" secondItem="gmd-EM-xEi" secondAttribute="bottom" constant="1" id="YMB-QL-QqB"/>
<constraint firstItem="655" firstAttribute="centerX" secondItem="x7S-Ww-gLm" secondAttribute="centerX" id="bPe-nc-G8S"/>
<constraint firstAttribute="bottom" secondItem="745" secondAttribute="bottom" constant="16" id="c9W-7d-MXn"/>
<constraint firstAttribute="bottom" secondItem="745" secondAttribute="bottom" constant="13" id="c9W-7d-MXn"/>
<constraint firstAttribute="bottom" secondItem="rqX-FA-o3e" secondAttribute="bottom" constant="52" id="drt-dw-JrT"/>
<constraint firstItem="536" firstAttribute="leading" secondItem="rqX-FA-o3e" secondAttribute="trailing" constant="32" id="gzW-um-0eE"/>
<constraint firstItem="5uI-IQ-e40" firstAttribute="leading" secondItem="372" secondAttribute="leading" constant="12" id="hwa-cU-Pnd"/>
<constraint firstAttribute="bottom" secondItem="839" secondAttribute="bottom" constant="10" id="ibd-gt-Ml2"/>
<constraint firstAttribute="bottom" secondItem="839" secondAttribute="bottom" constant="8" id="ibd-gt-Ml2"/>
<constraint firstAttribute="trailing" secondItem="KxO-Jf-gyu" secondAttribute="trailing" constant="-8" id="isR-LB-Ezc"/>
<constraint firstItem="rqX-FA-o3e" firstAttribute="top" secondItem="372" secondAttribute="top" constant="151" id="j4C-hj-Nqa"/>
<constraint firstItem="gmd-EM-xEi" firstAttribute="firstBaseline" secondItem="eJj-oN-VA2" secondAttribute="firstBaseline" constant="-1" id="jRI-Gh-Q9E"/>
@@ -722,7 +722,7 @@
<resources>
<image name="Compare" width="128" height="128"/>
<image name="CompareAlternate" width="128" height="128"/>
<image name="NSActionTemplate" width="20" height="20"/>
<image name="NSActionTemplate" width="19" height="19"/>
<image name="NSColorPanel" width="32" height="32"/>
<image name="Preferences" width="128" height="128"/>
<image name="PreferencesAlternate" width="128" height="128"/>
+4 -4
View File
@@ -448,8 +448,6 @@
CD6FD7AB2C7AAD87001C59F2 /* MainMenu.xib */,
CD5854D621A60B2000A438B0 /* PlistWindowController.h */,
CD5854D721A60B2000A438B0 /* PlistWindowController.m */,
CDF08CC71AC4C678009B3423 /* PrefsWindowController.h */,
CDF08CC81AC4C678009B3423 /* PrefsWindowController.m */,
CD24F076219DF3DB0081B0E5 /* Signing.h */,
CD24F075219DF3DA0081B0E5 /* Signing.m */,
1D21BC55172AF43D009D1CFD /* Supporting Files */,
@@ -541,13 +539,13 @@
CD0219511AD34D9A005148A2 /* AboutWindowController.h */,
CD0219521AD34D9A005148A2 /* AboutWindowController.m */,
CDA81D751A95B7C1009790E2 /* CategoryTableController.h */,
CD5A5F7B2EB95C0C00F5068F /* WelcomeWindowController.h */,
CD5A5F7C2EB95C0C00F5068F /* WelcomeWindowController.m */,
CDA81D761A95B7C1009790E2 /* CategoryTableController.m */,
CDA81DE71A997BF1009790E2 /* InfoWindowController.h */,
CDA81DE81A997BF1009790E2 /* InfoWindowController.m */,
CDA81D791A95D29B009790E2 /* ItemTableController.h */,
CDA81D7A1A95D29B009790E2 /* ItemTableController.m */,
CDF08CC71AC4C678009B3423 /* PrefsWindowController.h */,
CDF08CC81AC4C678009B3423 /* PrefsWindowController.m */,
CD02195F1AD39A83005148A2 /* ResultsWindowController.h */,
CD0219601AD39A83005148A2 /* ResultsWindowController.m */,
CD792FBA2D2530A800167649 /* UnknownItemsWindowController.h */,
@@ -556,6 +554,8 @@
CD2F21A321A8A7E300F67A83 /* UpdateWindowController.m */,
CDF08CDC1AC886F2009B3423 /* VTInfoWindowController.h */,
CDF08CDD1AC886F2009B3423 /* VTInfoWindowController.m */,
CD5A5F7B2EB95C0C00F5068F /* WelcomeWindowController.h */,
CD5A5F7C2EB95C0C00F5068F /* WelcomeWindowController.m */,
);
name = UIControllers;
sourceTree = "<group>";
+1 -1
View File
@@ -729,7 +729,7 @@ bail:
//NSLog(@"final calc: %f\n", (1.0 * totalCompressedData)/fileData.length);
//final calculation for architecture
if( ((1.0 * totalCompressedData)/fileData.length) > .2)
if( ((1.0 * totalCompressedData)/fileData.length) > .25)
{
//set
packed = YES;
+12
View File
@@ -12,6 +12,9 @@
}
}
},
"'%@' isn't known to VirusTotal" : {
"comment" : "'%@' isn't known to VirusTotal"
},
"a new version (%@) is available!" : {
"comment" : "a new version (%@) is available!",
"localizations" : {
@@ -211,6 +214,9 @@
}
}
},
"ERROR: %@" : {
"comment" : "ERROR: %@"
},
"ERROR: Failed to compare scans" : {
"comment" : "ERROR: Failed to compare scans",
"localizations" : {
@@ -268,6 +274,7 @@
},
"failed to submit '%@' to VirusTotal (HTTP response %ld)." : {
"comment" : "failed to submit '%@' to VirusTotal (HTTP response %ld).",
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
@@ -410,6 +417,7 @@
},
"No results found for '%@'" : {
"comment" : "No results found for '%@'",
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
@@ -591,6 +599,7 @@
},
"Submitting '%@'" : {
"comment" : "Submitting '%@'",
"extractionState" : "stale",
"localizations" : {
"es" : {
"stringUnit" : {
@@ -600,6 +609,9 @@
}
}
},
"Submitting '%@'..." : {
"comment" : "Submitting '%@'..."
},
"This allows the app to perform a comprehensive scan.\n\nIn System Preferences:\r ▪ Click the 🔒 to authenticate\r ▪ Click the to add KnockKnock.app\n" : {
"comment" : "This allows the app to perform a comprehensive scan.\n\nIn System Preferences:\r ▪ Click the 🔒 to authenticate\r ▪ Click the to add KnockKnock.app\n",
"extractionState" : "stale",
+1 -1
View File
@@ -57,7 +57,7 @@
</textFieldCell>
</textField>
<button hidden="YES" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Czs-Di-8Qw">
<rect key="frame" x="400" y="24" width="168" height="33"/>
<rect key="frame" x="400" y="26" width="168" height="33"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="View/Submit Items" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="71T-dO-S3a">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+53 -13
View File
@@ -9,6 +9,8 @@
<customObject id="-2" userLabel="File's Owner" customClass="UnknownItemsWindowController">
<connections>
<outlet property="activityIndicator" destination="YFJ-fV-od8" id="0dA-VM-qhD"/>
<outlet property="errorLabel" destination="Jld-3V-iRi" id="D9y-8x-9UR"/>
<outlet property="errorPopover" destination="Y6l-tV-hl3" id="ek9-gu-D84"/>
<outlet property="statusLabel" destination="cRD-QV-kp1" id="iww-ot-hR2"/>
<outlet property="submit" destination="p2q-DR-J4n" id="V3O-dR-GsD"/>
<outlet property="tableView" destination="4WG-Qw-U3m" id="n74-y3-lGx"/>
@@ -19,21 +21,21 @@
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Unknown Items" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="pvW-8N-g8T">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="403" y="305" width="643" height="339"/>
<rect key="contentRect" x="403" y="305" width="643" height="398"/>
<rect key="screenRect" x="0.0" y="0.0" width="3440" height="1409"/>
<value key="minSize" type="size" width="643" height="339"/>
<view key="contentView" id="XBF-k3-Nqu">
<rect key="frame" x="0.0" y="0.0" width="643" height="339"/>
<rect key="frame" x="0.0" y="0.0" width="643" height="398"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="26" horizontalPageScroll="10" verticalLineScroll="26" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mif-DC-CkF">
<rect key="frame" x="1" y="62" width="643" height="278"/>
<rect key="frame" x="1" y="62" width="643" height="284"/>
<clipView key="contentView" id="I4Y-ET-V9m">
<rect key="frame" x="1" y="1" width="641" height="276"/>
<rect key="frame" x="1" y="1" width="641" height="282"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="24" rowSizeStyle="large" headerView="mTM-rz-bsn" viewBased="YES" id="4WG-Qw-U3m">
<rect key="frame" x="0.0" y="0.0" width="723" height="253"/>
<rect key="frame" x="0.0" y="0.0" width="723" height="259"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -55,7 +57,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button tag="1001" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SKb-o1-3O3">
<rect key="frame" x="15" y="-3" width="29" height="18"/>
<rect key="frame" x="15" y="-4" width="29" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="D3n-cB-7oB">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@@ -93,6 +95,17 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button tag="100" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Eqw-zW-Xa6">
<rect key="frame" x="128" y="-3" width="16" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="help" bezelStyle="helpButton" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="YT4-vu-LOM">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="miniSystem"/>
</buttonCell>
<connections>
<action selector="showErrorInfo:" target="-2" id="vfR-ay-JhZ"/>
</connections>
</button>
</subviews>
<connections>
<outlet property="textField" destination="Cay-Kj-Uc7" id="FJh-s6-D19"/>
@@ -140,7 +153,7 @@
</subviews>
</clipView>
<scroller key="horizontalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="yyw-5X-sLC">
<rect key="frame" x="1" y="260" width="641" height="17"/>
<rect key="frame" x="1" y="266" width="641" height="17"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="gLe-AJ-eSK">
@@ -167,13 +180,24 @@
</connections>
</button>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cRD-QV-kp1">
<rect key="frame" x="18" y="22" width="451" height="15"/>
<rect key="frame" x="18" y="14" width="451" height="23"/>
<constraints>
<constraint firstAttribute="width" constant="447" id="4L7-sa-Vav"/>
<constraint firstAttribute="height" constant="15" id="HnK-1f-VOM"/>
<constraint firstAttribute="height" constant="23" id="HnK-1f-VOM"/>
</constraints>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" id="on5-Un-vIc">
<font key="font" size="13" name="Menlo-Regular"/>
<font key="font" size="15" name="Menlo-Regular"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MQ5-hC-zTd">
<rect key="frame" x="20" y="354" width="605" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" id="061-1p-frg">
<font key="font" metaFont="system"/>
<string key="title">These items arent known to VirusTotal.
Submitting them will upload the file to VirusTotal and open the resulting report in your browser.</string>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
@@ -188,19 +212,35 @@
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="mif-DC-CkF" secondAttribute="bottom" constant="62" id="00d-ob-Zdf"/>
<constraint firstItem="mif-DC-CkF" firstAttribute="top" secondItem="XBF-k3-Nqu" secondAttribute="top" constant="-1" id="5wD-mE-WXa"/>
<constraint firstItem="mif-DC-CkF" firstAttribute="top" secondItem="XBF-k3-Nqu" secondAttribute="top" constant="52" id="5wD-mE-WXa"/>
<constraint firstItem="cRD-QV-kp1" firstAttribute="top" secondItem="mif-DC-CkF" secondAttribute="bottom" constant="25" id="9WZ-Bk-4uo"/>
<constraint firstAttribute="trailing" secondItem="mif-DC-CkF" secondAttribute="trailing" constant="-1" id="CVV-X1-Kle"/>
<constraint firstItem="cRD-QV-kp1" firstAttribute="leading" secondItem="XBF-k3-Nqu" secondAttribute="leading" constant="20" symbolic="YES" id="Cdy-dt-0gQ"/>
<constraint firstItem="p2q-DR-J4n" firstAttribute="leading" secondItem="YFJ-fV-od8" secondAttribute="trailing" constant="16" id="FAn-FO-wk7"/>
<constraint firstAttribute="bottom" secondItem="p2q-DR-J4n" secondAttribute="bottom" constant="20" symbolic="YES" id="L3W-cR-gQ9"/>
<constraint firstAttribute="trailing" secondItem="p2q-DR-J4n" secondAttribute="trailing" constant="20" symbolic="YES" id="L9H-Gd-eDN"/>
<constraint firstAttribute="bottom" secondItem="cRD-QV-kp1" secondAttribute="bottom" constant="22" id="XnE-Kt-4pq"/>
<constraint firstAttribute="bottom" secondItem="cRD-QV-kp1" secondAttribute="bottom" constant="14" id="XnE-Kt-4pq"/>
<constraint firstItem="mif-DC-CkF" firstAttribute="leading" secondItem="XBF-k3-Nqu" secondAttribute="leading" constant="1" id="h6B-Mm-oRi"/>
<constraint firstAttribute="bottom" secondItem="YFJ-fV-od8" secondAttribute="bottom" constant="14" id="qWW-n0-w6s"/>
</constraints>
</view>
<point key="canvasLocation" x="-8.5" y="28.5"/>
<point key="canvasLocation" x="-8.5" y="-1"/>
</window>
<customView id="Y6l-tV-hl3">
<rect key="frame" x="0.0" y="0.0" width="479" height="102"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jld-3V-iRi">
<rect key="frame" x="18" y="15" width="447" height="67"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" selectable="YES" title="Error info:" id="bDg-MW-e9L">
<font key="font" size="11" name="Menlo-Regular"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<point key="canvasLocation" x="47" y="363"/>
</customView>
</objects>
</document>
+24
View File
@@ -19,6 +19,30 @@
}
}
},
"061-1p-frg.title" : {
"comment" : "Class = \"NSTextFieldCell\"; title = \"These items arent known to VirusTotal. \\nSubmitting them will upload the file to VirusTotal and open the resulting report in your browser.\"; ObjectID = \"061-1p-frg\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "These items arent known to VirusTotal. \nSubmitting them will upload the file to VirusTotal and open the resulting report in your browser."
}
}
}
},
"bDg-MW-e9L.title" : {
"comment" : "Class = \"NSTextFieldCell\"; title = \"Error info:\"; ObjectID = \"bDg-MW-e9L\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Error info:"
}
}
}
},
"G1q-Ag-u0M.title" : {
"comment" : "Class = \"NSButtonCell\"; title = \"View\"; ObjectID = \"G1q-Ag-u0M\";",
"extractionState" : "stale",
+7
View File
@@ -32,6 +32,13 @@
//status label
@property (weak) IBOutlet NSTextField *statusLabel;
//error
@property (strong) IBOutlet NSView *errorPopover;
//error label
@property (weak) IBOutlet NSTextField *errorLabel;
/* METHODS */
//checkbox button handler
+62 -6
View File
@@ -102,6 +102,10 @@
//result
NSDictionary* result = self.results[@(row)];
//erorr button
NSButton* moreInfo = (NSButton*)[cell viewWithTag:100];
moreInfo.hidden = YES;
//nothing
if(!result.count) {
@@ -117,6 +121,9 @@
cell.textField.stringValue = @"Failed to Submit";
cell.textField.toolTip = [NSString stringWithFormat:@"ERROR: %@", result[VT_ERROR]];
//show button
moreInfo.hidden = NO;
}
//ok
else
@@ -125,21 +132,29 @@
cell.textField.toolTip = @"";
cell.textField.stringValue = @"Submitted";
//already viewed?
// no need to show again
if(result[VT_REPORT_VIEWED]) {
break;
}
//got response?
// launch browser to show user
if(nil != result[VT_RESULTS_URL])
{
//update result to note we've shown report
NSMutableDictionary* updatedResults = [result mutableCopy];
updatedResults[VT_REPORT_VIEWED] = @(YES);
self.results[@(row)] = updatedResults;
//launch browser to show new report
dispatch_async(dispatch_get_main_queue(), ^{
//launch browser
[NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:result[VT_RESULTS_URL]]];
});
//wait to browser is up and happy
[NSThread sleepForTimeInterval:0.5];
}
}
@@ -160,6 +175,47 @@
return cell;
}
- (IBAction)showErrorInfo:(id)sender
{
//get the row for this button
NSInteger row = [self.tableView rowForView:sender];
if (row == -1)
{
return;
}
//get the result for this row
NSDictionary* result = self.results[@(row)];
if (!result)
{
return;
}
//popover
NSPopover *popover = [[NSPopover alloc] init];
//view controller
NSViewController *viewController = [[NSViewController alloc] init];
//set view
viewController.view = self.errorPopover;
//set text
self.errorLabel.stringValue = [NSString stringWithFormat:@"ERROR: %@", result[VT_ERROR]];
//init
popover.contentViewController = viewController;
popover.behavior = NSPopoverBehaviorTransient;
//show relative to the button
[popover showRelativeToRect:[sender bounds]
ofView:sender
preferredEdge:NSRectEdgeMaxY];
return;
}
//automatically invoked when user checks/unchecks checkbox in row
// enable/disable command state, plus handle some other button logic
-(IBAction)toggleTest:(NSButton*)sender
@@ -267,7 +323,7 @@
}
//set status
self.statusLabel.stringValue = [NSString stringWithFormat:NSLocalizedString(@"Submitting '%@'", @"Submitting '%@'"), ((File*)item).name];
self.statusLabel.stringValue = [NSString stringWithFormat:NSLocalizedString(@"Submitting '%@'...", @"Submitting '%@'..."), ((File*)item).name];
//inc
submittedItems++;
+3 -4
View File
@@ -151,7 +151,7 @@
self.analysisURL.hidden = YES;
//set unknown file msg
[self.unknownFile setStringValue:[NSString stringWithFormat:NSLocalizedString(@"No results found for '%@'", @"No results found for '%@'"), self.fileObj.name]];
[self.unknownFile setStringValue:[NSString stringWithFormat:NSLocalizedString(@"'%@' isn't known to VirusTotal", @"'%@' isn't known to VirusTotal"), self.fileObj.name]];
//show 'unknown file' msg
self.unknownFile.hidden = NO;
@@ -312,14 +312,13 @@
else {
//err msg
NSLog(@"ERROR: %@", result[VT_ERROR]);
//NSLog(@"ERROR: %@", result[VT_ERROR]);
//show error msg
dispatch_async(dispatch_get_main_queue(), ^{
//TODO:
//update status msg
[self.statusMsg setStringValue:[NSString stringWithFormat:NSLocalizedString(@"failed to submit '%@' to VirusTotal (HTTP response %ld).", @"failed to submit '%@' to VirusTotal (HTTP response %ld)."), self.fileObj.name, [(NSHTTPURLResponse *)result[VT_HTTP_RESPONSE] statusCode]]];
[self.statusMsg setStringValue:[NSString stringWithFormat:NSLocalizedString(@"ERROR: %@", @"ERROR: %@"), result[VT_ERROR]]];
//stop activity indicator
[self.progressIndicator stopAnimation:nil];
+57 -11
View File
@@ -18,21 +18,50 @@
//cmdline flag
extern BOOL cmdlineMode;
@implementation VirusTotal
extern NSString* scanID;
@implementation VirusTotal
//ask VT about all files for a given plugin
// note: always skips Apple binaries, as these won't be malware, and API keys usually rate limited
-(void)checkFiles:(PluginBase*)plugin apiKey:(NSString*)apiKey uiMode:(BOOL)uiMode completion:(void(^)(void))completion {
-(void)checkFiles:(PluginBase*)plugin apiKey:(NSString*)apiKey uiMode:(BOOL)uiMode completion:(void(^)(void))completion
{
//grab scan id
NSString* currentScanID = scanID;
//cmdline verbose mode
BOOL isVerbose = NO;
//make a snapshot
// prevents issues if scan was (re)started
NSArray* items = nil;
@synchronized(plugin.allItems) {
items = [plugin.allItems copy];
}
//sanity check
if(!plugin.allItems.count) {
if(!items.count) {
if(completion) completion();
return;
}
//for error msg
if( (!uiMode) &&
([NSProcessInfo.processInfo.arguments containsObject:@"-verbose"]) )
{
isVerbose = YES;
}
//all items in the plugin
for(ItemBase* item in plugin.allItems) {
for(ItemBase* item in items) {
//check if scan was stopped restarted
if( uiMode &&
![currentScanID isEqualToString:scanID])
{
if(completion) completion();
return;
}
//skip non-file items
if(![item isKindOfClass:[File class]]) {
@@ -53,6 +82,9 @@ extern BOOL cmdlineMode;
continue;
}
//TODO: remove
if(![file.name isEqualToString:@"orbit"]) continue;
//semaphore for synchronous request
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
@@ -68,7 +100,11 @@ extern BOOL cmdlineMode;
NSURLSessionDataTask* task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"VirusTotal ERROR: %@", error.localizedDescription);
//err msg
if(isVerbose) {
printf("\nERROR (VirusTotal): %s\n", error.localizedDescription.UTF8String);
}
//signal
dispatch_semaphore_signal(sema);
@@ -81,8 +117,11 @@ extern BOOL cmdlineMode;
//401 is API key issue
if (httpResponse.statusCode == 401) {
NSLog(@"VirusTotal ERROR: API key %@ is not valid", apiKey);
//err msg
if(isVerbose) {
printf("\nERROR (VirusTotal): API key %s issue (not valid?)\n", apiKey.UTF8String);
}
if(uiMode) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@@ -104,8 +143,7 @@ extern BOOL cmdlineMode;
//404 is file not found
if (httpResponse.statusCode == 404) {
NSLog(@"%@ is unknown to VirusTotal (hash: %@)", file.name, sha1);
//NSLog(@"%@ is unknown to VirusTotal (hash: %@)", file.name, sha1);
@synchronized(item.plugin.unknownItems) {
[item.plugin.unknownItems addObject:item];
@@ -126,7 +164,11 @@ extern BOOL cmdlineMode;
//all other error(s)
if (httpResponse.statusCode != 200) {
NSLog(@"VirusTotal HTTP error: %ld", (long)httpResponse.statusCode);
//err msg
if(isVerbose) {
printf("\nERROR (VirusTotal): HTTP %ld\n", (long)httpResponse.statusCode);
}
//signal
dispatch_semaphore_signal(sema);
@@ -137,7 +179,11 @@ extern BOOL cmdlineMode;
NSError* jsonError = nil;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(@"VirusTotal JSON error: %@", jsonError.localizedDescription);
//err msg
if(isVerbose) {
printf("\nERROR (VirusTotal): invalid JSON %s\n", jsonError.localizedDescription.UTF8String);
}
//signal
dispatch_semaphore_signal(sema);
+3
View File
@@ -239,6 +239,9 @@ enum Signer{None, Apple, AppStore, DevID, AdHoc};
//result url
#define VT_RESULTS_URL @"permalink"
//report was shown
#define VT_REPORT_VIEWED @"reportViewed"
//result hash
#define VT_RESULT_HASH @"hash"
+2 -2
View File
@@ -1170,12 +1170,12 @@ BOOL hasFDA(void) {
NSString *tccPath = [@"~/Library/Application Support/com.apple.TCC/TCC.db" stringByExpandingTildeInPath];
//dbg msg
NSLog(@"Checking for 'Full Disk Access'");
//NSLog(@"Checking for 'Full Disk Access'");
fileIsReadable = [NSFileManager.defaultManager isReadableFileAtPath:tccPath];
//dbg msg
NSLog(@"Result: %d", fileIsReadable);
//NSLog(@"Result: %d", fileIsReadable);
return fileIsReadable;
}