Skip to content

Commit ce364b7

Browse files
committed
Startup folder check, catch block logging, filterFindings fix (v0.4.7)
- Add startup folder persistence check (per-user + all-user, T1547.001) - Replace 22 empty catch blocks with Write-Verbose across Check-Accounts, Check-DefenseEvasion, Check-FileSystem, and Helpers - Fix filterFindings JS to pass button element instead of relying on implicit event variable - Collapse redundant if/else branch in Check-FileSystem.ps1 Made-with: Cursor
1 parent 0e5fba9 commit ce364b7

8 files changed

Lines changed: 130 additions & 39 deletions

File tree

AmIHacked.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ if ($script:NonInteractive) {
8080
$script:RedactMap = @{}
8181
$script:SuppressedCount = 0
8282

83-
$script:Version = "0.4.6"
83+
$script:Version = "0.4.7"
8484

8585
# ── Helpers (loaded first) ───────────────────────────────────────────────────
8686

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66

7+
## [0.4.7] - 2026-03-15
8+
9+
### Added
10+
- **Startup folder persistence check** -- scans per-user and all-user startup folders for executables, scripts, and shortcuts (WARNING, T1547.001)
11+
12+
### Fixed
13+
- **22 empty catch blocks** replaced with `Write-Verbose` across Check-Accounts.ps1, Check-DefenseEvasion.ps1, Check-FileSystem.ps1, and lib/Helpers.ps1 so failures are traceable with `-Verbose`
14+
- **Report filterFindings JS bug** -- implicit `event.target` replaced with explicit button element parameter, fixing potential strict-mode errors
15+
- **Redundant if/else in Check-FileSystem.ps1** -- collapsed identical branches for trusted-company severity assignment
16+
717
## [0.4.6] - 2026-03-15
818

919
### Added

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
[![PowerShell 5.1+](https://img.shields.io/badge/PowerShell-5.1%2B-0d1117?style=for-the-badge&logo=powershell&logoColor=5391FE)](https://docs.microsoft.com/powershell/)
1313
[![Windows 10/11](https://img.shields.io/badge/Windows-10%20%2F%2011-0d1117?style=for-the-badge&logo=windows&logoColor=white)](https://www.microsoft.com/windows)
1414
[![License: MIT](https://img.shields.io/badge/License-MIT-0d1117?style=for-the-badge&logoColor=white)](LICENSE)
15-
[![Version](https://img.shields.io/badge/Version-0.4.6-FF6B6B?style=for-the-badge)](#changelog)
15+
[![Version](https://img.shields.io/badge/Version-0.4.7-FF6B6B?style=for-the-badge)](#changelog)
1616

1717
[![Zero Dependencies](https://img.shields.io/badge/Dependencies-Zero-0d1117?style=flat-square&labelColor=0d1117)](#)
1818
[![MITRE ATT&CK](https://img.shields.io/badge/MITRE%20ATT%26CK-40%2B%20Techniques-ff3333?style=flat-square&labelColor=0d1117)](#mitre-attck-coverage)
@@ -140,7 +140,7 @@ Baselines enable **change detection** — the most powerful signal for catching
140140

141141
```
142142
---AMIHACKED-SUMMARY-JSON---
143-
{"verdict":"CAUTION","critical":0,"warning":3,"info":12,"suppressed":0,"total":15,"duration":28.4,"reportPath":"...","version":"0.4.6"}
143+
{"verdict":"CAUTION","critical":0,"warning":3,"info":12,"suppressed":0,"total":15,"duration":28.4,"reportPath":"...","version":"0.4.7"}
144144
```
145145

146146
- Exit code reflects findings: **0** = clean, **1** = warnings only, **2** = critical findings detected

lib/Helpers.ps1

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,9 @@ function Compare-Baseline {
539539
} else {
540540
$baselineAge = " ($([math]::Floor($age.TotalHours))h ago)"
541541
}
542-
} catch {}
542+
} catch {
543+
Write-Verbose "Could not parse baseline timestamp: $_"
544+
}
543545

544546
Write-Status "Baseline: $($old.Timestamp)$baselineAge" -Color Gray
545547

@@ -605,7 +607,9 @@ function Compare-Baseline {
605607
-MITRE @("T1547.001")
606608
}
607609
}
608-
} catch {}
610+
} catch {
611+
Write-Verbose "Could not read Run key '$keyPath' for baseline comparison: $_"
612+
}
609613
}
610614

611615
Write-Status "Baseline comparison complete."

lib/ReportGenerator.ps1

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -745,10 +745,10 @@ function Generate-HtmlReport {
745745
</div>
746746
747747
<div class="filter-bar">
748-
<button class="filter-btn active" onclick="filterFindings('all')">All ($totalCount)</button>
749-
<button class="filter-btn" onclick="filterFindings('critical')">Critical ($critCount)</button>
750-
<button class="filter-btn" onclick="filterFindings('warning')">Warning ($warnCount)</button>
751-
<button class="filter-btn" onclick="filterFindings('info')">Info ($infoCount)</button>
748+
<button class="filter-btn active" onclick="filterFindings(this, 'all')">All ($totalCount)</button>
749+
<button class="filter-btn" onclick="filterFindings(this, 'critical')">Critical ($critCount)</button>
750+
<button class="filter-btn" onclick="filterFindings(this, 'warning')">Warning ($warnCount)</button>
751+
<button class="filter-btn" onclick="filterFindings(this, 'info')">Info ($infoCount)</button>
752752
</div>
753753
754754
${findingsHtml}
@@ -780,9 +780,9 @@ function Generate-HtmlReport {
780780
}
781781
}
782782
783-
function filterFindings(level) {
783+
function filterFindings(btn, level) {
784784
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
785-
event.target.classList.add('active');
785+
btn.classList.add('active');
786786
document.querySelectorAll('.finding').forEach(f => {
787787
f.style.display = (level === 'all' || f.dataset.severity === level) ? 'block' : 'none';
788788
});

modules/Check-Accounts.ps1

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,9 @@ function Invoke-AccountsChecks {
204204
} `
205205
-MITRE @("T1021.001")
206206
}
207-
} catch {}
207+
} catch {
208+
Write-Verbose "Could not read RDP session history: $_"
209+
}
208210

209211
# ── 5. Event Log Clearing Detection ──────────────────────────────────
210212

@@ -240,7 +242,9 @@ function Invoke-AccountsChecks {
240242
-MITRE @("T1070.001")
241243
}
242244
}
243-
} catch {}
245+
} catch {
246+
Write-Verbose "Could not check event log clearing events: $_"
247+
}
244248

245249
# ── 6. Credential Dumping Artifacts ──────────────────────────────────
246250

@@ -315,6 +319,8 @@ function Invoke-AccountsChecks {
315319
-Remediation "Enable LSA Protection: Set registry HKLM\SYSTEM\CurrentControlSet\Control\Lsa\RunAsPPL to 1 and reboot." `
316320
-MITRE @("T1003.001")
317321
}
318-
} catch {}
322+
} catch {
323+
Write-Verbose "Could not check LSA protection: $_"
324+
}
319325

320326
}

modules/Check-DefenseEvasion.ps1

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ function Invoke-DefenseEvasionChecks {
6161
-Details @{ Key = "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender"; Value = 1 } `
6262
-MITRE @("T1562.001")
6363
}
64-
} catch {}
64+
} catch {
65+
Write-Verbose "Could not check Defender DisableAntiSpyware policy: $_"
66+
}
6567

6668
$amsiDll = "$env:SystemRoot\System32\amsi.dll"
6769
if (Test-Path $amsiDll) {
@@ -87,7 +89,9 @@ function Invoke-DefenseEvasionChecks {
8789
-Remediation "Re-register Windows Defender as an AMSI provider. Run 'sfc /scannow' and ensure Defender is properly installed." `
8890
-MITRE @("T1562.001")
8991
}
90-
} catch {}
92+
} catch {
93+
Write-Verbose "Could not enumerate AMSI providers: $_"
94+
}
9195

9296
try {
9397
$amsiEnable = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows Script\Settings" -Name "AmsiEnable" -ErrorAction SilentlyContinue
@@ -99,7 +103,9 @@ function Invoke-DefenseEvasionChecks {
99103
-Details @{ Key = "HKLM:\SOFTWARE\Microsoft\Windows Script\Settings\AmsiEnable"; Value = 0 } `
100104
-MITRE @("T1562.001")
101105
}
102-
} catch {}
106+
} catch {
107+
Write-Verbose "Could not check AMSI Windows Script Settings: $_"
108+
}
103109

104110
try {
105111
$sbl = Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -ErrorAction SilentlyContinue
@@ -111,7 +117,9 @@ function Invoke-DefenseEvasionChecks {
111117
-Details @{ Key = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging\EnableScriptBlockLogging"; Value = "absent or 0" } `
112118
-MITRE @("T1562.002")
113119
}
114-
} catch {}
120+
} catch {
121+
Write-Verbose "Could not check ScriptBlockLogging policy: $_"
122+
}
115123

116124
# ── 3. Windows Defender Real-Time Protection ─────────────────────────
117125

@@ -169,7 +177,9 @@ function Invoke-DefenseEvasionChecks {
169177
-Details @{ CurrentValue = $etwSecurity.Start; ExpectedValue = 1 } `
170178
-MITRE @("T1562.002")
171179
}
172-
} catch {}
180+
} catch {
181+
Write-Verbose "Could not check ETW Security autologger: $_"
182+
}
173183

174184
try {
175185
$disabledLoggers = @(
@@ -186,7 +196,9 @@ function Invoke-DefenseEvasionChecks {
186196
-MITRE @("T1562.002")
187197
}
188198
}
189-
} catch {}
199+
} catch {
200+
Write-Verbose "Could not check ETW Application/System autologgers: $_"
201+
}
190202

191203
# ── 5. Tamper Protection Check ───────────────────────────────────────
192204

@@ -201,6 +213,8 @@ function Invoke-DefenseEvasionChecks {
201213
-Remediation "Enable Tamper Protection through Windows Security > Virus & threat protection settings." `
202214
-MITRE @("T1562.001")
203215
}
204-
} catch {}
216+
} catch {
217+
Write-Verbose "Could not check Defender TamperProtection: $_"
218+
}
205219

206220
}

modules/Check-FileSystem.ps1

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,7 @@ function Invoke-FileSystemChecks {
133133
} elseif ($hasValidSig) {
134134
$severity = "INFO"
135135
} elseif ($versionInfo -and (Test-IsTrustedCompany $versionInfo.CompanyName)) {
136-
if ($inTrustedDir) {
137-
$severity = "WARNING"
138-
} else {
139-
$severity = "WARNING"
140-
}
136+
$severity = "WARNING"
141137
} elseif (-not $hasValidSig) {
142138
if ($inTrustedDir) {
143139
$severity = "WARNING"
@@ -302,7 +298,9 @@ function Invoke-FileSystemChecks {
302298
-MITRE @("T1564.004")
303299
}
304300
}
305-
} catch {}
301+
} catch {
302+
Write-Verbose "Could not scan alternate data streams in $dir : $_"
303+
}
306304
}
307305

308306
if ($adsCount -eq 0) {
@@ -338,7 +336,9 @@ function Invoke-FileSystemChecks {
338336
} `
339337
-MITRE @("T1555.003","T1560.001")
340338
}
341-
} catch {}
339+
} catch {
340+
Write-Verbose "Could not scan browser profile '$profileDir': $_"
341+
}
342342
}
343343

344344
$stealerPatterns = @("passwords.txt", "credentials.txt", "wallets.txt", "cookies.txt", "autofill.txt", "credit_cards.txt")
@@ -356,7 +356,9 @@ function Invoke-FileSystemChecks {
356356
-MITRE @("T1555","T1005")
357357
}
358358
}
359-
} catch {}
359+
} catch {
360+
Write-Verbose "Could not check info-stealer artifacts in temp: $_"
361+
}
360362

361363
$walletPaths = @(
362364
"$env:APPDATA\Electrum\wallets",
@@ -379,7 +381,9 @@ function Invoke-FileSystemChecks {
379381
-Details @{ Path = $wp; FilesAccessed = $recentAccess.Count } `
380382
-MITRE @("T1005","T1555")
381383
}
382-
} catch {}
384+
} catch {
385+
Write-Verbose "Could not check wallet file access at '$wp': $_"
386+
}
383387
}
384388

385389
# ── 6. Persistence via Common Autorun Locations ──────────────────────
@@ -449,7 +453,44 @@ function Invoke-FileSystemChecks {
449453
-MITRE @("T1547.001")
450454
}
451455
}
452-
} catch {}
456+
} catch {
457+
Write-Verbose "Could not read autorun key '$key': $_"
458+
}
459+
}
460+
461+
# ── 6b. Startup Folder Executables ───────────────────────────────────
462+
463+
Write-Status "Checking startup folder contents..."
464+
465+
$startupFolders = @(
466+
"$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup",
467+
"$env:ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp"
468+
)
469+
$startupExtensions = @('.exe', '.bat', '.cmd', '.vbs', '.ps1', '.lnk')
470+
471+
foreach ($startupFolder in $startupFolders) {
472+
if (-not (Test-Path $startupFolder)) { continue }
473+
try {
474+
$startupItems = Get-ChildItem $startupFolder -File -ErrorAction SilentlyContinue |
475+
Where-Object { $startupExtensions -contains $_.Extension.ToLower() }
476+
477+
foreach ($item in $startupItems) {
478+
Add-Finding -Severity "WARNING" -Category "FileSystem" `
479+
-Title "Startup Folder Entry: $($item.Name)" `
480+
-Description "Found '$($item.Name)' in startup folder '$startupFolder'. Files placed here execute automatically at user logon. Verify this is a legitimate application." `
481+
-Remediation "If unexpected, remove: Remove-Item '$($item.FullName)'" `
482+
-Details @{
483+
Path = $item.FullName
484+
Folder = $startupFolder
485+
Size = Format-ByteSize $item.Length
486+
Modified = $item.LastWriteTime
487+
Created = $item.CreationTime
488+
} `
489+
-MITRE @("T1547.001")
490+
}
491+
} catch {
492+
Write-Verbose "Could not scan startup folder '$startupFolder': $_"
493+
}
453494
}
454495

455496
# ── 7. Advanced Persistence: IFEO, AppInit_DLLs, Winlogon ────────────
@@ -474,7 +515,9 @@ function Invoke-FileSystemChecks {
474515
-MITRE @("T1546.012")
475516
}
476517
}
477-
} catch {}
518+
} catch {
519+
Write-Verbose "Could not check IFEO debugger keys: $_"
520+
}
478521

479522
try {
480523
$appInitReg = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows" -ErrorAction SilentlyContinue
@@ -486,7 +529,9 @@ function Invoke-FileSystemChecks {
486529
-Details @{ DLLs = $appInitReg.AppInit_DLLs; LoadEnabled = $appInitReg.LoadAppInit_DLLs } `
487530
-MITRE @("T1546.010")
488531
}
489-
} catch {}
532+
} catch {
533+
Write-Verbose "Could not check AppInit_DLLs: $_"
534+
}
490535

491536
try {
492537
$winlogon = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -ErrorAction SilentlyContinue
@@ -510,7 +555,9 @@ function Invoke-FileSystemChecks {
510555
-MITRE @("T1547.004")
511556
}
512557
}
513-
} catch {}
558+
} catch {
559+
Write-Verbose "Could not check Winlogon keys: $_"
560+
}
514561

515562
# ── 8. COM Hijacking ─────────────────────────────────────────────────
516563

@@ -559,9 +606,13 @@ function Invoke-FileSystemChecks {
559606
} `
560607
-MITRE @("T1546.015")
561608
}
562-
} catch {}
609+
} catch {
610+
Write-Verbose "Could not inspect CLSID '$($clsid.PSChildName)': $_"
611+
}
563612
}
564-
} catch {}
613+
} catch {
614+
Write-Verbose "Could not enumerate HKCU COM CLSID keys: $_"
615+
}
565616

566617
# ── 9. WMI Persistence ───────────────────────────────────────────────
567618

@@ -635,7 +686,9 @@ function Invoke-FileSystemChecks {
635686
-MITRE @("T1546.003")
636687
}
637688
}
638-
} catch {}
689+
} catch {
690+
Write-Verbose "Could not enumerate WMI namespaces: $_"
691+
}
639692

640693
# ── 10. Scheduled Tasks Check ────────────────────────────────────────
641694

@@ -706,7 +759,9 @@ function Invoke-FileSystemChecks {
706759
-MITRE @("T1053.005")
707760
}
708761
}
709-
} catch {}
762+
} catch {
763+
Write-Verbose "Could not inspect task '$($task.TaskName)': $_"
764+
}
710765
}
711766
} catch {
712767
Write-Status "Could not enumerate scheduled tasks." -Color Yellow
@@ -722,7 +777,9 @@ function Invoke-FileSystemChecks {
722777
$apiTaskNames = @()
723778
try {
724779
$apiTaskNames = Get-ScheduledTask -ErrorAction SilentlyContinue | ForEach-Object { $_.TaskName }
725-
} catch {}
780+
} catch {
781+
Write-Verbose "Could not enumerate scheduled tasks via API: $_"
782+
}
726783

727784
function Walk-TaskCache {
728785
param([string]$Path, [string]$TaskPathPrefix)

0 commit comments

Comments
 (0)