Al utilizar Wikipedia en Dictionary.app en MacOS Big Sur 11.0.1, Dictionary.app envía solicitudes HTTPS a *.b.akamaiedge.net
y no está utilizando el proxy del sistema (HTTP o socks5). ¿Cómo puedo arreglar esto?
Respuesta
¿Demasiados anuncios?Este fenómeno no es exclusivo de Big Sur, sino que probablemente se remonta a la introducción de la aplicación Dictionary en Tiger. @1110101001 hizo algo de ingeniería inversa para averiguar qué está pasando.
DictionaryServices.framework
hace conexiones de red a través del ahora obsoleto CFHTTPStream
. Según un ingeniero de Apple y Código propio de Apple cualquier software que utilice CFHTTPStream
ignorará la configuración del proxy del sistema, a menos que el desarrollador se esfuerce en añadir unas líneas de código adicionales.
Para solucionar este problema, tendremos que inyectar algo de código que haga lo que los desarrolladores originales no hicieron: decirle a la aplicación que aplique la configuración del proxy del sistema antes de ejecutar CFHTTPStream
.
En primer lugar, compila el siguiente código (por ejemplo clang -framework AppKit -framework Foundation -o ProxyFix.dylib -dynamiclib /path/to/code.m
) para crear una biblioteca que podamos inyectar. Esto también fue escrito en su mayor parte por 1110101001; lo ajusté para que funcione con aplicaciones que utilizan espacios de nombres de dos niveles.
#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);
Ahora tenemos que insertar esta biblioteca en la aplicación del Diccionario. Por suerte, MacOS viene con un mecanismo incorporado para inyectar código en forma de DYLD_INSERT_LIBRARIES
. Si usted, como yo, está ejecutando una versión antigua y adorablemente hackeable de MacOS como la 10.9, todo lo que necesita hacer es ejecutar su aplicación después de establecer esta variable de entorno. Por ejemplo, ejecutar en Terminal:
DYLD_INSERT_LIBRARIES=/path/to/ProxyFix.dylib /Applications/Dictionary.app/Contents/MacOS/Dictionary
Si está ejecutando MacOS 10.6 o inferior, o si la aplicación no está firmada (posiblemente porque usted eliminó la firma del código a través de optool o similar), también puedes añadir esta variable de entorno al Info.plist de la aplicación, para que la biblioteca se inyecte automáticamente.
defaults write /Applications/Dictionary.app/Contents/Info LSEnvironment -dict DYLD_INSERT_LIBRARIES @executable_path/../Frameworks/ProxyFix.dylib
Desafortunadamente, las nuevas versiones de MacOS tienen características de seguridad adicionales para evitar la inyección de código. A partir de la versión 10.11, tendrá que desactivar la protección de la integridad del sistema para poder utilizar DYLD_INSERT_LIBRARIES
. En los sistemas operativos más recientes, como Big Sur, es posible que tengas que tomar otras medidas (o no), como desactivar AMFI; no estoy del todo familiarizado con todos los nuevos controles de seguridad que Apple ha incorporado en los últimos años.
P.D. Si usted está ejecutando 10.6 - 10.9, envolví esto en un pequeño instalador que le ayuda a configurar un proxy, y luego aplica el parche anterior a la aplicación Diccionario. Sin la ayuda de un proxy, la funcionalidad de Wikipedia de la aplicación Diccionario ya no funciona en absoluto en estos sistemas. <a href="https://jonathanalland.com/downloads/wowfunhappy-https-proxy.dmg" rel="nofollow noreferrer">https://jonathanalland.com/downloads/wowfunhappy-https-proxy.dmg</a>
3 votos
¡Vaya, otra persona se encontró con este extraño caso límite! He confirmado que Dictionary también ignora descaradamente el proxy del sistema para acceder a Wikipedia en 10.6 (Snow Leopard), 10.9 (Mavericks) y 10.14 (Mojave), y presumiblemente lo hace en todos los sistemas operativos intermedios. En particular, Hopper hace que parezca que el Diccionario está leyendo una clave booleana sospechosamente llamada
DCSDisableProxyForWikipediaAccess
de alguna parte, pero nada de lo que establezca a través dedefaults write
¡parece tener algún efecto!0 votos
@Wowfunhappy Deberías poder configurarlo a través de
defaults write -g
, pero de cualquier manera esa clave no controla realmente el comportamiento del proxy. En cambio, controla si las solicitudes se envían a " lookup-api.apple.com/es.wikipedia.org ..." o simplemente a es.wikipedia.org directamente.0 votos
@Wowfunhappy La conexión real se realiza a través de
NSURLConnection
y no parece realmente fuera de lo común.NSUrlConnection
debe respetar el proxy del sistema. Lo único que se me ocurre es que como accede ahttp://...
que 307 redirige a la versión HTTPS, de alguna manera no honra el proxy https en ese caso.1 votos
Oh, aparentemente ese código de red en la aplicación principal del diccionario nunca se usa. Lo real está en DictionaryServices.framework. Utiliza CFHTTP que evita el proxy del sistema: developer.apple.com/forums/thread/69452
1 votos
También para una fuente autorizada ver: opensource.apple.com/source/CFNetwork/CFNetwork-128.2/Headers/ "Los proxies HTTP no se aplican automáticamente". Supongo que si quisieras parchearlo tú mismo podrías usar la inyección de dyld y sobrescribir "CFReadStreamCreateForHTTPRequest" para que siempre establezca el proxy del sistema antes de devolver el flujo de lectura.
0 votos
@1110101001 ¡Gracias, esto me ha estado molestando durante semanas! Estoy tratando de revivir la aplicación Diccionario (para Wikipedia) en OS X 10.9. El sistema operativo no soporta las modernas suites de cifrado SSL que ahora requiere Wikipedia, lo que significa que tengo que meter un proxy en el medio. Parece que tendré que intentar escribir un pequeño plugin de SIMBL...
0 votos
@Wowfunhappy No estoy seguro de si el plugin SIMBL es la mejor manera. Debido a que los métodos en cuestión no son métodos de objective-C, no se puede simplemente swizzle ellos. Lo ideal sería usar ld_preload para reemplazar CFReadStream con un wrapper que establezca el proxy antes de devolver el resultado. Esto romperá la firma de código (probablemente sin efecto negativo una vez que te resignes), pero puedes establecer LD_PRELOAD en el plist de información para que no haya problemas.
0 votos
Los plugins de SIMBL creo que se cargan después de que dyld termine su actividad, así que va a ser más complicado. Si necesitas usar SIMBL, puedes hacer el enganche de funciones ( github.com/Zeex/subhook ) para calzar el original.
0 votos
Opción alternativa para el gancho de función: github.com/kubo/plthook No lo he probado, pero parece que ambos deberían funcionar. Con hotpatch (subhook) usas dlsym para obtener el valor de la función y luego lo parcheas. Con plthook se reemplaza la entrada en la tabla PLT.
0 votos
@1110101001 Gracias. Todo esto está buscando fuera de mi rango de habilidad por desgracia (lo sé sólo suficiente Objective C para escribir plugins SIMBL muy simples). Ah, bueno... gracias por mirar. Me encantaría saber cómo fuiste capaz de hacer ingeniería inversa de estas cosas, si sabes de algún recurso.
0 votos
@Wowfunhappy No creo que sea muy difícil: no necesitas conocimientos de Objective-C, sólo necesitas conocimientos de C (que si no sabes ya, deberías aprender, ya que es útil para la ingeniería inversa en general). Si vas por la ruta de los plugins de simbl, usando las librerías mencionadas arriba si todo va bien solo deberían ser ~5 líneas de código. Pongo el pseudocódigo aquí pastebin.com/raw/8YGjPDNL
0 votos
Si usas ld_preload, es aún más fácil. No necesitas una librería externa, puedes simplemente declarar el método que quieres anular y dejar que el enlazador lo haga por ti. Pseudocódigo como este: pastebin.com/raw/zSuz6vLG
0 votos
Para la ingeniería inversa sólo he utilizado Hopper. Para las cosas sobre los internos de Osx y el enganche de funciones, etc., parte de ello es conocimiento del estudio de los internos del sistema (el libro de Jonathan Levin tiene un montón de buenos conocimientos y chismes), parte de ello son trucos que se recogen después de una cierta exposición.
0 votos
@Wowfunhappy Tenía curiosidad y como el pseudocódigo estaba al 95%, lo he implementado. ¿Puedes probar esto? pastebin.com/raw/EUbx7zig Compilar a través de
gcc -framework AppKit -framework Foundation -o dicthook.dylib -dynamiclib file.m
Carga a través deDYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=dicthook.dylib /Applications/Dictionary.app/Contents/MacOS/Dictionary
0 votos
@1110101001 ¡Eres increíble, eso funcionó totalmente! Gracias.
0 votos
@Wowfunhappy ¡Genial! Puedes partir de ahí y pulir la implementación. Puedes evitar el
DYLD_FORCE_FLAT_NAMESPACE
declarando el segmento de interposición en la biblioteca mach-o: opensource.apple.com/source/dyld/dyld-239.3/include/mach-o/ Entonces todo lo que tienes que hacer es modificar el plist para establecer la var. env. DYLD_INSERT_LIBRARY. No sé si te importa la firma de código, pero eso se romperá si modificas el plist. Alternativamente, crear su propia aplicación envolvente que establece el env y llama diccionario.0 votos
Si te sientes aventurero y todavía quieres usar SIMBL, entonces puedes probar una de las bibliotecas de ganchos de funciones que mencioné anteriormente. De esta manera no rompes la firma de código. Si estuvieras en 10.10+ podrías usar
dyld_dynamic_interpose
que permite parchear cosas en tiempo de ejecución.0 votos
(Desafío extra: Sólo los dylibs cargados a través de DYLD_INSERT_LIBRARIES pueden realizar la interposición. En ausencia de
dyld_dynamic_interpose
, todavía se puede simular este comportamiento de forma nativa a través de dyld utilizandoloadFromMemory
para cargar dinámicamente una dylib y luego llamar a "registerInterposing". Eso le proporciona las herramientas para interponer dinámicamente puramente a través de la inyección SIMBL y sin direcciones Parcheando. Consulte debugtrap.com/2016/11/14/librería-memoria-carga )0 votos
@1110101001 ¿Te importa si hago una redacción para el cuadro de respuestas?
0 votos
@Wowfunhappy ¡no dudes en hacerlo!