网上多数修改零钱是通过cycript修改,这种和reveal修改界面没什么区别,断开数据线或退出当前界面就没有了。要做到动态修改,就要分析来源,找出零钱是用了那个model的字段,然后写出tweak。
先吐槽下微信的代码,臃肿多又乱,新手不建议直接逆向微信。
1.先分析钱包和零钱界面,找到viewController
1.1 ssh root@localhost -p 2222(如果不是usb调试,请ssh到手机ip)->cycript -p WeChat->把keyWindow recursiveDescription写入文件
recursiveDescription写入文件有两个好处:一可避免cycript控制台显示不全,二避免cycript中文显示编码。
1.2 打开keyWindow.txt,直接搜索零钱,拿到零钱label地址0x18f79890
1.3通过nextResponder来找到当前的viewController
"<WCBizMainViewController: 0x17c16200>"就是当前viewController,可通过[#0x17c16200 setTitle:@"My Wallet"]修改标题来验证,也可以直接搜索你的余额,直接修改余额的值,这里就自行验证了。同理可得出零钱页面的WCPayBalanceDetailViewController。
以上的结论是: WCBizMainViewController是钱包界面的viewController, WCPayBalanceDetailViewController是零钱界面的viewController。
2.分析WCBizMainViewController和WCPayBalanceDetailViewController
2.1 class-dump WeChat拿到头文件
我只直接把需要的头文件拖入XCode,方便分析
2.2 先浏览下WCBizMainViewController的头文件
其中有两个refreshView的方法吸引了我。而且还是带参数的
2.3先分析refreshViewWithMallControlData方法,找出(id)arg1是什么
2.3.1 LLDB调试
0x00002000就是WeChat偏移的地址
2.3.2 使用IDA找到refreshViewWithMallControlData函数偏移的地址
2.3.3 设置断点并打印参数
r0是当前控制器,r1是当前函数,r2是函数的第一个参数
WCMallControlData是refreshViewWithMallControlData的参数
2.3.4分析WCMallControlData数据
2.3.4.1打开WCMallControlData.h
一眼看去,变量不是很多,但每个变量表示什么?
打开微信进入钱包页->cycript -p WeChat->choose(WCMallControlData),一个一个变量查看吧,或者觉得那个变量是符合的,打印出来。
打印第二个时候的显示了很多,看着像是配置信息,把\U转成中文。
这个可以放在.py中转换,需要用\u替换\U,否则python也解析不了。
把.py拖入终端
看到信用卡还款、微粒贷借钱、手机充值、理财通就知道这是腾讯服务这块了。还有icon_link,可以打开看看能不能对应上。
2.3.4.2分析WCPayControlData.h文件
WCPayControlData是refreshViewWithPayControlData的参数,可以用2.3的方法分析得出。我就不再赘述了。
一看头文件,500多行,我是晕的,一个一个打印,得到后年马月吗,我是个懒人,当然还是要找方便的方法。再吐槽下,model全放一起,是为了管理方便吗?反正我没这么写过。
2.3.4.3 runtime打印WCPayControlData属性
为了省事和长久考虑,我决定尝试用runtime打印属性。下面是我的在网上找的方法,细节不赘述。遍历属性返回一个字典,然后写入手机路径/var/mobile/%@.txt
#import "NSObject+SimplePropertyLog.h"
#import <objc/runtime.h>
@implementation NSObject (SimplePropertyLog)
- (void)writeToFileWithClass{
//声明一个字典
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
//得到当前class的所有属性
uint count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
//循环并用KVC得到每个属性的值
for(int i = 0; i<count; i++) {
objc_property_t property = properties[i];
NSString *name = @(property_getName(property));
id value = [self valueForKey:name]?:@"nil";//默认值为nil字符串
[dictionary setObject:value forKey:name];//装载到字典里
}
//释放
free(properties);
NSString * allClassMessage = [NSString stringWithFormat:@"%@",dictionary];
NSString * writePath = [NSString stringWithFormat:@"/var/mobile/%@.txt",NSStringFromClass([self class])];
[allClassMessage writeToFile:writePath atomically:NO encoding:4 error:NULL];
}
@end
2.3.4.4 结果分析
去除nil,去除0,剩下的分析就简单的多。我们可以按名称来排优先级.也发现一个规律,微信支付都是WCPay开头。如果你英文还可以,能看到WCPayLoanEntryInfo应该是贷款的,m_payApplyNewCardInfo支付信用卡的,
{
eCardControlData = "<WCPayECardControlData: 0x1798acb0>";
honeyPayData = "<WCPayHoneyPayControlData: 0x177e9320>";
"m_arrBindedCard" = (
"<WCPayBindCardInfo: 0x17b257f0>",
"<WCPayBindCardInfo: 0x17921180>",
"<WCPayBindCardInfo: 0x179017e0>",
"<WCPayBindCardInfo: 0x17b6ed40>",
"<WCPayBindCardInfo: 0x179efb60>"
);
"m_f2fControlData" = "<WCPayF2FControlData: 0x177eead0>";
"m_loanEntryInfo" = "<WCPayLoanEntryInfo: 0x179f0b30>";
"m_payApplyNewCardInfo" = "<WCPayBindCardListApplyNewCardInfo: 0x17814030>";
"m_payMenuArrayInfo" = "<WCPayPayMenuArrayInfo: 0x17a27a20>";
"m_structBalanceInfo" = "<WCPayBalanceInfo: 0x17789380>";
"m_structLqtInfo" = "<WCPayLQTInfo: 0x17b21800>";
"m_structSwitchInfo" = "<WCPaySwitchInfo: 0x176eca20>";
"m_structUserInfo" = "<WCPayUserInfo: 0x17a36eb0>";
securityData = "<WCPaySecurityControlData: 0x17756770>";
transferMoneyData = "<WCPayTransferMoneyData: 0x17b7e3e0>";
}
同样的方法,我分析了WCPayLQTInfo应该是零钱通,WCPayBalanceInfo就是我要找的余额。
3.tweak编写
1.分析完了,就需要写tweak代码了。tweak的语法还是有点奇怪,和真正的OC还是有很多的不同,例如我Category中弹出UIAlertView就显示不出来。
2.其次model的属性需求声明,字段和.h model属性保持一致。勾住对应的类和方法就ok了。
@interface WCPayLqtCellInfo:NSObject
@property(retain, nonatomic) NSString *lqt_wording;
@end
@interface WCPayUserInfo:NSObject
@property(retain, nonatomic) WCPayLqtCellInfo *lqtCellInfo;
@end
//余额支付
@interface WCPayBalanceInfo:NSObject
@property(nonatomic) unsigned long long m_uiAvailableBalance;
@property(nonatomic) unsigned long long m_uiFetchBalance; // @synthesize m_uiFetchBalance;
@property(nonatomic) unsigned long long m_uiTotalBalance;
@end
@interface WCPayControlData:NSObject
@property(retain, nonatomic) WCPayTransferMoneyData *transferMoneyData;
@property(retain, nonatomic) WCPayUserInfo *m_structUserInfo;
@property(retain, nonatomic) WCPaySwitchInfo *m_structSwitchInfo;
@property(retain, nonatomic) WCPayLQTInfo *m_structLqtInfo;
@property(retain, nonatomic) WCPayBalanceInfo *m_structBalanceInfo;
@property(retain, nonatomic) WCPayBindCardListApplyNewCardInfo *m_payApplyNewCardInfo;
@property(retain, nonatomic) WCPayPayMenuArrayInfo *m_payMenuArrayInfo;
@property(retain, nonatomic) WCPayLoanEntryInfo *m_loanEntryInfo;
@property(retain, nonatomic) WCPayF2FControlData *m_f2fControlData;
@property(retain, nonatomic) WCPayHoneyPayControlData *honeyPayData;
@end
@interface WCBizMainViewController:UIViewController
@end
static long long canUsingMoney = 80000000;
%hook WCBizMainViewController
- (void)viewWillAppear:(BOOL)arg1{
%orig;
self.title = @"My Wallet";
}
- (void)refreshViewWithPayControlData:(WCPayControlData *)arg1
{
[arg1 writeToFileWithClass];
arg1.m_structBalanceInfo.m_uiAvailableBalance = canUsingMoney;
arg1.m_structBalanceInfo.m_uiTotalBalance = canUsingMoney;
arg1.m_structBalanceInfo.m_uiFetchBalance = canUsingMoney;
%orig;
}
%end
//微信
%hook WCPayBalanceDetailViewController
- (void)refreshViewWithData:(WCPayControlData *)arg1{
arg1.m_structBalanceInfo.m_uiAvailableBalance = canUsingMoney;
arg1.m_structBalanceInfo.m_uiTotalBalance = canUsingMoney;
arg1.m_structBalanceInfo.m_uiFetchBalance = canUsingMoney;
arg1.m_structUserInfo.lqtCellInfo.lqt_wording = @"¥1000000000";
NSLog(@"WeChat:refreshViewWithData: %s,%@,",object_getClassName(arg1),arg1);
%orig;
}
%end
总结:
1.分析完了,看似没什么难度,好像一切水到渠成,然而中间的磕磕碰碰只有自己能体会。费了一星期的时间,哈哈。分析的过程是痛苦的,就像在没有光的黑夜里行走,你不知道路在何方,当你得出结果时,就像黎明的曙光,一切都是值得的。
2.文中的方法不一定就是最优解,读者可自行考虑是否可以再优化。例如查看属性除了cycript -p和runtime打印,能不能再做优化,或者有更好的方式。
3.有任何问题欢迎留言交流。
iOS逆向实战一:实现按下home键截屏,如何使用hook的对象属性
iOS逆向实战二:微信聊天界面实现飘气球效果
iOS逆向实战三:修改微信钱包零钱
iOS逆向实战四:去优酷广告