如何用逆向的方式强行在朋友圈斗图


前言

本文分享一下如何用逆向Hook的方式强行打开朋友圈表情包的选项
准备工作如下:
- 1.可越狱的iPhone(我使用iPhone6SPlus)
- 2.不可越狱的iPhone(我使用iPhone11ProMax)
- 3.MacBook Pro
- 4.Xcode
- 5.Hopper Disassembler
- 6.WeChat 7.0.10

步骤

  • 1.首先我们使用ssh连接我们已经越狱的iPhone控制台,然后使用frida对其进行砸壳(这里不演示)
  • 2.我们进入微信朋友圈的界面,依次按出 评论->笑脸,并不再操作保持锁屏。使用ps -e | grep WeChat勾住微信进程,拿到pid号。接着使用cycript -p pid号进入cy界面,再使用[[UIApp keyWindow] recursiveDescription].toString()打印并找出,评论框的视图的类名称(iOS中一般命名为XXView)
  • 3.使用class-dump打出WeChat的头文件,拿到EmoticonBoardView相关类的成员变量(属性,可以通过OC点语法调用) 完整代码EmoticonBoardView.h如下
//
//     Generated by class-dump 3.5 (64 bit) (Debug version compiled Jan 10 2020 14:01:04).
//
//  Copyright (C) 1997-2019 Steve Nygard.
//

#import "MMUIView.h"

#import "EmoticonBackupOperateMgrExt-Protocol.h"
#import "EmoticonBoardCameraEmoticonEntryViewDelegate-Protocol.h"
#import "EmoticonBoardCrossCollectionControllerDelegate-Protocol.h"
#import "EmoticonBoardDynamicTabBarDelegate-Protocol.h"
#import "EmoticonBoardRecommendViewDelegate-Protocol.h"
#import "EmoticonCustomAddLogicControllerDelegate-Protocol.h"
#import "EmoticonRecommendMgrExt-Protocol.h"
#import "EmoticonTabRecommendMgrExt-Protocol.h"
#import "IEmoticonMgrExt-Protocol.h"
#import "IEmoticonPackageMgrExt-Protocol.h"
#import "IMMLanguageMgrExt-Protocol.h"
#import "MMConfigMgrExt-Protocol.h"
#import "MMKernelExt-Protocol.h"
#import "MMUIViewControllerDelegate-Protocol.h"

@class CAShapeLayer, EmoticonBoardCrossCollectionController, EmoticonBoardDynamicTabBar, EmoticonCustomAddLogicController, EmoticonPreview, NSString, QQEmojiPreview, UIView;
@protocol BaseEmoticonViewDelegate, EmoticonBoardViewDelegate;

@interface EmoticonBoardView : MMUIView <IMMLanguageMgrExt, MMKernelExt, IEmoticonPackageMgrExt, EmoticonRecommendMgrExt, IEmoticonMgrExt, EmoticonBackupOperateMgrExt, EmoticonBoardDynamicTabBarDelegate, EmoticonTabRecommendMgrExt, MMUIViewControllerDelegate, EmoticonBoardRecommendViewDelegate, EmoticonBoardCameraEmoticonEntryViewDelegate, EmoticonBoardCrossCollectionControllerDelegate, EmoticonCustomAddLogicControllerDelegate, MMConfigMgrExt>
{
    id <BaseEmoticonViewDelegate> m_emoticonSendDelegate;
    UIView *m_backgroundView;
    CAShapeLayer *m_topCornerLayer;
    EmoticonBoardCrossCollectionController *m_pageCollectionController;
    EmoticonBoardDynamicTabBar *m_dynamicTabBar;
    QQEmojiPreview *m_qqEmojiPreview;
    EmoticonPreview *m_emoticonPreview;
    unsigned long long _boardShowTime;
    unsigned long long _boardQQEmojiClickIndex;
    unsigned long long _boardEmoticonClickIndex;
    unsigned long long _boardTabBarClickIndex;
    EmoticonCustomAddLogicController *m_emoticonAddLogicController;
    _Bool m_shouldHideGameEmoticon;
    _Bool _isSingleTab;
    _Bool _forceShowCameraEmoticonEntry;
    _Bool _hasCorner;
    _Bool _hasFoldButton;
    double m_bottomInset;
    id <EmoticonBoardViewDelegate> _m_delegate;
    unsigned long long _emojiUseScene;
    NSString *_finishButtonTitle;
    unsigned long long _style;
    unsigned long long _recentPulledByCameraEmoticonLabelTime;
    NSString *_externInfo;
}

+ (void)unRegisterInstanceDelegate;
+ (void)destroyInstance;
+ (id)shareInstanceForChat;
@property(retain, nonatomic) NSString *externInfo; // @synthesize externInfo=_externInfo;
@property(nonatomic) unsigned long long recentPulledByCameraEmoticonLabelTime; // @synthesize recentPulledByCameraEmoticonLabelTime=_recentPulledByCameraEmoticonLabelTime;
@property(nonatomic) _Bool hasFoldButton; // @synthesize hasFoldButton=_hasFoldButton;
@property(nonatomic) _Bool hasCorner; // @synthesize hasCorner=_hasCorner;
@property(nonatomic) unsigned long long style; // @synthesize style=_style;
@property(nonatomic) _Bool forceShowCameraEmoticonEntry; // @synthesize forceShowCameraEmoticonEntry=_forceShowCameraEmoticonEntry;
@property(nonatomic) _Bool isSingleTab; // @synthesize isSingleTab=_isSingleTab;
@property(retain, nonatomic) NSString *finishButtonTitle; // @synthesize finishButtonTitle=_finishButtonTitle;
@property(nonatomic) unsigned long long emojiUseScene; // @synthesize emojiUseScene=_emojiUseScene;
@property(nonatomic) __weak id <EmoticonBoardViewDelegate> m_delegate; // @synthesize m_delegate=_m_delegate;
@property(nonatomic) _Bool shouldHideGameEmoticon; // @synthesize shouldHideGameEmoticon=m_shouldHideGameEmoticon;
@property(nonatomic) double bottomInset; // @synthesize bottomInset=m_bottomInset;
- (void).cxx_destruct;
- (void)hideEmoticonPreview;
- (void)showEmoticonPreviewForWrap:(id)arg1 description:(id)arg2 frame:(struct CGRect)arg3;
- (void)hideQQEmojiPreview;
- (void)showQQEmojiPreviewForKey:(id)arg1 atCenterPoint:(struct CGPoint)arg2;
- (void)onTapRecommendWithPid:(id)arg1;
- (void)onTapCameraEmoticonCreateButton;
- (void)onTapEmoticonWrap:(id)arg1 atIndex:(long long)arg2 maxCountPerLine:(unsigned long long)arg3 fromSection:(id)arg4;
- (void)onTapQQEmojiDeleteButton;
- (void)onTapQQEmojiSendButton;
- (void)onTapQQEmojiWithCode:(id)arg1 isRecentUse:(_Bool)arg2 atIndex:(long long)arg3 maxCountPerLine:(unsigned long long)arg4;
- (void)didChangeToPage:(id)arg1;
- (void)onEmoticonBoardDynamicTabBarClickFloatingFoldButton;
- (void)onEmoticonBoardDynamicTabBarClickSettingItem;
- (void)onEmoticonBoardDynamicTabBarClickStorePlusItem;
- (void)onEmoticonBoardDynamicTabBarTabBarClickItem:(id)arg1 atIndex:(long long)arg2;
- (id)getViewController;
- (void)onUploadEmoticonQueueChanged;
- (void)onAddBackupEmoticonOK:(id)arg1 addEmoticonWrap:(id)arg2;
- (void)onMMDynamicConfigUpdated;
- (void)OnEmoticonTabRecommendChanged;
- (void)onPreQuit;
- (void)onLanguageChange;
- (void)OnEmoticonRecommendNewStateChangedForBoardView:(_Bool)arg1;
- (void)OnUpdateEmoticonPackageList;
- (void)OnUpdateEmoticonPackageListAfterSort;
- (void)OnUpdateEmoticonList;
- (long long)emotionRecommandMaxCountConfig;
- (id)cameraPackageId;
- (id)customPackageId;
- (id)GetCurrentViewController;
- (void)layoutSubviews;
- (_Bool)selectTabOfPid:(id)arg1 forceFirstPage:(_Bool)arg2 animated:(_Bool)arg3;
- (void)changeTabToPid:(id)arg1;
- (void)changeToPidPosition:(id)arg1;
- (void)showAddEmoticonActionSheet;
- (void)reloadEmoticonViewData;
- (void)reloadTabBarWithTabItems:(id)arg1;
- (id)checkImageExistInEmoticonWrapArray:(id)arg1 abortOnFailure:(_Bool)arg2;
- (id)getEmoticonListWithPid:(id)arg1 needCheckImageExist:(_Bool)arg2;
- (id)getCameraEmoticonListWithNeedCheckImageExist:(_Bool)arg1;
- (id)getCustomEmoticonListWithNeedCheckImageExist:(_Bool)arg1;
- (id)getEmoticonArrayWithPackageArray:(id)arg1;
- (id)getTabItemsWithStickerPackages:(id)arg1 recommandItems:(id)arg2;
- (id)getTabRecommandItemsWithStickerPackages:(id)arg1;
- (id)getStickerPackages;
- (id)emoticonAddLogicController;
- (void)resetEmotionBoardShowTimeAndClickIndex;
- (void)SetCanSend:(_Bool)arg1;
@property(readonly, nonatomic) double preferHeight;
- (void)UnRegisterDelegate;
- (void)RegisterDelegate:(id)arg1;
- (void)prepareForReuseWithoutReload;
- (_Bool)checkNeedReloadForReuse;
- (_Bool)isSticker;
- (void)reloadEmotionBoardView;
- (void)initView;
- (void)initData;
- (void)dealloc;
- (id)initWithFrame:(struct CGRect)arg1;

// Remaining properties
@property(readonly, copy) NSString *debugDescription;
@property(readonly, copy) NSString *description;
@property(readonly) unsigned long long hash;
@property(readonly) Class superclass;

@end

由于是成员变量或者叫做类属性,我们重点关注代码中的@property关键字,由于之前这个功能曾经开放过但又关闭了,可以联想到该属性应该为Bool型.
- 4.使用Hopper Disassembler打出WeChat的.m文件(方法实现文件)
搜索EmoticonBoardView关键字并配合查看.h文件中的属性,最终发现isSingleTab属性使用setter和getter方法

  • 5.使用hook语法修改其bool变量 由于不知道true和false代表的意思,这里我们先使用true
%hook EmoticonBoardView

- (BOOL)IsSingleTab {
    return true;
}

- (void)setIsSingleTab:(BOOL)arg {
    arg = true;
}

%end

尝试使用theos套件的make package install命令进行编译安装,查看效果

发现ture并未达到预期效果,接着使用false进行尝试

%hook EmoticonBoardView

- (BOOL)IsSingleTab {
    return true;
}

- (void)setIsSingleTab:(BOOL)arg {
    arg = true;
}

%end

再次安装查看效果

image.png

发现成功达到效果

  • 6.将dylib注入app安装到iPhone11ProMax

成功实现免越狱突破限制

遗憾

经过本文完成时测试,腾讯已经关闭了表情包消息上传接口,但本地可以依然可以看到。本文主要为分享思路,勿喷!插件可联系吐司群——清水川崎获得dylib和deb。