theos / logos

Preprocessor that simplifies Objective-C hooking.
https://theos.dev/docs/logos
Other
206 stars 34 forks source link

Multiple conditional %init in one %ctor #27

Closed liuxuan30 closed 5 years ago

liuxuan30 commented 5 years ago

Hi there,

I'm not sure if this is the right place to ask; sorry.

I want to ask, can multiple conditional %init work together in one %ctor? For example,

I have some function hooks as a group, I only want to init this group for certain condition, and other non-grouped hooks get still inited.

I have below code sample:

%ctor {
    %init();
    if (metCondition) {
        %init(SomeGroup)
    }    
}

Is this allowed? From what I tested, it seems %init(SomeGroup) will override %init(), meaning those ungrouped hooks is not initialized after %init(SomeGroup) is called.

If I am wrong, how can I achieve my goal? Thanks

kirb commented 5 years ago

%init; or %init(); with no group name implies initialising _ungrouped. Groups can’t override each other — actually you can have a hook for the same method in multiple groups and they will be applied in the order you init them. Nothing is overridden on Logos’ level; it’s just allowing you to control exactly where in the program Logos places the calls to Substrate to create the hooks.

Running Logos directly or checking for the processed Logos output under .theos/obj/arm64/Tweak.x.m might help you to understand what exactly Logos is doing and if it might be an issue on our side. See my example below.


Logos input ```logos %hook Thing - (id)description { returm @"Thing"; } - (NSInteger)florps { return 5; } %end %group MyGroup %hook Thing - (id)description { return [%orig stringByAppendingString:@" (of doom)"]; } - (id)anotherThing { return nil; } %end %end BOOL something = YES; %ctor { %init; if (something) { %init(MyGroup); } } ```
Logos output (Simplified for readability) ```objc #include @class Thing; static id (*_logos_orig$_ungrouped$Thing$description)(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST, SEL); static id _logos_method$_ungrouped$Thing$description(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST, SEL); static NSInteger (*_logos_orig$_ungrouped$Thing$florps)(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST, SEL); static NSInteger _logos_method$_ungrouped$Thing$florps(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST, SEL); static id _logos_method$_ungrouped$Thing$description(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST __unused self, SEL __unused _cmd) { returm @"Thing"; } static NSInteger _logos_method$_ungrouped$Thing$florps(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST __unused self, SEL __unused _cmd) { return 5; } static id (*_logos_orig$MyGroup$Thing$description)(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST, SEL); static id _logos_method$MyGroup$Thing$description(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST, SEL); static id (*_logos_orig$MyGroup$Thing$anotherThing)(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST, SEL); static id _logos_method$MyGroup$Thing$anotherThing(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST, SEL); static id _logos_method$MyGroup$Thing$description(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST __unused self, SEL __unused _cmd) { return [_logos_orig$MyGroup$Thing$description(self, _cmd) stringByAppendingString:@" (of doom)"]; } static id _logos_method$MyGroup$Thing$anotherThing(_LOGOS_SELF_TYPE_NORMAL Thing* _LOGOS_SELF_CONST __unused self, SEL __unused _cmd) { return nil; } BOOL something = YES; static __attribute__((constructor)) void _logosLocalCtor_36cf86a9(int __unused argc, char __unused **argv, char __unused **envp) { { Class _logos_class$_ungrouped$Thing = objc_getClass("Thing"); MSHookMessageEx(_logos_class$_ungrouped$Thing, @selector(description), (IMP)&_logos_method$_ungrouped$Thing$description, (IMP*)&_logos_orig$_ungrouped$Thing$description); MSHookMessageEx(_logos_class$_ungrouped$Thing, @selector(florps), (IMP)&_logos_method$_ungrouped$Thing$florps, (IMP*)&_logos_orig$_ungrouped$Thing$florps); } if (something) { { Class _logos_class$MyGroup$Thing = objc_getClass("Thing"); MSHookMessageEx(_logos_class$MyGroup$Thing, @selector(description), (IMP)&_logos_method$MyGroup$Thing$description, (IMP*)&_logos_orig$MyGroup$Thing$description); MSHookMessageEx(_logos_class$MyGroup$Thing, @selector(anotherThing), (IMP)&_logos_method$MyGroup$Thing$anotherThing, (IMP*)&_logos_orig$MyGroup$Thing$anotherThing); } } } ```
liuxuan30 commented 5 years ago

Hi @kirb, thanks for answering! It turned out that one of my MSHookMessageEx crashed, so it seems the init is overwritten. Deleting the crash code will work like you said.

btw, in my path .theos/obj/debug/arm64, I didn't see a Tweak.x.m like yours, just Tweak.xm.f4523a75.Td and Tweak.xm.f4523a75.o. Did I miss anything? Thank you.

I think this thread can be closed then