初涉iOS逆向工程:免越狱修改微信

破壳

​ 参考文章iOS逆向之博破壳

外观篇

​ 参考文章初涉iOS逆向工程:免越狱修改微信(外观篇)

功能篇

本文是在以上两篇文章的基础上来分析如何逆向修改微信原生功能,包含以下3个小功能

  • 微信消息防撤回
  • 修改微信运动步数
  • 掷骰子、石头剪刀布自定义

关于微信消息防撤回和修改微信步数网上也有很多的资料了,我也借鉴了一部分

原始代码参考于https://github.com/Abeautifulliar/WeChatHook,之后我自定义实现了掷骰子和剪刀石头布作弊功能

1.界面分析与准备

  • 头文件分析

    首先对破壳后拿到的头文件进行分析,根据文件类名、方法名、变量名等猜测其作用

    image.png

    文件名是如此之多,足足10000+,想要一个一个看文件名难免力不从心,这时就需要考验我们的技巧了,比如你想搜登录相关的逻辑可以搜索一些关键字进行过滤以找到你想要的文件,如搜索login ViewController manager。 头文件内又有很多实例变量和方法申明,我们也可以很容易猜测出用途

  • UI界面分析
    通过debug查看UI层级图可以很容易的知道当前UI界面所属的ViewController了

    image.png

    如图可以得知微信聊天界面所属的VC是BaseMsgContentViewController
    同样的方法可以知道设置界面是NewSettingViewController,通讯录界面是ContactsViewController

消息防撤回

网上很多资料也说了,微信的消息管理类是CMessageMgr,一些关键方法如下

- (void)AsyncOnAddMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AsyncOnDelMsg:(id)arg1;
- (void)onRevokeMsg:(id)arg1;

根据猜测得知微信接收到撤回消息时会先调用 onRevokeMsg方法,该方法会创建一条通知消息,即xxx撤回了一条消息,然后会调用AsyncOnDelMsg方法,该方法会将本地的消息删除,而我们要做的就是调用onRevokeMsg方法,但是不调用AsyncOnDelMsg方法,这样就达到了防撤回的目的

注:用户自己删除本地消息时也会调用AsyncOnDelMsg方法,所以为了不影响其它操作,我们应该只屏蔽掉因接受到撤回消息时调用AsyncOnDelMsg
关键代码如下

// 阻止撤回消息
CHOptimizedMethod1(self, void, CMessageMgr, onRevokeMsg, id, msg){
    [WeChatManager manager].revokeMsg = YES;
    CHSuper1(CMessageMgr, onRevokeMsg, msg);
}

CHDeclareMethod3(void, CMessageMgr, DelMsg, id, arg1, MsgList, id, arg2, DelAll, BOOL, arg3){
    if ([WeChatManager manager].revokeMsg) {
        [WeChatManager manager].revokeMsg = NO;
    } else {
        CHSuper3(CMessageMgr, DelMsg, arg1, MsgList, arg2, DelAll, arg3);
    }
}

WeChatManager是自定义的类,用于记录是否收到了通知撤回消息和保存要修改的步数

修改步数

修改步数的关键类是WCDeviceStepObject

#import "MMObject.h"

@class NSMutableArray;

@interface WCDeviceStepObject : MMObject
{
    unsigned int beginTime;
    unsigned int endTime;
    unsigned int m7StepCount;
    unsigned int hkStepCount;
    NSMutableArray *allHKSampleSource;
}

- (void).cxx_destruct;
@property(retain, nonatomic) NSMutableArray *allHKSampleSource; // @synthesize allHKSampleSource;
@property(nonatomic) unsigned int beginTime; // @synthesize beginTime;
@property(nonatomic) unsigned int endTime; // @synthesize endTime;
@property(nonatomic) unsigned int hkStepCount; // @synthesize hkStepCount;
@property(nonatomic) unsigned int m7StepCount; // @synthesize m7StepCount;

@end

只需Hook住m7StepCount方法即可
如下代码

CHOptimizedMethod0(self, unsigned int, WCDeviceStepObject, m7StepCount){
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[NSDate date]];
    NSDate *today = [cal dateFromComponents:components];
    components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[WeChatManager manager].lastChangeStepCountDate];
    NSDate *otherDate = [cal dateFromComponents:components];
    BOOL modifyToday = NO;
    if([today isEqualToDate:otherDate]) modifyToday = YES;
    if ([WeChatManager manager].stepCount < CHSuper0(WCDeviceStepObject, m7StepCount) || !modifyToday) {
        [WeChatManager manager].stepCount = CHSuper0(WCDeviceStepObject, m7StepCount);
    }
    return [WeChatManager manager].stepCount;
}

掷骰子、剪刀石头布

有过掷骰子、剪刀石头布的都知道,掷骰子的结果其实是在发送方就决定了,而不是到服务端或者接收方才确定的结果,所以我们把发送消息类型拦截就行啦~
原理和防撤回消息类似,当发送Emoticon消息时会调用- (void)AddEmoticonMsg:(id)arg1 MsgWrap:(id)arg2;,修改消息内容即可
代码如下

CHMethod(2, void, CMessageMgr, AddEmoticonMsg, id, arg1, MsgWrap, id, arg2) {
    id msgType = [arg2 valueForKey:@"m_extendInfoWithMsgType"];
    if (((NSNumber *)([msgType valueForKey:@"m_uiGameType"])).intValue == 2) {
        [msgType setValue:[NSNumber numberWithInt:[WeChatManager manager].gameContent2] forKey:@"m_uiGameContent"];
        [arg2 setValue:msgType forKey:@"m_extendInfoWithMsgType"];
    }
    if (((NSNumber *)([msgType valueForKey:@"m_uiGameType"])).intValue == 1) {
        [msgType setValue:[NSNumber numberWithInt:[WeChatManager manager].gameContent1] forKey:@"m_uiGameContent"];
        [arg2 setValue:msgType forKey:@"m_extendInfoWithMsgType"];
    }
    CHSuper(2, CMessageMgr, AddEmoticonMsg, arg1, MsgWrap, arg2);
}

注:m_uiGameType为1时表示剪刀石头布,为2时表示掷骰子,而当石头剪刀布时m_extendInfoWithMsgType的值为1~3,分别代表剪刀(1),石头(2)
,布(3),当为掷骰子时m_extendInfoWithMsgType的值分别为49,也就是掷骰子的结果(16)

其它

关于如何修改原生UI,拿设置界面举例,如果我们要添加一个自定义的设置选项,首先需要分析类NewSettingViewController

@class MMTableViewInfo, MMTipsViewController, NSString, WCAccountLogoutLogic, WCAccountSwitchLogic;

@interface NewSettingViewController : MMUIViewController <WCAccountSwitchLogicDelegate, WCAccountLogoutLogicDelegate, MMTipsViewControllerDelegate>
{
    MMTableViewInfo *m_tableViewInfo;
    _Bool m_bFromSetting;
    WCAccountSwitchLogic *m_switchLogic;
    WCAccountLogoutLogic *m_logoutLogic;
    MMTipsViewController *m_introView;
}
@end

根据头文件可知,该VC的tableView被封装到了m_tableViewInfo,类型为MMTableViewInfo,该类提供了一个- (void)insertSection:(id)arg1 At:(unsigned int)arg2;方法,所以我们想办法加一个section就行啦
代码如下

CHDeclareMethod0(void, NewSettingViewController, reloadTableData){
   CHSuper0(NewSettingViewController, reloadTableData);
   MMTableViewInfo *tableInfo = [self valueForKeyPath:@"m_tableViewInfo"];
   MMTableViewSectionInfo *sectionInfo = [objc_getClass("MMTableViewSectionInfo") sectionInfoDefaut];
   MMTableViewCellInfo *stepcountCellInfo1 = [objc_getClass("MMTableViewCellInfo") editorCellForSel:@selector(recordStepCount:) target:[WeChatManager manager] title:@"微信运动步数" margin:300.0 tip:@"请输入步数" focus:NO text:[NSString stringWithFormat:@"%ld", (long)[WeChatManager manager].stepCount]];
   MMTableViewCellInfo *cellInfo2 = [objc_getClass("MMTableViewCellInfo") editorCellForSel:@selector(recordGameContent1:) target:[WeChatManager manager] title:@"石头剪刀(1~3)" margin:300.0 tip:@"" focus:NO text:[NSString stringWithFormat:@"%ld", (long)[WeChatManager manager].gameContent1]];
   MMTableViewCellInfo *cellInfo3 = [objc_getClass("MMTableViewCellInfo") editorCellForSel:@selector(recordGameContent2:) target:[WeChatManager manager] title:@"掷骰子(1-6)" margin:300.0 tip:@"" focus:NO text:[NSString stringWithFormat:@"%ld", (long)[WeChatManager manager].gameContent2-3]];
   [sectionInfo addCell:stepcountCellInfo1];
   [sectionInfo addCell:cellInfo2];
   [sectionInfo addCell:cellInfo3];
   [tableInfo insertSection:sectionInfo At:0];
   MMTableView *tableView = [tableInfo getTableView];
   [tableView reloadData];
}

最后

随着微信防越狱技术的提高和版本的迭代,当前越狱版本可能在后续无法使用。而且第三方的越狱版app也不要太相信,可能会偷偷记录个人隐私。能自己弄的还是自己弄吧,且用且珍惜!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容