├── 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 | 
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 | 
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 ""
--------------------------------------------------------------------------------