MobileSubstrate/fr

From iPhone Development Wiki
MobileSubstrate/fr
Cydia Package
Developer saurik
Package ID mobilesubstrate
Latest Version 0.9.4001

Languages: English • français • ไทย

Cydia Substrate (anciennement nommé MobileSubstrate) est le de facto framework qui permet la 3ème partie des développeurs de fournit des correctifs d'exécutions (“Cydia Substrate extensions”) aux fonctions du système, similaire à Application Enhancer sur OS X.

Saurik a écrit tout un site de documentation sur Substrate. Cydia Substrate contient 3 composants majeurs: MobileHooker, MobileLoader et safe mode.

MobileHooker

MobileHooker est utilisé pour remplacer les fonctions du système. Ce processus est connu sous le nom d'hooking. Il y a 2 APIs que l'on pourrait utiliser:

IMP MSHookMessage(Class class, SEL selector, IMP replacement, const char* prefix); // prefix should be NULL.
void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP *result);
void MSHookFunction(void* function, void* replacement, void** p_original);

MSHookMessage() va remplacer l'implémentation du message obtenu dans l'Objective-C -[class selector] par replacement, et va retourner l'implémentation original. Pour accrocher une méthode de classe, fournir la meta class recherchée depuis objc_getMetaClass dans le MSHookeMessage(Ex)(Voir exemple en dessous). Ce remplacement dynamique est en fait une caractéristique Objective-C, et peut ainsi être utilisé method_setImplementation. MSHookMessage() est non thread-safe et a été déprécié en faveur de MSHookMessageEx()

MSHookFunction () est comme MSHookMessage (), mais c'est pour les fonctions utilisées en C / C++. Le remplacement doit être effectué au niveau de l'assemblage. Conceptuellement, MSHookFunction () écrira des instructions qui sautent à la fonction de remplacement, et allouent des octets sur un emplacement de mémoire de commande, qui possède les instructions de découpe d'origine. Depuis iOS,par défaut une page de mémoire ne peut pas être à la fois écrite et exécutable, un patch du noyau doit être appliquée pour MSHookFunction () pour fonctionner.

Dans la dernière version de MobileSubstrate, MSHookMessage()aussi requière un patch du noyau pour les "supercall" de fermeture et ainsi pour accrocher toutes les méthodes correctement.

Code d'exemple:

Utilisation de MSHookFunction:

static void (*original_CFShow)(CFTypeRef obj);  // a function pointer to store the original CFShow().
void replaced_CFShow(CFTypeRef obj) {           // our replacement of CFShow().
  printf("Calling original CFShow(%p)...", obj);
  original_CFShow(obj);                         // calls the original CFShow.
  printf(" done.\n");
}
...
// hook CFShow to our own implementation.
MSHookFunction(CFShow, replaced_CFShow, &original_CFShow);
// From now on any call to CFShow will pass through replaced_CFShow first.
...
CFShow(CFSTR("test"));

Utilisation de MSHookMessageEx:

static IMP original_UIView_setFrame_;
void replaced_UIView_setFrame_(UIView* self, SEL _cmd, CGRect frame) {  // Note the implicit self and _cmd parameters are needed explicitly here.
  CGRect originalFrame = self.frame;
  NSLog("Changing frame of %p from %@ to %@", self, NSStringFromCGRect(originalFrame), NSStringFromCGRect(frame));
  original_UIView_setFrame_(self, _cmd, frame);    // Remember to pass self and _cmd.
}
...
MSHookMessageEx([UIView class], @selector(setFrame:), (IMP)replaced_UIView_setFrame_, (IMP *)&original_UIView_setFrame_);
...
myView.frame = CGRectMake(0, 0, 100, 100);

Notez que si vous êtes accroché à une méthode de classe, vous devez mettre une méta-classe de la classe argument

MSHookMessageEx(objc_getMetaClass("UIView"), @selector(commitAnimations), replaced_UIView_commitAnimations, (IMP *)&original_UIView_commitAnimations);

Utilisation de MSHookFunction pour accrocher une fonction privée :

#define WebKit "/System/Library/PrivateFrameworks/WebKit.framework/WebKit"
#define WebCore "/System/Library/PrivateFrameworks/WebCore.framework/WebCore"

NSURLRequest* (*X_ZNK7WebCore15ResourceRequest12nsURLRequestEv)(void* something);

void (*X_ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE)(void* something, void* loader, unsigned long identifier,  void* request, const void** response);


MSHook(void, X_ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE, void* something, void* loader, unsigned long identifier,  void* request, const void** response) {
        
    NSURLRequest *nsRequest = X_ZNK7WebCore15ResourceRequest12nsURLRequestEv(request);
    //do something
    _X_ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE(something, loader, identifier, request, response);
}

template <typename Type_>
static void nlset(Type_ &function, struct nlist *nl, size_t index) {
    struct nlist &name(nl[index]);
    uintptr_t value(name.n_value);
    if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
        value |= 0x00000001;
    function = reinterpret_cast<Type_>(value);
}

...

 dlopen(WebKit, RTLD_LAZY | RTLD_NOLOAD);
 dlopen(WebCore, RTLD_LAZY | RTLD_NOLOAD);

struct nlist nl[2];
        bzero(&nl, sizeof(struct nlist) * 2);
        nl[0].n_un.n_name = (char*)"__ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE";
        
        if (nlist(WebKit, nl) < 0 || nl[0].n_type == N_UNDF) {
            fprintf(stderr, "\n nlist(%s, %s) failed\n",
                    "WebKit",
                    nl[0].n_un.n_name);
        } else {
            struct nlist nlsucker[2];
            bzero(&nlsucker, sizeof(struct nlist) * 2);
            nlsucker[0].n_un.n_name = (char*)"__ZNK7WebCore15ResourceRequest12nsURLRequestEv";
            
            if (nlist(WebCore, nlsucker) < 0 || nlsucker[0].n_type == N_UNDF) {
                fprintf(stderr, "\n nlist(%s, %s) failed\n",
                        "WebCore",
                        nlsucker[0].n_un.n_name);
            }
            else {
                
                nlset(X_ZNK7WebCore15ResourceRequest12nsURLRequestEv, nlsucker, 0);    
            nlset(X_ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE, nl, 0);
            MSHookFunction(X_ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE,
MSHake(X_ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE));
                }
        }


Parce que nous voulons que le pointeur ai un symbole privé, nous devons utiliser nlist.

MobileLoader

MobileLoader charge la 3ème partie du code de correction dans l'application en cours d'exécution. MobileLoader va d'abord se charger dans l'application de l'exécution utilisant la variable d'environnement DYLD_INSERT_LIBRARIES. Il recherche ensuite toutes les bibliothèques dynamiques dans le répertoire /Library/MobileSubstrate/DynamicLibraries/,Une extension doit utiliser le code de constructeur pour effectuer tous les travaux.

...
// The attribute forces this function to be called on load.
__attribute__((constructor))
static void initialize() {
  NSLog(@"MyExt: Loaded");
  MSHookFunction(CFShow, replaced_CFShow, &original_CFShow);
}