【iOS逆向】某茅台App算法分析还原
1.目标
某茅台软件的actParam算法分析还原。
2.使用工具
mac系统
frida-ios-dump:砸壳
已越狱iOS设备:脱壳及frida调试
IDA Pro:静态分析
Charles:抓包工具
Shadowrocket:小火箭,配合Charles使用
3.流程
处理启动闪退
在IDA Pro搜索SVC得到如下函数列表:
NOP掉sub_函数的最后一行汇编后,即可正常运行App
处理登录闪退
启动App,在登录页使用命令frida-trace -UF -m "-[UIViewController viewDidAppear:]"
,然后进入到任意页后再返回登录页,获取到当前类为XXLoginViewController,再使用命令frida-trace -UF -m "-[*LoginViewController *]"
,跟踪该类。点击登录后,啥也没获取到,呵呵。不过,看LoginViewController类有loginButton,在该方法看到登录按钮绑定的事件为LoginViewController类的login方法。使用IDA Pro打开该方法:
void __cdecl -[XXLoginViewController login](XXLoginViewController *self, SEL a2)
{
if ( qword_100F492E0 )
exit(0);
}
这么大的exit函数,查看该条件是在什么地方赋值,查看该变量的交叉引用
在sub_1002F52F44函数里对该变量进行赋值。接下来就是处理该函数的赋值逻辑(该方法仅是保证检测环境的qword_100F492E0为0,不排除有其他地方仍然有越狱检测等操作):
1、处理embedded.mobileprovision文件。(重签名后会生成该文件)
{
onEnter(log, args, state) {
this.fileName = new ObjC.Object(args[2]);
log(`-[NSBundle pathForResource:${new ObjC.Object(args[2])} ofType:${new ObjC.Object(args[3])}]`);
},
onLeave(log, retval, state) {
if (this.fileName.toString().toLowerCase().indexOf("embedded") != -1 ) {
retval.replace(0x0)
}
log(`-[NSBundle pathForResource:ofType:]=${new ObjC.Object(retval)}=`);
}
}
2、对sub_1002F52F44函数里,对该变量进行赋值的地方,一一处理。保证不会执行qword_100F492E0=1,处理完后即可正常登录:
寻找actParam算法
在IDA Pro搜索actParam字符串,没有发现该字符,说明该字符串被处理过了。按之前的套路,既然这在body里,那我们就使用命令frida-trace -U -f com.xxx.xxx -m "*[NSMutableURLRequest setHTTPBody:]" -m "*[NSBundle pathForResource:ofType:]"
获取到关键日志如下:
-[NSMutableURLRequest setHTTPBody:<7b226163 74506172 616d223a 22496469 77776474 52644542 68646548 6b614a62 71314a35 3972386a 35684c6a 33653334 76576d74 67523374 47486170 4e4c7752 73326237 31495435 614f6c32 42506a44 4f386277 7a793270 34664c34 6f483878 746c3048 78337069 716c6b50 4a4a5555 54677950 6a39397a 6c455750 34375c2f 596f397a 414b7762 6e726768 47585351 526a4f51 706c3636 31694541 347a6157 42657a51 3d3d222c 22697465 6d496e66 6f4c6973 74223a5b 7b22636f 756e7422 3a312c22 6974656d 4964223a 22313030 3536227d 5d2c2273 65737369 6f6e4964 223a3336 362c2273 686f7049 64223a22 31353135 31303132 32303031 227d>
NSMutableURLRequest setHTTPBody called from:
0x1007b8090 /var/containers/Bundle/Application/AFABDD2B-D35D-4F60-A4A1-DFC92CCC3251/iXX_1_2_15.app/moutai-mall!-[AFJSONRequestSerializer requestBySerializingRequest:withParameters:error:]
0x1007b3a24 /var/containers/Bundle/Application/AFABDD2B-D35D-4F60-A4A1-DFC92CCC3251/iXX_1_2_15.app/moutai-mall!-[AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:]
0x1007ab270 /var/containers/Bundle/Application/AFABDD2B-D35D-4F60-A4A1-DFC92CCC3251/iXX_1_2_15.app/moutai-mall!-[AFHTTPSessionManager dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:]
0x1009557dc /var/containers/Bundle/Application/AFABDD2B-D35D-4F60-A4A1-DFC92CCC3251/iXX_1_2_15.app/moutai-mall!-[XXBaseRequest startWithSuccess:failure:]
0x100a1b724 /var/containers/Bundle/Application/AFABDD2B-D35D-4F60-A4A1-DFC92CCC3251/iXX_1_2_15.app/moutai-mall!-[XXReserveViewController reserve]
0x100a1b0fc moutai-mall!0x2770fc (0x1002770fc)
0x100b0b6e4 /var/containers/Bundle/Application/AFABDD2B-D35D-4F60-A4A1-DFC92CCC3251/iXX_1_2_15.app/moutai-mall!-[RACSubscriber sendNext:]
0x100af3654 /var/containers/Bundle/Application/AFABDD2B-D35D-4F60-A4A1-DFC92CCC3251/iXX_1_2_15.app/moutai-mall!-[RACPassthroughSubscriber sendNext:]
0x1aeca8ac4 UIKitCore!-[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:]
0x1aecb0ccc UIKitCore!_UIGestureRecognizerSendTargetActions
0x1aecae670 UIKitCore!_UIGestureRecognizerSendActions
0x1aecadb9c UIKitCore!-[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:]
0x1aeca1c78 UIKitCore!_UIGestureEnvironmentUpdate
0x1aeca13a8 UIKitCore!-[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:]
0x1aeca1188 UIKitCore!-[UIGestureEnvironment _updateForEvent:window:]
0x1af0b97d0 UIKitCore!-[UIWindow sendEvent:]
body里正是我们提交里的参数,根据堆栈可知网络请求是在[XXReserveViewController reserve]发起的,使用IDA Pro查看对应的代码可知网络请求类是XXReserveRequest。使用命令frida-trace -U -f com.xxx.xxx -m "*[XXReserveRequest *]" -m "*[NSBundle pathForResource:ofType:]"
跟踪该类,获取到的日志如下:
-[XXReserveRequest setShopId:0x280dfd920]
-[XXReserveRequest setSessionId:0x16f]
-[XXReserveRequest setItemInfoList:0x280ec7f20]
-[XXReserveRequest ydLogId]
-[XXReserveRequest itemInfoList]
-[XXReserveRequest sessionId]
-[XXReserveRequest shopId]
-[XXReserveRequest ydToken]
-[XXReserveRequest requestParams]
-[XXReserveRequest ydLogId]
-[XXReserveRequest itemInfoList]
-[XXReserveRequest sessionId]
-[XXReserveRequest shopId]
-[XXReserveRequest ydToken]
-[XXReserveRequest getTYWZlObj]
-[XXReserveRequest requestParams]={
actParam = "IdiwwdtRdEBhdeHkaJbq1J59r8j5hLj3e34vWXXgR3sN9Cp03vhtPomwYoD2EtZM6dvuKXTI3BIjWffzkuwBXUIsms+sHaMW2D+1CMCwdZe2sLG0FXnHUIJIpXblOBJrlRAHk9Bn3fFSZsjYhaJoNw==";
}=
-[XXReserveRequest requestHeader]
-[XXReserveRequest getTYWZlObj]
+[XXReserveRequest requestPath]
+[XXReserveRequest requestPath]
+[XXReserveRequest requestType]
+[XXReserveRequest responseDataMapping]
-[XXReserveRequest .cxx_destruct]
根据日志可发现actParam在requestParams方法里返回的,继续使用IDA Pro查看该代码
sub函数一直点进去,就会发现(unsigned int)CCCrypt(v6, 0LL, 1LL, &v43, 32LL, v27, v28, v29, v41, v26, &v42) ,接下来就是对该函数进行调试,由于该方法,需要特写时间段才能使用。所以在此,我们查看此sub函数的交叉引用,发现在下单时,也有调用该加密函数。
使用命令frida-trace -U -f com.xxx.xxx -m "*[NSBundle pathForResource:ofType:]" -i CCCrypt
打印该参数,在创建订单时,获取到日志如下:
js代码
{
onEnter: function(log, args, state) {
this.op = args[0]
this.alg = args[1]
this.options = args[2]
this.key = args[3]
this.keyLength = args[4]
this.iv = args[5]
this.dataIn = args[6]
this.dataInLength = args[7]
this.dataOut = args[8]
this.dataOutAvailable = args[9]
this.dataOutMoved = args[10]
log('CCCrypt(' +
'op: ' + this.op + '[0:加密,1:解密]' + ', ' +
'alg: ' + this.alg + '[0:AES128,1:DES,2:3DES]' + ', ' +
'options: ' + this.options + '[1:ECB,2:CBC,3:CFB]' + ', ' +
'key: ' + this.key + ', ' +
'keyLength: ' + this.keyLength + ', ' +
'iv: ' + this.iv + ', ' +
'dataIn: ' + this.dataIn + ', ' +
'inLength: ' + this.inLength + ', ' +
'dataOut: ' + this.dataOut + ', ' +
'dataOutAvailable: ' + this.dataOutAvailable + ', ' +
'dataOutMoved: ' + this.dataOutMoved + ')')
if (this.op == 0) {
log("dataIn:")
log(hexdump(ptr(this.dataIn), {
length: this.dataInLength.toInt32(),
header: true,
ansi: true
}))
log("key: ")
log(hexdump(ptr(this.key), {
length: this.keyLength.toInt32(),
header: true,
ansi: true
}))
log("iv: ")
log(hexdump(ptr(this.iv), {
length: this.keyLength.toInt32(),
header: true,
ansi: true
}))
}
},
onLeave: function(log, retval, state) {
if (this.op == 1) {
log("dataOut:")
log(hexdump(ptr(this.dataOut), {
length: Memory.readUInt(this.dataOutMoved),
header: true,
ansi: true
}))
log("key: ")
log(hexdump(ptr(this.key), {
length: this.keyLength.toInt32(),
header: true,
ansi: true
}))
log("iv: ")
log(hexdump(ptr(this.iv), {
length: this.keyLength.toInt32(),
header: true,
ansi: true
}))
} else {
log("dataOut:")
log(hexdump(ptr(this.dataOut), {
length: Memory.readUInt(this.dataOutMoved),
header: true,
ansi: true
}))
}
log("CCCrypt did finish")
}
}
日志
96341 ms CCCrypt(op: 0x0[0:加密,1:解密], alg: 0x0[0:AES128,1:DES,2:3DES], options: 0x1[1:ECB,2:CBC,3:CFB], key: 0x16eecea70, keyLength: 0x20, iv: 0x2821adbe0, dataIn: 0x2815a80c0, inLength: undefined, dataOut: 0x281794580, dataOutAvailable: 0xa4, dataOutMoved: 0x16eecea68)
96341 ms dataIn:
96341 ms 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
2815a80c0 7b 22 64 65 6c 69 76 65 72 4d 65 74 68 6f 64 22 {"deliverMethod"
2815a80d0 3a 2d 31 2c 22 61 64 64 72 65 73 73 49 6e 66 6f :-1,"addressInfo
2815a80e0 22 3a 7b 22 73 68 69 70 41 64 64 72 65 73 73 49 ":{"shipAddressI
2815a80f0 64 22 3a 22 33 37 39 36 31 36 30 22 7d 2c 22 75 d":"3711160"},"u
2815a8100 73 65 72 49 64 22 3a 22 31 30 36 39 38 36 36 32 serId":"10008662
2815a8110 38 30 22 2c 22 69 74 65 6d 4c 69 73 74 22 3a 5b 80","itemList":[
2815a8120 7b 22 63 6f 75 6e 74 22 3a 31 2c 22 73 70 75 49 {"count":1,"spuI
2815a8130 64 22 3a 22 34 32 35 22 2c 22 73 74 6f 72 65 49 d":"425","storeI
2815a8140 64 22 3a 22 32 35 31 35 31 30 31 38 38 30 31 30 d":"251510182010
2815a8150 22 7d 5d 7d "}]}
96341 ms key:
96341 ms 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
16eecea70 71 62 68 61 6a 69 6e 6c 64 65 70 6d 75 63 73 6f qbhajinldepmucso
16eecea80 6e 61 61 61 63 63 67 79 70 77 75 76 63 6a 61 61 naaaccgypwuvcjaa
96341 ms iv:
96341 ms 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
2821adbe0 32 30 31 38 35 33 34 37 34 39 39 36 33 35 31 35 2018534749963515
2821adbf0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96345 ms dataOut:
96345 ms 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
281794580 b0 fd c3 5f a8 e8 de 45 80 ac 23 e6 2b d1 3f 2c ..._...E..#.+.?,
281794590 5d 4b 88 e9 88 99 7a 76 ab 7b c2 c5 88 40 fd 4f ]K....zv.{...@.O
2817945a0 38 37 c5 48 61 06 b1 a9 33 0d 1a 7d a7 59 3d fb 87.Ha...3..}.Y=.
2817945b0 05 88 cc 18 b8 68 cb ce a7 33 1e 32 f1 1f a2 ae .....h.....2....
2817945c0 0b 50 04 75 ed 19 36 eb 64 bd d7 79 a8 13 6a 4d .P.u..6.d..y..jM
2817945d0 9c bf 72 1c 42 6c 41 cc 76 86 85 cf bd 58 5b db ..r.BlA.v....X[.
2817945e0 05 74 ec e6 55 6e 84 10 ae zz 61 b8 64 81 7b 6f .t..Un....a.d.{o
2817945f0 02 df 42 a6 13 8e a6 41 ee 1a 0a b5 65 cb 45 29 ..B....F....e.E)
281794600 9b 86 ea 63 f6 8e 92 6c 1a 11 8b 70 09 b7 b5 ad ...c...l...p....
281794610 c6 f7 2c 70 91 12 eb 62 45 a4 0e b5 75 29 c4 be ..,p...bE...u)..
96345 ms CCCrypt did finish
日志里的dataOut数据,转换为base64后,和接口里的参数一致(注:日志里的敏感信息被我处理过)。
结果
见CCCrypt日志。在分析过程中,当我们发现参数是base64的时候,也可以先拦截base64EncodedStringWithOptions或CCCrypt函数,运气好的话,也能快速定位到加密算法。
End
阅读此文档的过程中遇到任何问题,请关注公众号【移动端Android和iOS开发技术分享
】或加QQ群【812546729
】
【iOS逆向】某茅台App算法分析还原的更多相关文章
- iOS逆向工程之App脱壳
本篇博客以微信为例,给微信脱壳."砸壳"在iOS逆向工程中是经常做的一件事情,,因为从AppStore直接下载安装的App是加壳的,其实就是经过加密的,这个“砸壳”的过程就是一个解 ...
- 逆向工程之App脱壳
http://www.cnblogs.com/ludashi/p/5725743.html iOS逆向工程之App脱壳 本篇博客以微信为例,给微信脱壳."砸壳"在iOS逆向工程中是 ...
- iOS逆向系列-逆向APP思路
界面分析 通过Cycript.Reveal. 对于Reveal安装配置可参考配置iOS逆向系列-Reveal 通过Reveal找到内存中的UI对象 静态分析 开发者编写的所有代码最终编译链接到Mach ...
- iOS逆向分析app
适合有一定的逆向编程基础的人看. 背景:自动抢红包的脚本工具:cyscript,reveal,class-dump,越狱的pod等. 这里先上一张reveal的分析图: 小结:获取到了真个软件的整体结 ...
- iOS逆向系列-脱壳
概述 通过iOS逆向系列-逆向App中使用class-dump工具导出App的Mach-O文件所有头文件.Hopper工具分析App的Mach-O文件代码大概实现.但是这些前体是App的Mach-O没 ...
- iOS逆向开发(1):基础工具 | ssh | scp | socat
小白:小程,我一直想问,什么是逆向来着?是逆向行驶吗? 小程:理解为逆向行驶也没错.一般的项目是从无到有,而逆向是从已有的状态入手,分析出已有的流程与结构的手段. iOS上的逆向开发,是一件有趣的事情 ...
- ios 逆向编程(环境搭建)
首先如果你想要逆向其他的APP 动态的查看 或者修改人家APP里面的东西 1, 首先要有一台越狱的手机 最好是9.1以下的,因为9.2以上(包括9.2)就不能完美越狱了 2,手机也要5s以上的(因为从 ...
- iOS逆向+越狱
感觉本文涉及内容有点多的,但是自己不愿意写太多,就简单的谢谢关于ios上手的东西吧 初级入手不免要用到,pp助手,i4 tools等 iOS逆向-ipa包重签名及非越狱手机安装多个应用 1.常识 我们 ...
- 偏执的iOS逆向研究员:收集全版本的macOS iOS+越狱+内核调试
Intro 虽然“只有偏执狂才能够生存”这句话已经被假药停给毁了,但是作为一只有逼格的高大上的iOS逆向分析研究员,难道如果有现成的macOS/iOS全版本镜像可以下载并且无限“漫游”,难道你就不想来 ...
- iOS逆向实战与工具使用(微信添加好友自动确认)
iOS逆向实战与工具使用(微信添加好友自动确认) 原文链接 源码地址 WeChatPlugin-iOS Mac OS 版微信小助手(远程控制.消息防撤回.自动回复.微信多开) 一.前言 本篇主要实现在 ...
随机推荐
- RHEL7从安装的字符界面转为桌面GUI图形化步骤
1.光驱装载原版光盘镜像 2.挂载光盘镜像 mount /dev/sr0 /media 3.配置本地yum源 vi /etc/yum.repos.d/local.repo [rhel] name=rh ...
- Controller以及RestFul风格
Controller以及RestFul风格 控制器Controller 控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方式实现 控制器负责解析用户的请求并将其转换为一个模型 在Spr ...
- linux 运维有趣的实用工具
1.实时监控磁盘 IO-IOTop IOTop 命令是专门显示硬盘 IO 的命令, 界面风格类似 top 命令. [root@localhost ~]# yum -y install iotop` 2 ...
- 关于“No loop matching the specified signature and casting was found for ufunc lstsq_n”问题的解决
下面这段代码是使用MatPlotLib绘制数据随时间变化的趋势. import datetime as dt import numpy as np import pandas as pd import ...
- Django 使用cmd 创建工程
一.Django 安装 1 通过pip安装 Django 如果你是通过升级的方式安装Django,那么你需要先卸载旧的版本. Django 提供3种发行版本,推荐使用官方的稳定版本: 你的操作系统提供 ...
- 通过helm搭建Harbor
文章转载自:http://www.mydlq.club/article/66/ 系统环境: kubernetes 版本:1.20.1 Traefik Ingress 版本:2.4.3 Harbor C ...
- 使用scrapy爬取长安有妖气小说
目标网站:https://www.snwx3.com/txt/434282.html 第一章地址:https://www.snwx3.com/book/434/434282/92792998.html ...
- Jenkins 运行权限问题
yum安装的Jenkins 配置文件默认位置/etc/sysconfig/jenkins 默认jenkins服务以jenkins用户运行,这时在jenkins执行maven脚本时可能会发生没有权限操作 ...
- 驱动开发:内核CR3切换读写内存
首先CR3是什么,CR3是一个寄存器,该寄存器内保存有页目录表物理地址(PDBR地址),其实CR3内部存放的就是页目录表的内存基地址,运用CR3切换可实现对特定进程内存地址的强制读写操作,此类读写属于 ...
- PAT (Basic Level) Practice 1005 继续(3n+1)猜想 分数 25
卡拉兹(Callatz)猜想已经在1001中给出了描述.在这个题目里,情况稍微有些复杂. 当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数.例如对 n=3 进行验证的时 ...