IOS逆向之某抓包APP

admin 2022年10月20日08:13:44评论345 views字数 6670阅读22分14秒阅读模式

0x00 前言

本文的测试目标是一个抓包的APP,可以使用hook的方式或者代理的方式来获取高级功能,如解密HTTPS流量、重写HTTP请求以及重放等功能。由于个人账户(没有付费成为苹果开发者账号)的限制,注入打包后,无法正常使用抓包功能,因此算是一篇半成品,不过本文主要提供一些思路以及介绍一下数据之间的转换。

0x01 分析

运行后发现高级功能都需要付费才可以,抓包发现请求和返回都加密了。

IOS逆向之某抓包APP
img

使用frida-ios-dump将ipa文件dump出来,之后用ida打开,发现该程序是用到了OC和swift。而且http请求采用了Alamofire,它是一个用 Swift 编写的 HTTP 网络库。

该程序较小,猜测加密函数中有encrypt关键字,于是在函数中搜索encrypt

当然也可以根据http请求的一些内容搜索进而去定位加密的算法,在这里就不演示了。

IOS逆向之某抓包APP
img

可以看到有一些,可以使用frida-trace来追踪一下是调用了哪个方法。

1frida-trace -U -f com.xxxx -m "*[* *encrypt*]"

使用该命令可以看到如下调用:

IOS逆向之某抓包APP
img

经过进一步验证发现是调用了类XMXXTEA相关的加密函数。一般这样同个类存在多个加(解)密,大多数都是简单的调用复杂的。从上图就可以看出来encryptStringToBase64String:stringKey:调用了encryptToBase64String:stringKey:

所以我们看 

+[XMXXTEA encryptStringToBase64String:stringKey:]即可。

命令如下:

1frida-trace -U -f com.xxxx -m "+[XMXXTEA encryptStringToBase64String:stringKey:]"

执行后可以发现与抓包的内容一致。

IOS逆向之某抓包APP
img

接下来我们看一下是否有数据的解密,同样搜decrypt

IOS逆向之某抓包APP
img

根据上面的经验,猜测解密的是+[XMXXTEA decryptBase64StringToString:stringKey:]。结果进行追踪后发现并没调用,这里解密采用的是+[XMXXTEA decryptBase64String:stringKey:]

可以看到解密数据。

IOS逆向之某抓包APP
img

不过解密结果不是字符串类型,我们用CyberChef的hex解码后是json数据。

IOS逆向之某抓包APP
img

返回的json中有几个关键的键值可以猜出其含义。例如isVip应该是判断是否为会员,expire_on表示到期时间,auth_quantity是授权数量,function_list应该是拥有的功能,比如非会员用户只有一个抓包功能,如果要拥有解密HTTPS、重写等功能,则function_list应该是[1,2,3]。当然这些只是猜测。

尝试修改一下isVip的值为1,看是否有反应。首先看一下+[XMXXTEA decryptBase64String:stringKey:]解密返回值的类型是什么。

主要代码:

1onLeave(log, retval, state) {
2    var ret = ObjC.Object(retval);
3    log(`ret type is -->`+ret.$className);
4  }

执行后返回的结果:

1ret type is -->NSConcreteData

返回值是NSConcreteData类型的,可以看作为是NSData。修改返回值有两种方法,第一种是将NSData转化为NSString,然后利用字符串替换来修改,修改完毕后转化NSData并替换;第二种是将NSData转化为可变数组NSMutableDictionary,然后修改键的值,最后再转化NSData并替换。

下面分别看一下两种方法的OC代码,以及翻译成frida的js实现的代码。

方法一:使用NSString替换

对应的主要OC代码如下:

1NSString *str = @"{"uid": "xxxxxxx", "userID": "xxxxx", "isVip": 0, "member_type": 0, "member_title": "\u57fa\u7840\u7248", "expire_on": "\u6682\u672a\u5f00\u901aVIP", "auth_quantity": 0, "auth_mail": null, "is_primary": 0, "trail_status": 0, "function_list": [1], "timestamp": 1666080682, "ts": 0}";
2NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];//NSString转换为NSData
3NSString *oldString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];//NSData转换为NSString
4NSString * newString = [str stringByReplacingOccurrencesOfString:@""isVip": 0" withString:@""isVip": 1"];//替换字符串
5NSLog(@"oldString is:n%@",oldString);
6NSLog(@"newString is:n%@",newString);

这里为了使用NSData数据,采用的是NSString转换而来的,当然也可以采用byte来生成。主要代码:

1Byte byte[] = {0x7B,..., 0x7D};
2NSData *byteData = [[NSData alloc] initWithBytes:byte length:sizeof(byte)/sizeof(Byte)];

OC代码执行的结果如下:

IOS逆向之某抓包APP
img

可以成功替换,翻译成frida的js实现如下:

1onLeave(log, retval, state) {
2  var ret = ObjC.Object(retval);
3  var oldNSStr = ObjC.classes.NSString.alloc().initWithData_encoding_(ret, 4);//NSData转换为NSString
4  log(`oldNSStr-->`+ oldNSStr);
5  var newNSStr = oldNSStr.stringByReplacingOccurrencesOfString_withString_('"isVip": 0','"isVip": 1');//替换字符串
6  log(`newNSStr-->`+ newNSStr);
7  retval.replace(newNSStr.dataUsingEncoding_(4));//NSString转换为NSData,并替换返回值
8}

执行结果:

IOS逆向之某抓包APP
img

同时查看我的账号界面可以看到PRO标志。

IOS逆向之某抓包APP
img

但是点击解密HTTPS流量、重写等功能还是跳转到会员开通界面,这是因为这些功能是从function_list中获取的,所以想要解锁功能还需修改这里。主要代码:

1var newNSStr = oldNSStr.stringByReplacingOccurrencesOfString_withString_('"isVip": 0','"isVip": 1').stringByReplacingOccurrencesOfString_withString_('"is_vip": 0','"is_vip": 1').stringByReplacingOccurrencesOfString_withString_('"member_type": 0','"member_type": 1').stringByReplacingOccurrencesOfString_withString_('"auth_quantity": 0','"auth_quantity": 3').stringByReplacingOccurrencesOfString_withString_('"function_list": [1]','"function_list": [1,2,3,4,5]').stringByReplacingOccurrencesOfString_withString_('\u6682\u672a\u5f00\u901aVIP','2099-09-09 14:22');
2log(`newNSStr-->`+ newNSStr);

再次执行

IOS逆向之某抓包APP
img

看到用户界面也成功变化了

IOS逆向之某抓包APP
img

高级功能也可以使用

IOS逆向之某抓包APP
img

例如重写功能,将请求的某度转到qq上

IOS逆向之某抓包APP
img

功能都是可以正常使用的。

方法二:使用NSMutableDictionary修改

对应的主要OC代码如下:

1NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];
2NSMutableDictionary * result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];//NSData转NSMutableDictionary
3[result setValue:[NSNumber numberWithInt:1] forKey:@"isVip"];//设置isVip为1
4[result setValue:@"[1,2,3,4,5]" forKey:@"function_list"];//设置function_list
5[result setValue:@"2099-09-09 14:22" forKey:@"expire_on"];//设置expire_on
6NSLog(@"oldString is:%@",str);
7NSLog(@"After Change is:%@",result);

查看执行的结果

IOS逆向之某抓包APP
img

这里翻译成frida的js实现时,有一个问题,生成NSMutableDictionary时,由于需要传入nil,而frida中无法生成,导致这种方法不能使用。根据别人提出的方法var nil=ObjC.Object(ptr("0x0"));,测试代码如下:

1var data = ObjC.classes.NSString.stringWithString_('{"aa":11,"bb":2}') ;
2var NSJSONSerialization = ObjC.classes.NSJSONSerialization;
3var nil=ObjC.Object(ptr("0x0"));
4NSJSONSerialization.JSONObjectWithData_options_error_(data,1,nil);

运行后直接崩溃,导致无法使用,因此在frida下,暂时放弃第二种方法。

分析的话到这里就结束了,但借助frida来获取高级版,不方便使用,而且无法在非越狱手机上使用,如果想在非越狱手机上使用的话,就需要使用一些插件来运行在非越狱手机上。

0x02 编写非越狱插件

编写插件采用了非越狱插件开发集成神器MonkeyDev,集成了theos+Tweaks+Reveal.framework+Cycript+class-dump+CaptainHook。

安装和卸载可以参考:

https://github.com/AloneMonkey/MonkeyDev/wiki/%E5%AE%89%E8%A3%85

安装完成后新建MonkeyApp,File->New->Project->MonkeyApp

项目建立后将砸壳后的APP拖入到TargetApp目录下。

这里使用Logos进行Hook代码,HOOK 某个类里面的某个对象方法语法:

1%hook 类名
2- (返回值)方法名:(id)arg1 ....
3{
4        ...
5}
6%end

根据上面的分析,这里我们需要对XMXXTEA 类的方法decryptBase64String:stringKey:进行HOOK,修改返回值,主要代码如下:

 1%hook XMXXTEA
2+ (id) decryptBase64String:(NSString*) stringData stringKey:(NSString*) key{
3     NSLog(@"Before : %@", %orig);
4    NSData *data = %orig;//NSData
5    NSMutableDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];//NSData转换NSMutableDictionary
6
7    [result setValue:[NSNumber numberWithInt:1] forKey:@"isVip"];
8    [result setValue:[NSNumber numberWithInt:1] forKey:@"member_type"];
9    [result setValue:[NSNumber numberWithInt:3] forKey:@"auth_quantity"];
10    [result setValue:@"[1,2,3,4,5]" forKey:@"function_list"];
11    [result setValue:@"2099-09-03 14:22" forKey:@"expire_on"];
12
13    NSData *data_result= [NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingPrettyPrinted error:nil];
14    NSLog(@"After : %@", data_result);
15    return data_result;
16}
17
18%end

其实和上面第二种方法中的OC代码一样,连接非越狱手机后使用⌘+R运行该项目。

首次在新设备上运行,需要设置-通用-描述文件与设备管理中信任证书,ios16以上需要开启开发者模式,隐私安全-开发者模式,而且需要重启。

运行后,高级版功能都可以打开,但是无法开启抓包功能。

因为开启抓包需要开通网络访问权限以及VPN的相关权限,由于账号没有付费成为苹果开发者账号,因此这些权限无法使用。

苹果开发者账号可用的权限:

IOS逆向之某抓包APP
img

非开发者账号可用的权限:

IOS逆向之某抓包APP
img

这里即使把权限添加上,也会编译不通过的。

IOS逆向之某抓包APP
img

这里就需要注册成开发者账号才可以继续进行,因此就放弃了。

0x03 总结

本文通过一款抓包APP借助于frida来获取高级权限,另外介绍了一下OC下NSData、NSString、NSMutableDictionary之间的数据转换,以及翻译成frida中js代码的实现。

其实也可以利用代理的方式,来修改返回包的内容,从而解锁会员功能。这里简单提供一下思路,可以借助第三方抓包软件(有重写功能的,手机上的也可以,如HTTP Catcher)。需要注意几点:一是每个设备加密key不一样,二是需要注意请求头中的t(时间戳),这个值与手机时间相差不能太多(可以修改手机时间)。大致流程就是首先获取加密算法的key,将请求头中的t、解密结果中的timestamp以及手机时间不要差太多,将修改后的数据加密后进行替换即可。或者自己搭建一个服务,将数据转发到自己服务上,解密修改后重新加密返回即可。


原文始发于微信公众号(猎户攻防实验室):IOS逆向之某抓包APP

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月20日08:13:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   IOS逆向之某抓包APPhttp://cn-sec.com/archives/1360298.html

发表评论

匿名网友 填写信息