mirror of
https://github.com/httptoolkit/frida-interception-and-unpinning.git
synced 2026-10-11 10:22:12 +02:00
Remove unnecessary (maybe problematic) setTimeout delays
This commit is contained in:
@@ -368,94 +368,92 @@ const getJavaClassIfExists = (clsName) => {
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
Java.perform(function () {
|
||||
if (DEBUG_MODE) console.log('\n === Disabling all recognized unpinning libraries ===');
|
||||
Java.perform(function () {
|
||||
if (DEBUG_MODE) console.log('\n === Disabling all recognized unpinning libraries ===');
|
||||
|
||||
const classesToPatch = Object.keys(PINNING_FIXES);
|
||||
const classesToPatch = Object.keys(PINNING_FIXES);
|
||||
|
||||
classesToPatch.forEach((targetClassName) => {
|
||||
const TargetClass = getJavaClassIfExists(targetClassName);
|
||||
if (!TargetClass) {
|
||||
// We skip patches for any classes that don't seem to be present. This is common
|
||||
// as not all libraries we handle are necessarily used.
|
||||
if (DEBUG_MODE) console.log(`[ ] ${targetClassName} *`);
|
||||
classesToPatch.forEach((targetClassName) => {
|
||||
const TargetClass = getJavaClassIfExists(targetClassName);
|
||||
if (!TargetClass) {
|
||||
// We skip patches for any classes that don't seem to be present. This is common
|
||||
// as not all libraries we handle are necessarily used.
|
||||
if (DEBUG_MODE) console.log(`[ ] ${targetClassName} *`);
|
||||
return;
|
||||
}
|
||||
|
||||
const patches = PINNING_FIXES[targetClassName];
|
||||
|
||||
let patchApplied = false;
|
||||
|
||||
patches.forEach(({ methodName, getMethod, overload, replacement }) => {
|
||||
const namedTargetMethod = getMethod
|
||||
? getMethod(TargetClass)
|
||||
: TargetClass[methodName];
|
||||
|
||||
const methodDescription = `${methodName}${
|
||||
overload === '*'
|
||||
? '(*)'
|
||||
: overload
|
||||
? '(' + overload.map((argType) => {
|
||||
// Simplify arg names to just the class name for simpler logs:
|
||||
const argClassName = argType.split('.').slice(-1)[0];
|
||||
if (argType.startsWith('[L')) return `${argClassName}[]`;
|
||||
else return argClassName;
|
||||
}).join(', ') + ')'
|
||||
// No overload:
|
||||
: ''
|
||||
}`
|
||||
|
||||
let targetMethodImplementations = [];
|
||||
try {
|
||||
if (namedTargetMethod) {
|
||||
if (!overload) {
|
||||
// No overload specified
|
||||
targetMethodImplementations = [namedTargetMethod];
|
||||
} else if (overload === '*') {
|
||||
// Targetting _all_ overloads
|
||||
targetMethodImplementations = namedTargetMethod.overloads;
|
||||
} else {
|
||||
// Or targetting a specific overload:
|
||||
targetMethodImplementations = [namedTargetMethod.overload(...overload)];
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Overload not present
|
||||
}
|
||||
|
||||
|
||||
// We skip patches for any methods that don't seem to be present. This is rarer, but does
|
||||
// happen due to methods that only appear in certain library versions or whose signatures
|
||||
// have changed over time.
|
||||
if (targetMethodImplementations.length === 0) {
|
||||
if (DEBUG_MODE) console.log(`[ ] ${targetClassName} ${methodDescription}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const patches = PINNING_FIXES[targetClassName];
|
||||
targetMethodImplementations.forEach((targetMethod, i) => {
|
||||
const patchName = `${targetClassName} ${methodDescription}${
|
||||
targetMethodImplementations.length > 1 ? ` (${i})` : ''
|
||||
}`;
|
||||
|
||||
let patchApplied = false;
|
||||
|
||||
patches.forEach(({ methodName, getMethod, overload, replacement }) => {
|
||||
const namedTargetMethod = getMethod
|
||||
? getMethod(TargetClass)
|
||||
: TargetClass[methodName];
|
||||
|
||||
const methodDescription = `${methodName}${
|
||||
overload === '*'
|
||||
? '(*)'
|
||||
: overload
|
||||
? '(' + overload.map((argType) => {
|
||||
// Simplify arg names to just the class name for simpler logs:
|
||||
const argClassName = argType.split('.').slice(-1)[0];
|
||||
if (argType.startsWith('[L')) return `${argClassName}[]`;
|
||||
else return argClassName;
|
||||
}).join(', ') + ')'
|
||||
// No overload:
|
||||
: ''
|
||||
}`
|
||||
|
||||
let targetMethodImplementations = [];
|
||||
try {
|
||||
if (namedTargetMethod) {
|
||||
if (!overload) {
|
||||
// No overload specified
|
||||
targetMethodImplementations = [namedTargetMethod];
|
||||
} else if (overload === '*') {
|
||||
// Targetting _all_ overloads
|
||||
targetMethodImplementations = namedTargetMethod.overloads;
|
||||
} else {
|
||||
// Or targetting a specific overload:
|
||||
targetMethodImplementations = [namedTargetMethod.overload(...overload)];
|
||||
}
|
||||
}
|
||||
targetMethod.implementation = replacement(targetMethod);
|
||||
|
||||
if (DEBUG_MODE) console.log(`[+] ${patchName}`);
|
||||
patchApplied = true;
|
||||
} catch (e) {
|
||||
// Overload not present
|
||||
// In theory, errors like this should never happen - it means the patch is broken
|
||||
// (e.g. some dynamic patch building fails completely)
|
||||
console.error(`[!] ERROR: ${patchName} failed: ${e}`);
|
||||
}
|
||||
|
||||
|
||||
// We skip patches for any methods that don't seem to be present. This is rarer, but does
|
||||
// happen due to methods that only appear in certain library versions or whose signatures
|
||||
// have changed over time.
|
||||
if (targetMethodImplementations.length === 0) {
|
||||
if (DEBUG_MODE) console.log(`[ ] ${targetClassName} ${methodDescription}`);
|
||||
return;
|
||||
}
|
||||
|
||||
targetMethodImplementations.forEach((targetMethod, i) => {
|
||||
const patchName = `${targetClassName} ${methodDescription}${
|
||||
targetMethodImplementations.length > 1 ? ` (${i})` : ''
|
||||
}`;
|
||||
|
||||
try {
|
||||
targetMethod.implementation = replacement(targetMethod);
|
||||
|
||||
if (DEBUG_MODE) console.log(`[+] ${patchName}`);
|
||||
patchApplied = true;
|
||||
} catch (e) {
|
||||
// In theory, errors like this should never happen - it means the patch is broken
|
||||
// (e.g. some dynamic patch building fails completely)
|
||||
console.error(`[!] ERROR: ${patchName} failed: ${e}`);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (!patchApplied) {
|
||||
console.warn(`[!] Matched class ${targetClassName} but could not patch any methods`);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
console.log('== Certificate unpinning completed ==');
|
||||
if (!patchApplied) {
|
||||
console.warn(`[!] Matched class ${targetClassName} but could not patch any methods`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('== Certificate unpinning completed ==');
|
||||
});
|
||||
+66
-67
@@ -13,81 +13,80 @@
|
||||
* in the native connect() hook script.
|
||||
*/
|
||||
|
||||
setTimeout(() => {
|
||||
Java.perform(() => {
|
||||
// Set default JVM system properties for the proxy address. Notably these are used
|
||||
// to initialize WebView configuration.
|
||||
Java.use('java.lang.System').setProperty('http.proxyHost', PROXY_HOST);
|
||||
Java.use('java.lang.System').setProperty('http.proxyPort', PROXY_PORT.toString());
|
||||
Java.use('java.lang.System').setProperty('https.proxyHost', PROXY_HOST);
|
||||
Java.use('java.lang.System').setProperty('https.proxyPort', PROXY_PORT.toString());
|
||||
Java.perform(() => {
|
||||
// Set default JVM system properties for the proxy address. Notably these are used
|
||||
// to initialize WebView configuration.
|
||||
Java.use('java.lang.System').setProperty('http.proxyHost', PROXY_HOST);
|
||||
Java.use('java.lang.System').setProperty('http.proxyPort', PROXY_PORT.toString());
|
||||
Java.use('java.lang.System').setProperty('https.proxyHost', PROXY_HOST);
|
||||
Java.use('java.lang.System').setProperty('https.proxyPort', PROXY_PORT.toString());
|
||||
|
||||
Java.use('java.lang.System').clearProperty('http.nonProxyHosts');
|
||||
Java.use('java.lang.System').clearProperty('https.nonProxyHosts');
|
||||
Java.use('java.lang.System').clearProperty('http.nonProxyHosts');
|
||||
Java.use('java.lang.System').clearProperty('https.nonProxyHosts');
|
||||
|
||||
// Some Android internals attempt to reset these settings to match the device configuration.
|
||||
// We block that directly here:
|
||||
const controlledSystemProperties = [
|
||||
'http.proxyHost',
|
||||
'http.proxyPort',
|
||||
'https.proxyHost',
|
||||
'https.proxyPort',
|
||||
'http.nonProxyHosts',
|
||||
'https.nonProxyHosts'
|
||||
];
|
||||
Java.use('java.lang.System').clearProperty.implementation = function (property) {
|
||||
if (controlledSystemProperties.includes(property)) {
|
||||
if (DEBUG_MODE) console.log(`Ignoring attempt to clear ${property} system property`);
|
||||
return this.getProperty(property);
|
||||
}
|
||||
return this.clearProperty(...arguments);
|
||||
// Some Android internals attempt to reset these settings to match the device configuration.
|
||||
// We block that directly here:
|
||||
const controlledSystemProperties = [
|
||||
'http.proxyHost',
|
||||
'http.proxyPort',
|
||||
'https.proxyHost',
|
||||
'https.proxyPort',
|
||||
'http.nonProxyHosts',
|
||||
'https.nonProxyHosts'
|
||||
];
|
||||
Java.use('java.lang.System').clearProperty.implementation = function (property) {
|
||||
if (controlledSystemProperties.includes(property)) {
|
||||
if (DEBUG_MODE) console.log(`Ignoring attempt to clear ${property} system property`);
|
||||
return this.getProperty(property);
|
||||
}
|
||||
Java.use('java.lang.System').setProperty.implementation = function (property) {
|
||||
if (controlledSystemProperties.includes(property)) {
|
||||
if (DEBUG_MODE) console.log(`Ignoring attempt to override ${property} system property`);
|
||||
return this.getProperty(property);
|
||||
}
|
||||
return this.setProperty(...arguments);
|
||||
return this.clearProperty(...arguments);
|
||||
}
|
||||
Java.use('java.lang.System').setProperty.implementation = function (property) {
|
||||
if (controlledSystemProperties.includes(property)) {
|
||||
if (DEBUG_MODE) console.log(`Ignoring attempt to override ${property} system property`);
|
||||
return this.getProperty(property);
|
||||
}
|
||||
return this.setProperty(...arguments);
|
||||
}
|
||||
|
||||
// Configure the app's proxy directly, via the app connectivity manager service:
|
||||
const ConnectivityManager = Java.use('android.net.ConnectivityManager');
|
||||
const ProxyInfo = Java.use('android.net.ProxyInfo');
|
||||
ConnectivityManager.getDefaultProxy.implementation = () => ProxyInfo.$new(PROXY_HOST, PROXY_PORT, '');
|
||||
// (Not clear if this works 100% - implying there are ConnectivityManager subclasses handling this)
|
||||
// Configure the app's proxy directly, via the app connectivity manager service:
|
||||
const ConnectivityManager = Java.use('android.net.ConnectivityManager');
|
||||
const ProxyInfo = Java.use('android.net.ProxyInfo');
|
||||
ConnectivityManager.getDefaultProxy.implementation = () => ProxyInfo.$new(PROXY_HOST, PROXY_PORT, '');
|
||||
// (Not clear if this works 100% - implying there are ConnectivityManager subclasses handling this)
|
||||
|
||||
console.log(`== Proxy system configuration overridden to ${PROXY_HOST}:${PROXY_PORT} ==`);
|
||||
console.log(`== Proxy system configuration overridden to ${PROXY_HOST}:${PROXY_PORT} ==`);
|
||||
|
||||
// Configure the proxy indirectly, by overriding the return value for all ProxySelectors everywhere:
|
||||
const Collections = Java.use('java.util.Collections');
|
||||
const ProxyType = Java.use('java.net.Proxy$Type');
|
||||
const InetSocketAddress = Java.use('java.net.InetSocketAddress');
|
||||
const ProxyCls = Java.use('java.net.Proxy'); // 'Proxy' is reserved in JS
|
||||
// Configure the proxy indirectly, by overriding the return value for all ProxySelectors everywhere:
|
||||
const Collections = Java.use('java.util.Collections');
|
||||
const ProxyType = Java.use('java.net.Proxy$Type');
|
||||
const InetSocketAddress = Java.use('java.net.InetSocketAddress');
|
||||
const ProxyCls = Java.use('java.net.Proxy'); // 'Proxy' is reserved in JS
|
||||
|
||||
const targetProxy = ProxyCls.$new(
|
||||
ProxyType.HTTP.value,
|
||||
InetSocketAddress.$new(PROXY_HOST, PROXY_PORT)
|
||||
const targetProxy = ProxyCls.$new(
|
||||
ProxyType.HTTP.value,
|
||||
InetSocketAddress.$new(PROXY_HOST, PROXY_PORT)
|
||||
);
|
||||
const getTargetProxyList = () => Collections.singletonList(targetProxy);
|
||||
|
||||
const ProxySelector = Java.use('java.net.ProxySelector');
|
||||
|
||||
// Find every implementation of ProxySelector by quickly scanning method signatures, and
|
||||
// then checking whether each match actually implements java.net.ProxySelector:
|
||||
const proxySelectorClasses = Java.enumerateMethods('*!select(java.net.URI): java.util.List/s')
|
||||
.flatMap((matchingLoader) => matchingLoader.classes
|
||||
.map((classData) => Java.use(classData.name))
|
||||
.filter((Cls) => ProxySelector.class.isAssignableFrom(Cls.class))
|
||||
);
|
||||
const getTargetProxyList = () => Collections.singletonList(targetProxy);
|
||||
|
||||
const ProxySelector = Java.use('java.net.ProxySelector');
|
||||
|
||||
// Find every implementation of ProxySelector by quickly scanning method signatures, and
|
||||
// then checking whether each match actually implements java.net.ProxySelector:
|
||||
const proxySelectorClasses = Java.enumerateMethods('*!select(java.net.URI): java.util.List/s')
|
||||
.flatMap((matchingLoader) => matchingLoader.classes
|
||||
.map((classData) => Java.use(classData.name))
|
||||
.filter((Cls) => ProxySelector.class.isAssignableFrom(Cls.class))
|
||||
);
|
||||
|
||||
// Replace the 'select' of every implementation, so they all send traffic to us:
|
||||
proxySelectorClasses.forEach(ProxySelectorCls => {
|
||||
if (DEBUG_MODE) {
|
||||
console.log('Rewriting', ProxySelectorCls.toString());
|
||||
}
|
||||
ProxySelectorCls.select.implementation = () => getTargetProxyList()
|
||||
});
|
||||
|
||||
console.log(`== Proxy configuration overridden to ${PROXY_HOST}:${PROXY_PORT} ==`);
|
||||
// Replace the 'select' of every implementation, so they all send traffic to us:
|
||||
proxySelectorClasses.forEach(ProxySelectorCls => {
|
||||
if (DEBUG_MODE) {
|
||||
console.log('Rewriting', ProxySelectorCls.toString());
|
||||
}
|
||||
ProxySelectorCls.select.implementation = () => getTargetProxyList()
|
||||
});
|
||||
});
|
||||
|
||||
console.log(`== Proxy configuration overridden to ${PROXY_HOST}:${PROXY_PORT} ==`);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user