欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS逆向-支付宝基金查看实时收益变动

程序员文章站 2022-04-01 12:28:33
前言:现在全民买基的情况下,女票也买了一些,对于买基新手来说,总是想打开支付宝看看到底今天是赚是赔,女票说支付宝收益第二天才显示太慢了,要是能打开直接看到收益就好了,作为一个合格的程序员,怎么能不满足这小小的需求?写篇记录一下过程。工具:半越狱 iphone 5smac电脑一台爱思助手一、砸壳(一)安装CrackerXI+在cydia 中添加 源地址 http://cydia.iphonecake.com 或者 http://apt.cydiami.com ,添加成功后,在cydia....

前言:现在全民买基的情况下,女票也买了一些,对于买基新手来说,总是想打开支付宝看看到底今天是赚是赔,女票说支付宝收益第二天才显示太慢了,要是能打开直接看到收益就好了,作为一个合格的程序员,怎么能不满足这小小的需求?写篇记录一下过程。

效果图:
iOS逆向-支付宝基金查看实时收益变动

工具:

  1. CrackerXI+
  2. 爱思助手
  3. Class-dump
  4. MonkeyDev

一、砸壳

(一)越狱机安装CrackerXI+
  1. 在cydia 中添加 源地址 http://cydia.iphonecake.com 或者 http://apt.cydiami.com ,添加成功后,在cydia中搜索CrackerXI+并安装。
  2. 打开CrackerXI+,在settings中设置CrackerXI Hook为enable
    iOS逆向-支付宝基金查看实时收益变动

(二)砸壳

  1. 先在App store下载安装蚂蚁财富,然后打开CrackerXI+选中蚂蚁财富,然后选择 YES,FULL IPA 开始砸壳
  2. 砸壳完毕会显示砸壳后IPA的路径的路径/var/mobile/Documents/CrackerXI/
  3. 打开爱思助手或者用ssh链接都可以,按照路径导出ipa包就可以了。

iOS逆向-支付宝基金查看实时收益变动
终端输入以下命令 可以查看有么有砸成功:

otool -l 可执行文件路径 | grep crypt 

iOS逆向-支付宝基金查看实时收益变动
cryptid 0 砸壳成功

二、安装MonkeyDev

git地址:https://github.com/AloneMonkey/MonkeyDev

准备

  1. 安装最新的theos
 sudo git clone --recursive https://github.com/theos/theos.git /opt/theos 
  1. 安装ldid(如安装theos过程安装了ldid,跳过)
 brew install ldid 

安装

你可以通过以下命令选择指定的Xcode进行安装:

 sudo xcode-select -s /Applications/Xcode-beta.app 

默认安装的Xcode为:

 xcode-select -p 

执行安装命令:

 sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-install)" 

卸载

 sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-uninstall)" 

更新

 sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-update)" 

安装成功效果图:
iOS逆向-支付宝基金查看实时收益变动

三、逆向分析

(一)Class-dump导出头文件

class-dump -H [.app文件的路径] -o [输出文件夹路径] 

导出如下:
iOS逆向-支付宝基金查看实时收益变动

(二)新建monkeyDev工程

把IPA放入工程指定目录iOS逆向-支付宝基金查看实时收益变动
运行程序分析界面:

iOS逆向-支付宝基金查看实时收益变动

页面是一个WKWebView,我们只需要获取H5页面请求后的数据就可以了。然后我们用safari开发模式看一下页面,结果在控制台看到了接口打印数据,正是我们需要的数据,线程回调结果:

iOS逆向-支付宝基金查看实时收益变动
NSOperation结合NSURLConnection,搜索头文件,找到一个 DTURLRequestOperation文件,继承了NSURLConnectionDataDelegate, NSURLProtocolClient, NSURLSessionDataDelegate协议,还包含了request和response,一看就知道是和wkwebview请求有关,尝试拦截一下。
iOS逆向-支付宝基金查看实时收益变动
iOS逆向-支付宝基金查看实时收益变动
看到可以拦截到WKWebview的请求,下一步从众多请求中找出我们需要的请求数据就可以了。

iOS逆向-支付宝基金查看实时收益变动

四、Hook

线程名称包含在请求头中,根据线程名筛选需要的请求结果:

// 自选关注的基金信息
com.alipay.wealthbffweb.fund.optional.queryV3
// 持有的基金信息
com.alipay.wealthbffweb.fund.commonAsset.queryAssetDetail

筛选要求获取的请求结果

// 获取请求返回数据 +(void)hookWithOperation:(DTRpcOperation *)operation{ @try { NSDictionary *allHTTPHeaderFields = operation.request.allHTTPHeaderFields; NSString *type = allHTTPHeaderFields[@"Operation-Type"]; if([type isEqualToString: @"com.alipay.wealthbffweb.fund.optional.queryV3"]){ // 计算收益 [self calculateIncomeWithOperation:operation]; }else if([type isEqualToString: @"com.alipay.wealthbffweb.fund.commonAsset.queryAssetDetail"]){ // 获取份额 [self getFundSharesWithOperation:operation]; } } @catch (NSException *exception) { NSLog(@"error:%@", exception); } } #pragma mark - holdingMap // 份额 本地保存路径 + (NSString *)FundSharesDicPath { static NSString *path; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; path = [documentsDirectory stringByAppendingPathComponent:@"FundSharesDic.plist"]; }); return path; } + (void)loadFundSharesDic { NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithContentsOfFile:self.FundSharesDicPath]; if (!dic) { dic = NSMutableDictionary.dictionary; } fundSharesDic = dic; } /// 读取本地保存的份额 + (NSString *)getFundSharesWithFundCode:(NSString *)fundCode { //fundCode 基金代码 if (fundSharesDic == nil) { [self loadFundSharesDic]; } return fundSharesDic[fundCode]; } #pragma mark - handle // 计算收益 + (void)calculateIncomeWithOperation:(DTRpcOperation *)operation { NSDictionary *json = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableLeaves error:nil]; if (json && [json isKindOfClass:NSDictionary.class]) { // 解析数据 NSMutableDictionary *m_json = [json mutableCopy]; NSMutableDictionary *result = [m_json[@"result"] mutableCopy]; NSArray *optionalList = result[@"optionalList"]; NSMutableArray *modifyList = NSMutableArray.array; NSMutableArray *incomes = NSMutableArray.array; for (NSDictionary *obj in optionalList) { NSMutableDictionary *model = [obj mutableCopy]; BOOL holdingPosition = [model[@"holdingPosition"] boolValue]; if (holdingPosition) { // 获取份额 NSString *value = [self getFundSharesWithFundCode:model[@"fundCode"]]; // 获取时间 NSString *netValueReportDate = model[@"netValueReportDate"]; NSString *estimateDate = model[@"estimateDate"]; // 有效份额 才参与统计 if (value.doubleValue > 0) { NSMutableArray *contentTags = NSMutableArray.array; // 预估时间不等于网络净值时间时 统计收益 if ([netValueReportDate isKindOfClass:NSString.class] && [estimateDate isKindOfClass:NSString.class]) { NSString *netValue = model[@"netValue"]; if ( ![netValueReportDate isEqualToString:estimateDate]) { NSString *estimateNetValue = model[@"estimateNetValue"]; // 没有预估时 忽略收益 if (estimateNetValue.doubleValue && netValue.doubleValue) { double income = (estimateNetValue.doubleValue - netValue.doubleValue) * value.doubleValue; [incomes addObject:@(income)]; [contentTags addObject:@{ @"visible": @YES, @"text": [NSString stringWithFormat:@"收益:%0.2f", income], @"type": @"BULL_FUND", }]; } } else { NSString *dayOfGrowth = model[@"dayOfGrowth"]; if (dayOfGrowth.length) { NSString *modifyWorth = [NSString stringWithFormat:@"%0.4f",netValue.doubleValue / (1 + dayOfGrowth.doubleValue)]; double income = (netValue.doubleValue - modifyWorth.doubleValue) * value.doubleValue; [incomes addObject:@(income)]; [contentTags addObject:@{ @"visible": @YES, @"text": [NSString stringWithFormat:@"净收:%0.2f", income], @"type": @"BULL_FUND", }]; } } } if (!contentTags.count) { [contentTags addObject:@{ @"visible": @YES, @"text": [NSString stringWithFormat:@"份额:%@", value], @"type": @"BULL_FUND", }]; } model[@"contentTags"] = contentTags; } else { model[@"contentTags"] = @[ @{ @"visible": @YES, @"text": @"点击读取份额", @"type": @"BULL_FUND", }, ]; } } [modifyList addObject:model]; } result[@"optionalList"] = modifyList; m_json[@"result"] = result; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:m_json options:NSJSONWritingPrettyPrinted error:nil]; operation.responseData = jsonData; if (incomes.count) { NSDecimalNumber *sum = [incomes valueForKeyPath:@"@sum.doubleValue"]; NSString *desc = [NSString stringWithFormat:@"有效统计%ld只,当前总收益%0.2f", incomes.count, sum.doubleValue]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ UILabel *label = UILabel.new; UIWindow *keyWindow = UIApplication.sharedApplication.keyWindow; label.frame = CGRectMake(20, CGRectGetMaxY(keyWindow.frame) - 118, CGRectGetMaxX(keyWindow.frame) - 40, 40); label.layer.cornerRadius = 5.f; label.layer.masksToBounds = YES; label.backgroundColor = [UIColor redColor]; label.text = desc; label.textAlignment = NSTextAlignmentCenter; label.textColor = UIColor.whiteColor; label.font = [UIFont systemFontOfSize:16]; [keyWindow addSubview:label]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int6![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807142125730.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NjYwMjc3Mw==,size_16,color_FFFFFF,t_70) 4_t)(2.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [label removeFromSuperview]; }); }); } } } // 获取份额 + (void)getFundSharesWithOperation:(DTRpcOperation *)operation { NSDictionary *json = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableLeaves error:nil]; if (json && [json isKindOfClass:NSDictionary.class]) { // 解析数据 NSMutableDictionary *result = json[@"result"]; NSString *availableShare = result[@"availableShare"]; //        设置本地记录份额 if (availableShare.doubleValue > 0) { NSString *fundCode = result[@"fundCode"]; if (fundSharesDic == nil) { [self loadFundSharesDic]; } fundSharesDic[fundCode] = availableShare; [fundSharesDic writeToFile:self.FundSharesDicPath atomically:YES]; } } } 

最终效果:

最后放上项目地址:
https://github.com/FORMAT-qi/hookAntWealth

砸过壳的app下载地址:
链接: https://pan.baidu.com/s/1UUQhm9ymM74d0UtbnqrEew
密码: n49h

@end

本文地址:https://blog.csdn.net/weixin_46602773/article/details/107831917