Lors de l'utilisation de Wikipédia dans Dictionary.app sur MacOS Big Sur 11.0.1, Dictionary.app envoie des requêtes HTTPS à *.b.akamaiedge.net
et n'utilise pas de proxy système (HTTP ou socks5). Comment puis-je résoudre ce problème ?
Réponse
Trop de publicités?Ce phénomène n'est pas propre à Big Sur - il remonte probablement à l'époque où l'application Dictionary a été introduite dans Tiger. @1110101001 a fait un peu d'ingénierie inverse pour comprendre ce qui se passe.
DictionaryServices.framework
établit des connexions réseau par le biais de l'option désormais obsolète CFHTTPStream
. Selon un ingénieur d'Apple y Le code propre d'Apple tout logiciel qui utilise CFHTTPStream
ignorera les paramètres du proxy du système, à moins que le développeur ne fasse l'effort d'ajouter quelques lignes de code supplémentaires.
Pour résoudre ce problème, nous devrons injecter du code qui fait ce que les développeurs d'origine n'ont pas fait, à savoir demander à l'application d'appliquer les paramètres du proxy du système avant de lancer l'application CFHTTPStream
.
Tout d'abord, compilez le code suivant (par ex. clang -framework AppKit -framework Foundation -o ProxyFix.dylib -dynamiclib /path/to/code.m
) pour créer une bibliothèque que nous pouvons injecter. Ceci a également été écrit en grande partie par 1110101001 ; je l'ai modifié pour qu'il fonctionne avec les applications qui utilisent des espaces de noms à deux niveaux.
#include <stdio.h>
#include <objc/runtime.h>
#include <Foundation/Foundation.h>
#include <dlfcn.h>
#include <AppKit/AppKit.h>
#define DYLD_INTERPOSE(_replacement,_replacee) \
__attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \
__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee };
CFReadStreamRef myCFReadStreamCreateForHTTPRequest(CFAllocatorRef alloc, CFHTTPMessageRef request) {
printf("Injected ProxyFix!\n");
CFReadStreamRef ref = CFReadStreamCreateForHTTPRequest(alloc, request);
CFDictionaryRef systemProxyDict = CFNetworkCopySystemProxySettings();
CFReadStreamSetProperty(ref, kCFStreamPropertyHTTPProxy, systemProxyDict);
return ref;
}
DYLD_INTERPOSE(myCFReadStreamCreateForHTTPRequest, CFReadStreamCreateForHTTPRequest);
Nous devons maintenant insérer cette bibliothèque dans l'application Dictionary. Heureusement, MacOS dispose d'un mécanisme intégré permettant d'injecter du code sous la forme de fichiers DYLD_INSERT_LIBRARIES
. Si, comme moi, vous utilisez une version ancienne et adorablement piratable de MacOS telle que 10.9, il vous suffit de lancer votre application après avoir défini cette variable d'environnement. Par exemple, lancez dans Terminal :
DYLD_INSERT_LIBRARIES=/path/to/ProxyFix.dylib /Applications/Dictionary.app/Contents/MacOS/Dictionary
Si vous utilisez MacOS 10.6 ou une version inférieure, ou si l'application n'est pas signée (probablement parce que vous a supprimé la signature du code via optool ou similaire), vous pouvez également ajouter cette variable d'environnement au fichier Info.plist de l'application, afin que la bibliothèque soit injectée automatiquement.
defaults write /Applications/Dictionary.app/Contents/Info LSEnvironment -dict DYLD_INSERT_LIBRARIES @executable_path/../Frameworks/ProxyFix.dylib
Malheureusement, les versions plus récentes de MacOS disposent de fonctions de sécurité supplémentaires pour empêcher l'injection de code. À partir de la version 10.11, vous devrez désactiver la protection de l'intégrité du système afin d'utiliser DYLD_INSERT_LIBRARIES
. Sur les systèmes d'exploitation les plus récents, tels que Big Sur, vous devrez peut-être (ou non) prendre des mesures supplémentaires, comme la désactivation de l'AMFI - je ne suis pas tout à fait familier avec tous les nouveaux contrôles de sécurité qu'Apple a ajoutés ces dernières années.
P.S. Si vous utilisez la version 10.6 - 10.9, j'ai regroupé tout cela dans un petit programme d'installation qui vous aide à configurer un proxy, puis applique le correctif ci-dessus à l'application Dictionary. Sans l'aide d'un proxy, la fonctionnalité Wikipedia de l'application Dictionary ne fonctionne plus du tout sur ces systèmes. <a href="https://jonathanalland.com/downloads/wowfunhappy-https-proxy.dmg" rel="nofollow noreferrer">https://jonathanalland.com/downloads/wowfunhappy-https-proxy.dmg</a>
3 votes
Une autre personne s'est trouvée confrontée à cet étrange cas de figure ! J'ai confirmé que Dictionnaire ignore également de manière flagrante le proxy système pour l'accès à Wikipédia sur 10.6 (Snow Leopard), 10.9 (Mavericks) et 10.14 (Mojave), et vraisemblablement sur tous les systèmes d'exploitation intermédiaires. Notamment, Hopper donne l'impression que Dictionary lit une clé booléenne nommée de façon suspecte
DCSDisableProxyForWikipediaAccess
de quelque part, mais rien de ce que j'ai défini viadefaults write
semble avoir un effet !0 votes
@Wowfunhappy La connexion réelle se fait via
NSURLConnection
et ne semble pas vraiment sortir de l'ordinaire.NSUrlConnection
doit respecter le proxy du système. La seule chose à laquelle je peux penser est que, parce qu'il accède àhttp://...
qui 307 redirige vers la version HTTPS, il n'honore pas le proxy https dans ce cas.1 votes
Oh apparemment ce code de mise en réseau dans l'application principale du dictionnaire n'est jamais utilisé. Le vrai code se trouve dans DictionaryServices.framework. Il utilise CFHTTP qui contourne le proxy du système : developer.apple.com/forums/thread/69452
1 votes
Pour une source faisant autorité, voir également opensource.apple.com/source/CFNetwork/CFNetwork-128.2/Headers/ "Les proxys HTTP ne sont pas appliqués automatiquement". Je suppose que si vous voulez le corriger vous-même, vous pouvez utiliser l'injection dyld et écraser "CFReadStreamCreateForHTTPRequest" pour toujours définir le proxy du système avant de renvoyer le flux de lecture.
0 votes
@1110101001 Merci, cela fait des semaines que cela me tracasse ! J'essaie de faire revivre l'application Dictionnaire (pour Wikipedia) sur OS X 10.9. Le système d'exploitation ne prend pas en charge les suites de chiffrement SSL modernes désormais requises par Wikipedia, ce qui signifie que je dois placer un proxy au milieu. Il semblerait que je doive essayer d'écrire un petit plugin SIMBL...
0 votes
@Wowfunhappy Je ne suis pas sûr que le plugin SIMBL soit la meilleure solution. Parce que les méthodes en question ne sont pas des méthodes Objective-C, vous ne pouvez pas simplement les swizzler. Idéalement, vous devriez utiliser ld_preload pour remplacer CFReadStream par un wrapper qui définit le proxy avant de renvoyer le résultat. Cela brisera le code-signing (probablement sans effet néfaste une fois que vous vous serez résigné), mais vous pouvez définir LD_PRELOAD dans l'info plist pour que cela se fasse de manière transparente.
0 votes
Les plugins SIMBL sont, je pense, chargés après que dyld ait terminé son travail, donc ce sera plus désordonné. Si vous avez besoin d'utiliser SIMBL, vous pouvez faire du hooking de fonction ( github.com/Zeex/subhook ) pour caler l'original.
0 votes
Option alternative pour le crochet de fonction : github.com/kubo/plthook Je n'ai pas testé, mais les deux semblent devoir fonctionner. Avec hotpatch (subhook) vous utilisez dlsym pour obtenir la valeur de la fonction et ensuite la patcher. Avec plthook, vous remplacez l'entrée dans la table PLT à la place.
0 votes
@1110101001 Merci. Tout cela est malheureusement en dehors de mes compétences (je sais que les juste suffisamment d'Objective C pour écrire des plugins SIMBL très simples). Ah bon... merci d'avoir regardé. J'aimerais bien savoir comment vous avez réussi à faire de l'ingénierie inverse, si vous connaissez des ressources.
0 votes
@Wowfunhappy Je ne pense pas que ce soit trop difficile : vous n'avez pas du tout besoin de connaissances en Objective-C, vous avez seulement besoin de connaissances en C (que vous devriez apprendre si vous ne le connaissez pas déjà, car c'est utile pour la rétro-ingénierie en général). Si vous optez pour le plugin simbl, en utilisant les librairies mentionnées ci-dessus, si tout se passe bien, il ne devrait y avoir que ~5 lignes de code. J'ai mis du pseudocode ici pastebin.com/raw/8YGjPDNL
0 votes
Si vous utilisez ld_preload, c'est encore plus facile. Vous n'avez pas besoin de bibliothèque externe, vous pouvez simplement déclarer la méthode que vous voulez surcharger et laisser l'éditeur de liens le faire pour vous. Voici un pseudo-code : pastebin.com/raw/zSuz6vLG
0 votes
Pour l'ingénierie inverse, j'ai utilisé Hopper. Pour ce qui est de l'interne d'osx et de l'accrochage de fonctions, etc., il s'agit en partie de connaissances acquises en étudiant l'interne du système (le livre de Jonathan Levin contient beaucoup de bonnes connaissances et d'anecdotes), et en partie d'astuces que l'on acquiert après avoir été exposé à l'interne.
0 votes
@Wowfunhappy J'étais curieux et comme le pseudo-code était déjà à 95%, je l'ai implémenté. Pouvez-vous essayer ceci ? pastebin.com/raw/EUbx7zig Compiler via
gcc -framework AppKit -framework Foundation -o dicthook.dylib -dynamiclib file.m
Chargement viaDYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=dicthook.dylib /Applications/Dictionary.app/Contents/MacOS/Dictionary
0 votes
@1110101001 Tu es génial, ça a marché ! Je vous remercie !
0 votes
@Wowfunhappy Génial ! Vous pouvez partir de là et peaufiner la mise en œuvre. Vous pouvez éviter les
DYLD_FORCE_FLAT_NAMESPACE
en déclarant le segment interpose dans la bibliothèque mach-o : opensource.apple.com/source/dyld/dyld-239.3/include/mach-o/ Il suffit alors de modifier la plist pour définir la variable d'environnement DYLD_INSERT_LIBRARY. Je ne sais pas si vous vous souciez de la signature du code, mais elle sera cassée si vous modifiez la plist. Alternativement, créez votre propre application wrapper qui définit l'env et appelle le dictionnaire.0 votes
Si vous vous sentez aventureux et que vous voulez toujours utiliser SIMBL, vous pouvez essayer l'une des bibliothèques de fonctions que j'ai mentionnées plus haut. De cette façon, vous n'interrompez pas la signature du code. Si vous étiez sur 10.10+, vous auriez pu utiliser
dyld_dynamic_interpose
qui vous permet de corriger les choses au moment de l'exécution.0 votes
(Défi supplémentaire : Seuls les dylibs chargés via DYLD_INSERT_LIBRARIES peuvent effectuer l'interposition. En l'absence de
dyld_dynamic_interpose
mais vous pouvez toujours simuler ce comportement de manière native via dyld en utilisantloadFromMemory
pour charger dynamiquement une dylib et appeler ensuite "registerInterposing". Cela vous donne les outils pour interposer dynamiquement purement via l'injection SIMBL et sans les adresses Parcheando. Se référer à debugtrap.com/2016/11/14/library-memory-loading )0 votes
@1110101001 Cela vous dérange si je fais un résumé pour la boîte à réponses ?
0 votes
@Wowfunhappy n'hésitez pas !