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

文章正文
发布时间:2025-11-12 04:15

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

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

准备工具 分析数据包

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

图片1.png (412.3 KB, 下载次数: 2)

下载附件

图片1

2024-12-12 23:26 上传

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

分析dex

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

图片2.png (140.97 KB, 下载次数: 2)

下载附件

图片2

2024-12-12 23:26 上传

继续往下跟踪:

图片3.png (38.24 KB, 下载次数: 2)

下载附件

2024-12-12 23:26 上传


图片4.png (84.64 KB, 下载次数: 2)

下载附件

2024-12-12 23:26 上传

分析libsign.so

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

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

图片5.png (77.52 KB, 下载次数: 2)

下载附件

图片5

2024-12-12 23:26 上传

直接点开Java_co_runner_app_jni_NativeToolImpl_getSignatureV2查看逻辑:

图片6.png (231.89 KB, 下载次数: 1)

下载附件

图片6

2024-12-12 23:27 上传

发现逻辑如下:

Java层传入的第1, 2个参数(IDA中为a3, a4)作为内部函数getSign的第1, 2个参数使用

内部函数getSecret()获取了一个Secret值,作为内部函数getSign的第3个参数使用

先分析Secret是怎么来的:

图片7.png (258.66 KB, 下载次数: 2)

下载附件

图片7

2024-12-12 23:27 上传

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

(假装这里有一张截图)

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

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

图片8.png (174.25 KB, 下载次数: 2)

下载附件

图片8

2024-12-12 23:27 上传

分析起来不难,使用了三个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 (65.45 KB, 下载次数: 2)

下载附件

2024-12-12 23:27 上传

一些花絮

一些大模型反编译平台(MLM01等)会出现搜索不到函数,还会出现AI瞎编代码逻辑的情况

同时使用 Android 14、15 和 KernelSU 的 Zygisk 模块时,会出现frida无法spawn程序的情况,报错为等待zygote程序(的PID)超时,尝试了一些办法(例如kill掉zygote进程)均无法解决,希望有大佬支招

这个App的34个dex让我的18G小内存在jadx搜索时不堪重负

Secret的位置是上Linux课的时候摸鱼试出来的

尾声

谁写的getSecret,建议开除

 

免费评分 参与人数 5威望 +1 吾爱币 +23 热心值 +3 理由

xiaodu3335
      + 1   我很赞同!  

正己
  + 1   + 20   + 1   感谢发布原创作品,吾爱破解论坛因你更精彩!  

xuezhang18
    + 1     我很赞同!  

leger1210
    + 1     热心回复!  

Hawcett
    + 1   + 1   感谢发布原创作品,吾爱破解论坛因你更精彩!  

查看全部评分

首页
评论
分享
Top