Skip to content

Commit 3672ba9

Browse files
committed
Pull more more Frida script fixes around native TLS hooks
1 parent bd8c3a6 commit 3672ba9

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

overrides/frida/native-tls-hook.js

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,31 @@ function patchTargetLib(targetLib) {
9999

100100
const buildVerificationCallback = (realCallbackAddr) => {
101101
if (!verificationCallbackCache[realCallbackAddr]) {
102-
const realCallback = realCallbackAddr
102+
const realCallback = (!realCallbackAddr || realCallbackAddr.isNull())
103103
? new NativeFunction(realCallbackAddr, 'int', ['pointer','pointer'])
104104
: () => SSL_VERIFY_INVALID; // Callback can be null - treat as invalid (=our validation only)
105105

106+
let pendingCheckThreads = new Set();
107+
106108
const hookedCallback = new NativeCallback(function (ssl, out_alert) {
107-
let realResult = false;
109+
let realResult = false; // False = not yet called, 0/1 = call result
110+
111+
const threadId = Process.getCurrentThreadId();
112+
const alreadyHaveLock = pendingCheckThreads.has(threadId);
113+
114+
// We try to have only one thread running these checks at a time, as parallel calls
115+
// here on the same underlying callback seem to crash in some specific scenarios
116+
while (pendingCheckThreads.size > 0 && !alreadyHaveLock) {
117+
Thread.sleep(0.01);
118+
}
119+
pendingCheckThreads.add(threadId);
108120

109121
if (targetLib !== 'libboringssl.dylib') {
110122
// Cronet assumes its callback is always called, and crashes if not. iOS's BoringSSL
111123
// meanwhile seems to use some negative checks in its callback, and rejects the
112124
// connection independently of the return value here if it's called with a bad cert.
113125
// End result: we *only sometimes* proactively call the callback.
114-
realResult = realCallback(ssl, out_alert)
126+
realResult = realCallback(ssl, out_alert);
115127
}
116128

117129
// Extremely dumb certificate validation: we accept any chain where the *exact* CA cert
@@ -138,16 +150,18 @@ function patchTargetLib(targetLib) {
138150
const certData = new Uint8Array(certPointer.readByteArray(certDataLength));
139151

140152
if (certData.every((byte, j) => CERT_DER[j] === byte)) {
153+
if (!alreadyHaveLock) pendingCheckThreads.delete(threadId);
141154
return SSL_VERIFY_OK;
142155
}
143156
}
144157

145158
// No matched peer - fallback to the provided callback instead:
146-
if (realResult !== false) {
147-
return realResult;
148-
} else {
149-
return realCallback(ssl, out_alert);
159+
if (realResult === false) { // Haven't called it yet
160+
realResult = realCallback(ssl, out_alert);
150161
}
162+
163+
if (!alreadyHaveLock) pendingCheckThreads.delete(threadId);
164+
return realResult;
151165
}, 'int', ['pointer','pointer']);
152166

153167
verificationCallbackCache[realCallbackAddr] = hookedCallback;

0 commit comments

Comments
 (0)