├── ForensicMiner ├── Modules │ └── PSSQlite.zip ├── 02-Analyze │ ├── 05-RecentItems.ps1 │ ├── 06-WiFiHistory.ps1 │ ├── 02-RunMRU.ps1 │ ├── 08-TypedPaths.ps1 │ ├── 03-MUICache.ps1 │ ├── 01-BAM.ps1 │ ├── 07-BrowserAnalyzer.ps1 │ └── 04-RecentDocs.ps1 ├── 01-Options │ ├── 03-Purge.ps1 │ ├── 01-ZIP.ps1 │ ├── 02-Menu.ps1 │ └── 04-Update.ps1 ├── 03-Collect │ ├── 01-SystemEvents.ps1 │ └── 02-BrowserHistory.ps1 └── ForensicMiner.ps1 ├── LICENSE.txt └── README.md /ForensicMiner/Modules/PSSQlite.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securityjoes/ForensicMiner/HEAD/ForensicMiner/Modules/PSSQlite.zip -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Eilay Yosfan (DFIR) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ForensicMiner/02-Analyze/05-RecentItems.ps1: -------------------------------------------------------------------------------- 1 | Write-Output "" 2 | New-Item -ItemType Directory -Force -Path C:\ForensicMiner\MyEvidence\05-RecentItems | Out-Null 3 | $RecentFileLocation = "\AppData\Roaming\Microsoft\Windows\Recent" 4 | $UsersPath = Get-ChildItem C:\Users -Exclude ("Public","TEMP","Default") -Directory 5 | 6 | foreach ($User in $UsersPath) { 7 | $RecentFilePath = Join-Path -Path $User.FullName -ChildPath $RecentFileLocation 8 | $RecentItems = Get-ChildItem $RecentFilePath -Exclude ('CustomDestinations','AutomaticDestinations')| Select-Object -First 300 | Where-Object { $_.Name.Length -le 90 } 9 | Write-Output "" 10 | Write-Output "Recent Files Touched By -> $($User.Name)" 11 | Write-Output "" 12 | $count = 1 13 | $RecentItems | Sort-Object -Property LastAccessTime -Descending | ForEach-Object { 14 | $line = "#$count $($_.LastAccessTime) $($_.Name)" 15 | $count++ 16 | $line 17 | } | Out-File -Force -FilePath "C:\ForensicMiner\MyEvidence\05-RecentItems\RecentItemsTouchedBy-$($User.Name).txt" 18 | 19 | Get-Content -Path "C:\ForensicMiner\MyEvidence\05-RecentItems\RecentItemsTouchedBy-$($User.Name).txt" 20 | } 21 | Write-Output "" 22 | Write-Output "+-------------------------------------------------------------+" 23 | Write-Output "|The record of this forensic evidence is saved on this machine|" 24 | Write-Output "+-------------------------------------------------------------+" 25 | Write-Output '| Path - "C:\ForensicMiner\MyEvidence\05-RecentItems" |' 26 | Write-Output "+-------------------------------------------------------------+" -------------------------------------------------------------------------------- /ForensicMiner/01-Options/03-Purge.ps1: -------------------------------------------------------------------------------- 1 | $Root_FM_Fodler = "C:\ForensicMiner\" 2 | 3 | if (Test-Path -Path $Root_FM_Fodler) { 4 | Write-Output "List of deleted files from root ForensicMiner folder" 5 | Write-Output "+--------------------------------------------------+" 6 | $files = Get-ChildItem -Path "$Root_FM_Fodler\*" 7 | $filesToDelete = @() 8 | 9 | foreach ($file in $files) { 10 | $fileInfo = [pscustomobject]@{ 11 | CreationTime = $file.CreationTime 12 | Name = $file.Name 13 | } 14 | $filesToDelete += $fileInfo 15 | } 16 | 17 | foreach ($fileInfo in $filesToDelete) { 18 | Write-Output ("Creation Time: {0}, Name: {1}" -f $fileInfo.CreationTime,$fileInfo.Name) 19 | Remove-Item -Path "$FolderRemove\$($fileInfo.Name)" -ErrorAction SilentlyContinue -Force -Recurse 20 | } 21 | # space 22 | Start-Sleep -Milliseconds 500 23 | Write-Output "" 24 | Write-Output "Purge Status" 25 | Write-Output "+----------+" 26 | Write-Output "[*] ForensicMiner has been successfully removed from this machine." 27 | } 28 | 29 | else { 30 | Write-Output "An error occurred while attempting to remove ForensicMiner" 31 | Write-Output "+--------------------------------------------------------+" 32 | Write-Output "[!] Root ForensicMiner Folder was not found under C:\ - please remove manually." 33 | Write-Output "[!] Verify if you running as Administrator, essential for proper removal." 34 | Write-Output "[!] Alternatively, check where did you installed ForensicMiner." 35 | } 36 | 37 | 38 | # space 39 | Write-Output "" 40 | 41 | cd .. 42 | $CurrentPath = Get-Location 43 | Write-Output "Terminal Path Change" 44 | Write-Output "+------------------+" 45 | Write-Output "[*] Current directory path is now $CurrentPath" 46 | 47 | # Double delete verify 48 | Start-Sleep -Seconds 1.5 49 | Remove-Item -Path "C:\ForensicMiner" -Force -Recurse -ErrorAction SilentlyContinue | Out-Null 50 | 51 | # secret dev option related 52 | Remove-Item "C:\Archive.zip" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 53 | 54 | # space 55 | Write-Output "" 56 | -------------------------------------------------------------------------------- /ForensicMiner/03-Collect/01-SystemEvents.ps1: -------------------------------------------------------------------------------- 1 | $hostname3 = hostname 2 | $targetDirectory = "C:\ForensicMiner\MyCollectedFiles\01-SystemEvents" 3 | $eventLogsPath = "C:\Windows\System32\winevt\Logs\*" 4 | New-Item -ItemType Directory -Path $targetDirectory -ErrorAction SilentlyContinue | Out-Null 5 | 6 | $filesCount = (Get-ChildItem -Path $eventLogsPath -File).Count 7 | Copy-Item -Path $eventLogsPath -Destination $targetDirectory -Force > $null 8 | 9 | Write-Output "$filesCount Windows event logs was found on $Hostname3!" 10 | Write-Output "Important Windows event logs check: (Found\Missing)" 11 | Write-Output "" 12 | Write-Output " Event Status" 13 | #Security.evtx 14 | if (Test-Path -Path "$targetDirectory\Security.evtx") { 15 | Write-Output "1. Security.evtx Found" 16 | } 17 | 18 | else { 19 | Write-Output "1. Security.evtx Missing" 20 | } 21 | 22 | #System.evtx 23 | if (Test-Path -Path "$targetDirectory\System.evtx") { 24 | Write-Output "2. System.evtx Found" 25 | } 26 | 27 | 28 | else { 29 | Write-Output "2. System.evtx Missing" 30 | } 31 | 32 | #Application.evtx 33 | if (Test-Path -Path "$targetDirectory\Application.evtx") { 34 | Write-Output "3. Application.evtx Found" 35 | } 36 | 37 | 38 | else { 39 | Write-Output "3. Application.evtx Missing" 40 | } 41 | 42 | #Windows PowerShell.evtx 43 | if (Test-Path -Path "$targetDirectory\Windows PowerShell.evtx") { 44 | Write-Output "4. Windows PowerShell.evtx Found" 45 | } 46 | 47 | 48 | else { 49 | Write-Output "4. Windows PowerShell.evtx Missing" 50 | } 51 | 52 | #Setup.evtx 53 | if (Test-Path -Path "$targetDirectory\Setup.evtx") { 54 | Write-Output "5. Setup.evtx Found" 55 | } 56 | 57 | 58 | else { 59 | Write-Output "5. Setup.evtx Missing" 60 | } 61 | Write-Output "" 62 | Write-Output "+-------------------------------------------------------------+" 63 | Write-Output "|The record of this forensic evidence is saved on this machine|" 64 | Write-Output "+-------------------------------------------------------------+" 65 | Write-Output '| Path - "C:\ForensicMiner\MyCollectedFiles\01-SystemEvents" |' 66 | Write-Output "+-------------------------------------------------------------+" -------------------------------------------------------------------------------- /ForensicMiner/01-Options/01-ZIP.ps1: -------------------------------------------------------------------------------- 1 | # path variables 2 | $Hostname = hostname 3 | $ZipFolderPath = "C:\ForensicMiner\MyZIP" 4 | $MyEvidence = "C:\ForensicMiner\MyEvidence" 5 | $MyCollectedFiles = "C:\ForensicMiner\MyCollectedFiles" 6 | $ZipFileName = "C:\ForensicMiner\MyZIP\$Hostname.zip" 7 | 8 | # ZIP status 9 | Write-Output "" 10 | Write-Output "ZIP Status" 11 | Write-Output "+--------+" 12 | 13 | # check if $ZipFolderPath already exist 14 | if (Test-Path -Path $ZipFolderPath) { 15 | Remove-Item -Path $ZipFolderPath -Forc -Recurse | Out-Null 16 | Start-Sleep -Milliseconds 300 17 | Write-Output "[*] Old MyZIP folder was successfully removed." 18 | } 19 | 20 | # check if MyZIP folder was created 21 | New-Item -ItemType Directory -Force -Path $ZipFolderPath | Out-Null 22 | if (Test-Path -Path $ZipFolderPath) { 23 | Start-Sleep -Milliseconds 300 24 | Write-Output "[*] MyZIP folder was successfully created." 25 | } 26 | else { 27 | Start-Sleep -Milliseconds 300 28 | Write-Output "[!] MyZIP folder failed to be cretaed, check terminal permissions." 29 | Start-Sleep -Milliseconds 300 30 | Write-Output "[!] Stopping ZIP process." 31 | Exit 32 | } 33 | 34 | # create and check $ZipFileName 35 | New-Item -Path $ZipFileName -Force | Out-Null 36 | if (Test-Path -Path $ZipFileName) { 37 | Start-Sleep -Milliseconds 300 38 | Write-Output "[*] $Hostname.zip was successfully created under MyZIP folder." 39 | } 40 | else { 41 | Start-Sleep -Milliseconds 300 42 | Write-Output "$Hostname.zip failed to be created undesr MyZIP folder." 43 | Start-Sleep -Milliseconds 300 44 | Write-Output "[!] Stopping ZIP process." 45 | Exit 46 | } 47 | 48 | if ((Get-ChildItem -Path $MyEvidence -Force).Count -ge 1) { 49 | Compress-Archive -Path $MyEvidence -DestinationPath $ZipFileName -Update 50 | Start-Sleep -Milliseconds 300 51 | Write-Output "[*] Adding MyEvidence to MyZIP folder." 52 | } 53 | 54 | else { 55 | Start-Sleep -Milliseconds 300 56 | Write-Output "[*] MyEvidence is empty." 57 | } 58 | 59 | if ((Get-ChildItem -Path $MyCollectedFiles -Force).Count -ge 1) { 60 | Compress-Archive -Path $MyCollectedFiles -DestinationPath $ZipFileName -Update 61 | Start-Sleep -Milliseconds 300 62 | Write-Output "[*] Adding MyCollectedFiles to MyZIP folder." 63 | } 64 | 65 | else { 66 | Start-Sleep -Milliseconds 300 67 | Write-Output "[*] MyCollectedFiles is empty." 68 | } 69 | 70 | Write-Output "[*] Your ZIP file is ready!" 71 | 72 | # Space 73 | Write-Output "" 74 | 75 | Write-Output "ZIP Path -> $ZipFileName" 76 | 77 | # Space 78 | Write-Output "" -------------------------------------------------------------------------------- /ForensicMiner/03-Collect/02-BrowserHistory.ps1: -------------------------------------------------------------------------------- 1 | Write-Output "" 2 | New-Item -ItemType Directory -Force -Path C:\ForensicMiner\MyCollectedFiles\02-BrowserHistory | Out-Null 3 | $UsersPath = Get-ChildItem C:\Users -Exclude ("Public","TEMP") -Directory 4 | $BrowserPaths = @{ 5 | "Chrome" = "\AppData\Local\Google\Chrome\User Data\Default\History" 6 | "Brave" = "AppData\Local\BraveSoftware\Brave-Browser\User Data\Default\History" 7 | "Firefox" = "AppData\Roaming\Mozilla\Firefox\Profiles\*\places.sqlite" 8 | "Edge" = "AppData\Local\Microsoft\Edge\User Data\Default\History" 9 | "Opera" = "AppData\Roaming\Opera Software\Opera Stable\History" 10 | } 11 | $UsersWithoutBrowser = @() 12 | $DestinationFolder = "C:\ForensicMiner\MyCollectedFiles\02-BrowserHistory" 13 | Write-Output "User Installed Browser" 14 | Write-Output "----------------------" 15 | if (-not (Test-Path $DestinationFolder)) { 16 | New-Item -ItemType Directory -Path $DestinationFolder | Out-Null 17 | } 18 | 19 | foreach ($User in $UsersPath) { 20 | $InstalledBrowsers = @() 21 | foreach ($Browser in $BrowserPaths.Keys) { 22 | $CompleteBrowserPath = Join-Path -Path $User.FullName -ChildPath $BrowserPaths[$Browser] 23 | if (Test-Path $CompleteBrowserPath) { 24 | $InstalledBrowsers += $Browser.ToLower() 25 | $DestinationPath = Join-Path -Path $DestinationFolder -ChildPath "$($User.Name)_$Browser.sqlite" 26 | Copy-Item -Path $CompleteBrowserPath -Destination $DestinationPath -Force 27 | } 28 | } 29 | 30 | if ($InstalledBrowsers.Count -gt 0) { 31 | Write-Output "$($User.Name) - has history files of - $($InstalledBrowsers -join ', ')." 32 | } else { 33 | $UsersWithoutBrowser += $User.Name 34 | } 35 | } 36 | 37 | if ($UsersWithoutBrowser.Count -gt 0) { 38 | Write-Output "" 39 | Write-Output "#No Browser Found:" 40 | Write-Output "The following users do not have a browser installed: $($UsersWithoutBrowser -join ', ')." 41 | } 42 | Write-Output "" 43 | Write-Output "+-------------------------------------------------------------+" 44 | Write-Output "|The record of this forensic evidence is saved on this machine|" 45 | Write-Output "+-------------------------------------------------------------+" 46 | Write-Output '| Path - "C:\ForensicMiner\MyCollectedFiles\02-BrowserHistory"|' 47 | Write-Output "+-------------------------------------------------------------+" 48 | Write-Output "| Compatible with: Chrome, Brave, Firefox, Edge, Opera. |" 49 | Write-Output "+-------------------------------------------------------------+" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ForensicMiner v1.4 2 | ###### "ForensicMiner, Redefine DFIR Automations" 3 | ![Banner](https://github.com/YosfanEilay/ForensicMiner/assets/132997318/72d572fc-2f43-48dd-a16b-1b545eb6aad6) 4 | ###### Created & Maintained by: [Eilay Yosfan](https://github.com/YosfanEilay#-eilay-yosfan) 5 | 6 | ## What is ForensicMiner ? 7 | ForensicMiner, a PowerShell-based DFIR automation tool, revolutionizes the field of digital investigations. 8 | Designed for efficiency, it automates artifact and evidence collection from Windows machines. Compatibility 9 | with Flacon Crowdstrike RTR and Palo Alto Cortex XDR Live Terminal, along with its swift performance and 10 | user-friendly interface, makes ForensicMiner an indispensable asset for investigators navigating the complexities 11 | of forensic analysis. Streamlined and effective, this tool sets a new standard in the realm of digital forensics. 12 | 13 | ## How To Install ? 14 | ![How To Install](https://github.com/YosfanEilay/ForensicMiner/assets/132997318/36c30bc3-c9f1-49f7-a3ac-b56c01e53dd1) 15 | 16 | #### Know This Before Installation 17 | * Always install ForensicMiner on "C:\" drive. 18 | * Always run ForensicMiner as administrator, if not, some things may not work properly. 19 | * Don't run the tool using Windows PowerShell (x86)! if you do, some things may not work properly. 20 | * Make sure your PowerShell Execution Policy is on Bypass, if not, scripts could not run on your system. 21 | * For more information use this PS Execution Policy Guide - https://www.youtube.com/watch?v=L0fgZ0FJIv0 22 | 23 | #### Installation Process - Text Guide 24 | 1. In this GitHub repository, click on "<> Code," and then select "Download ZIP." 25 | 2. Extract "ForensicMiner" folder from "ForensicMiner-main.zip". 26 | 3. Move "ForensicMiner" folder to C:\\ drive. 27 | 5. That's it! ForensicMiner is now installed. Enjoy 28 | 29 | #### Installation Process - Video Guide 30 | https://github.com/YosfanEilay/ForensicMiner/assets/132997318/e163abfe-0a60-4181-806a-2426cbe26711 31 | 32 | ### How To Install On Falcon Crowdstrike ? 33 | #### Installation Process On - Falcon Crowdstrike RTR - Video Guide 34 | https://github.com/YosfanEilay/ForensicMiner/assets/132997318/c0be8264-fc0f-47fc-83ad-fe3e5edf5056 35 | 36 | ### How To Install On Palo Alto Cortex XDR ? 37 | ### Installation Process On - Palo Alto Cortex XDR - Video Guide 38 | https://github.com/YosfanEilay/ForensicMiner/assets/132997318/397f3e3c-d271-4fd3-8ed5-2072a28d1395 39 | 40 | ## Quick Start Guide - How To Use ForensicMiner ? 41 | https://github.com/YosfanEilay/ForensicMiner/assets/132997318/0f32bc7c-b4fe-4ac5-88cb-09ea701878bd 42 | After installing ForensicMiner on the machine using the execution of "FM-Extractor.ps1"
43 | A new folder should be created on the "C:\" drive, called "ForensicMiner".
44 |
45 | Navigate to This folder using the following command: 46 | ``` 47 | PS C:\> cd ForensicMiner 48 | ``` 49 | And now you can execute ForensicMiner menu page to view all available features and options using this command: 50 | ``` 51 | PS C:\ForensicMiner> .\ForensicMiner.ps1 -O Menu 52 | ``` 53 | #### Show Menu - Video Guide 54 | https://github.com/YosfanEilay/ForensicMiner/assets/132997318/163c6656-cc14-439c-bc7a-f775d175dd73 55 | 56 | ### Running Feature Example - RunMRU 57 | In this example you will see how ForensicMiner manage to collect all the Run.exe execution history
58 | of all the users (Online or Offline) in the machine and log them under "C:\ForensicMiner\MyEvidence" 59 | 60 | https://github.com/YosfanEilay/ForensicMiner/assets/132997318/043674b4-20ca-45e2-9ca6-f2218350862a 61 | 62 | ## Credits Section 63 | | Name | Why is the credit ? | 64 | | ------------------------------------ | -------------------------------------------- | 65 | | Ido Naor, Security Joes CEO | For supporting this project | 66 | | Warren Frame (RamblingCookieMonster) | Using Warre's PSSQLite in ForensicMiner | 67 | | Jan Moronia & Felipe Duarte | Helping to manage time spent on this project | 68 | | Nir Avron | For letting me test on his machine | 69 | -------------------------------------------------------------------------------- /ForensicMiner/01-Options/02-Menu.ps1: -------------------------------------------------------------------------------- 1 | Write-Output "┌> How To Run Example: ForensicMiner.ps1 -O ZIP" 2 | Write-Output "├~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~╮" 3 | Write-Output "│ Options (-O) │" 4 | Write-Output "├~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~┤" 5 | Write-Output "│ │" 6 | Write-Output "│1. ZIP ZIP evidence you gathered from Forensic Miner tool │" 7 | Write-Output "│ │" 8 | Write-Output "│2. Menu Show menu of whatyou can do with Forensic Miner tool │" 9 | Write-Output "│ │" 10 | Write-Output "│3. Purge Purge Forensic Miner tool footprint from this host │" 11 | Write-Output "│ │" 12 | Write-Output "│4. Update Update Forensic Miner to the latest version │" 13 | Write-Output "│ │" 14 | Write-Output "╰~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~╯" 15 | Write-Output "" 16 | Write-Output "┌> How To Run Example: ForensicMiner.ps1 -A RunMRU" 17 | Write-Output "├~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~╮" 18 | Write-Output "│ Analyze (-A) │" 19 | Write-Output "├~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~┤" 20 | Write-Output "│ │" 21 | Write-Output '│0. Harvest Harvest all "Analyze" table features │' 22 | Write-Output "│ │" 23 | Write-Output "│1. BAM Get all users evidence of executions using BAM.sys │" 24 | Write-Output "│ │" 25 | Write-Output "│2. RunMRU Get record all users history of Run.exe │" 26 | Write-Output "│ │" 27 | Write-Output "│3. MUICache Get record of Applications\Tools Installed\Run by users │" 28 | Write-Output "│ │" 29 | Write-Output "│4. RecentDocs Get processed and fillterd RecentDocs artifact all users │" 30 | Write-Output "│ │" 31 | Write-Output "│5. RecentItems Get list of all the users RecentItems folder │" 32 | Write-Output "│ │" 33 | Write-Output "│6. WiFiHistory Get information record of Wi-Fi History\Activity\Settings │" 34 | Write-Output "│ │" 35 | Write-Output "│7. BrowserAnalyzer Get analyzed information on all users browsers │" 36 | Write-Output "│ │" 37 | Write-Output "│8. TypedPaths Get record of Explorer.exe TypedPaths │" 38 | Write-Output "│ │" 39 | Write-Output "╰~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~╯" 40 | Write-Output "" 41 | Write-Output "┌> How To Run Example: ForensicMiner.ps1 -C BrowserHistory" 42 | Write-Output "├~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~╮" 43 | Write-Output "│ Collect Artifacts (-C) │" 44 | Write-Output "├~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~┤" 45 | Write-Output "│ │" 46 | Write-Output "│1. SystemEvents Collect all windows system events from this host │" 47 | Write-Output "│ │" 48 | Write-Output "│2. BrowserHistory Collect history files from all installed browsers │" 49 | Write-Output "│ │" 50 | Write-Output "╰~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~╯" 51 | Write-Output "" 52 | -------------------------------------------------------------------------------- /ForensicMiner/01-Options/04-Update.ps1: -------------------------------------------------------------------------------- 1 | # making sure 2 | Remove-Item "C:\ForensicMiner-main" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 3 | Remove-Item "C:\ForensicMiner.zip" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 4 | 5 | # process title 6 | Write-Output "ForensicMiner Update Process" 7 | Write-Output "+--------------------------+" 8 | Start-Sleep -Milliseconds 300 9 | Write-Output "[*] Checking connection to GitHub." 10 | 11 | # GitHub domain variable 12 | $GitHub = "GitHub.com" 13 | 14 | # test conection to GitHub domain 15 | $ConnectionStatus = Test-Connection -ComputerName $GitHub -Count 2 -ErrorAction SilentlyContinue | Select-Object -Property * 16 | 17 | # statment to check if the there is connection to GitHub or not 18 | if ($ConnectionStatus) { 19 | Start-Sleep -Milliseconds 300 20 | Write-Output "[*] GitHub is reachable." 21 | } 22 | 23 | # execute this if connection to GitHub is NOT reachable 24 | else { 25 | Start-Sleep -Milliseconds 150 26 | Write-Output "[!] GitHub is NOT reachable." 27 | Start-Sleep -Milliseconds 150 28 | Write-Output "[!] Please check your internet connection." 29 | Start-Sleep -Milliseconds 150 30 | Write-Output "[!] Update failed." 31 | exit 32 | } 33 | 34 | # write that ForensicMiner-main.zip is now downloading 35 | Start-Sleep -Milliseconds 300 36 | Write-Output "[*] Downloading the latest ForensicMiner." 37 | 38 | # invoke a web request to download the latest ForensicMiner ZIP file 39 | Invoke-WebRequest https://github.com/YosfanEilay/ForensicMiner/archive/main/ForensicMiner.zip -OutFile C:\ForensicMiner.zip 40 | 41 | # if statment to check if download completed successfully 42 | if (Test-Path -Path "C:\ForensicMiner.zip"){ 43 | Start-Sleep -Milliseconds 300 44 | Write-Output "[*] Download completed successfully." 45 | } 46 | 47 | # new file was not found after download under C:\ drive. 48 | else { 49 | Start-Sleep -Milliseconds 150 50 | Write-Output "[!] New ForensicMiner was not found under C:\ drive." 51 | Start-Sleep -Milliseconds 150 52 | Write-Output "[!] Update failed." 53 | exit 54 | } 55 | 56 | # ForensicMiner root folder path variable 57 | $RootForensicMienr = "C:\ForensicMiner" 58 | 59 | # check if ForensicMiner root folder is under C:\ForensicMiner 60 | if (Test-Path -Path $RootForensicMienr) { 61 | Write-Output "[*] Old ForensicMiner was found under C:\ drive." 62 | } 63 | 64 | # if ForensicMiner root folder is NOT under C:\ForensicMiner 65 | else { 66 | Start-Sleep -Milliseconds 150 67 | Write-Output "[!] Old ForensicMiner was NOT found under C:\ drive." 68 | Start-Sleep -Milliseconds 150 69 | Write-Output "[!] ForensicMiner has to be installed under C:\ drive." 70 | Start-Sleep -Milliseconds 150 71 | Write-Output "[!] Update failed." 72 | exit 73 | } 74 | 75 | # move back 1 time to be able to remove ForensicMiner root folder 76 | cd .. 77 | 78 | # delete ForensicMiner root folder 79 | Start-Sleep -Milliseconds 300 80 | Write-Output "[*] Removing old ForensicMiner" 81 | Remove-Item $RootForensicMienr -Force -Recurse -ErrorAction SilentlyContinue | Out-Null 82 | 83 | # check if deletion was complete successfully 84 | if (Test-Path -Path $RootForensicMienr) { 85 | Start-Sleep -Milliseconds 150 86 | Write-Output "[!] Failed to remove old ForensicMiner." 87 | Start-Sleep -Milliseconds 150 88 | Write-Output "[!] Update failed." 89 | exit 90 | } 91 | 92 | # if remove was successfull execute this else. 93 | else { 94 | Start-Sleep -Milliseconds 300 95 | Write-Output "[*] Remove completed successfully." 96 | } 97 | 98 | # extract relevent folder from the ZIP 99 | Expand-Archive -Path "C:\ForensicMiner.zip" -DestinationPath "C:\" 100 | 101 | if (Test-Path -Path "C:\ForensicMiner-main") { 102 | Start-Sleep -Milliseconds 300 103 | Write-Output "[*] Extracting new ForensicMiner completed successfully." 104 | } 105 | 106 | else { 107 | Start-Sleep -Milliseconds 150 108 | Write-Output "[!] Failed to extract new ForensicMiner." 109 | Start-Sleep -Milliseconds 150 110 | Write-Output "[!] Update failed." 111 | exit 112 | } 113 | 114 | # move new forensicminer to c:\ from ForensicMiner-main 115 | Move-Item -Path "C:\ForensicMiner-main\ForensicMiner" -Destination "C:\" -Force 116 | 117 | if (Test-Path -Path "C:\ForensicMiner") { 118 | Start-Sleep -Milliseconds 300 119 | Write-Output "[*] New ForensicMiner are in place." 120 | Start-Sleep -Milliseconds 300 121 | Write-Output "[*] Update completed successfully." 122 | cd "C:\ForensicMiner" 123 | } 124 | 125 | else { 126 | Write-Output "[!] New ForensicMiner root folder not found." 127 | Start-Sleep -Milliseconds 150 128 | Write-Output "[!] Update failed." 129 | exit 130 | } 131 | 132 | # remove package from C:\ 133 | Remove-Item "C:\ForensicMiner-main" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 134 | Remove-Item "C:\ForensicMiner.zip" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 135 | Write-Output "" -------------------------------------------------------------------------------- /ForensicMiner/ForensicMiner.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | # Options 3 | [Parameter(Mandatory = $false)] 4 | [ValidateSet('Menu','ZIP','Purge','Update')] 5 | [string]$O, 6 | 7 | # Analyze 8 | [Parameter(Mandatory = $false)] 9 | [ValidateSet('RecentItems','WiFiHistory','BAM','RunMRU','RecentDocs','MUICache','BrowserAnalyzer','Harvest','TypedPaths')] 10 | [string]$A, 11 | 12 | # Collect 13 | [Parameter(Mandatory = $false)] 14 | [ValidateSet('BrowserHistory','SystemEvents')] 15 | [string]$C 16 | 17 | ) 18 | 19 | # Variable to record from where the Forensic Miner is running (for the dot sourcing) 20 | $RunningPath = Get-Location 21 | 22 | #Create the "C:\ForensicMiner\MyEvidence" folder. 23 | New-Item -ItemType Directory -Force -Path C:\ForensicMiner\MyEvidence | Out-Null 24 | 25 | #Create the "C:\ForensicMiner\MyCollectedFiles" folder. 26 | New-Item -ItemType Directory -Force -Path C:\ForensicMiner\MyCollectedFiles | Out-Null 27 | 28 | # current script version 29 | $CurrentVersion = "v1.4" 30 | 31 | # test conection to GitHub domain 32 | $ConnectionStatus = Test-Connection -ComputerName "GitHub.com" -Count 1 -ErrorAction SilentlyContinue 33 | 34 | # statment to check if the there is connection to GitHub or not 35 | if ($ConnectionStatus) { 36 | $ConnectionFlag = "True" 37 | 38 | # GitHub API URL for the repository releases 39 | $FM_URL = "https://api.github.com/repos/YosfanEilay/ForensicMiner/releases/latest" 40 | 41 | # Use Invoke-RestMethod to make a GET request to the GitHub API 42 | $response = Invoke-RestMethod -Uri $FM_URL -Method Get -ErrorAction Continue 43 | 44 | # Extract the version number from the response 45 | $Latestversion = $response.tag_name 46 | 47 | } 48 | 49 | # execute this if connection to GitHub is NOT reachable 50 | else { 51 | $ConnectionFlag = "False" 52 | } 53 | 54 | Write-Output "" 55 | Write-Output "███████╗ ██████╗ ██████╗ ███████╗███╗ ██╗███████╗██╗ ██████╗" 56 | Write-Output "██╔════╝██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔════╝██║██╔════╝" 57 | Write-Output "█████╗ ██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████╗██║██║" 58 | Write-Output "██╔══╝ ██║ ██║██╔══██╗██╔══╝ ██║╚██╗██║╚════██║██║██║" 59 | Write-Output "██║ ╚██████╔╝██║ ██║███████╗██║ ╚████║███████║██║╚██████╗" 60 | Write-Output "╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═════╝" 61 | Write-Output "" 62 | Write-Output " ███╗ ███╗██╗███╗ ██╗███████╗██████╗" 63 | Write-Output " ████╗ ████║██║████╗ ██║██╔════╝██╔══██╗" 64 | Write-Output " ██╔████╔██║██║██╔██╗ ██║█████╗ ██████╔╝" 65 | Write-Output " ██║╚██╔╝██║██║██║╚██╗██║██╔══╝ ██╔══██╗" 66 | Write-Output " ██║ ╚═╝ ██║██║██║ ╚████║███████╗██║ ██║" 67 | Write-Output " ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝" 68 | 69 | if ($ConnectionFlag -eq "True") { 70 | # if statment to comper versions 71 | if ($CurrentVersion -eq $Latestversion) { 72 | Write-Output " You are using the latest version $CurrentVersion" 73 | Write-Output " No update is required." 74 | } 75 | 76 | else { 77 | Write-Output " Update Available: You are using version $CurrentVersion" 78 | Write-Output " The latest version is $latestVersion" 79 | Write-Output " Update is required." 80 | } 81 | } 82 | 83 | else { 84 | Write-Output "" 85 | Write-Output " Version: $CurrentVersion" 86 | } 87 | 88 | # space 89 | Write-Output "" 90 | 91 | switch ($O) { 92 | 'ZIP' { 93 | . $RunningPath\01-Options\01-ZIP.ps1 94 | } 95 | 'Menu' { 96 | . $RunningPath\01-Options\02-Menu.ps1 97 | } 98 | 'Purge' { 99 | . $RunningPath\01-Options\03-Purge.ps1 100 | } 101 | 'Update' { 102 | . $RunningPath\01-Options\04-Update.ps1 103 | } 104 | } 105 | 106 | switch ($A) { 107 | 'Harvest' { 108 | . $RunningPath\02-Analyze\01-BAM.ps1 109 | Start-Sleep -Milliseconds 500 110 | . $RunningPath\02-Analyze\02-RunMRU.ps1 111 | Start-Sleep -Milliseconds 500 112 | . $RunningPath\02-Analyze\03-MUICache.ps1 113 | Start-Sleep -Milliseconds 500 114 | . $RunningPath\02-Analyze\04-RecentDocs.ps1 115 | Start-Sleep -Milliseconds 500 116 | . $RunningPath\02-Analyze\05-RecentItems.ps1 117 | Start-Sleep -Milliseconds 500 118 | . $RunningPath\02-Analyze\06-WiFiHistory.ps1 119 | Start-Sleep -Milliseconds 500 120 | . $RunningPath\02-Analyze\07-BrowserAnalyzer.ps1 121 | Start-Sleep -Milliseconds 500 122 | . $RunningPath\02-Analyze\08-TypedPaths.ps1 123 | } 124 | 'BAM' { 125 | . $RunningPath\02-Analyze\01-BAM.ps1 126 | } 127 | 'RunMRU' { 128 | . $RunningPath\02-Analyze\02-RunMRU.ps1 129 | } 130 | 'MUICache' { 131 | . $RunningPath\02-Analyze\03-MUICache.ps1 132 | } 133 | 'RecentDocs' { 134 | . $RunningPath\02-Analyze\04-RecentDocs.ps1 135 | } 136 | 'RecentItems' { 137 | . $RunningPath\02-Analyze\05-RecentItems.ps1 138 | } 139 | 'WiFiHistory' { 140 | . $RunningPath\02-Analyze\06-WiFiHistory.ps1 141 | } 142 | 'BrowserAnalyzer' { 143 | . $RunningPath\02-Analyze\07-BrowserAnalyzer.ps1 144 | } 145 | 'TypedPaths' { 146 | . $RunningPath\02-Analyze\08-TypedPaths.ps1 147 | } 148 | } 149 | 150 | 151 | switch ($C) { 152 | 'SystemEvents' { 153 | . $RunningPath\03-Collect\01-SystemEvents.ps1 154 | } 155 | 'BrowserHistory' { 156 | . $RunningPath\03-Collect\02-BrowserHistory.ps1 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /ForensicMiner/02-Analyze/06-WiFiHistory.ps1: -------------------------------------------------------------------------------- 1 | #Check if "WiFiHistory" exist. 2 | $folderPath = "C:\ForensicMiner\MyEvidence\06-WiFiHistory" 3 | if (Test-Path $folderPath) { 4 | Remove-Item $folderPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 5 | } 6 | 7 | $Hostname2 = hostname 8 | $outputFilePath = "C:\ForensicMiner\MyEvidence\06-WiFiHistory\WiFiHistory-of-$Hostname2.txt" 9 | New-Item -ItemType Directory -Force -Path "C:\ForensicMiner\MyEvidence\06-WiFiHistory" | Out-Null 10 | Write-Output "#################### Wi-Fi Security Details ####################" | Tee-Object -FilePath $outputFilePath -Append 11 | Write-Output "" | Tee-Object -FilePath $outputFilePath -Append 12 | $profiles = netsh wlan show profiles | Select-String "All User Profile\s+:\s+(.+)" 13 | 14 | foreach ($profile in $profiles) { 15 | $wifiName = $profile.Matches.Groups[1].Value 16 | 17 | Write-Output "Wi-Fi Name(SSID): $wifiName" | Tee-Object -FilePath $outputFilePath -Append 18 | 19 | $profileInfo1 = netsh wlan show profile name="$wifiName" key=clear | Select-String "Key Content\s+:\s+(.+)" 20 | $profileInfo2 = netsh wlan show profile name="$wifiName" key=clear | Select-String "Authentication\s+:\s+(.+)" 21 | 22 | if ($profileInfo1) { 23 | $keyContent = $profileInfo1.Matches.Groups[1].Value 24 | Write-Output "Wi-Fi password: $keyContent" | Tee-Object -FilePath $outputFilePath -Append 25 | } else { 26 | Write-Output "Wi-Fi password: No Password" | Tee-Object -FilePath $outputFilePath -Append 27 | } 28 | 29 | if ($profileInfo2) { 30 | $authentication = $profileInfo2.Matches.Groups[1].Value 31 | Write-Output "Wi-Fi security protocol: $authentication" | Tee-Object -FilePath $outputFilePath -Append 32 | } else { 33 | Write-Output "Wi-Fi security protocol: No Security Protocol" | Tee-Object -FilePath $outputFilePath -Append 34 | } 35 | 36 | Write-Output "" | Tee-Object -FilePath $outputFilePath -Append 37 | } 38 | 39 | Write-Output "#################### Last Wi-Fi Connection ####################" | Tee-Object -FilePath $outputFilePath -Append 40 | Write-Output "" | Tee-Object -FilePath $outputFilePath -Append 41 | # Specify the parent registry path and value names 42 | $parentPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles" 43 | $dateLastConnectedValueName = "DateLastConnected" 44 | $profileNameValueName = "ProfileName" 45 | 46 | # Get all subkeys under the parent path 47 | $subkeys = Get-ChildItem -Path $parentPath 48 | 49 | # Function to swap the position of every 2 hexadecimal characters within a 4-character block 50 | function SwapHexChars ($hexValue) { 51 | $swappedValue = "" 52 | $hexArray = $hexValue -split " " 53 | 54 | foreach ($block in $hexArray) { 55 | $swappedBlock = "" 56 | for ($i = 0; $i -lt $block.Length; $i += 4) { 57 | $swappedChars = $block.Substring($i + 2,2) + $block.Substring($i,2) 58 | $swappedBlock += $swappedChars 59 | } 60 | $swappedValue += $swappedBlock + " " 61 | } 62 | 63 | return $swappedValue.Trim() 64 | } 65 | 66 | # Iterate through each subkey and retrieve the values of the specified properties 67 | foreach ($subkey in $subkeys) { 68 | $dateLastConnectedValue = Get-ItemPropertyValue -Path $subkey.PSPath -Name $dateLastConnectedValueName 69 | $profileNameValue = Get-ItemPropertyValue -Path $subkey.PSPath -Name $profileNameValueName 70 | 71 | $hexValue = [System.BitConverter]::ToString($dateLastConnectedValue).Replace("-","") 72 | 73 | $formattedHexValue = "" 74 | for ($i = 0; $i -lt $hexValue.Length; $i += 4) { 75 | if ($i -gt 0) { 76 | $formattedHexValue += " " 77 | } 78 | $formattedHexValue += $hexValue.Substring($i,4) 79 | } 80 | 81 | $formattedHexValue = SwapHexChars $formattedHexValue 82 | 83 | $hexValue = $formattedHexValue 84 | 85 | # Split the hex value into individual parts 86 | $hexParts = $hexValue -split ' ' 87 | 88 | # Convert each hex part to decimal 89 | $decimalParts = foreach ($part in $hexParts) { 90 | $decimal = [convert]::ToInt32($part,16) 91 | $decimal 92 | } 93 | 94 | # Extract the date and time components 95 | $year = $decimalParts[0] 96 | $month = $decimalParts[1] 97 | $dayOfWeek = $decimalParts[2] 98 | $dayOfMonth = $decimalParts[3] 99 | $hour = $decimalParts[4] 100 | $minutes = $decimalParts[5] 101 | $seconds = $decimalParts[6] 102 | $thousandths = $decimalParts[7] 103 | 104 | # Create a DateTime object using the extracted components 105 | $date = Get-Date -Year $year -Month $month -Day $dayOfMonth -Hour $hour -Minute $minutes -Second $seconds 106 | 107 | # Format the final complete date including the time 108 | $finalDate = $date.ToString("dd/MM/yyyy HH:mm:ss") 109 | 110 | # Print the final complete date 111 | Write-Output "Wi-Fi Name (SSID): $profileNameValue" | Tee-Object -FilePath $outputFilePath -Append 112 | Write-Output "Last Wi-Fi Connection: $finalDate" | Tee-Object -FilePath $outputFilePath -Append 113 | Write-Output "" | Tee-Object -FilePath $outputFilePath -Append 114 | 115 | } 116 | Write-Output "#################### End of Wi-Fi History ####################" | Tee-Object -FilePath $outputFilePath -Append 117 | Write-Output "" 118 | Write-Output "+-------------------------------------------------------------+" 119 | Write-Output "|The record of this forensic evidence is saved on this machine|" 120 | Write-Output "+-------------------------------------------------------------+" 121 | Write-Output '| Path - "C:\ForensicMiner\MyEvidence\06-WiFiHistory" |' 122 | Write-Output "+-------------------------------------------------------------+" -------------------------------------------------------------------------------- /ForensicMiner/02-Analyze/02-RunMRU.ps1: -------------------------------------------------------------------------------- 1 | #Check if "RunMRU-History" exists. 2 | $folderPath = "C:\ForensicMiner\MyEvidence\02-RunMRU-History" 3 | if (Test-Path $folderPath) { 4 | Remove-Item $folderPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 5 | } 6 | 7 | #Create the "RunMRU-History" folder. 8 | New-Item -ItemType Directory -Force -Path "C:\ForensicMiner\MyEvidence\02-RunMRU-History" | Out-Null 9 | 10 | #Define the variable path to RunMRU 11 | $RunMRU = "Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU" 12 | 13 | # Define the variable path to NTUSER.DAT 14 | $NTUSER = "\NTUSER.DAT" 15 | 16 | # Define and exclude the relevant users for the foreach loop 17 | $Users = Get-ChildItem C:\Users -Exclude ("Public","TEMP","Default") -Directory 18 | 19 | # Use foreach loop to name the hives 20 | foreach ($user in $Users) { 21 | 22 | # Define full NTUSER.DAT path for each user 23 | $NTUSER_PATH = Join-Path -Path $User.FullName -ChildPath $NTUSER 24 | 25 | # Name of each user on the system without the "Name" column 26 | $OnlyUserName = $user | Select-Object -Property Name | ForEach-Object { $_.Name } 27 | 28 | #Text $Outfile Veriable 29 | $OutFile = "C:\ForensicMiner\MyEvidence\02-RunMRU-History\RunMRU-History-of-$($OnlyUserName).txt" 30 | 31 | # Load the NTUSER.DAT of the user and capture the output 32 | $output = reg load HKLM\Offline-$OnlyUserName "$NTUSER_PATH" 2>&1 33 | 34 | # Check if the output contains the success message 35 | if ($output -like "The operation completed successfully.") { 36 | 37 | # Output of offline loaded users hives 38 | Write-Output "+-------------------------------------" | Tee-Object -FilePath $OutFile -Append 39 | Write-Output "|User Type: Offline" | Tee-Object -FilePath $OutFile -Append 40 | Write-Output "|User Name: $OnlyUserName" | Tee-Object -FilePath $OutFile -Append 41 | Write-Output "|Which Hive: NTUSER.DAT" | Tee-Object -FilePath $OutFile -Append 42 | Write-Output "|Hive Status: Registry Was Loaded!" | Tee-Object -FilePath $OutFile -Append 43 | Write-Output "|Registry Path: HKLM\Offline-$OnlyUserName" | Tee-Object -FilePath $OutFile -Append 44 | Write-Output "+-------------------------------------" | Tee-Object -FilePath $OutFile -Append 45 | 46 | #The RunMRL List of offline Users 47 | $registryPath = "HKLM:\Offline-$OnlyUserName\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU" 48 | $runMRU = Get-ItemProperty -Path $registryPath -ErrorAction SilentlyContinue 49 | 50 | # Calculate the order of execution 51 | Write-Output "|User RunMRU List" | Tee-Object -FilePath $OutFile -Append 52 | Write-Output "|----------------" | Tee-Object -FilePath $OutFile -Append 53 | $mruList = $runMRU.MRUList -split '' 54 | $orderedValues = @{} 55 | foreach ($valueName in $mruList) { 56 | $valueData = $runMRU | Select-Object -ExpandProperty $valueName -ErrorAction SilentlyContinue 57 | if ($valueData -and $valueName -match '^[a-z]$') { 58 | $orderedValues.Add($valueName,$valueData.TrimEnd('\1')) 59 | } 60 | } 61 | 62 | # Sort the values by the order of execution 63 | $sortedValues = $orderedValues.GetEnumerator() | Sort-Object { $mruList.IndexOf($_.Key) } -ErrorAction SilentlyContinue 64 | 65 | # Display the sorted results with MRUList first 66 | $index = 1 67 | try { Write-Output ("├#{0}. MRUList : {1}" -f $index,$runMRU.MRUList.TrimEnd('\1') | Tee-Object -FilePath $OutFile -Append) } catch {} 68 | $index++ 69 | 70 | foreach ($entry in $sortedValues) { 71 | Write-Output ("├#{0}. {1} : {2}" -f $index,$entry.Key,$entry.Value) -ErrorAction SilentlyContinue | Tee-Object -FilePath $OutFile -Append 72 | $index++ 73 | } 74 | 75 | } 76 | $Quiet = reg unload HKLM\Offline-$OnlyUserName 2>&1 77 | if ($output -like "The operation completed successfully.") { 78 | 79 | } 80 | else { 81 | # Output of online loaded users hives 82 | Write-Output "+-----------------------------------" | Tee-Object -FilePath $OutFile -Append 83 | Write-Output "|User Type: Online" | Tee-Object -FilePath $OutFile -Append 84 | Write-Output "|User Name: $OnlyUserName" | Tee-Object -FilePath $OutFile -Append 85 | Write-Output "|Which Hive: NTUSER.DAT" | Tee-Object -FilePath $OutFile -Append 86 | Write-Output "|Registry Path: HKEY_USERS" | Tee-Object -FilePath $OutFile -Append 87 | Write-Output "|Hive Status: Hive Already Loaded!" | Tee-Object -FilePath $OutFile -Append 88 | Write-Output "+-----------------------------------" | Tee-Object -FilePath $OutFile -Append 89 | 90 | # Retrieve the user SID using WMI query 91 | $SID = (Get-WmiObject -Class Win32_UserProfile | Where-Object { $_.LocalPath.EndsWith($OnlyUserName) }).SID 92 | 93 | #Get Full Registry Path to HKEY_USERS 94 | $FullRegPath = "Registry::HKEY_USERS\$SID\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU" 95 | $runMRU = Get-ItemProperty -Path $FullRegPath 96 | 97 | # Calculate the order of execution 98 | Write-Output "|User RunMRU List" | Tee-Object -FilePath $OutFile -Append 99 | Write-Output "|----------------" | Tee-Object -FilePath $OutFile -Append 100 | $mruList = $runMRU.MRUList -split '' 101 | $orderedValues = @{} 102 | foreach ($valueName in $mruList) { 103 | $valueData = $runMRU | Select-Object -ExpandProperty $valueName -ErrorAction SilentlyContinue 104 | if ($valueData -and $valueName -match '^[a-z]$') { 105 | $orderedValues.Add($valueName,$valueData.TrimEnd('\1')) 106 | } 107 | } 108 | 109 | # Sort the values by the order of execution 110 | $sortedValues = $orderedValues.GetEnumerator() | Sort-Object { $mruList.IndexOf($_.Key) } -ErrorAction SilentlyContinue 111 | 112 | # Display the sorted results with MRUList first 113 | $index = 1 114 | try { Write-Output ("├#{0}. MRUList : {1}" -f $index,$runMRU.MRUList.TrimEnd('\1') | Tee-Object -FilePath $OutFile -Append) } catch {} 115 | $index++ 116 | 117 | foreach ($entry in $sortedValues) { 118 | Write-Output ("├#{0}. {1} : {2}" -f $index,$entry.Key,$entry.Value) -ErrorAction SilentlyContinue | Tee-Object -FilePath $OutFile -Append 119 | $index++ 120 | } 121 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 122 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 123 | 124 | } 125 | } 126 | Write-Output "" 127 | Write-Output "" 128 | Write-Output "+-------------------------------------------------------------+" 129 | Write-Output "|The record of this forensic evidence is saved on this machine|" 130 | Write-Output "+-------------------------------------------------------------+" 131 | Write-Output '| Path - "C:\ForensicMiner\MyEvidence\02-RunMRU-History" |' 132 | Write-Output "+-------------------------------------------------------------+" 133 | Write-Output "" 134 | -------------------------------------------------------------------------------- /ForensicMiner/02-Analyze/08-TypedPaths.ps1: -------------------------------------------------------------------------------- 1 | $EmpthSubkey_HT = @{} 2 | 3 | #Check if "TypedPaths" folder exists. 4 | $FolderPath = "C:\ForensicMiner\MyEvidence\08-TypedPaths" 5 | if (Test-Path $FolderPath) { 6 | Remove-Item $FolderPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 7 | } 8 | 9 | #Create the "TypedPaths" folder. 10 | New-Item -ItemType Directory -Force -Path $FolderPath | Out-Null 11 | 12 | # create online folder 13 | $OnlineFolder = "C:\ForensicMiner\MyEvidence\08-TypedPaths\01-Online-Users" 14 | New-Item -ItemType Directory -Force -Path $OnlineFolder | Out-Null 15 | 16 | # create offline folder 17 | $OfflineFolder = "C:\ForensicMiner\MyEvidence\08-TypedPaths\02-Offline-Users" 18 | New-Item -ItemType Directory -Force -Path $OfflineFolder | Out-Null 19 | 20 | # define the variable path to TypedPaths on registry 21 | $HalfPathTypedPaths = "Software\Microsoft\Windows\CurrentVersion\Explorer\TypedPaths" 22 | 23 | # define the variable path to NTUSER.DAT 24 | $NTUSER = "\NTUSER.DAT" 25 | 26 | # Define and exclude the relevant users for the foreach loop 27 | $Users = Get-ChildItem C:\Users -Exclude ("Public","TEMP","Default","*.NET*") -Directory 28 | 29 | # Use foreach loop to name the hives 30 | foreach ($user in $Users) { 31 | 32 | # define full NTUSER.DAT path for each user 33 | $NTUSER_PATH = Join-Path -Path $User.FullName -ChildPath $NTUSER 34 | 35 | # if statment to check if the not excluded usesr has NTUSER.DAT in his profile folder 36 | if (Test-Path -Path $NTUSER_PATH) { 37 | 38 | # Name of each user on the system without the "Name" column 39 | $OnlyUserName = $user | Select-Object -Property Name | ForEach-Object { $_.Name } 40 | 41 | # Load the NTUSER.DAT of the user and capture the output 42 | $output = reg load HKLM\Offline-$OnlyUserName "$NTUSER_PATH" 2>&1 43 | 44 | # if statment for offline users 45 | if ($output -like "The operation completed successfully.") { 46 | 47 | # full registry path with offline user hive to TypedPaths 48 | $FullOfflineRegistryPath = "Registry::HKEY_LOCAL_MACHINE\Offline-$OnlyUserName\$HalfPathTypedPaths" 49 | 50 | if (Test-Path -Path $FullOfflineRegistryPath) { 51 | 52 | # Get all properties of the registry path $FullRegTypedPath 53 | $OfflineRegistryProperties = Get-ItemProperty -Path $FullOfflineRegistryPath | Select-Object * -ExcludeProperty ("PSProvider","PSChildName","PSParentPath","PSPath") 54 | 55 | # variable to store the number of propertie counts 56 | $OfflinePropertieCount = $OfflineRegistryProperties.PSObject.Properties.Name.Count 57 | 58 | if ($OfflinePropertieCount -ge 1) { 59 | 60 | # create the log text file for Offline users 61 | $OfflineOutFile = "C:\ForensicMiner\MyEvidence\08-TypedPaths\02-Offline-Users\$OnlyUserName.txt" 62 | 63 | Write-Output "+-------------------------------------" | Tee-Object -FilePath $OfflineOutFile -Append 64 | Write-Output "|User Type: Offline" | Tee-Object -FilePath $OfflineOutFile -Append 65 | Write-Output "|User Name: $OnlyUserName" | Tee-Object -FilePath $OfflineOutFile -Append 66 | Write-Output "|Which Hive: NTUSER.DAT" | Tee-Object -FilePath $OfflineOutFile -Append 67 | Write-Output "|Hive Status: Registry Was Loaded!" | Tee-Object -FilePath $OfflineOutFile -Append 68 | Write-Output "|Registry Path: HKLM\Offline-$OnlyUserName" | Tee-Object -FilePath $OfflineOutFile -Append 69 | Write-Output "+-------------------------------------" | Tee-Object -FilePath $OfflineOutFile -Append 70 | Write-Output "|User TypedPaths List" | Tee-Object -FilePath $OfflineOutFile -Append 71 | Write-Output "|--------------------" | Tee-Object -FilePath $OfflineOutFile -Append 72 | 73 | # Iterate through each property in the hashtable and print each line separately 74 | foreach ($property in $OfflineRegistryProperties.PSObject.Properties) { 75 | Write-Output "|#$($property.Name -replace 'url','') - $($property.Value)" | Tee-Object -FilePath $OfflineOutFile -Append 76 | } 77 | } 78 | 79 | else { 80 | $EmpthSubkey_HT[$OnlyUserName] = "[!] TypedPaths registry subkey is empty for user $OnlyUserName." 81 | } 82 | } 83 | 84 | # if statment for users who don't have this path $FullOnlineRegistryPath 85 | else { 86 | } 87 | 88 | # space 89 | Write-Output "" 90 | } 91 | 92 | # if statment for online users 93 | else { 94 | 95 | # Retrieve the user SID using WMI query 96 | $SID = (Get-WmiObject -Class Win32_UserProfile | Where-Object { $_.LocalPath.EndsWith($OnlyUserName) }).SID 97 | 98 | # if statment to check if $SID variable has a SID in it 99 | if ($SID -ge 30) { 100 | 101 | # full variable of the user path to "TypedPath" 102 | $FullRegTypedPath = "Registry::HKEY_USERS\$SID\$HalfPathTypedPaths" 103 | 104 | # if statement to check if $FullRegTypedPath exists 105 | if (Test-Path -Path $FullRegTypedPath) { 106 | 107 | # Get all properties of the registry path $FullRegTypedPath 108 | $registryProperties = Get-ItemProperty -Path $FullRegTypedPath | Select-Object * -ExcludeProperty ("PSProvider","PSChildName","PSParentPath","PSPath") 109 | 110 | # variable to store the number of propertie counts 111 | $PropertieCount = $registryProperties.PSObject.Properties.Name.Count 112 | 113 | if ($PropertieCount -ge 1) { 114 | 115 | # create the log text file for Online users 116 | $OnlineOutFile = "C:\ForensicMiner\MyEvidence\08-TypedPaths\01-Online-Users\$OnlyUserName.txt" 117 | 118 | Write-Output "+-----------------------------------" | Tee-Object -FilePath $OnlineOutFile -Append 119 | Write-Output "|User Type: Online" | Tee-Object -FilePath $OnlineOutFile -Append 120 | Write-Output "|User Name: $OnlyUserName" | Tee-Object -FilePath $OnlineOutFile -Append 121 | Write-Output "|Which Hive: NTUSER.DAT" | Tee-Object -FilePath $OnlineOutFile -Append 122 | Write-Output "|Registry Path: HKEY_USERS" | Tee-Object -FilePath $OnlineOutFile -Append 123 | Write-Output "|Hive Status: Hive Already Loaded!" | Tee-Object -FilePath $OnlineOutFile -Append 124 | Write-Output "+-----------------------------------" | Tee-Object -FilePath $OnlineOutFile -Append 125 | Write-Output "|User TypedPaths List" | Tee-Object -FilePath $OnlineOutFile -Append 126 | Write-Output "|--------------------" | Tee-Object -FilePath $OnlineOutFile -Append 127 | 128 | foreach ($property in $registryProperties.PSObject.Properties) { 129 | Write-Output "|#$($property.Name -replace 'url','') - $($property.Value)" | Tee-Object -FilePath $OnlineOutFile -Append 130 | } 131 | } 132 | 133 | else { 134 | $EmpthSubkey_HT[$OnlyUserName] = "[!] TypedPaths registry subkey is empty for user $OnlyUserName." 135 | } 136 | } 137 | # space 138 | Write-Output "" 139 | } 140 | 141 | else { 142 | } 143 | } 144 | } 145 | } 146 | 147 | $EmpthSubkeyCount = $EmpthSubkey_HT.Values.Count 148 | if ($EmpthSubkeyCount -ge 1) { 149 | Write-Output "Empty TypedPaths User Table" 150 | Write-Output "+-------------------------+" 151 | $EmpthSubkey_HT.Values 152 | } 153 | 154 | else { 155 | } 156 | 157 | Write-Output "" 158 | Write-Output "+-------------------------------------------------------------+" 159 | Write-Output "|The record of this forensic evidence is saved on this machine|" 160 | Write-Output "+-------------------------------------------------------------+" 161 | Write-Output '| Path - "C:\ForensicMiner\MyEvidence\08-TypedPaths" |' 162 | Write-Output "+-------------------------------------------------------------+" 163 | Write-Output "" 164 | -------------------------------------------------------------------------------- /ForensicMiner/02-Analyze/03-MUICache.ps1: -------------------------------------------------------------------------------- 1 | #Check if "AppHistory(MUICache)" exist. 2 | $folderPath = "C:\ForensicMiner\MyEvidence\03-AppHistory(MUICache)" 3 | if (Test-Path $folderPath) { 4 | Remove-Item $folderPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 5 | } 6 | 7 | # Create the "AppHistory(MUICache)" folder. 8 | New-Item -ItemType Directory -Force -Path "C:\ForensicMiner\MyEvidence\03-AppHistory(MUICache)" | Out-Null 9 | 10 | # Define the variable path to MuiCache ('Online' and 'Offline') 11 | $Online_MuiCache = "Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache" 12 | $Offline_MuiCache = "Local Settings\Software\Microsoft\Windows\Shell\MuiCache" 13 | 14 | # Define the variable path to NTUSER.DAT 15 | $UsrClass = "\AppData\Local\Microsoft\Windows\UsrClass.DAT" 16 | 17 | # Define and exclude the relevant users for the foreach loop 18 | $Users = Get-ChildItem C:\Users -Exclude ("Public","TEMP","Default") -Directory 19 | 20 | # Use foreach loop to load offline users hive 21 | foreach ($user in $Users) { 22 | 23 | # Define full NTUSER.DAT path for each user 24 | $UsrClass_PATH = Join-Path -Path $User.FullName -ChildPath $UsrClass 25 | 26 | # Name of each user on the system without the "Name" column 27 | $OnlyUserName = $user | Select-Object -Property Name | ForEach-Object { $_.Name } 28 | 29 | # Text $Outfile Veriable 30 | $OutFile = "C:\ForensicMiner\MyEvidence\03-AppHistory(MUICache)\AppHistory-Of-$OnlyUserName.txt" 31 | 32 | # Load the NTUSER.DAT of the user and capture the output 33 | $output = reg load HKLM\Offline-$OnlyUserName "$UsrClass_PATH" 2>&1 34 | 35 | # Check if the output contains the success message 36 | if ($output -like "The operation completed successfully.") { 37 | 38 | # RegPath to UsrClass.DAT on the Registry 39 | $FullRegPath = "HKLM:\Offline-$OnlyUserName\$Offline_MuiCache" 40 | 41 | # Offline Username 42 | Write-Output "" 43 | Write-Output "#################[Offline Users]#################" | Tee-Object -FilePath $OutFile -Append 44 | Write-Output "User Name: $OnlyUserName" | Tee-Object -FilePath $OutFile -Append 45 | Write-Output "Load Path: HKLM:\Offline-$OnlyUserName" | Tee-Object -FilePath $OutFile -Append 46 | Write-Output "Load Status: UsrClass.DAT was loaded to - [HKLM:]" | Tee-Object -FilePath $OutFile -Append 47 | Write-Output "Hive Status: Hive will be unloaded at next reboot" | Tee-Object -FilePath $OutFile -Append 48 | Write-Output "#################################################" | Tee-Object -FilePath $OutFile -Append 49 | 50 | # Create a variable for the usage of exclusion 51 | $Exclude = @("PSPath","PSParentPath","PSProvider","PSDrive","PSChildName","LangID") 52 | 53 | #Create a variable that retrieve the correct subkeys and exclude the unwanted subkeys 54 | $SubKeys = Get-ItemProperty -Path $FullRegPath | ForEach-Object {$_.PSObject.Properties.Name} | Where-Object { $_ -notin $Exclude } 55 | 56 | # Loop through the subkeys using foreach 57 | foreach ($SubKey in $SubKeys) { 58 | 59 | # Variable that cut the executable name from the $Subkey var 60 | $PartKey = $SubKey -replace '.*\\([^\\]+\.exe)\..*', '$1' 61 | 62 | if ($SubKey -like "*.FriendlyAppName") { 63 | 64 | # Cretae the variable for the value of each subkey 65 | $Value = Get-ItemPropertyValue -Path $FullRegPath -Name $SubKey 66 | 67 | $Result = $SubKey -replace '.*\\([^\\]+\.exe)\..*', '$1' 68 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 69 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 70 | Write-Output "Application Name: $Result" | Tee-Object -FilePath $OutFile -Append 71 | Write-Output "Metadata File Description: $Value" | Tee-Object -FilePath $OutFile -Append 72 | 73 | } 74 | 75 | elseif ($SubKey -like "*.ApplicationCompany") { 76 | 77 | # Create a var for $subkey without ".app*" 78 | $NewSubkey = $SubKey -replace ('\.ApplicationCompany$','') | Tee-Object -FilePath $OutFile -Append 79 | 80 | Write-Output "Metadata Company Name: $Value" | Tee-Object -FilePath $OutFile -Append 81 | Write-Output "Application Path: $NewSubkey" | Tee-Object -FilePath $OutFile -Append 82 | 83 | # Check if app is still there. 84 | $Check = Test-Path -Path $NewSubkey 85 | Write-Output "Application Still There? - $Check" | Tee-Object -FilePath $OutFile -Append 86 | 87 | 88 | } 89 | } 90 | $Quiet = reg unload HKLM\Offline-$OnlyUserName 2>&1 91 | if ($output -like "The operation completed successfully.") { 92 | 93 | } 94 | } 95 | 96 | else { 97 | # Online Username 98 | Write-Output "" 99 | Write-Output "#######[Online Users]########" | Tee-Object -FilePath $OutFile -Append 100 | Write-Output "User Name: $OnlyUserName" | Tee-Object -FilePath $OutFile -Append 101 | Write-Output "Which Hive: HKEY_USERS" | Tee-Object -FilePath $OutFile -Append 102 | Write-Output "Hive Status: Hive is Live" | Tee-Object -FilePath $OutFile -Append 103 | Write-Output "#############################" | Tee-Object -FilePath $OutFile -Append 104 | 105 | # Retrieve the user SID using WMI query 106 | $SID = (Get-WmiObject -Class Win32_UserProfile | Where-Object { $_.LocalPath.EndsWith($OnlyUserName) }).SID 107 | 108 | # Create a variable for the usage of exclusion 109 | $Exclude = @("PSPath","PSParentPath","PSProvider","PSDrive","PSChildName","LangID") 110 | 111 | # Get Full Registry Path to HKEY_USERS 112 | $FullRegPath = "Registry::HKEY_USERS\$SID\$Online_MuiCache" 113 | 114 | #Create a variable that retrieve the correct subkeys and exclude the unwanted subkeys 115 | $SubKeys = Get-ItemProperty -Path $FullRegPath | ForEach-Object {$_.PSObject.Properties.Name} | Where-Object { $_ -notin $Exclude } 116 | 117 | # Loop through the subkeys using foreach 118 | foreach ($SubKey in $SubKeys) { 119 | 120 | # Variable that cut the executable name from the $Subkey var 121 | $PartKey = $SubKey -replace '.*\\([^\\]+\.exe)\..*', '$1' 122 | 123 | if ($SubKey -like "*.FriendlyAppName") { 124 | 125 | # Cretae the variable for the value of each subkey 126 | $Value = Get-ItemPropertyValue -Path $FullRegPath -Name $SubKey 127 | 128 | $Result = $SubKey -replace '.*\\([^\\]+\.exe)\..*', '$1' 129 | 130 | 131 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 132 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 133 | Write-Output "Application Name: $Result" | Tee-Object -FilePath $OutFile -Append 134 | Write-Output "Metadata File Description: $Value" | Tee-Object -FilePath $OutFile -Append 135 | 136 | } 137 | 138 | elseif ($SubKey -like "*.ApplicationCompany") { 139 | 140 | # Create a var for $subkey without ".app*" 141 | $NewSubkey = $SubKey -replace ('\.ApplicationCompany$','') 142 | 143 | Write-Output "Metadata Company Name: $Value" | Tee-Object -FilePath $OutFile -Append 144 | Write-Output "Application Path: $NewSubkey" | Tee-Object -FilePath $OutFile -Append 145 | 146 | # Check if app is still there. 147 | $Check = Test-Path -Path $NewSubkey 148 | Write-Output "Application Still There? - $Check" | Tee-Object -FilePath $OutFile -Append 149 | 150 | 151 | } 152 | } 153 | Write-Output "" 154 | 155 | } 156 | } 157 | Write-Output "" 158 | Write-Output "" 159 | Write-Output "+-------------------------------------------------------------+" 160 | Write-Output "|The record of this forensic evidence is saved on this machine|" 161 | Write-Output "+-------------------------------------------------------------+" 162 | Write-Output '| Path - "C:\ForensicMiner\MyEvidence\03-AppHistory(MUICache)"|' 163 | Write-Output "+-------------------------------------------------------------+" 164 | Write-Output "" -------------------------------------------------------------------------------- /ForensicMiner/02-Analyze/01-BAM.ps1: -------------------------------------------------------------------------------- 1 | # Pre-Execution Validation title. 2 | Write-Output "" 3 | Write-Output "Pre-Execution Validation" 4 | Write-Output "+----------------------+" 5 | 6 | # check if $folderPath exist, delete if true. 7 | $FolderPath = "C:\ForensicMiner\MyEvidence\01-Evidence-Of-Execution" 8 | if (Test-Path -Path $FolderPath) { 9 | Start-Sleep -Milliseconds 500 10 | Write-Output "[*] Deleting old BAM evidence folder and creating a new empty one." 11 | Remove-Item -Path $FolderPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 12 | New-Item -ItemType Directory -Force -Path $folderPath | Out-Null 13 | } 14 | 15 | # if $FolderPath is missing, cretae it. 16 | else { 17 | Start-Sleep -Milliseconds 500 18 | Write-Output "[*] Creating BAM evidence folder." 19 | New-Item -ItemType Directory -Force -Path $folderPath | Out-Null 20 | } 21 | 22 | # variable for bam.sys full path. 23 | $BamPath = Join-Path -Path $env:windir -ChildPath "system32\drivers\bam.sys" 24 | 25 | # if statment to check if $bam_path exist on system. 26 | if (Test-Path -Path $BamPath) { 27 | Start-Sleep -Milliseconds 500 28 | Write-Output "[*] bam.sys was found under $BamPath." 29 | 30 | # check if $UserSettings path is found under the registry. 31 | $UserSettingsPath = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" 32 | if (Test-Path -Path $UserSettingsPath) { 33 | $UserSettingsFlag = "True" 34 | Start-Sleep -Milliseconds 500 35 | Write-Output "[*] ProfileList registry path was found." 36 | } 37 | else { 38 | $UserSettingsFlag = "False" 39 | Start-Sleep -Milliseconds 500 40 | Write-Output "[*] ProfileList registry path was NOT found." 41 | } 42 | 43 | # if statment to check if $BamRegistryPath exist. 44 | $BamRegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Services\bam\State\UserSettings" 45 | if (Test-Path -Path $BamRegistryPath) { 46 | Start-Sleep -Milliseconds 500 47 | Write-Output "[*] bam registry path was found." 48 | Start-Sleep -Milliseconds 500 49 | Write-Output "[*] script can be start." 50 | Write-Output "" 51 | 52 | # this is the part of the actual script after the Pre-Execution Validation. 53 | $SIDsWithPath = Get-Item -Path "$BamRegistryPath\*" | Select-Object -ExpandProperty Name 54 | $SIDs = $SIDsWithPath -replace '.*\\UserSettings\\','' 55 | 56 | # foreach statment to separate SIDs to each SID 57 | foreach ($SID in $SIDs) { 58 | 59 | # if statment to show only $SID with more then 30 characters 60 | if ($SID.length -ge 30) { 61 | 62 | # create the log text file for each user 63 | $OutFile = "C:\ForensicMiner\MyEvidence\01-Evidence-Of-Execution\$($SID).txt" 64 | 65 | # conect the $BamRegistryPath with $SID 66 | $FullSIDRegistryPath = "$BamRegistryPath\$SID" 67 | 68 | # Get the values under the registry key 69 | $values = Get-ItemProperty -Path $FullSIDRegistryPath | Select-Object -Property * 70 | 71 | # Create an empty array to store the sorted results 72 | $sortedResults = @() 73 | 74 | # Loop through the values and add them to the array 75 | foreach ($valueName in $values.PSObject.Properties.Name) { 76 | if ($valueName -like '\Device\*') { 77 | $valueData = [BitConverter]::ToInt64($values.$valueName,0) 78 | $result = $valueName -replace '^\\Device\\HarddiskVolume\d+\\' 79 | $timestamp = if ($valueData -ne $null) { 80 | [datetime]::FromFileTime($valueData) 81 | } else { 82 | "Not available" 83 | } 84 | 85 | # Create an object with the properties 86 | $sortedResults += [pscustomobject]@{ 87 | Software = $result 88 | Timestamp = $timestamp 89 | } 90 | } 91 | } 92 | 93 | # Sort the results based on the 'Timestamp' property in descending order 94 | $sortedResults = $sortedResults | Sort-Object -Property Timestamp -Descending 95 | 96 | # Display the sorted results 97 | Start-Sleep -Milliseconds 500 98 | Write-Output "┌---------------------------------------------------┐" | Tee-Object -FilePath $OutFile -Append 99 | 100 | # if statment to check if $UserSettingsFlag exist using a flag 101 | if ($UserSettingsFlag -eq "True") { 102 | 103 | # SIDS hash table. 104 | $SID_HashTable = @{ 105 | "SIDS" = @() 106 | } 107 | # cleaning the SIDS from the path 108 | $DirtySIDS = Get-ItemProperty -Path $UserSettingsPath | Select-Object -ExpandProperty PSChildName 109 | $US_SIDS = $DirtySIDS -replace '.bak','' 110 | 111 | # foreach statment to make SIDS to SID 112 | foreach ($US_SID in $US_SIDS) { 113 | if ($US_SID.length -ge 30) { 114 | $SID_HashTable["SIDS"] += $US_SID 115 | } 116 | } 117 | 118 | # check if the $SID_HashTable hashtable has $SID in it 119 | if ($SID_HashTable["SIDS"] -contains $SID) { 120 | $HalfProfileListPath = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\" 121 | $FullProfileListPath = Join-Path -Path $HalfProfileListPath -ChildPath $SID 122 | 123 | # if the SID exist, print the username 124 | if (Test-Path -Path $FullProfileListPath) { 125 | $UserProfilePath = Get-ItemProperty -Path $FullProfileListPath | Select-Object -ExpandProperty ProfileImagePath 126 | $CleanUserName = $UserProfilePath -replace '^[a-z,A-Z]{1}\:\\Users\\','' 127 | Write-Output "├User: $CleanUserName" | Tee-Object -FilePath $OutFile -Append 128 | } 129 | 130 | # if not, try to add to the end of the SID a .bak 131 | elseif (Test-Path -Path "$FullProfileListPath.bak") { 132 | $UserProfilePath = Get-ItemProperty -Path "$FullProfileListPath.bak" | Select-Object -ExpandProperty ProfileImagePath 133 | $CleanUserName = $UserProfilePath -replace '^[a-z,A-Z]{1}\:\\Users\\','' 134 | Write-Output "├User: $CleanUserName" | Tee-Object -FilePath $OutFile -Append 135 | } 136 | 137 | # if there is no SID, print this 138 | else { 139 | Write-Output "├User: Username not found." | Tee-Object -FilePath $OutFile -Append 140 | } 141 | 142 | } 143 | else { 144 | Write-Output "├User: Username not found." | Tee-Object -FilePath $OutFile -Append 145 | } 146 | 147 | } 148 | else { 149 | } 150 | 151 | Write-Output "├SID: $SID" | Tee-Object -FilePath $OutFile -Append 152 | Write-Output "|" | Tee-Object -FilePath $OutFile -Append 153 | 154 | foreach ($result in $sortedResults) { 155 | Write-Output "├Software: $($result.Software)" | Tee-Object -FilePath $OutFile -Append 156 | Write-Output "├Timestamp: $($result.Timestamp)" | Tee-Object -FilePath $OutFile -Append 157 | Write-Output "|" | Tee-Object -FilePath $OutFile -Append 158 | } 159 | 160 | Write-Output "└-> End-of-List" | Tee-Object -FilePath $OutFile -Append 161 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 162 | 163 | 164 | 165 | } 166 | 167 | # execute this on SIDs with less then 30 characters 168 | else { 169 | } 170 | 171 | # end of the ($SID in $SIDS) foreach loop. 172 | } 173 | Write-Output "" 174 | Write-Output "+-------------------------------------------------------------+" 175 | Write-Output "|The record of this forensic evidence is saved on this machine|" 176 | Write-Output "+-------------------------------------------------------------+" 177 | Write-Output '|Path - "C:\ForensicMiner\MyEvidence\01-Evidence-Of-Execution"|' 178 | Write-Output "+-------------------------------------------------------------+" 179 | Write-Output "" 180 | 181 | } 182 | 183 | # if $BamRegistryPath is not exist, execute this else. 184 | else { 185 | Start-Sleep -Milliseconds 500 186 | Write-Output "[!] bam registry path was not found." 187 | Start-Sleep -Milliseconds 500 188 | Write-Output '[!] Check if "HKLM:\SYSTEM\CurrentControlSet\Services\bam\State\UserSettings" exist on registry.' 189 | Start-Sleep -Milliseconds 500 190 | Write-Output "[!] Script cannot continue, stopping script." 191 | } 192 | 193 | } 194 | 195 | # if $bam_path is not exist, execute this else. 196 | else { 197 | Start-Sleep -Milliseconds 500 198 | Write-Output "[!] bam.sys was not found under $BamPath" 199 | Start-Sleep -Milliseconds 500 200 | Write-Output "[!] Script cannot continue, stopping script." 201 | } 202 | 203 | # space 204 | Write-Output "" 205 | -------------------------------------------------------------------------------- /ForensicMiner/02-Analyze/07-BrowserAnalyzer.ps1: -------------------------------------------------------------------------------- 1 | # Module Install Section. 2 | # Related Variables. 3 | $ModulePath = "C:\Program Files\WindowsPowerShell\Modules" 4 | $ModuleZIPPath = "C:\ForensicMiner\Modules\PSSQlite.zip" 5 | 6 | # First Main Title. 7 | Write-Output "" 8 | Write-Output "PSQLite Install Process" 9 | Write-Output "-----------------------" 10 | 11 | # Module install error handling. 12 | if (Test-Path -Path "$ModulePath\PSSQLite"){ 13 | Start-Sleep -Milliseconds 500 14 | # Path "C:\Program Files\WindowsPowerShell\Modules" 15 | Write-Output "[*] PSSQLite already exist in this system." 16 | Start-Sleep -Milliseconds 500 17 | Write-Output "[*] PSSQLite install process was successfully done." 18 | } 19 | else { 20 | # Check if PSSQLite ZIP exist in root ForensicMiner folder. 21 | if (Test-Path -Path $ModuleZIPPath){ 22 | Start-Sleep -Milliseconds 500 23 | Write-Output "[*] PSSQLite module was found in root ForensicMiner folder." 24 | Start-Sleep -Milliseconds 500 25 | Write-Output "[*] Extracting PSSQLite module in to the system." 26 | Expand-Archive -Path $ModuleZIPPath -DestinationPath $ModulePath | Out-Null 27 | if (Test-Path -Path "$ModulePath\PSSQLite"){ 28 | Start-Sleep -Milliseconds 500 29 | Write-Output "[*] PSSQLite was successfully extracted in to the system." 30 | Start-Sleep -Milliseconds 500 31 | Write-Output "[*] Importing PSSQLite in to the system." 32 | Import-Module PSSQLite 33 | if (Get-Command Invoke-SqliteQuery) { 34 | Start-Sleep -Milliseconds 500 35 | Write-Output "[*] PSSQLite was successfully imported in to the system." 36 | Start-Sleep -Milliseconds 500 37 | Write-Output "[*] PSSQLite install process was successfully done." 38 | Start-Sleep -Milliseconds 500 39 | } 40 | else { 41 | Start-Sleep -Milliseconds 500 42 | Write-Output "[!] There was a problem importing PSSQLite in to the system." 43 | Start-Sleep -Milliseconds 500 44 | Write-Output "[!] Script has been canceled." 45 | exit 46 | } 47 | } 48 | else { 49 | Start-Sleep -Milliseconds 500 50 | Write-Output "[!] There was a problem extracting PSSQLite in to the system." 51 | Start-Sleep -Milliseconds 500 52 | Write-Output "[!] Script has been canceled." 53 | exit 54 | } 55 | } 56 | else { 57 | Start-Sleep -Milliseconds 500 58 | Write-Output "[!] PSSQLite was not found in root ForensicMiner folder." 59 | Start-Sleep -Milliseconds 500 60 | Write-Output "[!] Script has been canceled." 61 | exit 62 | } 63 | } 64 | 65 | # First text output 66 | Write-Output "" 67 | Write-Output "Browser Analysis Process" 68 | Write-Output "------------------------" 69 | 70 | # Variable to store C:\Users output. 71 | $Names = Get-ChildItem -Path "C:\Users" 72 | 73 | # foreach loop to make single user name at a time. 74 | foreach ($Name in $Names) { 75 | 76 | # Full user name path. 77 | $Full_User_Path = Join-Path -Path C:\Users -ChildPath $Name 78 | 79 | 80 | # List of browser path. 81 | $BrowserPaths = @{ 82 | "Chrome" = "\AppData\Local\Google\Chrome\User Data\Default\History" 83 | "Brave" = "AppData\Local\BraveSoftware\Brave-Browser\User Data\Default\History" 84 | "Edge" = "AppData\Local\Microsoft\Edge\User Data\Default\History" 85 | #"Opera" = "AppData\Roaming\Opera Software\Opera Stable\Default\History" 86 | #"Firefox" = "AppData\Roaming\Mozilla\Firefox\Profiles\*\places.sqlite" 87 | } 88 | 89 | 90 | # foreach loop to make single search for each browser path. 91 | foreach ($browserName in $BrowserPaths.Keys) { 92 | 93 | # Full path to chech each user for each browser path 94 | $User_With_Browser_Path = Join-Path -Path $Full_User_Path -ChildPath $BrowserPaths[$browserName] 95 | 96 | # if the user have the browser path. 97 | if (Test-Path $User_With_Browser_Path) { 98 | 99 | # Create each user a record folder. 100 | New-Item -ItemType Directory -Force -Path "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record" | Out-Null 101 | 102 | New-Item -ItemType Directory -Force -Path "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\$browserName" | Out-Null 103 | 104 | # Copy and past browser hisotry file. 105 | Copy-Item -Path $User_With_Browser_Path -Destination "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\$browserName\$Name-$browserName-History-File.sqlite" 106 | 107 | # Analyzing part. 108 | # Path variables. 109 | $Out_URL_Analysis = "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\$browserName\$Name-$browserName-URL-Analysis.txt" 110 | $Out_Keyword_Search_Terms_Analysis = "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\$browserName\$Name-$browserName-Keyword-Search-Terms-Analysis.txt" 111 | $Out_Download_Analysis = "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\$browserName\$Name-$browserName-Download-Analysis.txt" 112 | $DB = "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\$browserName\$Name-$browserName-History-File.sqlite" 113 | 114 | # variable related to the browser analysis process table 115 | $HisotryGrabPath = "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\$browserName\$Name-$browserName-History-File.sqlite" 116 | 117 | # URL_Analysis Query 118 | Invoke-SqliteQuery -DataSource $DB -Query "SELECT datetime((last_visit_time / 1000000) - 11644473600, 'unixepoch') AS 'Visit Time UTC Form', substr(datetime((last_visit_time / 1000000) - 11644473600, 'unixepoch', '+3 hours'), 12, 8) AS 'GMT+3 IL', substr(datetime((last_visit_time / 1000000) - 11644473600, 'unixepoch', '+2 hours'), 12, 8) AS 'GMT+2 IL', visit_count AS 'Count', SUBSTR(title, 1, 90) AS 'URL Title', url AS 'Full URL' FROM urls ORDER BY last_visit_time DESC" | Select-Object 'Visit Time UTC Form', 'GMT+3 IL', 'GMT+2 IL' ,'Count', 'URL Title', 'Full URL' | Format-Table -AutoSize | Out-File -FilePath $Out_URL_Analysis -Width ([int]::MaxValue) 119 | 120 | # Keyword_Search_Terms_Analysis Query 121 | Invoke-SqliteQuery -DataSource $DB -Query "SELECT url_id AS 'Term ID', term AS 'Browser Keyword Search Term' FROM keyword_search_terms ORDER BY url_id DESC" | Select-Object 'Term ID', 'Browser Keyword Search Term' | Format-Table -AutoSize | Out-File -FilePath $Out_Keyword_Search_Terms_Analysis -Width ([int]::MaxValue) 122 | 123 | # Download_Analysis Query 124 | Invoke-SqliteQuery -DataSource $DB -Query "SELECT datetime((start_time / 1000000) - 11644473600, 'unixepoch') AS 'Download Start Time', strftime('%H:%M:S', (end_time / 1000000) - 11644473600, 'unixepoch') AS 'End Time', (ROUND(total_bytes / 1048576.0, 3) || ' MB') AS 'File Size', SUBSTR(mime_type, 1, 30) AS 'File Type', CASE WHEN opened = 1 THEN 'Yes' WHEN opened = 0 THEN 'No' ELSE opened END AS 'Opened From Browser?', current_path AS 'Path Of The Downloaded File', tab_url AS 'File Was Downloaded From This Link' FROM downloads ORDER BY start_time DESC" | Select-Object 'Download Start Time', 'End Time', 'File Size', 'File Type', 'Opened From Browser?', 'Path Of The Downloaded File', 'File Was Downloaded From This Link' | Format-Table -AutoSize | Out-File -FilePath $Out_Download_Analysis -Width ([int]::MaxValue) 125 | 126 | # if statment for the Success \ Failure table 127 | # grab history statment 128 | if (Test-Path -Path $HisotryGrabPath) { 129 | $HisGrb = "Success" 130 | } 131 | else { 132 | $HisGrb = "Failure" 133 | } 134 | 135 | # URL analysis statment 136 | if (Test-Path -Path $Out_URL_Analysis) { 137 | $URLchk = "Success" 138 | } 139 | else { 140 | $URLchk = "Failure" 141 | } 142 | 143 | # Download Analysis statment 144 | if (Test-Path -Path $Out_Download_Analysis) { 145 | $dwnchk = "Success" 146 | } 147 | else { 148 | $dwnchk = "Failure" 149 | } 150 | 151 | # Keyword search term Analysis statment 152 | if (Test-Path -Path $Out_Keyword_Search_Terms_Analysis) { 153 | $serchk = "Success" 154 | } 155 | else { 156 | $serchk = "Failure" 157 | } 158 | 159 | # check if the $browserName is Edge or Chrom 160 | if ($browserName -like "Edge") { 161 | 162 | # edge related variables 163 | $EdgeUserPicPath = "C:\Users\$Name\AppData\Local\Microsoft\Edge\User Data\Default\Edge Profile Picture.png" 164 | $FMEdgeUserPicPath = "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\Edge\$Name-Profile-Picture.png" 165 | 166 | if (Test-Path -Path $EdgeUserPicPath -PathType Leaf) { 167 | Copy-Item -Path $EdgeUserPicPath -Destination $FMEdgeUserPicPath 168 | if (Test-Path -Path $FMEdgeUserPicPath -PathType Leaf) { 169 | $edgpic = "Success" 170 | } 171 | else { 172 | $edgpic = "Missing" 173 | } 174 | } 175 | else { 176 | $edgpic = "Missing" 177 | } 178 | } 179 | 180 | elseif ($browserName -like "Chrome") { 181 | 182 | # chrome related variables 183 | $ChromeUserPicPath = "C:\Users\$Name\AppData\Local\Google\Chrome\User Data\Default\Google Profile Picture.png" 184 | $FMChromeUserPicPath = "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer\$Name-Browser-Record\Chrome\$Name-Profile-Picture.png" 185 | 186 | if (Test-Path -Path $ChromeUserPicPath -PathType Leaf) { 187 | Copy-Item -Path $ChromeUserPicPath -Destination $FMChromeUserPicPath 188 | if (Test-Path -Path $FMChromeUserPicPath -PathType Leaf) { 189 | $chrpic = "Success" 190 | } 191 | else { 192 | $chrpic = "Missing" 193 | } 194 | } 195 | else { 196 | $chrpic = "Missing" 197 | } 198 | } 199 | 200 | else { 201 | } 202 | 203 | 204 | # table of status for the browser analysis operation 205 | Write-Output "[*] Browser: $browserName" 206 | Write-Output "[*] Username: $Name" 207 | Write-Output "+----------------------+-----------+" 208 | Write-Output "| #OPERATION | #Status |" 209 | Write-Output "+----------------------+-----------+" 210 | Write-Output "| Grab Hisotry File | $HisGrb |" 211 | Write-Output "+----------------------+-----------+" 212 | Write-Output "| URL Analysis | $URLchk |" 213 | Write-Output "+----------------------+-----------+" 214 | Write-Output "| Download Analysis | $dwnchk |" 215 | Write-Output "+----------------------+-----------+" 216 | Write-Output "| Search Term Analysis | $serchk |" 217 | Write-Output "+----------------------+-----------+" 218 | 219 | if ($browserName -like "Chrome") { 220 | if ($chrpic -like "Success") { 221 | Write-Output "| User Profile Picture | $chrpic | <- Found User Chrome Profile" 222 | Write-Output "+----------------------+-----------+" 223 | } 224 | else { 225 | Write-Output "| User Profile Picture | $chrpic | <- User Chrome Profile Not Found" 226 | Write-Output "+----------------------+-----------+" 227 | } 228 | } 229 | else{ 230 | } 231 | 232 | if ($browserName -like "Edge") { 233 | if ($edgpic -like "Success") { 234 | Write-Output "| User Profile Picture | $edgpic | <- Found User Edge Profile" 235 | Write-Output "+----------------------+-----------+" 236 | } 237 | else { 238 | Write-Output "| User Profile Picture | $edgpic | <- User Edge Profile Not Found" 239 | Write-Output "+----------------------+-----------+" 240 | } 241 | } 242 | else{ 243 | } 244 | Write-Output "" 245 | Start-Sleep -Milliseconds 500 246 | } 247 | # if the user does not have the browser path. 248 | else { 249 | } 250 | } # here the foreach loop is ending 251 | 252 | } 253 | 254 | Write-Output "" 255 | Write-Output "+-------------------------------------------------------------+" 256 | Write-Output "|The record of this forensic evidence is saved on this machine|" 257 | Write-Output "+-------------------------------------------------------------+" 258 | Write-Output '| Path - "C:\ForensicMiner\MyEvidence\07-BrowserAnalyzer" |' 259 | Write-Output "+-------------------------------------------------------------+" 260 | Write-Output "" -------------------------------------------------------------------------------- /ForensicMiner/02-Analyze/04-RecentDocs.ps1: -------------------------------------------------------------------------------- 1 | #Check if "RecentDocs" exist. 2 | $folderPath = "C:\ForensicMiner\MyEvidence\04-RecentDocs" 3 | if (Test-Path $folderPath) { 4 | Remove-Item $folderPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 5 | } 6 | 7 | # Create the "RecentDocs" folder. 8 | New-Item -ItemType Directory -Force -Path "C:\ForensicMiner\MyEvidence\04-RecentDocs" | Out-Null 9 | 10 | # Text $Outfile Veriable 11 | $OutFile = "C:\ForensicMiner\MyEvidence\04-RecentDocs\RecentDocs-History.txt" 12 | 13 | # Define the variable path to RecentDocs 14 | $RecentDocs = "Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs" 15 | 16 | # Define the variable path to NTUSER.DAT 17 | $NTUSER = "\NTUSER.DAT" 18 | 19 | # Define and exclude the relevant users for the foreach loop 20 | $Users = Get-ChildItem C:\Users -Exclude ("Public","TEMP","Default") -Directory 21 | 22 | # Use foreach loop to load offline users hive 23 | foreach ($user in $Users) { 24 | 25 | # Define full NTUSER.DAT path for each user 26 | $NTUSER_PATH = Join-Path -Path $User.FullName -ChildPath $NTUSER 27 | 28 | # Name of each user on the system without the "Name" column 29 | $OnlyUserName = $user | Select-Object -Property Name | ForEach-Object { $_.Name } 30 | 31 | # Load the NTUSER.DAT of the user and capture the output 32 | $output = reg load HKLM\Offline-$OnlyUserName "$NTUSER_PATH" 2>&1 33 | 34 | # Check if the output contains the success message 35 | if ($output -like "The operation completed successfully.") { 36 | 37 | # Online Username 38 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 39 | Write-Output "#################[Offline Users]#################" | Tee-Object -FilePath $OutFile -Append 40 | Write-Output "User Name: $OnlyUserName" | Tee-Object -FilePath $OutFile -Append 41 | Write-Output "Load Path: HKLM:\Offline-$OnlyUserName" | Tee-Object -FilePath $OutFile -Append 42 | Write-Output "Load Status: NTUSER.DAT was loaded to - [HKLM:]" | Tee-Object -FilePath $OutFile -Append 43 | Write-Output "Hive Status: Hive will be unloaded at next reboot" | Tee-Object -FilePath $OutFile -Append 44 | Write-Output "#################################################" | Tee-Object -FilePath $OutFile -Append 45 | Write-Output "|" | Tee-Object -FilePath $OutFile -Append 46 | Write-Output "V" | Tee-Object -FilePath $OutFile -Append 47 | 48 | # The RecentDocs List of offline Users 49 | $FullRegPath = "HKLM:\Offline-$OnlyUserName\$RecentDocs" 50 | 51 | $PathToExclude = "HKEY_LOCAL_MACHINE\Offline-$OnlyUserName\$RecentDocs\" 52 | 53 | # Get the subkeys under the registry path 54 | $subkeys = Get-ChildItem -Path $FullRegPath | ForEach-Object { $_.Name } 55 | 56 | # Filter the subkeys based on the character count 57 | $filteredSubkeys = $subkeys | Where-Object { $_.Substring($_.LastIndexOf("\") + 1).Length -le 11 } 58 | 59 | # Display the filtered subkeys 60 | foreach ($filteredSubkey in $filteredSubkeys) { 61 | 62 | # Replacing variable to remove path and showing only the file extension 63 | $FileEx = $filteredSubkey -replace [regex]::Escape($PathToExclude),'' 64 | 65 | # Removing the '.' from the $FileEx3 using regex 66 | $FileEx2 = $FileEx 67 | $FileEx3 = $FileEx2 -replace '\.','' 68 | 69 | 70 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 71 | Write-Output "Filename Extension: ($FileEx3)" | Tee-Object -FilePath $OutFile -Append 72 | 73 | # Exclude not important properties 74 | $Properties = Get-ItemProperty -Path "Registry::$filteredSubkey" | ForEach-Object { 75 | $_.PSObject.Properties.Remove('PSPath'), 76 | $_.PSObject.Properties.Remove('PSParentPath') 77 | $_.PSObject.Properties.Remove('PSChildName') 78 | $_.PSObject.Properties.Remove('PSProvider') 79 | $_ 80 | } 81 | 82 | $MRUListEx = $Properties.MRUListEx | ForEach-Object { "{0:X2}" -f $_ } 83 | $FormattedResult = $MRUListEx -join '-' 84 | $MRU = $FormattedResult -replace "-","," -replace ",FF,FF,FF,FF","" -replace ",00,00,00","" 85 | $MRU = $MRU -split ',' | ForEach-Object { [Convert]::ToInt32($_,16) } 86 | 87 | Write-Output "Order Of Execution: ($MRU)" | Tee-Object -FilePath $OutFile -Append 88 | Write-Output "+----[History]----+" | Tee-Object -FilePath $OutFile -Append 89 | 90 | $propertiesToExclude = @("MRUListEx") 91 | $orderedVariables = @() 92 | 93 | # Convert byte arrays to hexadecimal strings and display the values 94 | $Properties | ForEach-Object { 95 | $_.PSObject.Properties | Where-Object { $propertiesToExclude -notcontains $_.Name } | ForEach-Object { 96 | $name = $_.Name 97 | if ($name -ne "MRUListEx") { # Skip processing "MRUListEx" property 98 | $hexValue = [BitConverter]::ToString($_.Value).Replace("-","").Replace("00","") 99 | $bytes = [byte[]]::new($hexValue.Length / 2) 100 | for ($i = 0; $i -lt $hexValue.Length; $i += 2) { 101 | $bytes[$i / 2] = [System.Convert]::ToByte($hexValue.Substring($i,2),16) 102 | } 103 | $textValue = [System.Text.Encoding]::ASCII.GetString($bytes) 104 | $index = $textValue.IndexOf('?') 105 | if ($index -ge 0) { 106 | $textValue = $textValue.Substring(0,$index) 107 | } 108 | 109 | $orderedVariables += New-Object PSObject -Property @{ 110 | Name = $name 111 | TextValue = $textValue -replace ('.lnk.*','') 112 | } 113 | } 114 | } 115 | } 116 | 117 | # Convert the $MRU array to a string array 118 | $MRUStrings = $MRU | ForEach-Object { "$_" } 119 | 120 | # Sort the variables based on their MRU order 121 | $orderedVariables = $orderedVariables | Sort-Object @{ Expression = { $MRUStrings.IndexOf($_.Name) } } 122 | 123 | # Remove double file names using regex 124 | $FileEx1 = "$FileEx.*" 125 | 126 | $orderedVariables | ForEach-Object { 127 | Write-Output "($($_.Name)) $($_.TextValue -replace "$FileEx1","$FileEx")" | Tee-Object -FilePath $OutFile -Append 128 | 129 | 130 | } 131 | Write-Output " " | Tee-Object -FilePath $OutFile -Append 132 | } 133 | } 134 | $Quiet = reg unload HKLM\Offline-$OnlyUserName 2>&1 135 | if ($output -like "The operation completed successfully.") { 136 | 137 | } 138 | 139 | else { 140 | 141 | # Online Username 142 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 143 | Write-Output "#######[Online Users]########" | Tee-Object -FilePath $OutFile -Append 144 | Write-Output "User Name: $OnlyUserName" | Tee-Object -FilePath $OutFile -Append 145 | Write-Output "Which Hive: NT_USERS" | Tee-Object -FilePath $OutFile -Append 146 | Write-Output "Hive Status: Hive is Live" | Tee-Object -FilePath $OutFile -Append 147 | Write-Output "#############################" | Tee-Object -FilePath $OutFile -Append 148 | Write-Output " " | Tee-Object -FilePath $OutFile -Append 149 | Write-Output " " | Tee-Object -FilePath $OutFile -Append 150 | 151 | # Retrieve the user SID using WMI query 152 | $SID = (Get-WmiObject -Class Win32_UserProfile | Where-Object { $_.LocalPath.EndsWith($OnlyUserName) }).SID 153 | 154 | # Get Full Registry Path to HKEY_USERS 155 | $FullRegPath = "Registry::HKEY_USERS\$SID\Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs" 156 | 157 | # Variable for exclusion using -replace 158 | $PathToExclude = "HKEY_USERS\$SID\Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs\" 159 | 160 | # Get the subkeys under the registry path 161 | $subkeys = Get-ChildItem -Path $FullRegPath | ForEach-Object { $_.Name } 162 | 163 | # Filter the subkeys based on the character count 164 | $filteredSubkeys = $subkeys | Where-Object { $_.Substring($_.LastIndexOf("\") + 1).Length -le 11 } 165 | 166 | # Display the filtered subkeys 167 | foreach ($filteredSubkey in $filteredSubkeys) { 168 | 169 | # Replacing variable to remove path and showing only the file extension 170 | $FileEx = $filteredSubkey -replace [regex]::Escape($PathToExclude),'' 171 | 172 | # Removing the '.' from the $FileEx3 using regex 173 | $FileEx2 = $FileEx 174 | $FileEx3 = $FileEx2 -replace '\.','' 175 | 176 | 177 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 178 | Write-Output "Filename Extension: ($FileEx3)" | Tee-Object -FilePath $OutFile -Append 179 | 180 | # Exclude not important properties 181 | $Properties = Get-ItemProperty -Path "Registry::$filteredSubkey" | ForEach-Object { 182 | $_.PSObject.Properties.Remove('PSPath'), 183 | $_.PSObject.Properties.Remove('PSParentPath') 184 | $_.PSObject.Properties.Remove('PSChildName') 185 | $_.PSObject.Properties.Remove('PSProvider') 186 | $_ 187 | } 188 | 189 | $MRUListEx = $Properties.MRUListEx | ForEach-Object { "{0:X2}" -f $_ } 190 | $FormattedResult = $MRUListEx -join '-' 191 | $MRU = $FormattedResult -replace "-","," -replace ",FF,FF,FF,FF","" -replace ",00,00,00","" 192 | $MRU = $MRU -split ',' | ForEach-Object { [Convert]::ToInt32($_,16) } 193 | 194 | Write-Output "Order Of Execution: ($MRU)" | Tee-Object -FilePath $OutFile -Append 195 | Write-Output "+----[History]----+" | Tee-Object -FilePath $OutFile -Append 196 | 197 | $propertiesToExclude = @("MRUListEx") 198 | $orderedVariables = @() 199 | 200 | # Convert byte arrays to hexadecimal strings and display the values 201 | $Properties | ForEach-Object { 202 | $_.PSObject.Properties | Where-Object { $propertiesToExclude -notcontains $_.Name } | ForEach-Object { 203 | $name = $_.Name 204 | if ($name -ne "MRUListEx") { # Skip processing "MRUListEx" property 205 | $hexValue = [BitConverter]::ToString($_.Value).Replace("-","").Replace("00","") 206 | $bytes = [byte[]]::new($hexValue.Length / 2) 207 | for ($i = 0; $i -lt $hexValue.Length; $i += 2) { 208 | $bytes[$i / 2] = [System.Convert]::ToByte($hexValue.Substring($i,2),16) 209 | } 210 | $textValue = [System.Text.Encoding]::ASCII.GetString($bytes) 211 | $index = $textValue.IndexOf('?') 212 | if ($index -ge 0) { 213 | $textValue = $textValue.Substring(0,$index) 214 | } 215 | 216 | $orderedVariables += New-Object PSObject -Property @{ 217 | Name = $name 218 | TextValue = $textValue -replace ('.lnk.*','') 219 | } 220 | } 221 | } 222 | } 223 | 224 | # Convert the $MRU array to a string array 225 | $MRUStrings = $MRU | ForEach-Object { "$_" } 226 | 227 | # Sort the variables based on their MRU order 228 | $orderedVariables = $orderedVariables | Sort-Object @{ Expression = { $MRUStrings.IndexOf($_.Name) } } 229 | 230 | # Remove double file names using regex 231 | $FileEx1 = "$FileEx.*" 232 | 233 | $orderedVariables | ForEach-Object { 234 | Write-Output "($($_.Name)) $($_.TextValue -replace "$FileEx1","$FileEx")" | Tee-Object -FilePath $OutFile -Append 235 | 236 | 237 | } 238 | Write-Output "" | Tee-Object -FilePath $OutFile -Append 239 | } 240 | } 241 | } 242 | Write-Output "+-------------------------------------------------------------+" 243 | Write-Output "|The record of this forensic evidence is saved on this machine|" 244 | Write-Output "+-------------------------------------------------------------+" 245 | Write-Output '| Path - "C:\ForensicMiner\MyEvidence\04-RecentDocs" |' 246 | Write-Output "+-------------------------------------------------------------+" 247 | Write-Output "" --------------------------------------------------------------------------------