mirror of
https://github.com/qtmleap/revkit.git
synced 2026-10-11 04:11:51 +02:00
feat(tweak): add HMAC_CTX/SHA384/EVP_Digest hooks to trace appboot sign key derivation
Add incremental HMAC hooks (HMAC_CTX_new, HMAC_Init_ex, HMAC_Update, HMAC_Final), one-shot SHA384, and EVP_DigestInit_ex/Update/Final_ex hooks in NFWebCrypto to correlate full key material across multi-step HMAC sequences. HKDF offset hooks are logged as candidate addresses but not installed (prototype unverified) to avoid crashes. Log reveals 38b2030d and 8887ddf1 appear first in HMAC_Init_ex and are not produced by any HMAC operation, pointing to an upstream derivation path (HKDF, AES whitebox, or DH derive) not yet captured. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
e1f68dca27
commit
6a0b085d48
@@ -86,6 +86,110 @@ static volatile int g_inHook = 0;
|
||||
// Counter for large HMAC data dumps
|
||||
static int g_hmacDumpCount = 0;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HMAC_CTX tracking table
|
||||
// Correlates ctx pointer -> accumulated state across Init/Update/Final calls.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#define HMAC_CTX_TABLE_SIZE 32
|
||||
|
||||
typedef struct {
|
||||
void *ctx; // non-NULL means slot is in use
|
||||
uint8_t key[128];
|
||||
int key_len;
|
||||
int md_nid; // NID of the EVP_MD (or -1 if unknown)
|
||||
uint8_t data_head[64]; // first 64B of input data
|
||||
size_t data_head_len;
|
||||
size_t data_total;
|
||||
int seq; // call sequence number
|
||||
} HmacCtxEntry;
|
||||
|
||||
static HmacCtxEntry g_hmacCtxTable[HMAC_CTX_TABLE_SIZE];
|
||||
static int g_hmacCtxSeq = 0;
|
||||
|
||||
static HmacCtxEntry *hmacCtxFind(void *ctx) {
|
||||
for (int i = 0; i < HMAC_CTX_TABLE_SIZE; i++) {
|
||||
if (g_hmacCtxTable[i].ctx == ctx) return &g_hmacCtxTable[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HmacCtxEntry *hmacCtxAlloc(void *ctx) {
|
||||
// Reuse existing slot
|
||||
HmacCtxEntry *e = hmacCtxFind(ctx);
|
||||
if (e) return e;
|
||||
// Find free slot
|
||||
for (int i = 0; i < HMAC_CTX_TABLE_SIZE; i++) {
|
||||
if (g_hmacCtxTable[i].ctx == NULL) {
|
||||
memset(&g_hmacCtxTable[i], 0, sizeof(HmacCtxEntry));
|
||||
g_hmacCtxTable[i].ctx = ctx;
|
||||
g_hmacCtxTable[i].md_nid = -1;
|
||||
g_hmacCtxTable[i].seq = __sync_fetch_and_add(&g_hmacCtxSeq, 1);
|
||||
return &g_hmacCtxTable[i];
|
||||
}
|
||||
}
|
||||
// Table full — evict slot 0
|
||||
memset(&g_hmacCtxTable[0], 0, sizeof(HmacCtxEntry));
|
||||
g_hmacCtxTable[0].ctx = ctx;
|
||||
g_hmacCtxTable[0].md_nid = -1;
|
||||
g_hmacCtxTable[0].seq = __sync_fetch_and_add(&g_hmacCtxSeq, 1);
|
||||
return &g_hmacCtxTable[0];
|
||||
}
|
||||
|
||||
static void hmacCtxFree(void *ctx) {
|
||||
HmacCtxEntry *e = hmacCtxFind(ctx);
|
||||
if (e) memset(e, 0, sizeof(HmacCtxEntry));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// EVP_DigestCtx tracking table (for SHA384 incremental)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#define EVP_CTX_TABLE_SIZE 16
|
||||
|
||||
typedef struct {
|
||||
void *ctx;
|
||||
int md_nid;
|
||||
uint8_t data_head[64];
|
||||
size_t data_head_len;
|
||||
size_t data_total;
|
||||
int seq;
|
||||
} EvpCtxEntry;
|
||||
|
||||
static EvpCtxEntry g_evpCtxTable[EVP_CTX_TABLE_SIZE];
|
||||
static int g_evpCtxSeq = 0;
|
||||
|
||||
static EvpCtxEntry *evpCtxFind(void *ctx) {
|
||||
for (int i = 0; i < EVP_CTX_TABLE_SIZE; i++) {
|
||||
if (g_evpCtxTable[i].ctx == ctx) return &g_evpCtxTable[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static EvpCtxEntry *evpCtxAlloc(void *ctx) {
|
||||
EvpCtxEntry *e = evpCtxFind(ctx);
|
||||
if (e) return e;
|
||||
for (int i = 0; i < EVP_CTX_TABLE_SIZE; i++) {
|
||||
if (g_evpCtxTable[i].ctx == NULL) {
|
||||
memset(&g_evpCtxTable[i], 0, sizeof(EvpCtxEntry));
|
||||
g_evpCtxTable[i].ctx = ctx;
|
||||
g_evpCtxTable[i].md_nid = -1;
|
||||
g_evpCtxTable[i].seq = __sync_fetch_and_add(&g_evpCtxSeq, 1);
|
||||
return &g_evpCtxTable[i];
|
||||
}
|
||||
}
|
||||
memset(&g_evpCtxTable[0], 0, sizeof(EvpCtxEntry));
|
||||
g_evpCtxTable[0].ctx = ctx;
|
||||
g_evpCtxTable[0].md_nid = -1;
|
||||
g_evpCtxTable[0].seq = __sync_fetch_and_add(&g_evpCtxSeq, 1);
|
||||
return &g_evpCtxTable[0];
|
||||
}
|
||||
|
||||
static void evpCtxFree(void *ctx) {
|
||||
EvpCtxEntry *e = evpCtxFind(ctx);
|
||||
if (e) memset(e, 0, sizeof(EvpCtxEntry));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Opaque types (OpenSSL)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -179,7 +283,371 @@ static unsigned char *hook_HMAC(const EVP_MD *evp_md,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 2: NSData dataWithContentsOfFile: — catch large file reads (4-10 KB)
|
||||
// HOOK 2: HMAC_CTX_new — log context creation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static void *(*orig_HMAC_CTX_new)(void);
|
||||
|
||||
static void *hook_HMAC_CTX_new(void) {
|
||||
void *ctx = orig_HMAC_CTX_new ? orig_HMAC_CTX_new() : NULL;
|
||||
if (ctx && !g_inHook) {
|
||||
g_inHook = 1;
|
||||
hmacCtxAlloc(ctx);
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:@"[NFXEntityAuth][HMAC_CTX_new] ctx=%p", ctx]);
|
||||
g_inHook = 0;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 3: HMAC_Init_ex(ctx, key, key_len, evp_md, engine)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int (*orig_HMAC_Init_ex)(void *ctx, const void *key, int key_len,
|
||||
const EVP_MD *evp_md, void *engine);
|
||||
|
||||
// Forward-declare so we can get NID inside the hook
|
||||
typedef int (*EVP_MD_type_fn)(const EVP_MD *);
|
||||
static EVP_MD_type_fn g_EVP_MD_type = NULL;
|
||||
|
||||
static int hook_HMAC_Init_ex(void *ctx, const void *key, int key_len,
|
||||
const EVP_MD *evp_md, void *engine) {
|
||||
int ret = orig_HMAC_Init_ex ? orig_HMAC_Init_ex(ctx, key, key_len, evp_md, engine) : 1;
|
||||
|
||||
if (ctx && !g_inHook) {
|
||||
g_inHook = 1;
|
||||
|
||||
HmacCtxEntry *e = hmacCtxAlloc(ctx);
|
||||
if (e && key && key_len > 0 && key_len <= (int)sizeof(e->key)) {
|
||||
memcpy(e->key, key, (size_t)key_len);
|
||||
e->key_len = key_len;
|
||||
}
|
||||
if (e && evp_md && g_EVP_MD_type) {
|
||||
e->md_nid = g_EVP_MD_type(evp_md);
|
||||
}
|
||||
// Reset data tracking on re-init
|
||||
if (e) {
|
||||
e->data_head_len = 0;
|
||||
e->data_total = 0;
|
||||
}
|
||||
|
||||
int nid = e ? e->md_nid : -1;
|
||||
int seq = e ? e->seq : -1;
|
||||
NSString *keyHex = (key && key_len > 0)
|
||||
? hexEncodeShort((const uint8_t *)key, (size_t)key_len) : @"(null)";
|
||||
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][HMAC_Init_ex] seq=%d ctx=%p nid=%d key(%dB)=%@",
|
||||
seq, ctx, nid, key_len, keyHex]);
|
||||
g_inHook = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 4: HMAC_Update(ctx, data, len)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int (*orig_HMAC_Update)(void *ctx, const unsigned char *data, size_t len);
|
||||
|
||||
static int hook_HMAC_Update(void *ctx, const unsigned char *data, size_t len) {
|
||||
int ret = orig_HMAC_Update ? orig_HMAC_Update(ctx, data, len) : 1;
|
||||
|
||||
if (ctx && !g_inHook) {
|
||||
g_inHook = 1;
|
||||
|
||||
HmacCtxEntry *e = hmacCtxFind(ctx);
|
||||
if (e) {
|
||||
// Accumulate first 64B of data
|
||||
if (data && len > 0 && e->data_head_len < sizeof(e->data_head)) {
|
||||
size_t copy = sizeof(e->data_head) - e->data_head_len;
|
||||
if (copy > len) copy = len;
|
||||
memcpy(e->data_head + e->data_head_len, data, copy);
|
||||
e->data_head_len += copy;
|
||||
}
|
||||
e->data_total += len;
|
||||
}
|
||||
|
||||
int seq = e ? e->seq : -1;
|
||||
NSString *dataHex = (data && len > 0)
|
||||
? hexEncodeShort((const uint8_t *)data, len) : @"(null)";
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][HMAC_Update] seq=%d ctx=%p data(%zuB)=%@",
|
||||
seq, ctx, len, dataHex]);
|
||||
g_inHook = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 5: HMAC_Final(ctx, md, md_len)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int (*orig_HMAC_Final)(void *ctx, unsigned char *md, unsigned int *md_len);
|
||||
|
||||
static int hook_HMAC_Final(void *ctx, unsigned char *md, unsigned int *md_len) {
|
||||
int ret = orig_HMAC_Final ? orig_HMAC_Final(ctx, md, md_len) : 1;
|
||||
|
||||
if (ctx && !g_inHook) {
|
||||
g_inHook = 1;
|
||||
|
||||
HmacCtxEntry *e = hmacCtxFind(ctx);
|
||||
unsigned int outLen = (md_len && *md_len > 0) ? *md_len : 0;
|
||||
// Derive expected output size from the tracked NID if md_len was not set
|
||||
if (outLen == 0 && md) {
|
||||
int nidGuess = e ? e->md_nid : -1;
|
||||
if (nidGuess == 673) outLen = 48; // SHA384
|
||||
else if (nidGuess == 674) outLen = 64; // SHA512
|
||||
else outLen = 32; // SHA256 or unknown
|
||||
}
|
||||
|
||||
int seq = e ? e->seq : -1;
|
||||
int nid = e ? e->md_nid : -1;
|
||||
int keyLen = e ? e->key_len : 0;
|
||||
NSString *keyHex = (e && e->key_len > 0)
|
||||
? hexEncode(e->key, (size_t)e->key_len) : @"(none)";
|
||||
NSString *dataHeadHex = (e && e->data_head_len > 0)
|
||||
? hexEncode(e->data_head, e->data_head_len) : @"(none)";
|
||||
NSString *outHex = (md && outLen > 0)
|
||||
? hexEncode(md, outLen) : @"(null)";
|
||||
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][HMAC_Final] seq=%d ctx=%p nid=%d key(%dB)=%@ "
|
||||
@"data_total=%zuB data_head=%@ output(%uB)=%@",
|
||||
seq, ctx, nid, keyLen, keyHex,
|
||||
e ? e->data_total : (size_t)0, dataHeadHex,
|
||||
outLen, outHex]);
|
||||
|
||||
// If output is 48B (SHA384), log specially — first 32B might be the sign key
|
||||
if (outLen >= 48 && md) {
|
||||
NSString *first32 = hexEncode(md, 32);
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][HMAC_Final] SHA384 first32=%@", first32]);
|
||||
}
|
||||
|
||||
hmacCtxFree(ctx);
|
||||
g_inHook = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 6: SHA384 one-shot
|
||||
// unsigned char *SHA384(const unsigned char *d, size_t n, unsigned char *md)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static unsigned char *(*orig_SHA384)(const unsigned char *d, size_t n, unsigned char *md);
|
||||
|
||||
static unsigned char *hook_SHA384(const unsigned char *d, size_t n, unsigned char *md) {
|
||||
unsigned char *ret = orig_SHA384 ? orig_SHA384(d, n, md) : NULL;
|
||||
|
||||
if (!g_inHook && ret) {
|
||||
g_inHook = 1;
|
||||
NSString *dataHex = hexEncodeShort((const uint8_t *)d, n);
|
||||
NSString *outHex = hexEncode(ret, 48);
|
||||
NSString *first32 = hexEncode(ret, 32);
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][SHA384] data(%zuB)=%@ digest(48B)=%@ first32=%@",
|
||||
n, dataHex, outHex, first32]);
|
||||
g_inHook = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 7: EVP_DigestInit_ex(ctx, evp_md, engine) — track SHA384 incremental
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int (*orig_EVP_DigestInit_ex)(void *ctx, const EVP_MD *evp_md, void *engine);
|
||||
|
||||
static int hook_EVP_DigestInit_ex(void *ctx, const EVP_MD *evp_md, void *engine) {
|
||||
int ret = orig_EVP_DigestInit_ex ? orig_EVP_DigestInit_ex(ctx, evp_md, engine) : 1;
|
||||
|
||||
if (ctx && !g_inHook) {
|
||||
g_inHook = 1;
|
||||
int nid = (evp_md && g_EVP_MD_type) ? g_EVP_MD_type(evp_md) : -1;
|
||||
// NID 673 = SHA384, 672 = SHA256, 674 = SHA512
|
||||
// Only track SHA384 (NID 673)
|
||||
if (nid == 673) {
|
||||
EvpCtxEntry *e = evpCtxAlloc(ctx);
|
||||
if (e) {
|
||||
e->md_nid = nid;
|
||||
e->data_head_len = 0;
|
||||
e->data_total = 0;
|
||||
}
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][EVP_DigestInit_ex] SHA384 seq=%d ctx=%p",
|
||||
e ? e->seq : -1, ctx]);
|
||||
}
|
||||
g_inHook = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 8: EVP_DigestUpdate(ctx, data, len)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int (*orig_EVP_DigestUpdate)(void *ctx, const void *data, size_t len);
|
||||
|
||||
static int hook_EVP_DigestUpdate(void *ctx, const void *data, size_t len) {
|
||||
int ret = orig_EVP_DigestUpdate ? orig_EVP_DigestUpdate(ctx, data, len) : 1;
|
||||
|
||||
if (ctx && !g_inHook) {
|
||||
EvpCtxEntry *e = evpCtxFind(ctx);
|
||||
if (e) {
|
||||
g_inHook = 1;
|
||||
if (data && len > 0 && e->data_head_len < sizeof(e->data_head)) {
|
||||
size_t copy = sizeof(e->data_head) - e->data_head_len;
|
||||
if (copy > len) copy = len;
|
||||
memcpy(e->data_head + e->data_head_len, data, copy);
|
||||
e->data_head_len += copy;
|
||||
}
|
||||
e->data_total += len;
|
||||
NSString *dataHex = (data && len > 0)
|
||||
? hexEncodeShort((const uint8_t *)data, len) : @"(null)";
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][EVP_DigestUpdate] SHA384 seq=%d ctx=%p data(%zuB)=%@",
|
||||
e->seq, ctx, len, dataHex]);
|
||||
g_inHook = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 9: EVP_DigestFinal_ex(ctx, md, s)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int (*orig_EVP_DigestFinal_ex)(void *ctx, unsigned char *md, unsigned int *s);
|
||||
|
||||
static int hook_EVP_DigestFinal_ex(void *ctx, unsigned char *md, unsigned int *s) {
|
||||
int ret = orig_EVP_DigestFinal_ex ? orig_EVP_DigestFinal_ex(ctx, md, s) : 1;
|
||||
|
||||
if (ctx && !g_inHook) {
|
||||
EvpCtxEntry *e = evpCtxFind(ctx);
|
||||
if (e) {
|
||||
g_inHook = 1;
|
||||
unsigned int outLen = (s && *s > 0) ? *s : 48; // SHA384 = 48B
|
||||
NSString *outHex = (md && outLen > 0 && outLen <= 64)
|
||||
? hexEncode(md, outLen) : @"(null)";
|
||||
NSString *first32 = (md && outLen >= 32)
|
||||
? hexEncode(md, 32) : @"(short)";
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][EVP_DigestFinal_ex] SHA384 seq=%d ctx=%p "
|
||||
@"data_total=%zuB output(%uB)=%@ first32=%@",
|
||||
e->seq, ctx, e->data_total, outLen, outHex, first32]);
|
||||
evpCtxFree(ctx);
|
||||
g_inHook = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 10: HKDF offset hooks in NFWebCrypto
|
||||
//
|
||||
// NFWebCrypto offsets (from IPA analysis):
|
||||
// HKDF-Extract : 0x00011990
|
||||
// HKDF-Expand : 0x000119b8
|
||||
//
|
||||
// Both functions are static C++ — no exported symbol, hook by offset.
|
||||
// Prototype guessed from HKDF spec:
|
||||
// int HKDF_extract(const EVP_MD *digest,
|
||||
// const uint8_t *salt, size_t salt_len,
|
||||
// const uint8_t *ikm, size_t ikm_len,
|
||||
// uint8_t *prk, size_t *prk_len)
|
||||
//
|
||||
// int HKDF_expand(const EVP_MD *digest,
|
||||
// const uint8_t *prk, size_t prk_len,
|
||||
// const uint8_t *info, size_t info_len,
|
||||
// uint8_t *okm, size_t okm_len)
|
||||
//
|
||||
// NOTE: These offsets are for NFWebCrypto v15.48.1 and may need adjustment.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
typedef int (*HKDF_extract_fn)(const EVP_MD *digest,
|
||||
const uint8_t *salt, size_t salt_len,
|
||||
const uint8_t *ikm, size_t ikm_len,
|
||||
uint8_t *prk, size_t *prk_len);
|
||||
typedef int (*HKDF_expand_fn)(const EVP_MD *digest,
|
||||
const uint8_t *prk, size_t prk_len,
|
||||
const uint8_t *info, size_t info_len,
|
||||
uint8_t *okm, size_t okm_len);
|
||||
|
||||
static HKDF_extract_fn orig_HKDF_extract = NULL;
|
||||
static HKDF_expand_fn orig_HKDF_expand = NULL;
|
||||
|
||||
static int hook_HKDF_extract(const EVP_MD *digest,
|
||||
const uint8_t *salt, size_t salt_len,
|
||||
const uint8_t *ikm, size_t ikm_len,
|
||||
uint8_t *prk, size_t *prk_len) {
|
||||
int ret = orig_HKDF_extract
|
||||
? orig_HKDF_extract(digest, salt, salt_len, ikm, ikm_len, prk, prk_len)
|
||||
: 0;
|
||||
|
||||
if (!g_inHook) {
|
||||
g_inHook = 1;
|
||||
int nid = (digest && g_EVP_MD_type) ? g_EVP_MD_type(digest) : -1;
|
||||
size_t outLen = (prk_len && *prk_len > 0) ? *prk_len : (nid == 673 ? 48 : 32);
|
||||
NSString *saltHex = salt ? hexEncodeShort(salt, salt_len) : @"(null)";
|
||||
NSString *ikmHex = ikm ? hexEncodeShort(ikm, ikm_len) : @"(null)";
|
||||
NSString *prkHex = prk ? hexEncode(prk, outLen) : @"(null)";
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][HKDF_extract] nid=%d salt(%zuB)=%@ ikm(%zuB)=%@ prk(%zuB)=%@",
|
||||
nid, salt_len, saltHex, ikm_len, ikmHex, outLen, prkHex]);
|
||||
if (prk && outLen >= 32) {
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][HKDF_extract] prk_first32=%@",
|
||||
hexEncode(prk, 32)]);
|
||||
}
|
||||
g_inHook = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hook_HKDF_expand(const EVP_MD *digest,
|
||||
const uint8_t *prk, size_t prk_len,
|
||||
const uint8_t *info, size_t info_len,
|
||||
uint8_t *okm, size_t okm_len) {
|
||||
int ret = orig_HKDF_expand
|
||||
? orig_HKDF_expand(digest, prk, prk_len, info, info_len, okm, okm_len)
|
||||
: 0;
|
||||
|
||||
if (!g_inHook) {
|
||||
g_inHook = 1;
|
||||
int nid = (digest && g_EVP_MD_type) ? g_EVP_MD_type(digest) : -1;
|
||||
NSString *prkHex = prk ? hexEncodeShort(prk, prk_len) : @"(null)";
|
||||
NSString *infoHex = info ? hexEncodeShort(info, info_len) : @"(null)";
|
||||
NSString *okmHex = okm ? hexEncodeShort(okm, okm_len) : @"(null)";
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][HKDF_expand] nid=%d prk(%zuB)=%@ info(%zuB)=%@ okm(%zuB)=%@",
|
||||
nid, prk_len, prkHex, info_len, infoHex, okm_len, okmHex]);
|
||||
if (okm && okm_len >= 32) {
|
||||
file_log(g_log_hmac,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth][HKDF_expand] okm_first32=%@",
|
||||
hexEncode(okm, 32)]);
|
||||
}
|
||||
g_inHook = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HOOK 11: NSData dataWithContentsOfFile: — catch large file reads (4-10 KB)
|
||||
// that could be device_key_data / devicetoken source material.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -518,6 +986,121 @@ static void installNFWebCryptoHooks(void) {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC symbol not found");
|
||||
}
|
||||
|
||||
// Resolve EVP_MD_type for NID lookups in new hooks
|
||||
sym = dlsym(nfwc, "EVP_MD_type");
|
||||
if (sym) {
|
||||
g_EVP_MD_type = (EVP_MD_type_fn)sym;
|
||||
file_log(g_log_general, @"[NFXEntityAuth] EVP_MD_type resolved");
|
||||
}
|
||||
|
||||
// HMAC_CTX_new
|
||||
sym = dlsym(nfwc, "HMAC_CTX_new");
|
||||
if (sym) {
|
||||
MSHookFunction(sym, (void *)hook_HMAC_CTX_new, (void **)&orig_HMAC_CTX_new);
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC_CTX_new hooked");
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC_CTX_new not found");
|
||||
}
|
||||
|
||||
// HMAC_Init_ex
|
||||
sym = dlsym(nfwc, "HMAC_Init_ex");
|
||||
if (sym) {
|
||||
MSHookFunction(sym, (void *)hook_HMAC_Init_ex, (void **)&orig_HMAC_Init_ex);
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC_Init_ex hooked");
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC_Init_ex not found");
|
||||
}
|
||||
|
||||
// HMAC_Update
|
||||
sym = dlsym(nfwc, "HMAC_Update");
|
||||
if (sym) {
|
||||
MSHookFunction(sym, (void *)hook_HMAC_Update, (void **)&orig_HMAC_Update);
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC_Update hooked");
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC_Update not found");
|
||||
}
|
||||
|
||||
// HMAC_Final
|
||||
sym = dlsym(nfwc, "HMAC_Final");
|
||||
if (sym) {
|
||||
MSHookFunction(sym, (void *)hook_HMAC_Final, (void **)&orig_HMAC_Final);
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC_Final hooked");
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] HMAC_Final not found");
|
||||
}
|
||||
|
||||
// SHA384 one-shot
|
||||
sym = dlsym(nfwc, "SHA384");
|
||||
if (sym) {
|
||||
MSHookFunction(sym, (void *)hook_SHA384, (void **)&orig_SHA384);
|
||||
file_log(g_log_general, @"[NFXEntityAuth] SHA384 hooked");
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] SHA384 not found");
|
||||
}
|
||||
|
||||
// EVP_DigestInit_ex
|
||||
sym = dlsym(nfwc, "EVP_DigestInit_ex");
|
||||
if (sym) {
|
||||
MSHookFunction(sym, (void *)hook_EVP_DigestInit_ex, (void **)&orig_EVP_DigestInit_ex);
|
||||
file_log(g_log_general, @"[NFXEntityAuth] EVP_DigestInit_ex hooked");
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] EVP_DigestInit_ex not found");
|
||||
}
|
||||
|
||||
// EVP_DigestUpdate
|
||||
sym = dlsym(nfwc, "EVP_DigestUpdate");
|
||||
if (sym) {
|
||||
MSHookFunction(sym, (void *)hook_EVP_DigestUpdate, (void **)&orig_EVP_DigestUpdate);
|
||||
file_log(g_log_general, @"[NFXEntityAuth] EVP_DigestUpdate hooked");
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] EVP_DigestUpdate not found");
|
||||
}
|
||||
|
||||
// EVP_DigestFinal_ex
|
||||
sym = dlsym(nfwc, "EVP_DigestFinal_ex");
|
||||
if (sym) {
|
||||
MSHookFunction(sym, (void *)hook_EVP_DigestFinal_ex, (void **)&orig_EVP_DigestFinal_ex);
|
||||
file_log(g_log_general, @"[NFXEntityAuth] EVP_DigestFinal_ex hooked");
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] EVP_DigestFinal_ex not found");
|
||||
}
|
||||
|
||||
// HKDF functions by offset in NFWebCrypto image
|
||||
// Determine the NFWebCrypto image base
|
||||
{
|
||||
uint32_t imgCount = _dyld_image_count();
|
||||
uintptr_t nfwcBase = 0;
|
||||
for (uint32_t i = 0; i < imgCount; i++) {
|
||||
const char *name = _dyld_get_image_name(i);
|
||||
if (name && strstr(name, "NFWebCrypto.framework/NFWebCrypto")) {
|
||||
nfwcBase = (uintptr_t)_dyld_get_image_header(i);
|
||||
file_log(g_log_general,
|
||||
[NSString stringWithFormat:@"[NFXEntityAuth] NFWebCrypto base=0x%lx",
|
||||
(unsigned long)nfwcBase]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nfwcBase != 0) {
|
||||
// HKDF-Extract and HKDF-Expand are static C++ functions with uncertain
|
||||
// prototypes. Hooking them by hardcoded offset risks a crash if the
|
||||
// calling convention does not match. Instead, log their addresses so
|
||||
// they can be verified with a debugger before enabling offset hooks.
|
||||
uintptr_t extractAddr = nfwcBase + 0x11990;
|
||||
uintptr_t expandAddr = nfwcBase + 0x119b8;
|
||||
file_log(g_log_general,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth] HKDF_extract candidate addr=0x%lx (not hooked — verify offset first)",
|
||||
(unsigned long)extractAddr]);
|
||||
file_log(g_log_general,
|
||||
[NSString stringWithFormat:
|
||||
@"[NFXEntityAuth] HKDF_expand candidate addr=0x%lx (not hooked — verify offset first)",
|
||||
(unsigned long)expandAddr]);
|
||||
} else {
|
||||
file_log(g_log_general, @"[NFXEntityAuth] NFWebCrypto base not found — HKDF address logging skipped");
|
||||
}
|
||||
}
|
||||
|
||||
g_nfwcHooked = YES;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user