BandarHL / BHTwitter

Awesome tweak for Twitter
1.89k stars 275 forks source link

Move Font hooking to Runtime #102

Closed ExTBH closed 1 year ago

ExTBH commented 1 year ago

I have not tested it with BHTwitter as i can't get it to compile without using my mac(which i don't wanna use cuz im lazy ) but i tested it as a standalone tweak it it worked

BandarHL commented 1 year ago

Thanks for your PR, I’m going to test all the code you published today and the others PR

ExTBH commented 1 year ago

forgot to copy from my project to the fork

ExTBH commented 1 year ago

the BH_BaseImp is a wrapper to let us call the original method IMP's on runtime named BaseImp because its the base for all methods (id self, SEL _cmd), could be used in the future for methods of the same signature. it is marked as returning a UIFont* could be changed later to id for general purpose

BandarHL commented 1 year ago

crash from memory, that's why i hate working with pointers it's unsafe and hard to debug

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_PROTECTION_FAILURE at 0x000000016bc6c6f0
Exception Codes: 0x0000000000000002, 0x000000016bc6c6f0
VM Region Info: 0x16bc6c6f0 is in 0x16bb74000-0x16bc70000;  bytes after start: 1017584  bytes before end: 14607
      REGION TYPE                 START - END      [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      Stack Guard              16bb70000-16bb74000 [   16K] ---/rwx SM=NUL  
--->  Stack                    16bb74000-16bc70000 [ 1008K] rw-/rwx SM=PRV  thread 0
      Stack Guard              16bc70000-16bc74000 [   16K] ---/rwx SM=NUL  
Termination Reason: SIGNAL 11 Segmentation fault: 11
Terminating Process: exc handler [5059]
BandarHL commented 1 year ago

Sometimes work and some crash it's unstable

ExTBH commented 1 year ago

uhh could be https://github.com/BandarHL/BHTwitter/blob/e3424615b6935cfab2f034961b2bc2d13d7db7dd/BHTwitter/TWHeaders.h#L416 because this method behaves weirdly, might be returning something else because a method doesnt exist?

wrapping this in a try catch could solve it for now https://github.com/BandarHL/BHTwitter/blob/e3424615b6935cfab2f034961b2bc2d13d7db7dd/BHTwitter/BHTwitter.xm#L1068-L1073

BandarHL commented 1 year ago

Also, you need to pass the pointer as Void * in valueWithPointer something like that

[originalFontsIMP setObject:[NSValue valueWithPointer:&oldImp] forKey:sel];
BandarHL commented 1 year ago

in the main time im gonna released stable version

ExTBH commented 1 year ago

when i wrote it yesterday passing a pointer insta-crash it, im gonna work on it later

BandarHL commented 1 year ago

I remember PoomSmart work in something like that in YTABConfig https://github.com/PoomSmart/YTABConfig/blob/main/Tweak.xm

ExTBH commented 1 year ago

is there a view that it crashes on? i can't get it to crash for me

ExTBH commented 1 year ago

should prevent non-implemented methods from being hooked

BandarHL commented 1 year ago

You're methods didn't compile with me because the conversion of pointer, so I edit the code like that:

static UIFont *TAEStandardFontGroupReplacement(UIFont *self, SEL _cmd){
    BH_BaseImp orig  = (BH_BaseImp)originalFontsIMP[NSStringFromSelector(_cmd)].pointerValue;
    UIFont *origFont = orig(self, _cmd);
    UIFont *newFont  = BH_getDefaultFont(origFont);
    return newFont != nil ? newFont : origFont;
}
static void batchSwizzlingOnClass(Class cls, NSArray<NSString*>*origSelectors, IMP new){
    for(NSString *sel in origSelectors){
    SEL origSel = NSSelectorFromString(sel);
        Method origMethod = class_getInstanceMethod(cls, origSel);
        BH_BaseImp oldImp = (BH_BaseImp)class_replaceMethod(cls, origSel, new, method_getTypeEncoding(origMethod));
    [originalFontsIMP setObject:[NSValue valueWithPointer:&oldImp] forKey:sel];
    }
}

Do you think that is the reason for the instant crash?

ExTBH commented 1 year ago

i am using https://github.com/theos/sdks/tree/master/iPhoneOS14.5.sdk

whats yours? and what error do you get

ExTBH commented 1 year ago

if i understand oldImp holds a pointer to the implementation doing &oldImp we are passing a pointer to an IMP pointer

BandarHL commented 1 year ago

As I said conversion error xcode tell me you can't convert void to BH_imp. And it's reasonable error and solve it by convert the pointer from void to BH_imp

BandarHL commented 1 year ago

And i used ios 16 sdk

BandarHL commented 1 year ago

Do you used flags to suppress this error?

ExTBH commented 1 year ago

no i havent, my Makefile

TARGET := iphone:clang:latest:11.0
INSTALL_TARGET_PROCESSES = Twitter

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = bhtwitterpatch

bhtwitterpatch_FILES = Tweak.x
bhtwitterpatch_CFLAGS = -fobjc-arc

include $(THEOS_MAKE_PATH)/tweak.mk

and my tweak.x

typedef UIFont *(*BH_BaseImp)(id,SEL);
static NSMutableDictionary<NSString*, NSValue*>* originalFontsIMP;

static UIFont *newMethod(UIFont *self, SEL _cmd){

    BH_BaseImp orig  = originalFontsIMP[NSStringFromSelector(_cmd)].pointerValue;
    UIFont *origFont = orig(self, _cmd);
    UIFont *newFont  = [UIFont systemFontOfSize:20];
    return newFont != nil ? newFont : origFont;
}

static void batchSwizzlingOnClass(Class cls, NSArray<NSString*>*origSelectors, IMP new){
    for(NSString *sel in origSelectors){
        SEL origSel = NSSelectorFromString(sel);
        Method origMethod = class_getInstanceMethod(cls, origSel);
        if (origMethod != NULL){
            BH_BaseImp oldImp = (BH_BaseImp)class_replaceMethod(cls, origSel, new, method_getTypeEncoding(origMethod));
            [originalFontsIMP setObject:[NSValue valueWithPointer:oldImp] forKey:sel];
        }
    }
}

%hook TAEStandardFontGroup
+ (TAEStandardFontGroup*)sharedFontGroup{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSArray *fontsMethods = @[
            @"profilesFollowingCountFont", @"profilesFollowingFont", @"userCellFollowsYouFont", @"dashFollowingCountFont",
            @"dashFollowingFont", @"carouselUsernameFont", @"carouselDisplayNameFont", @"profilesFullNameFont",
            @"profilesUsernameFont", @"readerModeSmallFont", @"readerModeSmallBoldFont", @"readerModeMediumFont",
            @"readerModeMediumBoldFont", @"readerModeLargeFont", @"readerModeLargeBoldFont", @"treeTopicsDescriptionFont",
            @"treeTopicsCategoryNameFont", @"treeTopicsNameFont", @"treeTopicsCategoryNameLargeFont", @"topicsPillNameFont",
            @"topicsDescriptionFont", @"topicsNameFont", @"composerTextEditorFont", @"statusCellEdgeToEdgeBodyBoldFont",
            @"statusCellEdgeToEdgeBodyFont", @"statusCellBodyFont", @"statusCellBodyBoldFont", @"cardAttributionFont",
            @"cardTitleBoldFont", @"cardTitleFont", @"tweetDetailBoldFont", @"tweetDetailFont",
            @"directMessageBubbleBodyFont", @"directMessageComposePersistentBarFont", @"fixedJumboBoldFont", @"fixedXLargeBoldFont",
            @"fixedLargeBoldFont", @"fixedNormalBoldFont", @"fixedSmallBoldFont", @"fixedJumboFont",
            @"fixedXLargeFont", @"fixedLargeFont", @"fixedNormalFont", @"fixedSmallFont",
            @"jumboBoldFont", @"xLargeBoldFont", @"largeBoldFont", @"normalBoldFont",
            @"smallBoldFont", @"jumboFont", @"xLargeFont", @"largeFont",
            @"normalFont", @"smallFont", @"buttonXLargeFont", @"buttonLargeFont",
            @"buttonMediumFont", @"buttonMedium_CondensedFont", @"buttonMedium_CondensedLighterFont", @"buttonSmallFont",
            @"buttonSmallLighterFont", @"buttonSmall_CondensedFont", @"buttonSmall_CondensedLighterFont", @"buttonNavigationBarFont",
            @"buttonHeavyNavigationBarFont"
        ];
        originalFontsIMP = [NSMutableDictionary new];
        batchSwizzlingOnClass([self class], fontsMethods, (IMP)newMethod);
    });
    return %orig;
}
%end

which compiles fine without errors

ExTBH commented 1 year ago

iOS 16 sdk without any errors, it works flawlessly

image
BandarHL commented 1 year ago
Cannot initialize a variable of type 'BH_BaseImp' (aka 'UIFont *(*)(__strong id, SEL)') with an rvalue of type 'void * _Nullable'
BandarHL commented 1 year ago

i don't why it's working with you and should be not because it's different types

ExTBH commented 1 year ago

try casting before assigning, (BH_BaseImp)...

BandarHL commented 1 year ago

no it's not fixed. The problem is the pointer itself see in the code BH_BaseImp orig = originalFontsIMP[NSStringFromSelector(_cmd)].pointerValue; the pointerValue return Void * and you want to BH_BaseImp like that BH_BaseImp orig = (BH_BaseImp)originalFontsIMP[NSStringFromSelector(_cmd)].pointerValue;

BandarHL commented 1 year ago

the same issue here in [NSValue valueWithPointer:oldImp]

BandarHL commented 1 year ago

and when you convert it, just crash

ExTBH commented 1 year ago

If the project isn't dependent on MonkeyDev i could test and build it,

I would suggest moving the project to just theos and use Kabir's toolchain and Orion branch, if you want the auto completion of xCode It is achievable with Theos i use it with all my projects

ExTBH commented 1 year ago

the same issue here in [NSValue valueWithPointer:oldImp]

Try casting oldImp here as BH_BaseImp

It is a clang problem most likely should be suppressible with a flag

BandarHL commented 1 year ago

the same issue here in [NSValue valueWithPointer:oldImp]

Try casting oldImp here as BH_BaseImp

It is a clang problem most likely should be suppressible with a flag

same error because valueWithPointer: expect void * you cant pass BH_imp

ExTBH commented 1 year ago

found the problem you're using objc++ while i am using objc, in C you can assign a variable with return type of void * but c++ doesn't allow you

ExTBH commented 1 year ago

basic fix is to change BHTwitter.xm to BHTwitter.x but i would guess it might generate some errors

ExTBH commented 1 year ago

try this, I've added some c++ voodoo

BandarHL commented 1 year ago

Thanks i just convert it to objc and it's works

BandarHL commented 1 year ago

so im going to close the PR and clean up the code and push it with you're name. thanks

ExTBH commented 1 year ago

@BandarHL just saw thoose, they should be deleted

image