破殼
? 參考文章iOS逆向之博破殼
外觀篇
? 參考文章初涉iOS逆向工程:免越獄修改微信(外觀篇)
功能篇
本文是在以上兩篇文章的基礎(chǔ)上來分析如何逆向修改微信原生功能,包含以下3個小功能
- 微信消息防撤回
- 修改微信運動步數(shù)
- 擲骰子、石頭剪刀布自定義
關(guān)于微信消息防撤回和修改微信步數(shù)網(wǎng)上也有很多的資料了萍摊,我也借鑒了一部分
原始代碼參考于https://github.com/Abeautifulliar/WeChatHook,之后我自定義實現(xiàn)了擲骰子和剪刀石頭布作弊功能
1.界面分析與準備
-
頭文件分析
首先對破殼后拿到的頭文件進行分析酷鸦,根據(jù)文件類名疙咸、方法名、變量名等猜測其作用
image.png
文件名是如此之多鲜屏,足足10000+肉盹,想要一個一個看文件名難免力不從心昔驱,這時就需要考驗我們的技巧了,比如你想搜登錄相關(guān)的邏輯可以搜索一些關(guān)鍵字進行過濾以找到你想要的文件上忍,如搜索login
ViewController
manager
骤肛。 頭文件內(nèi)又有很多實例變量和方法申明纳本,我們也可以很容易猜測出用途 -
UI界面分析
通過debug查看UI層級圖可以很容易的知道當前UI界面所屬的ViewController了
image.png
如圖可以得知微信聊天界面所屬的VC是BaseMsgContentViewController
同樣的方法可以知道設(shè)置界面是NewSettingViewController
,通訊錄界面是ContactsViewController
消息防撤回
網(wǎng)上很多資料也說了,微信的消息管理類是CMessageMgr
,一些關(guān)鍵方法如下
- (void)AsyncOnAddMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AsyncOnDelMsg:(id)arg1;
- (void)onRevokeMsg:(id)arg1;
根據(jù)猜測得知微信接收到撤回消息時會先調(diào)用 onRevokeMsg
方法腋颠,該方法會創(chuàng)建一條通知消息,即xxx撤回了一條消息
繁成,然后會調(diào)用AsyncOnDelMsg
方法,該方法會將本地的消息刪除淑玫,而我們要做的就是調(diào)用onRevokeMsg
方法巾腕,但是不調(diào)用AsyncOnDelMsg
方法,這樣就達到了防撤回的目的
注:用戶自己刪除本地消息時也會調(diào)用
AsyncOnDelMsg
方法絮蒿,所以為了不影響其它操作尊搬,我們應(yīng)該只屏蔽掉因接受到撤回消息時調(diào)用AsyncOnDelMsg
關(guān)鍵代碼如下
// 阻止撤回消息
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是自定義的類,用于記錄是否收到了通知撤回消息和保存要修改的步數(shù)
修改步數(shù)
修改步數(shù)的關(guān)鍵類是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;
}
擲骰子土涝、剪刀石頭布
有過擲骰子佛寿、剪刀石頭布的都知道,擲骰子的結(jié)果其實是在發(fā)送方就決定了但壮,而不是到服務(wù)端或者接收方才確定的結(jié)果冀泻,所以我們把發(fā)送消息類型攔截就行啦~
原理和防撤回消息類似,當發(fā)送Emoticon消息時會調(diào)用- (void)AddEmoticonMsg:(id)arg1 MsgWrap:(id)arg2;
蜡饵,修改消息內(nèi)容即可
代碼如下
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,也就是擲骰子的結(jié)果(16)
其它
關(guān)于如何修改原生UI肢专,拿設(shè)置界面舉例,如果我們要添加一個自定義的設(shè)置選項您没,首先需要分析類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
根據(jù)頭文件可知鸟召,該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:@"微信運動步數(shù)" margin:300.0 tip:@"請輸入步數(shù)" 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];
}
最后
隨著微信防越獄技術(shù)的提高和版本的迭代压状,當前越獄版本可能在后續(xù)無法使用仆抵。而且第三方的越獄版app也不要太相信,可能會偷偷記錄個人隱私种冬。能自己弄的還是自己弄吧镣丑,且用且珍惜!