长亭百川云 - 文章详情

ppp买菜IOS版设备风控浅析与算法还原

矛和盾的故事

68

2024-07-13

本文仅限学习交流,请勿用于非法以及商业用途,由于时间和水平有限,文中错漏之处在所难免,敬请各位大佬多多批评指正。

目录:一、线上买菜场景简述二、风控在业务中的应用三、产品整体框架四、初始化分析五、反爬签名流程六、设备指纹分析七、算法还原八、总结

一、线上买菜场景简述

1、分析说明

1. 产品基本信息产品名称:ppp买菜(匿称);产品版本:5.25.0;Slogan:30分钟送达,新鲜送得快;所处行业:生鲜电商;2. 设备环境机型:iPhone 7;系统:IOS 13.4;工具: IDA7.6 Frida;

2、简单流程梳理

一次完整的线上买菜过程都经过了哪些环节呢?大致流程是从供应商送货到仓或到店,再由零售商售卖,最终到用户手里,这样便完成了一次买菜,如图1-1所示:

                        图1-1

上图的业务流程从供应商送货到仓或到店,再由零售商售卖,最终可以多种方式到用户手里,完成了一次买菜的过程。

二、反作弊风控在业务中的应用

1、APP推广拉新

还记得在2020年的下半年时候,当时生鲜电商的社区团购大战非常火爆,各种买菜APP蜂拥而入,砸钱、抢流量,你争我抢玩得不亦乐乎。
不夸张地说,我记得当时最常见的情形是,你随便在小区溜达一圈,就能碰见穿着各种颜色制服的地推工作人员,追赶着小哥哥小姐姐下载APP给送福利,下载完APP后注册登录APP买菜。

2、存在的风险

烧大把的钱把流量吸引过来,这个过程中会有黑灰产人员通过非法的技术手段,伪造新增用户并从中获利的行为,如果只是把流量吸引过来不考虑质量的话,会增加大量的企业无效成本。怎么识别出有效的流量与虚假流量,需要一个完善的风控体系与制定有效的策略找出高质量流量,然后把这些流量留下来。
接下来为了提高用户的购买频率,实现反复转化,就出现了各种红包、优惠券活动吸引用户提高打开APP频率与购买频率。这个环节中就会有各种薅羊毛的人群出现,同样需要完善的风控体系与制定有效的策略来最大程度地甄别风险。
活动流程大致如图2-1所示:

                        图2-1

三、产品整体框架

3.1、从初化到获取设备指纹整个框架如图3-1与3-2所示:

                        图3-1

                        图3-2

下面将围绕框架进行详细分析与算法还原。

四、初始化分析

4.1、代码混淆

在正式进行代码分析之前还是很必要交代一下我分析过程中发现的代码混淆,方便后继分析代码做准备。

反F5:大致模板如下:
__text:0000000103743850 FF C3 00 D1 SUB             SP, SP, #0x30 ; '0'

原理是通过动态赋值给x30实现跳转,X30链接寄存器(LR),用于保存子程序的返回地址。通篇都是这样的代码混淆方式,基本不怎么影响分析或脚本直接清除。
动态调试时如图4-1所示: 

                            图4-1

字符串加解密:

__text:000000010180C0C0             DecStrng_sub_1036F80C0

通用的解密字符串,同样可以用脚本跑一遍就可以解密出来。

采集设备信息跳转:
__text:0000000101864F1C 

只要在上面地方下好断点就能分析对应的采集设备信息的方法。

4.2、解密资源文件获取PIC

生成密钥:

获取APP Bundle ID:

com.baobaoaichi.imaicai

解析Info.plist读取ss中的值:

885B25AAFD830249B81AF699187E5752

解密常量字符串:

WU@TEN

组合字符串,BundleID+常量字符串(WU@TEN)+Info.plist中的ss值:

com.baobaoaichi.imaicaiWU@TEN885B25AAFD830249B81AF699187E5752

计算组合后字符的hmac值:

__text:0000000101B834F8             hamc_256_loc_1052974F8 

计算后的值:

39 D3 B7 71 76 74 09 F5 E7 4F 4B 57 9B 86 8A 5C  01 92 13 18 61 C1 79 1C

转换成字符串:

39d3b771767409f5e74f4b579b868a5c0192131861c1791c833b5c95e99c412b

读取mt_security

__text:0000000101B202CC             Read_mt_security_loc_1052342CC

读取后数据(部分):

0000000104899800  89 50 4E 47 0D 0A 1A 0A  00 00 00 0D 49 48 44 52  .PNG........IHDR

解析图片:

__int64 __fastcall sub_1036B61F0(

解析返回PIC数据(部分):

00000001050CDA00  2E 50 49 43 90 01 00 00  10 02 00 00 AC 02 00 00  .PIC............

4.3、解密PIC数据

生成AES KEY

将上面计算得到的hmac值转换成16进制:

39d3b771767409f5e74f4b579b868a5c0192131861c1791c833b5c95e99c412b

转换后:

0000000281E86790  39 D3 B7 71 76 74 09 F5  E7 4F 4B 57 9B 86 8A 5C

取转换后的的前0x10字节生成最终的AES KEY

__text:0000000101B2170C             GenAesKey_loc_102FD570C 

生成后的AESKEY:

38 90 B6 70 76 74 00 C0  E6 4E 4A 02 98 80 8A 1C

AES解密PIC数据:

__text:0000000101B1FA10 82 07 00 94 BL              DecPic_loc_105235818    ; x0:第1个指针pic数据,X1:key

解密后数据(部分)

0000000104486020  78 9C 45 92 6D 6F DA 30  14 85 FF 4B B4 7D DA 44  x.E.mo.....K.}..

解压缩AES解密后数据得到明文,后面的加解密数据都会使用里面数据做为KEY:

{"a1":1,"a10":400,"a2":"com.baobaoaichi.imaicai","a11":"0a76d34357f7c7859c1a3fd25516b4e4021ec931fd56b6a36ebf73e5aa34c406","a3":"b9eb65dbc4c7109259edc07826390faf3bd09e3920d66580b04a0853d3ee172b","a4":5230,"k0":{"k1":"meituan1sankuai0","k2":"meituan0sankuai1","k3":"$MXMYBS@HelloPay","k4":"Maoyan010iauknaS","k5":"34281a9dw2i701d4","k6":"X%rj@KiuU+|xY}?f"},"a5":"5.23.0","a0":"sdk9xWZTg5V9nKAxVFB5mB1ipZIJGmYSysreJ1f/rlvXJ7Ydxd3hJRdWb4QdZKr/","a6":"HdPfNPzY9GK6wzp0lEgaMaX06uEMke8y0H3eD0l4RapMpRmVaOWzyQkHMmOavR47","a7":"1yuZHjO43la6rhDXzMkjGiseg9yoRxxDtzwourYASiiAp4Yl0TUGvOiN4UcoJ6pQ","c0":{"c1":true,"c2":false},"a9":"gC4xYEhYfboH/8kOYsdIcbyYRTKfrVgmHLb3x8uNBag=","a8":1627281940842}

解析上面的json数据获取对应的key:

__text:0000000101AFF460 04 8E 00 94 BL              getPICkey_sub_102CF2C70 ; x0:返回pic json中的key

五、反爬签名流程

5.1、APP防爬背景

App防爬主要通过对App客户端发起的请求进行签名。然后将签名与业务数据请求发送到服务器端,服务端WAF应用服务器收到的请求后,通过解析签名串进行风险识别、拦截恶意请求,通过校验App请求签名,识别App业务中的风险、拦截恶意请求,实现App防护的目的。
如图5-1所示,请求头中携带的签名信息:

                            图5-1

识别异常爬虫:
App签名异常:对使用未携带签名或签名非法的App访问防爬防护目标的请求进行检测和拦截。
设备特征异常:检测设备的异常特征,是否使用模拟器、使用代理、Root设备、HOOK框架等。
基于以上逻辑,所以app会检测客户端环境。

5.2、扫描设备风险

检测越狱、hook框架等, 风险特征:

{

检测后结果:

{

压缩后json

0000000107C97080  78 9C 6D 90 4D 0E 84 30  08 85 EF C2 DA 69 A0 4A  x.m.M..0.....i.J
RC4加密压缩后数据:

组合加密密钥:

1635653901 6d1efb41-1bb2-4db1-88ee-b89d21d06e5f  //当前时间加获取appkey(ak:info.plist)

加密:

__text:00000001052F9848             Rc4Enc_sub_10310D848

RC4加密后:

0000000107C97080  25 F2 BB 8E 4A F9 CA 7C  F7 9A 5F 7D CD 38 67 69  %.............gi

Base64加密:

JfK7jkr5ynz3ml99zThnaS5L743O5fhYgFXWDl6zy2oq2xSv1zXcpe0CqFjp2Kso5D/1COlqjX9Rx7MmT40OQrIc2cpvc8gGaA9kMNErfgB2oSWrauzR/meaKYKkRDEuFAuW5jGBHzTycaqGYKjAzj0WI4Nhp8Bq5qAqoHprH0KQMMxZXwN/7US2vDa1DJedgqDk5qvCyE4p91XKh9CaH45tV1IAaL8fYtjdZ+Q=

5.3、获取本地XID

判断本地是否有存储,如果有优先读取本地,如果本地没有存储就生成一个,详细逻辑在设备指纹一节中再细说。

__text:00000001052E2E58 E0 7B 7B A9 LDP             X0, X30, [SP,#-0x50]

如果是第一次运行APP或本地没有存储时就本地生成XID:

-[SAKGuardDeviceFingerprint generateLocalXID]

本地存储获取到的xid:

mw0bruZSgWId6ew08pp0a3d2Vpfq1fcZfyJrTVmk89oqGNr5754r2zbh6YfpvQ4CijQe+0LfaB+WbyR9njkTQ8iCiFQzqg8rh18j7EntWdk=

5.4、获取dfpid

同样也是如果也是判断本地是否有存储,如果有优先读取本地,如果本地没有存储就生成一个

+[SAKGuardDeviceFingerprint getFingerprintID]

如果是第一次运行APP或本地没有存储时就本地生成dfpid:

+[SAKGuardLocalIDKeychainStorage generateLocalID]

本地存储获取到的dfpid:

dad72f7de813ef8dfd0bbd58f3a775dacf5121ec1a2552173a0e314b

5.5、获取系统风险

{

压缩json

0000000283F81500  78 9C AB 56 32 50 B2 32  D2 51 32 54 B2 8A 56 D2  x..V2P.2..2T..V.

解密解析pic获取加密key(k6)

X%rj@KiuU+|xY}?f

计算压缩后数据的crc值:

__text:00000001052CC27C E0 7B 7B A9 LDP             X0, X30, [SP,#-0x50]

计算后得到:

73bbf8c5

取PIC中获到的值(k6)后8字节与crc值组合做为AES KEY:

000000016B707800  55 2B 7C 78 59 7D 3F 66  00 00 00 00 00 00 00 00  U+|xY}?f

AES加密压缩后的数据:

IV 0102030405060708

加密后:

0000000280D20750  F7 7A 2E 6A 76 E2 C9 B4  70 F0 62 3B 07 62 91 D7  ....v...p....b..

base64加密与crc值组合:

73bbf8c593ouanbiybRw8GI7B2KR179Y36ZpGtEOD95qhzQAuGKu2soVnxJif9J7sNG8+ulF //前8字节为上面计算的crc值

第一次组合签名json,还差计算a2值:

{

5.6、计算请求体签名

获取请求体,与上面组合的json签名拼接在一起计算签名

__text:00000001052DC014 E0 7B 7B A9 LDP             X0, X30, [SP,#-0x50]

组合后的请求体

00000001080B5600  50 4F 53 54 20 2F 61 70  70 75 70 64 61 74 65 2F  POST /appupdate/

解密PIC获取a0值

sdk9xWZTg5V9nKAxVFB5mB1ipZIJGmYSysreJ1f/rlvXJ7Ydxd3hJRdWb4QdZKr/

解密a0

key appkey:6d1efb41-1bb2-4db1-88ee-b89d21d06e5f

解密后a0

0000000280A08750  7C 55 57 4A 14 0E 42 69  67 06 3B 06 4A 49 07 0C  |UWJ..Big.;.JI..

再次解密a0分为两组

000000016D10C530            20 09  0B 16 48 52 1E 35 3B 5A  66666. ...HR.5;Z

将第二次解密后的a0值其中一组与请求体组合

00000001089E5A00  4A 63 61 7C 22 38 74 5F  51 30 0D 30 7C 7F 31 3A  Jca|"8t_Q0.0|.1:

计算hmac值

__text:00000001052EEEDC             hmac_256_sub_105182EDC   

计算后的值

000000016B7078B0  D8 49 F8 46 FA 3A 4C 93  AC 68 76 4E 15 11 6C E2

计算后hmac值与解密后的a0其中一组组合

000000016B707850                                    20 09 0B 16 48

再次计算hmac值

000000016B707A50  58 26 1C D2 C2 35 BC D4  CE 83 F3 AF E0 BA 76 8C

加密计算的hmac值得到最终的签名值

__text:0000000105353BC4             loc_105353BC4

加密后

0000000280190580  7F 26 8F D8 7F 5D 01 F3  2D D5 C7 E0 86 84 87 8E

转换成字符串

7f268fd87f5d01f32dd5c7e08684878e

组合成最终的签名

{

整个请求体的签名结束,然后发起网络请求。

六、设备指纹分析

6.1、请求服务器设备指纹

应用启动后会生成两个ID,一个是XID,一个是DFPID,如图6-1、6-2所示:

                        图6-1

                        图6-1

6.2、XID生成

获取设备信息:

__text:00000001010F3234             getmDeviceInfo_loc_104F0F234 

将每一个获取到的信息组合单个json值,格式如下

{"value":"E68684F0-7573-4EBC-99BD-A03D58888888","code":1} //获取的IDFA

获取本地XID,如果是第一次或本地没有存储就本地生成一个:

-[SAKGuardDeviceFingerprint generateLocalXID]

检测风险工具:

/Library/MobileSubstrate/DynamicLibraries/AXJ.plist

检测代码

__text:00000001010FAACC E0 7B 7B A9 LDP             X0, X30, [SP,#-0x50]

转换成最终的json格式

{

压缩json文数据,压缩后(部分)

0000000104AF3800  78 9C 6D 56 CB 6E 2B C7  11 FD 15 82 AB 3C 44 BA  x.mV..+......<D.

解密PIC获取key(k1)

meituan1sankuai0

AES加密压缩后数据

_text:00000001010BEA08 E0 7B 7B A9 LDP             X0, X30, [SP,#-0x50]

AES加密后(部分)

0000000104AC3200  2C 36 30 1D 89 2C 90 E9  7E F7 1C DB 62 73 D7 5E  ,60..,.......s..

base64加密

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

组合请求体

{

计算签名,签名过程与上面分析的流程是一样的。

+[SAKGuardCommon sign:attachSiua:]

dfpid逻辑差不多,这里就不分析了。

七、算法还原

7.1、加密设备指纹请求体算法(不全部展开了吧,大多都是标准算法)

设备指纹相关用到的算法有AES、压缩、RC4、hmac、base64。
RC4:

#include <stdio.h>

AES

/*******************

测试解密设备指纹请求体

//解密fingerPrintData

解密出来的数据与上面分析的组合设备指纹json是一样的,解密成功,如图7-1所示:

                        图7-1

八、总结

我从分析的角度说下自己的看法,不对的地方还请指正,抗分析能力一般,代码混淆规律性很强,字符串加密方法用的一个容易被一次性还原。获取设备信息过于频繁,影响性能,回到开始说的风控在业务中的作用,大部分用户使用生鲜类APP时的目的性比较强,业务在拉新促活增加用户粘性的同时高质量留存与业务安全更是重中之重,所以产品流畅的用户体验是促进高留存的重要条件之一。
还有一些隐藏的彩蛋比较有意思,感兴趣的可以去自行分析。

样本太大,获取方式,关注公众号,公众号输入框回复“mc” 获取下载链接。

作者简介:
我是小三,目前从事软件安全相关工作,虽己工作多年,但内心依然有着执着的追求,信奉终身成长,不定义自己,热爱技术但不拘泥于技术,爱好分享,喜欢读书和乐于结交朋友,欢迎加我微信与我交朋友(公众号输入框回复“wx”即可)

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2