diff --git a/config.js b/config.js index 6b48343..99d02de 100644 --- a/config.js +++ b/config.js @@ -150,3 +150,50 @@ function pemToDer(input) { } const CERT_DER = pemToDer(CERT_PEM); + +function waitForModule(moduleName, callback) { + if (Array.isArray(moduleName)) { + moduleName.forEach(module => waitForModule(module, callback)); + } + + try { + Module.ensureInitialized(moduleName); + callback(moduleName); + return; + } catch (e) { + try { + Module.load(moduleName); + callback(moduleName); + return; + } catch (e) {} + } + + MODULE_LOAD_CALLBACKS[moduleName] = callback; +} + +const getModuleName = (nameOrPath) => { + const endOfPath = nameOrPath.lastIndexOf('/'); + return nameOrPath.slice(endOfPath + 1); +}; + +const MODULE_LOAD_CALLBACKS = {}; +new ApiResolver('module').enumerateMatches('exports:linker*!*dlopen*').forEach((dlopen) => { + Interceptor.attach(dlopen.address, { + onEnter(args) { + const moduleArg = args[0].readCString(); + if (moduleArg) { + this.moduleName = getModuleName(moduleArg); + } + }, + onLeave() { + if (!this.moduleName) return; + + Object.keys(MODULE_LOAD_CALLBACKS).forEach((key) => { + if (this.moduleName === key) { + MODULE_LOAD_CALLBACKS[key](this.moduleName); + delete MODULE_LOAD_CALLBACKS[key]; + } + }); + } + }); +}); \ No newline at end of file diff --git a/native-tls-hook.js b/native-tls-hook.js index 93b392b..598d1f1 100644 --- a/native-tls-hook.js +++ b/native-tls-hook.js @@ -40,43 +40,20 @@ const TARGET_LIBS = [ ]; TARGET_LIBS.forEach((targetLib) => { - let loaded = false; - - try { - Module.ensureInitialized(targetLib.name); - loaded = true; - } catch (e) { - try { - Module.load(targetLib.name); - loaded = true; - } catch (e) { - if (targetLib.name === 'libboringssl.dylib' && Process.platform === 'darwin') { - // On iOS, we expect this to always work, so print a warning if we ever have to - // skip this TLS patching process. - console.log(`\n !!! --- Could not load ${targetLib.name} to hook TLS --- !!!`); - } - } - } - - if (loaded === true) { - patchTargetLib(targetLib.name); + waitForModule(targetLib.name, (moduleName) => { + patchTargetLib(moduleName); targetLib.hooked = true; - } -}); - -// Watch for any other target libraries to be loaded later on: -new ApiResolver('module').enumerateMatches('exports:linker*!*dlopen*').forEach((dlopen) => { - Interceptor.attach(dlopen.address, { - onEnter(args) { - const moduleName = args[0].readCString(); - TARGET_LIBS.filter(({ hooked }) => !hooked).forEach((targetLib) => { - if (moduleName.includes(targetLib.name)) { - patchTargetLib(targetLib.name); - targetLib.hooked = true; - } - }); - } }); + + if ( + targetLib.name === 'libboringssl.dylib' && + Process.platform === 'darwin' && + !targetLib.hooked + ) { + // On iOS, we expect this to always work immediately, so print a warning if we + // ever have to skip this TLS patching process. + console.log(`\n !!! --- Could not load ${targetLib.name} to hook TLS --- !!!`); + } }); function patchTargetLib(targetLib) {