From 0f15779472640a26082f50149bf764a34ee97780 Mon Sep 17 00:00:00 2001 From: mnerv <24420859+mnerv@users.noreply.github.com> Date: Tue, 3 Feb 2026 21:57:10 +0100 Subject: [PATCH] Add Jump Lists collection (Get-JumpLists.ps1) Collect Jump List artifacts showing recent files per application. Includes smart app detection via content scanning, LNK file enumeration with target extraction, and both automatic/custom destinations. Supports -ShowAll and -MaxPerApp parameters. Mark Jump Lists complete in TODO.md. --- TODO.md | 2 +- windows/Get-JumpLists.ps1 | 208 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 windows/Get-JumpLists.ps1 diff --git a/TODO.md b/TODO.md index 7d6de12..c550ad2 100644 --- a/TODO.md +++ b/TODO.md @@ -18,7 +18,7 @@ - [ ] UserAssist - Programs run by user through Windows Explorer - [ ] ShimCache (AppCompatCache) - Executable files that have been run - [ ] AmCache - Program execution with file hashes and timestamps -- [ ] Jump Lists - Recently accessed files per application +- [x] Jump Lists - Recently accessed files per application - [ ] Prefetch files - Program execution history with run counts - [ ] BAM/DAM - Background Activity Moderator (program execution timestamps) diff --git a/windows/Get-JumpLists.ps1 b/windows/Get-JumpLists.ps1 new file mode 100644 index 0000000..232bbcc --- /dev/null +++ b/windows/Get-JumpLists.ps1 @@ -0,0 +1,208 @@ +# Get-JumpLists.ps1 +# Lists Jump List artifacts showing recently accessed files per application + +param( + [int]$MaxPerApp = 10, + [switch]$ShowAll +) + +Write-Host "=== Jump Lists ===" -ForegroundColor Cyan +Write-Host "Recently accessed files per application`n" + +if ($ShowAll) { + $MaxPerApp = [int]::MaxValue +} + +# Jump List locations +$automaticDestinations = "$env:APPDATA\Microsoft\Windows\Recent\AutomaticDestinations" +$customDestinations = "$env:APPDATA\Microsoft\Windows\Recent\CustomDestinations" + +# Common AppIDs (application identifiers) +# Note: AppIDs are CRC-64 hashes of executable paths and vary between systems +# We'll rely primarily on content detection instead +$knownAppIDs = @{ + # Only including well-known, verified AppIDs + "1b4dd67f29cb1962" = "Internet Explorer" + "6d809377-6af0-444b-8957-a3773f02200e" = "Remote Desktop Connection" +} + +# Function to try identifying app from jump list content +function Get-AppNameFromJumpList { + param([string]$filePath) + + try { + # Try to read first few KB and look for common strings + $bytes = [System.IO.File]::ReadAllBytes($filePath) | Select-Object -First 8192 + $text = [System.Text.Encoding]::Unicode.GetString($bytes) + + # Look for common app identifiers in the content + if ($text -match 'chrome\.exe') { return "Google Chrome" } + if ($text -match 'firefox\.exe') { return "Mozilla Firefox" } + if ($text -match 'msedge\.exe') { return "Microsoft Edge" } + if ($text -match 'Code\.exe') { return "Visual Studio Code" } + if ($text -match 'WINWORD\.EXE') { return "Microsoft Word" } + if ($text -match 'EXCEL\.EXE') { return "Microsoft Excel" } + if ($text -match 'POWERPNT\.EXE') { return "Microsoft PowerPoint" } + if ($text -match 'notepad\+\+\.exe') { return "Notepad++" } + if ($text -match 'sublime_text\.exe') { return "Sublime Text" } + if ($text -match 'devenv\.exe') { return "Visual Studio" } + if ($text -match 'pycharm.*\.exe') { return "PyCharm" } + if ($text -match 'idea.*\.exe') { return "IntelliJ IDEA" } + if ($text -match 'vlc\.exe') { return "VLC Media Player" } + if ($text -match 'AcroRd.*\.exe') { return "Adobe Reader" } + if ($text -match '7zFM\.exe') { return "7-Zip" } + if ($text -match 'WindowsTerminal\.exe') { return "Windows Terminal" } + if ($text -match 'powershell\.exe') { return "Windows PowerShell" } + if ($text -match 'explorer\.exe') { return "File Explorer" } + + return $null + } catch { + return $null + } +} + +$totalFiles = 0 +$totalApps = 0 + +# Process AutomaticDestinations (automatically managed jump lists) +Write-Host "--- Automatic Destinations ---" -ForegroundColor Yellow +if (Test-Path $automaticDestinations) { + $autoJumpLists = Get-ChildItem -Path $automaticDestinations -Filter "*.automaticDestinations-ms" -ErrorAction SilentlyContinue + + if ($autoJumpLists) { + foreach ($jumpList in $autoJumpLists) { + # Extract AppID from filename + $appID = $jumpList.Name -replace '\.automaticDestinations-ms$', '' + + # Try to identify app from known AppIDs first + $appName = if ($knownAppIDs.ContainsKey($appID)) { + $knownAppIDs[$appID] + } else { + # Try to identify from file content + $detectedName = Get-AppNameFromJumpList -filePath $jumpList.FullName + if ($detectedName) { + "$detectedName (detected)" + } else { + "Unknown Application" + } + } + + Write-Host "`n$appName" -ForegroundColor Green + Write-Host " AppID: $appID" -ForegroundColor Gray + Write-Host " File: $($jumpList.Name)" -ForegroundColor Gray + Write-Host " Modified: $($jumpList.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Gray + Write-Host " Size: $($jumpList.Length) bytes" -ForegroundColor Gray + + # Note: Parsing .automaticDestinations-ms files requires complex OLE/compound file parsing + # This would need a specialized library or tool like JLECmd (Eric Zimmerman) + Write-Host " (Use JLECmd or similar tool for detailed parsing)" -ForegroundColor Cyan + + $totalApps++ + } + + Write-Host "`nTotal applications with jump lists: $totalApps" -ForegroundColor Green + } else { + Write-Host "No automatic destination jump lists found" -ForegroundColor Gray + } +} else { + Write-Host "AutomaticDestinations directory not found" -ForegroundColor Gray +} + +# Process CustomDestinations (manually pinned items) +Write-Host "`n--- Custom Destinations (Pinned Items) ---" -ForegroundColor Yellow +if (Test-Path $customDestinations) { + $customJumpLists = Get-ChildItem -Path $customDestinations -Filter "*.customDestinations-ms" -ErrorAction SilentlyContinue + + if ($customJumpLists) { + $pinnedApps = 0 + foreach ($jumpList in $customJumpLists) { + # Extract AppID from filename + $appID = $jumpList.Name -replace '\.customDestinations-ms$', '' + + # Try to identify app from known AppIDs first + $appName = if ($knownAppIDs.ContainsKey($appID)) { + $knownAppIDs[$appID] + } else { + # Try to identify from file content + $detectedName = Get-AppNameFromJumpList -filePath $jumpList.FullName + if ($detectedName) { + "$detectedName (detected)" + } else { + "Unknown Application" + } + } + + Write-Host "`n$appName" -ForegroundColor Green + Write-Host " AppID: $appID" -ForegroundColor Gray + Write-Host " File: $($jumpList.Name)" -ForegroundColor Gray + Write-Host " Modified: $($jumpList.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Gray + Write-Host " Size: $($jumpList.Length) bytes" -ForegroundColor Gray + Write-Host " (Contains user-pinned items)" -ForegroundColor Cyan + + $pinnedApps++ + } + + Write-Host "`nTotal applications with pinned items: $pinnedApps" -ForegroundColor Green + } else { + Write-Host "No custom destination jump lists found" -ForegroundColor Gray + } +} else { + Write-Host "CustomDestinations directory not found" -ForegroundColor Gray +} + +# Recent Items (LNK files) +Write-Host "`n--- Recent Items (LNK Files) ---" -ForegroundColor Yellow +$recentItems = "$env:APPDATA\Microsoft\Windows\Recent" + +if (Test-Path $recentItems) { + $lnkFiles = Get-ChildItem -Path $recentItems -Filter "*.lnk" -ErrorAction SilentlyContinue | + Sort-Object LastWriteTime -Descending + + if ($lnkFiles) { + Write-Host "Recent files accessed (via LNK shortcuts):`n" -ForegroundColor Cyan + + $count = 0 + foreach ($lnk in ($lnkFiles | Select-Object -First $MaxPerApp)) { + $count++ + $totalFiles++ + + Write-Host " $count. $($lnk.Name -replace '\.lnk$', '')" -ForegroundColor Green + Write-Host " Last Accessed: $($lnk.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Gray + Write-Host " Path: $($lnk.FullName)" -ForegroundColor Gray + + # Try to extract target path using Shell.Application + try { + $shell = New-Object -ComObject WScript.Shell + $shortcut = $shell.CreateShortcut($lnk.FullName) + if ($shortcut.TargetPath) { + Write-Host " Target: $($shortcut.TargetPath)" -ForegroundColor Cyan + } + [System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell) | Out-Null + } catch { + # Silently fail if COM object can't be created + } + } + + if ($lnkFiles.Count -gt $MaxPerApp) { + Write-Host "`n ... and $($lnkFiles.Count - $MaxPerApp) more" -ForegroundColor Gray + } + + Write-Host "`nTotal recent LNK files: $($lnkFiles.Count)" -ForegroundColor Green + } else { + Write-Host "No recent LNK files found" -ForegroundColor Gray + } +} else { + Write-Host "Recent items directory not found" -ForegroundColor Gray +} + +Write-Host "`n=== Summary ===" -ForegroundColor Cyan +Write-Host "Applications with jump lists: $totalApps" -ForegroundColor Green +Write-Host "Recent LNK files displayed: $totalFiles" -ForegroundColor Green + +Write-Host "`nNote: For detailed Jump List parsing, use specialized tools:" -ForegroundColor Yellow +Write-Host " - JLECmd (Eric Zimmerman): https://github.com/EricZimmerman/JLECmd" -ForegroundColor Cyan +Write-Host " - Autopsy with Jump List Analyzer plugin" -ForegroundColor Cyan +Write-Host " - Registry Explorer for viewing shellbags" -ForegroundColor Cyan + +Write-Host "`nJump List files are compound OLE documents requiring specialized parsing" -ForegroundColor Yellow +Write-Host "This script shows metadata; use JLECmd for full content extraction" -ForegroundColor Yellow