param( [string]$OutputDir = "runs/offline-broute-reverse", [string]$ReportPath = "docs/source-discovery/2026-07-12-offline-broute-reverse-index.md" ) $ErrorActionPreference = "Stop" $repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path $outDir = Join-Path $repo $OutputDir $reportFullPath = Join-Path $repo $ReportPath New-Item -ItemType Directory -Force -Path $outDir | Out-Null New-Item -ItemType Directory -Force -Path (Split-Path -Parent $reportFullPath) | Out-Null $samples = @( @{ path = "runs/offline-real-client-window/full/zyl/Impp/IMPlatformClient.exe" role = "main managed client; text send, chat window, plugin/IPC candidates" expected_sha256 = "E2966E58360DAEEBF178410A961E2DC52748C63E9CCBD94BD6EC8434A1A09CB7" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Service.dll" role = "file upload service candidates" expected_sha256 = "F859DE2F34E024B5F372D95F22CBF8A018C780F24203E7A76D392E52BD90CADD" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Interface.dll" role = "service/interface contract candidates" expected_sha256 = "DD093CF61FAE85C2D2581F289B01AA477546712E098FEF81272FDD989E50D12D" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Model.dll" role = "model/parameter types" expected_sha256 = "7CBABDD23A7234D15E294C549EEEC78EFBAD6E957CD45A6E8A85309349A624A5" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.UI.dll" role = "UI/plugin helpers and possible send controls" expected_sha256 = "4C61212519C01D1B731ED4F20DF3411C491616F4ADA98A4529722A6AA3689E6D" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Common.dll" role = "shared utility and message types" expected_sha256 = "02A47C99C27C9BFE2BADC438389300C92220B07609BD87C48B4B5E1B4EE6AEB4" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/IMPP.Helper.dll" role = "helper abstractions" expected_sha256 = "30932D082B6678699C832C63F923E01EAD84674FAEDB613D631E034E03742FB9" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/smack.dll" role = "XMPP chat/send layer" expected_sha256 = "BAD0BB0591765DB153B17CECC1112B0BBDBF3B1D3370DDF973F91974E92CEC66" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/TcpFileTransfer.dll" role = "native/transfer candidate" expected_sha256 = "6C4874B46D1E7DC04C9B6784180603452400B881E04509D464A0D58814EFEDA7" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/HttpServerLib.dll" role = "local API/IPC candidate" expected_sha256 = "FFDB633216AE332B8EDFFC83E2AE546B7A80144C659FF4053FDFE4FE382A8D12" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/INetwork.dll" role = "network abstraction candidate" expected_sha256 = "E40BE4EE2439E4280461F4D2BADB318A5F4572428F069AB6D17B4C4F0E8CFAC9" }, @{ path = "runs/offline-real-client-window/full/zyl/Impp/IOClientNetwork.dll" role = "network implementation candidate" expected_sha256 = "64CA231A614771325741A5F098E52EBF20F7190E339B64962DE2EDEDCFFFF904" } ) $entries = foreach ($sample in $samples) { $fullPath = Join-Path $repo $sample.path $exists = Test-Path -LiteralPath $fullPath -PathType Leaf $item = $null $sha256 = "" $matches = $false if ($exists) { $item = Get-Item -LiteralPath $fullPath $sha256 = (Get-FileHash -LiteralPath $fullPath -Algorithm SHA256).Hash.ToUpperInvariant() $matches = ($sha256 -eq $sample.expected_sha256) } [pscustomobject]@{ path = $sample.path file_name = Split-Path -Leaf $sample.path role = $sample.role exists = $exists size_bytes = if ($item) { $item.Length } else { $null } last_write_time = if ($item) { $item.LastWriteTime.ToString("o") } else { $null } sha256 = $sha256 expected_sha256 = $sample.expected_sha256 sha256_matches_expected = $matches } } $summary = [pscustomobject]@{ generated_at = (Get-Date).ToUniversalTime().ToString("o") repository = $repo output_dir = $OutputDir samples_total = @($entries).Count samples_present = @($entries | Where-Object { $_.exists }).Count hash_matches = @($entries | Where-Object { $_.sha256_matches_expected }).Count originals_copied = $false originals_modified = $false entries = $entries } $jsonPath = Join-Path $outDir "index.json" $summary | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $jsonPath -Encoding UTF8 $lines = New-Object System.Collections.Generic.List[string] $lines.Add("# Offline B-Route Reverse Index") $lines.Add("") $lines.Add("Date: 2026-07-12") $lines.Add("") $lines.Add("## Scope") $lines.Add("") $lines.Add("This index records the read-only offline samples for B-route reverse engineering. The script reads metadata and SHA256 hashes only; it does not copy or modify the original binaries.") $lines.Add("") $lines.Add("## Summary") $lines.Add("") $lines.Add("- Samples total: $($summary.samples_total)") $lines.Add("- Samples present: $($summary.samples_present)") $lines.Add("- Hash matches: $($summary.hash_matches)") $lines.Add("- Originals copied: false") $lines.Add("- Originals modified: false") $lines.Add("- Machine JSON: ``$OutputDir/index.json``") $lines.Add("") $lines.Add("## Sample table") $lines.Add("") $lines.Add("| Sample | Role | Size | SHA256 match | SHA256 |") $lines.Add("| --- | --- | ---: | --- | --- |") foreach ($entry in $entries) { $size = if ($null -ne $entry.size_bytes) { [string]$entry.size_bytes } else { "missing" } $match = if ($entry.sha256_matches_expected) { "yes" } else { "no" } $sha = if ($entry.sha256) { $entry.sha256 } else { "missing" } $lines.Add("| ``$($entry.path)`` | $($entry.role) | $size | $match | ``$sha`` |") } $lines.Add("") $lines.Add("## Verified facts") $lines.Add("") $lines.Add("- All metadata came from local filesystem reads under the repository workspace.") $lines.Add("- The expected primary B-route samples are present if `Samples present` equals `Samples total`.") $lines.Add("- Hash matching only proves local file identity against this plan's recorded sample list; it does not prove runtime invocability.") $lines.Add("") $lines.Add("## Next reverse targets") $lines.Add("") $lines.Add("1. Text-send static call graph: `SendTxtMessageByJid`, `MessageScheduling.SendChatMessage`, `Chat.SendMessage`, `XMPPConnection.send`.") $lines.Add("2. File-send/upload static call graph: `OffLineFileSend.sendFile`, `FileTransfer.FileUpload`, `AsynFileUpload`, `sendFileMessage`.") $lines.Add("3. Bridge/IPC/plugin map: `HttpServerLib`, plugin loaders, local HTTP, named pipes, command-line switches, services.") ($lines -join "`n") + "`n" | Set-Content -LiteralPath $reportFullPath -Encoding UTF8 [pscustomobject]@{ ok = $true json_path = $jsonPath report_path = $reportFullPath samples_total = $summary.samples_total samples_present = $summary.samples_present hash_matches = $summary.hash_matches originals_copied = $false originals_modified = $false } | ConvertTo-Json -Depth 4