mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
refactor(windows): split Windows code into winapi (#575)
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
//go:build windows && abe_embed
|
||||
|
||||
package crypto
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//go:generate make -C ../.. payload
|
||||
|
||||
//go:embed abe_extractor_amd64.bin
|
||||
var abePayloadAmd64 []byte
|
||||
|
||||
func ABEPayload(arch string) ([]byte, error) {
|
||||
switch arch {
|
||||
case "amd64":
|
||||
if len(abePayloadAmd64) == 0 {
|
||||
return nil, fmt.Errorf("abe: amd64 payload is empty (build system bug)")
|
||||
}
|
||||
return abePayloadAmd64, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("abe: arch %q not supported in this build", arch)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
//go:build windows && !abe_embed
|
||||
|
||||
package crypto
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ABEPayload(arch string) ([]byte, error) {
|
||||
return nil, fmt.Errorf(
|
||||
"abe: payload not embedded in this build (rebuild with -tags abe_embed; arch=%s)",
|
||||
arch,
|
||||
)
|
||||
}
|
||||
@@ -3,9 +3,7 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
"github.com/moond4rk/hackbrowserdata/utils/winapi"
|
||||
)
|
||||
|
||||
// gcmNonceSize is defined in crypto.go (cross-platform).
|
||||
@@ -32,47 +30,10 @@ func DecryptYandex(key, ciphertext []byte) ([]byte, error) {
|
||||
return AESGCMDecrypt(key, nonce, payload)
|
||||
}
|
||||
|
||||
type dataBlob struct {
|
||||
cbData uint32
|
||||
pbData *byte
|
||||
}
|
||||
|
||||
func newBlob(d []byte) *dataBlob {
|
||||
if len(d) == 0 {
|
||||
return &dataBlob{}
|
||||
}
|
||||
return &dataBlob{
|
||||
pbData: &d[0],
|
||||
cbData: uint32(len(d)),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *dataBlob) bytes() []byte {
|
||||
d := make([]byte, b.cbData)
|
||||
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
|
||||
return d
|
||||
}
|
||||
|
||||
// DecryptDPAPI (Data Protection Application Programming Interface)
|
||||
// is a simple cryptographic application programming interface
|
||||
// available as a built-in component in Windows 2000 and
|
||||
// later versions of Microsoft Windows operating systems
|
||||
// DecryptDPAPI decrypts a DPAPI-protected blob using the current user's
|
||||
// master key. The actual Win32 call (and its DATA_BLOB / LocalFree dance)
|
||||
// lives in utils/winapi so every package that needs a syscall handle
|
||||
// shares a single declaration instead of re-opening Crypt32.dll per call.
|
||||
func DecryptDPAPI(ciphertext []byte) ([]byte, error) {
|
||||
crypt32 := syscall.NewLazyDLL("Crypt32.dll")
|
||||
kernel32 := syscall.NewLazyDLL("Kernel32.dll")
|
||||
unprotectDataProc := crypt32.NewProc("CryptUnprotectData")
|
||||
localFreeProc := kernel32.NewProc("LocalFree")
|
||||
|
||||
var outBlob dataBlob
|
||||
r, _, err := unprotectDataProc.Call(
|
||||
uintptr(unsafe.Pointer(newBlob(ciphertext))),
|
||||
0, 0, 0, 0, 0,
|
||||
uintptr(unsafe.Pointer(&outBlob)),
|
||||
)
|
||||
if r == 0 {
|
||||
return nil, fmt.Errorf("CryptUnprotectData failed with error %w", err)
|
||||
}
|
||||
|
||||
defer localFreeProc.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
|
||||
return outBlob.bytes(), nil
|
||||
return winapi.DecryptDPAPI(ciphertext)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/moond4rk/hackbrowserdata/crypto"
|
||||
"github.com/moond4rk/hackbrowserdata/crypto/windows/payload"
|
||||
"github.com/moond4rk/hackbrowserdata/log"
|
||||
"github.com/moond4rk/hackbrowserdata/utils/browserutil"
|
||||
"github.com/moond4rk/hackbrowserdata/utils/injector"
|
||||
"github.com/moond4rk/hackbrowserdata/utils/winutil"
|
||||
)
|
||||
|
||||
const envEncKeyB64 = "HBD_ABE_ENC_B64"
|
||||
@@ -36,12 +36,12 @@ func (r *ABERetriever) RetrieveKey(storage, localStatePath string) ([]byte, erro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payload, err := crypto.ABEPayload("amd64")
|
||||
pl, err := payload.Get("amd64")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("abe: %w", err)
|
||||
}
|
||||
|
||||
exePath, err := browserutil.ExecutablePath(browserKey)
|
||||
exePath, err := winutil.ExecutablePath(browserKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("abe: %w", err)
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (r *ABERetriever) RetrieveKey(storage, localStatePath string) ([]byte, erro
|
||||
}
|
||||
|
||||
inj := &injector.Reflective{}
|
||||
key, err := inj.Inject(exePath, payload, env)
|
||||
key, err := inj.Inject(exePath, pl, env)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("abe: inject into %s: %w", exePath, err)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ ABE_ARCH ?= amd64
|
||||
ABE_TARGET ?= x86_64-windows-gnu
|
||||
|
||||
ABE_SRC_DIR = crypto/windows/abe_native
|
||||
ABE_BIN_DIR = crypto
|
||||
ABE_BIN_DIR = crypto/windows/payload
|
||||
ABE_BIN = $(ABE_BIN_DIR)/abe_extractor_$(ABE_ARCH).bin
|
||||
|
||||
ABE_CFLAGS = -shared -s -O2 \
|
||||
@@ -38,7 +38,7 @@ payload-verify: $(ABE_BIN)
|
||||
fi
|
||||
|
||||
payload-clean:
|
||||
rm -f $(ABE_BIN_DIR)/abe_extractor_*.bin
|
||||
rm -f $(ABE_BIN_DIR)/abe_extractor_*.bin $(ABE_BIN_DIR)/abe_extractor*.lib
|
||||
|
||||
# Scratch-layout codegen. The C header bootstrap_layout.h is the single
|
||||
# source of truth; the Go constants in crypto/windows/abe_native/bootstrap
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
//go:build windows && abe_embed
|
||||
|
||||
// Package payload holds the compiled reflective-injection ABE payload
|
||||
// binary and exposes it to the rest of HackBrowserData. The `abe_embed`
|
||||
// build tag selects between a real //go:embed'd binary (this file) and
|
||||
// a stub (stub_windows.go) so the default `go build ./...` succeeds on
|
||||
// machines without the zig toolchain.
|
||||
package payload
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//go:generate make -C ../../.. payload
|
||||
|
||||
//go:embed abe_extractor_amd64.bin
|
||||
var abePayloadAmd64 []byte
|
||||
|
||||
// Get returns the embedded ABE payload for the given architecture.
|
||||
// Only "amd64" is supported today; x86 / ARM64 payloads are future work.
|
||||
func Get(arch string) ([]byte, error) {
|
||||
switch arch {
|
||||
case "amd64":
|
||||
if len(abePayloadAmd64) == 0 {
|
||||
return nil, fmt.Errorf("abe: amd64 payload is empty (build system bug)")
|
||||
}
|
||||
return abePayloadAmd64, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("abe: arch %q not supported in this build", arch)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//go:build windows && !abe_embed
|
||||
|
||||
package payload
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Get returns an error in non-release builds so feature code that needs
|
||||
// the payload fails fast with a clear message. Release builds (built
|
||||
// with -tags abe_embed) replace this with the //go:embed'd binary.
|
||||
func Get(arch string) ([]byte, error) {
|
||||
return nil, fmt.Errorf(
|
||||
"abe: payload not embedded in this build (rebuild with -tags abe_embed; arch=%s)",
|
||||
arch,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user