吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8355|回复: 56
收起左侧

[Android 原创] 某上市导购平台Android APP签到sign逆向分析并使用Python复写加密算法

  [复制链接]
白水饮 发表于 2023-1-11 22:19
本帖最后由 cry980285208 于 2023-1-12 10:00 编辑

导购平台网址:aHR0cHM6Ly93d3cuc216ZG0uY29tLw==

由于不想每天手动签到且经常忘记签到,于是便去Github搜索相关结果,果不其然,是有相关结果的,并且更新时间还是Last Month,但是在使用过程中发现,接口总是返回验证码错误,手动在WEB端签到,发现是有滑块验证码的,在APP端签到就没有验证。


本想偷懒,看下网上有没有现成的APP端签到源码之类的,搜了一圈,没有找到,只能自己动手了,于是便有了这篇文章。

首先,直接用小黄鸟抓包看一下,找到签到接口,接口地址https://user-api.smzdm.com/checkin,看下请求的参数:
小黄鸟.jpg

经过多次抓包,发现变化的值,只有sign和time,weixin,f,v,sk,token都是固定值,captcha和touchstone_event为空


再然后直接使用Jadx打开apk安装包,搜索"sign",如下图:


Dingtalk_20230111195839.jpg

上面的这些类看起来都是第三方SDK里面的相关内容,下面的这个混淆过的这个方法e.e.b.a.n.a.a.a,非常可疑,我们进去看看,分析下


Dingtalk_20230111200122.jpg

在这里我们就可以看到签到接口传的f,v,weixin,time一些参数了,sign这个值,是由a方法生成,我们直接点击a方法,跳转至相关代码,再进行分析:


Dingtalk_20230111200254.jpg

到了这里,可以看到这个a方法传入了一个map,并对其进行了排序遍历拼接,在最后还拼接了一个&key=,这个key的值是由ZDMKeyUtil.a().b()生成的,并且最终的返回值应该是经过F这个类中的a方法进行了加密,我们先跳转至ZDMKeyUtil这个类里面再进行分析


Dingtalk_20230111212113.jpg

ZDMKeyUtil这个类里面应该是加载了一个固定的key,这里我也不太确定,后面我们再通过Xposed去Hook相关方法,打印log查看


然后我们再去分析F类中的这个a方法,直接点击跳转,如下图:


Dingtalk_20230111201611.jpg

好家伙,这一看基本就可以确定是MD5加密了


通过上面的分析,我们来总结下:sign的值是由e.e.b.a.n.a.a这个类中的a方法生成的,a这个方法做了哪些事呢?传入了一个map,并对其排序遍历拼接,最终还通过ZDMKeyUtil生成了一个key拼接后面。接下来就是通过Fa这个类中的a方法,对上面拼接的这个字符串进行MD5加密,最终生成32位大写的sign值


那么我们怎么才能得到加密前的参数并且复写加密算法呢?


我的方法是通过Xposed Hook相关类和方法,获取传参和返回值:
1.通过hook e.e.b.a.n.a.a这个类中的a方法,获取传入的map和sign值,对比小黄鸟抓包抓到的参数和sign值,确定是否是我们需要找的签到接口,因为还有其他很多接口都调用了这个方法
2.通过hook ZDMKeyUtil这个类中的方法,获取最终拼接在后面的key参数
3.通过hook Fa这个类中的a方法,获取加密前的字符串和加密后的值,注意,这里加密后为小写的sign,需转为大写的32位


相关Hook代码如下图,代码很烂,仅供参考:
Dingtalk_20230111201533.jpg


分析Xposed Log文件,Log打印结果如下图:


4B3690D5-500B-4b7a-B8FE-B03F724475FE.png

通过查看Xposed打印的log,我们可以得出加密前的字符串格式为f=android&sk=xxx&time={timestamp}000&token=xxx&v=9.9.12&weixin=1&key=xxx,其中拼接在最后的key为固定值,如图hook success5后面的即为key的值


有了加密的文本和加密的方法,接下来,就可以用python进行复写了

[Python] 纯文本查看 复制代码
# -*- coding: utf-8 -*-
import time
import random
import hashlib
import requests


# MD5加密
def md5(rawstr):
    # 创建md5对象
    hl = hashlib.md5()
    hl.update(rawstr.encode(encoding='UTF-8'))
    return hl.hexdigest().upper()


def checkin(cookie):
    signurl = "https://user-api.smzdm.com/checkin"
    zdmkey = 'apr1$AwP!wRRT$gJ/q.X24poeBInlUJC'
    zdmsk = '填写抓包抓到的sk值'
    zdmtoken = cookie[5:]
    timestamp = int(time.time())
    rawdata = f'f=android&sk={zdmsk}&time={timestamp}000&token={zdmtoken}&v=9.9.12&weixin=1&key={zdmkey}'
    sign = md5(rawdata)
    formdata = {
        "sk": zdmsk,
        "sign": sign,
        "weixin": "1",
        "v": "9.9.12",
        "captcha": "",
        "f": "android",
        "token": zdmtoken,
        "touchstone_event": "",
        "time": f"{timestamp}000"
    }
    headers = {
        "User-Agent": 'smzdm_android_V9.9.12 rv:683 (Redmi K20 Pro;Android11;zh)smzdmapp',
        "Cookie": cookie,
        "Accept-Encoding": 'gzip',
        "Connection": "Keep-Alive",
        "request_key": f"{random.randint(10000000, 99999999)}{timestamp}",
    }
    resp = requests.post(signurl, headers=headers, data=formdata).json()
    if resp["error_code"] == '0':
        resp_data = resp["data"]
        checkin_num = resp_data["daily_num"]
        gold = resp_data["cgold"]
        silver = resp_data["pre_re_silver"]
        point = resp_data["cpoints"]
        exp = resp_data["cexperience"]
        rank = resp_data["rank"]
        cards = resp_data["cards"]
        msg = f"""🏅签到成功\n🏅已连续签到{checkin_num}天\n🏅等级{rank}\n🏅补签卡{cards}\n🏅碎银{silver}\n🏅金币{gold}\n🏅积分{point}\n🏅经验{exp}"""
        print(msg)
    else:
        msg = f'签到失败!失败原因:{resp["error_msg"]}'
        print(msg)


if __name__ == "__main__":
    zdmcookie = "填写ZDMCookie"
    checkin(zdmcookie)


写在最后:签到接口中,headers中还有一个参数request_key,通过Jadx分析APP源码,可以发现request_key是由一个随机数拼接当前时间戳而成的,源代码如下:


Dingtalk_20230111205644.jpg

sk参数为固定值,分析app源码,似乎是由Cookie中的sess,用户id等信息生成的,具体怎么生成的就不深究了,反正为固定值,直接用抓包中的值就行了
token参数也是固定值,也就是Cookie中的sess
感兴趣的可以将代码用云函数改写一下,每天定时签到,也可以加上server酱,钉钉,企业微信推送,我就不献丑了

免费评分

参与人数 25威望 +2 吾爱币 +124 热心值 +22 收起 理由
junjia215 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
Schwarz + 1 谢谢@Thanks!
ranbow1989 + 1 谢谢@Thanks!
clocker321 + 1 + 1 热心回复!
Quincy379 + 1 + 1 八仙过海,各显神通!
padao + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xlone2001 + 1 + 1 我很赞同!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
莫奇 + 1 + 1 我很赞同!
笙若 + 1 + 1 谢谢@Thanks!
开心的一逼 + 1 + 1 热心回复!
allspark + 1 + 1 用心讨论,共获提升!
gaosld + 1 + 1 谢谢@Thanks!
Cerem + 1 + 1 我很赞同!
bot123 + 1 + 1 热心回复!
tonyYzh + 1 我很赞同!
shiyucj + 1 + 1 热心回复!
初七的果子狸 + 1 + 1 热心回复!
极地企鹅 + 1 + 1 谢谢@Thanks!
viewing727360 + 1 + 1 热心回复!
brainyyt + 1 热心回复!
teenage1997 + 1 + 1 很有用
红内裤 + 1 + 1 谢谢@Thanks!
chaseboy + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
正己 + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

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

saoyi 发表于 2023-1-13 18:43
感谢大佬分享
ranbow1989 发表于 2023-2-9 02:00
感谢分享,额外补充一句,如果有还在用python2.7的朋友,f开头作为formatting的几句要替换掉。
例如
[Asm] 纯文本查看 复制代码
rawdata = f'f=android&sk={zdmsk}&time={timestamp}000&token={zdmtoken}&v=9.9.12&weixin=1&key={zdmkey}'

要替换为
[Asm] 纯文本查看 复制代码
rawdata = 'f=android&sk='+zdmsk+'&time='+str(timestamp)+'000&token='+zdmtoken+'&v=9.9.12&weixin=1&key='+zdmkey


再次感谢~
rustyjackal 发表于 2023-1-12 13:52
sunzhw 发表于 2023-1-12 14:13
支持,感谢分享
红内裤 发表于 2023-1-12 14:44
收到,这就去改!
chenyicai 发表于 2023-1-12 15:12
感谢大神分享
teenage1997 发表于 2023-1-12 15:24
很强,git上的脚本都失效了,把你这个放到qinglong跑,立马签到上了
CfengSmeng 发表于 2023-1-12 15:32
ooopppp
小黄鸟好评
tanzhijun8 发表于 2023-1-12 15:36
谢谢分享
一剑封侯人 发表于 2023-1-12 15:47
大佬一出手
一剑封侯人 发表于 2023-1-12 15:56
teenage1997 发表于 2023-1-12 15:24
很强,git上的脚本都失效了,把你这个放到qinglong跑,立马签到上了

我放在ql怎么跑不起来啊,老哥,带带
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-21 20:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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