吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1329|回复: 17
收起左侧

[Android 原创] 逆向分析某红色跑步App的API

  [复制链接]
hitachimako 发表于 2024-12-12 23:32
本帖最后由 hitachimako 于 2024-12-12 23:54 编辑

逆向分析某红色跑步App的API

前言

群友尝试破解自己学校的某红色校园跑App,来帮个忙

准备工具

分析数据包

使用Reqable抓取上传跑步数据时的请求,内容如图:

图片1

图片1

一眼看到Header存在一个校验字段:_sign,内容是一个大写的的16字节HexString

分析dex

这里已经怀疑可能是MD5,将Apk拖入jadx搜索_sign找到如图请求位置:

图片2

图片2

继续往下跟踪:
图片3.png
图片4.png

分析libsign.so

至此找到调用生成_sign的函数getSignatureV2 这个函数是一个native实现,经过对目录lib/arm64-v8a的寻找,发现极为可疑的文件libsign.so

libsign.so导入IDA分析,可见JNI函数:

图片5

图片5

直接点开Java_co_runner_app_jni_NativeToolImpl_getSignatureV2查看逻辑:

图片6

图片6

发现逻辑如下:

  1. Java层传入的第1, 2个参数(IDA中为a3, a4)作为内部函数getSign的第1, 2个参数使用
  2. 内部函数getSecret()获取了一个Secret值,作为内部函数getSign的第3个参数使用

先分析Secret是怎么来的:

图片7

图片7

全部是一些memcpy,strcat之类的操作,说明Secret的生成路径是固定的,没有依靠时间等seed对其进行随机处理(getSign1getSign3以及其调用的函数也没有使用随机,这里就先不放图了),所以我们基本可以认为使用frida对函数getSecret()进行钩取,可以获得其固定返回值。

(假装这里有一张截图)

由于我手上暂时没有 Android 13 及以下的环境,所以让群友代抓了一下getSecret()函数的返回值,多次发送请求进行抓取,发现Secret确实为固定值20eca08916b92********2786e315dea

拿到了三个参数,我们就可以研究函数getSign的逻辑了。双击getSign,跳转到函数中查看逻辑,如图:

图片8

图片8

分析起来不难,使用了三个std::__put_character_sequence<char,std::char_traits<char>>,基本可以看出来是把三个参数顺序连接了起来,而后面MD5函数的调用也印证了前面的猜想。

继续让群友代劳,抓了一些调用Java层调用getSignatureV2的参数和返回值,用来验证猜测是否正确。但是我在这一步卡了很久,因为我认为Secret在最后,最后多试了几种排列方法才发现Secret实际上在两个Java层传入参数的中间。

重新实现Java层参数

接下来看一下Java层传入的两个参数都是什么东西。

第一个参数

见上图分析dex时的图片可知,第一个参数是一个Map<String, String> paramValueMap经过sort得到的顺序,再以该顺序将其每个键与值从前到后拼接在一起得到的。就像这样:contentheartrate[]lasttime1733995696meter196nodetimenomo...

尝试在Python中还原该逻辑:

params = {}
for segment in dataStr.split("&"):
    if "=" in segment:
        k, v = segment.split("=", 1)
    else:
        k, v = segment, ""
    k = urllib.parse.unquote_plus(k)
    v = urllib.parse.unquote_plus(v)
    params[k] = v

sorted_keys = sorted(params.keys())

sb = []
for key in sorted_keys:
    sb.append(key)
    sb.append(params[key])

dataFinalStr = "".join(sb)

库自带的parse会导致没有值的键消失,比如解析&content=&xxx=***的时候,content就离奇失踪了。

第二个参数

我们可以看到uid > 0 ? (uid + sid).getBytes() : new byte[0] 其实就是把uid和sid直接拼一起而已。

王牌飞行员

接下来的事就是把_sign应用到脚本里了,效果如图:
图片9.png

一些花絮

  • 一些大模型反编译平台(MLM01等)会出现搜索不到函数,还会出现AI瞎编代码逻辑的情况
  • 同时使用 Android 14、15 和 KernelSU 的 Zygisk 模块时,会出现frida无法spawn程序的情况,报错为等待zygote程序(的PID)超时,尝试了一些办法(例如kill掉zygote进程)均无法解决,希望有大佬支招
  • 这个App的34个dex让我的18G小内存在jadx搜索时不堪重负
  • Secret的位置是上Linux课的时候摸鱼试出来的

尾声

谁写的getSecret,建议开除

免费评分

参与人数 4威望 +1 吾爱币 +23 热心值 +2 收起 理由
正己 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xuezhang18 + 1 我很赞同!
leger1210 + 1 热心回复!
Hawcett + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hawcett 发表于 2024-12-13 11:00
Zygisk和frida的spawn模式就是经常不对付,但是如果把zygisk卸载的话,lsposed可又用不了了,进而造成算法助手用不了了。我这里有两个解决方案
1. 如果不想放弃zygisk,现在的算法助手也支持导入Frida脚本了,拿算法助手替代frida的spawn模式,缺点就是操作都得在算法助手上进行,肯定是不如电脑hook的方便
2. 把zygisk换成riru,改成magisk + riru方案,我就是采用这种的,lsposed也有riru版的,测试后发现无论是frida的spawn和lsposed都能完美运行,目前还没发现其他BUG,我的设备是安卓9真机,高版本的未测试
希望对你有帮助

免费评分

参与人数 3吾爱币 +4 热心值 +3 收起 理由
小朋友呢 + 2 + 1 热心回复!
loveqq520 + 1 + 1 我很赞同!
hitachimako + 1 + 1 谢谢@Thanks!

查看全部评分

心中的影子 发表于 2024-12-13 11:59
wantwill 发表于 2024-12-13 16:17
zyt0339 发表于 2024-12-13 16:30
感谢分享, 给我提供了思路,niubilitity
Ok166 发表于 2024-12-13 21:35
感谢分享
han163426 发表于 2024-12-13 21:38
跑步app真是折磨
wolong11 发表于 2024-12-14 09:51
感谢分享思路
头像被屏蔽
pomxion 发表于 2024-12-14 15:04
提示: 作者被禁止或删除 内容自动屏蔽
若然 发表于 2024-12-14 21:53
56万公里,楼主跑出国了嘛
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-1-6 19:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表