题目: 计算前 100 页的数字加在一块 求和。
考察的是 Java 层加密
对于 App 的爬虫,我首先想到的是抓包、找到数据接口,请求接口拿到数据。
往往事情没那么简单😤
对于抓包的方式有很多种,例如:安装App HttpCanary、PC端Filddler、Charles等等
这些方法我都试过了,App会检测是否使用了代理、验证证书之类的,导致我们无法正常使用 App。
App防止抓包可以参考:https://www.jianshu.com/p/9921db646c59
可以使用 frida hook 具体的函数(需要搭建环境,没用过)
还有一种方法可以通过 xp模块,如 JustTrutMe 来忽略证书验证,就是手机需要 root,安装 xp框架,但是目前 App 不支持模拟器运行。
工具:红米 K50 Pro、HttpCanary、VMOS Pro
1、首先手机安装上述两种软件
2、在VMOS中创建虚拟机,安装 Xposed、Root权限,下载模块 TrustMeAlready(和JustTrustMe差不多)
3、在真机上安装 HttpCanary证书(在软件中,需要自己找),并将证书导出
4、然后在VMOS虚拟机中也安装HttpCanary,在虚拟机中导入从真机导出的证书
5、在虚拟机中打开需要抓包的软件,在真机HttpCanary中对VMOS软件进行抓包。
按照这个差不多就能抓到包了。(还有一种方法,fiddler 和 drony 搭配)
抓到了接口
https://appmatch.yuanrenxue.com/time
这个获取服务器时间的
GET
https://appmatch.yuanrenxue.com/app1
这个是用来获取数据的接口
POST
参数
page=1
t=上一个接口获取的时间
sign=xxxxxxx
这里 sign 值就是一个加密的参数,每一次都不一样,并且还具有时效性。
为了获取 Sign 的值,我们只能反编译 这个 Apk,找到了这个参数的算法。
我一开始用的 MT管理器进行的反编译;后来直接换成了 jadx;
下面会有Jadx 工具编译命令。
使用 jadx 打开 Apk 文件进行反编译;
然后就是搜索各种关键字 例如:/app1
、sign
找呀找找🤔
找到了这个类 ChallengeOneFragment
发现了这一行代码
public /* synthetic */ o00Ooo lambda$initListeners$0(o00O000.OooOO0O oooOO0O) throws Exception {
StringBuilder sb = new StringBuilder();
sb.append("page=");
sb.append(this.page);
long longValue = oooOO0O.OooO00o().longValue();
sb.append(longValue);
return ((o0O0ooO.OooO0O0) this.mRequest.OooOOO0(o0O0ooO.OooO0O0.class)).OooO00o(Integer.valueOf(this.page), new Sign().sign(sb.toString().getBytes(StandardCharsets.UTF_8)), Long.valueOf(longValue));
}
参数分别为:page、sign、t时间戳
然后就是把 Sign 这个类以及 sign 方法关联的类都搞到我们的 idea 尝试跑通这个方法;
最终定位到了这三个类:OooO0O0
、OooO0OO
、OooO00o
、Sign
这里sign值是由 encrypt("page=" + page + timestamp) 加密后得到的
Sign类中sign方法返回的就是我们要的sign值
使用最新版 Jadx 反编译的坑,有几块代码反编译的有问题,导致代码无法运行或者是导致最终生成的Sign值与实际中不一样。
第一个地方
package o00OO;
/* compiled from: proguard-dict.txt */
/* loaded from: classes2.dex */
public class OooO00o {
/* renamed from: OooO00o reason: collision with root package name */
public static final String[] f8180OooO00o;
static {
f8180OooO00o = r0;
String[] strArr = {"茅茑馇筀ꆕ茪馃筆ꆄ茪首筎ꆅ荖駳筕ꆧ荡馢筬ꆨ荢茆馇筀ꆕ茍馕筍ꆇ茴首筗ꆈ荂茆馇筀ꆕ茆馇筀ꆕ茑馇筀ꆕ茪馃筆ꆄ茪首筎ꆅ荖駳筕ꆧ荡馢筬ꆨ荢茕駣笵ꇴ荽駣笵ꇴ荽駣笵ꇴ荽駣笵ꇴ荽茎\ueaf9㖿猪茨馇筕ꆖጃ췗\u20fc썑茌馈筌ꆅ荎香筋ꆇ荈馃茁馔筄ꆈ荎茄駮茄駯茕ᘟ㔯並찜왎\u1ad7廊췅힎㕚쵧\ue40c\uec9f㔎庘籛茎\ueaf9㖿猪茨馇筕ꆖጃ췗\u20fc썑茉\ueaf9㖿猪茨馇筕ꆖጃ췗ᢗ⦊\uea99茀\ue97f⫾\uf8f2Ꮽ曇茍졋᠌\uefc6\ue824\u09c6⫿\u10358a茚馮筱ꆲ荵馵笿ꇩ茪馧筵ꆶ荨馧筱ꆥ荭駨筼ꆳ荤馨筷ꆣ荫馾筰ꆣ茫馥筪ꆫ茇P\ue370茎\ueaf9㖿猪茨馇筕ꆖጃ췗\u20fc썑茇穀\uf349茉\ueaf9㖿猪茨馇筕ꆖጃ췗ᢗ⦊\uea99茁馔筄ꆈ荎茌馈筌ꆅ荎香筋ꆇ荈馃茌馈筌ꆅ荎香筋ꆇ荈馃茄駶茄駮茄駯茏馥筤ꆥ荠馴筱ꇨ荵馣筨茇馊答茋馥筪ꆶ荼馅筠ꆴ荱馀筬ꆪ荠駼笥茆馧筵ꆭ茄駩茂馫筪ꆳ荫馲筠ꆢ茅茄駩茏馥筤ꆥ荠馴筱ꇨ荵馣筨茇馊答茏馥筤ꆥ荠馴筱ꇨ荵馣筨茁馊答ꇫ茻茂馫筤ꆲ荦馮笵ꇵ茈駷笽ꇶ茫駱笳ꇨ茳駶笫ꇴ茱駲茁駣笵ꇲ荡茁馊答ꇫ茻茄駪茂馶筤ꆢ荡馯筫ꆡ茂馶筤ꆢ荡馯筫ꆡ茧馓筫ꆣ荽馶筠ꆥ荱馣筡ꇦ荡馣筣ꆧ荰馪筱ꇦ荱馴筰ꆵ荱駦筨ꆧ荫馧筢ꆣ荷馵笿茆馄筎ꆕ茉馥筩ꆯ荠馨筱ꆅ荄駨筧ꆭ荶茕馋筟ꇲ荦馩筿ꆟ茽馗筰ꇵ茷馓筿ꆁ荠茕馋筟ꇲ荦馩筿ꆟ茽馗筰ꇵ茷馓筿ꆁ荠茆馒等ꆕ茞馮筱ꆲ荵馵笿ꇩ茪駷笽ꇶ茫駱笳ꇨ茳駶笫ꇴ茱駲笿ꇷ茽駲笱ꇵ茆馅筋ꇻ茄駪茀馞笫ꇳ茵駿蝪駫笨ꇫ茨駫筇ꆃ荂馏筋ꇦ荆馃筗ꆒ荌馀筌ꆅ荄馒筀ꇫ茨駫笨ꇫ茏馋筌ꆏ荁馁筯ꆅ荆馇筢ꆏ荆馅答ꆅ荇馔筗ꆬ荨馍筷ꆃ荐馾筿ꆇ荋馄筢ꆭ荴馮筮ꆯ荂駿筲ꇶ荇馇答ꆵ荃馇筁ꆄ荊馋答ꆵ荲馅答ꆟ荁馐答ꆗ荂馃筲ꆌ茱駌筠ꆂ荀馊筈ꆇ荮馁筄ꇷ荐馃筆ꆇ荲馅筠ꆎ荢馾筆ꆼ荄馌筇ꆡ荋馐筇ꆇ荦馋筄ꆨ荭駲筈ꆗ荶馱筆ꆗ荜馂筓ꆗ荔馍筁ꆇ荏駲筠ꆂ荀馊筈ꆇ荮馁筄ꇷ荐馃笏ꆅ荲馱筆ꆣ荍馡筽ꆅ荿馇筏ꆄ荢馈筓ꆄ荄馋筈ꆇ荫馮笱ꆋ荆馇筝ꆂ荑馏筼ꆋ荁馋筽ꆉ荑馏筿ꆋ荑馥筿ꆋ茴馩筜ꆂ荿馏筽ꆋ药馏筲ꆋ药馏筿ꆋ药馋筽ꇌ荋馼筈ꆼ荒馬筇ꆉ荈馗筶ꆱ荆馗筜ꆂ荓馗答ꆁ荀馱筏ꇲ荠馂筀ꆊ荈馇筮ꆁ荄駷筐ꆃ荆馇筲ꆅ荠馎筢ꆾ荆馼筄ꆌ荇馡筋ꆐ荇馇筦ꆋ荄馨筭ꇲ荈馗筶ꆱ茏馅答ꆟ荁馐答ꆗ荎馂筄ꆌ茱馣筁ꆃ草馋筄ꆭ荂馇笴ꆓ荀馅筲ꆱ荆馣筍ꆡ荽馅筿ꆇ荏馄筢ꆈ荓馄筄ꆋ荈馇筫ꆮ茱馋筌ꆏ荇馏筯ꆇ荋馄筢ꆭ荴馮筮ꆯ荂駌笼ꆱ茵馄筄ꆗ荀馀筄ꆇ荊馅筄ꆗ茽馇筈ꆏ荌馄筆ꆡ荎馅筄ꆗ荀馇笳ꆭ荐馳筩ꆄ荠馟筋ꆅ荄馨答ꇰ荼馼筫ꆷ荣馨筝ꆯ荵駳筡ꆬ茳馵笼ꆎ荂馕答ꆈ荭馥笏ꇲ荃馲筳ꆪ荔馾筮ꆜ荧馬筜ꆣ荫馷笶ꇷ荓馑笱ꆶ荠馥筍ꇭ茱駲筲ꆡ荋馄筶ꆴ荩馒筰ꆰ茵馂筇ꆷ荢駴筐ꇶ茵馨筤ꆷ荦駴等ꆖ茳馏筭ꆤ荜馩筓ꆭ荿駵策ꇌ荴馧筯ꆠ荲馊筂ꆁ荌駾筵ꆄ荳馮筵ꆵ荠馐筇ꆗ荼馰筶ꆱ茴馾笷ꇵ荦馴筀ꆁ茼馶筇ꆏ荂駳笰ꇰ荋馳筶ꆊ荧馅筜ꆤ荲馾筯ꇲ荶馷筨ꇿ荫馱筌ꇱ荼馔筇ꆃ茏馎筒ꆵ荈馒策ꆗ荪馒筌ꆪ荇馓筕ꆞ荕駰策ꆮ荓駳筶ꆐ荡馩筑ꆥ荁馢等ꆢ荖馅筂ꆂ荪馋筦ꇭ茴馬筊ꆢ茼馕筧ꆫ荷馫筈ꆨ荈馏笴ꇱ荖馔笷ꆄ荊駶筷ꇩ荁駌筏ꆞ荆馭笷ꇾ荱馕筑ꆾ荄馶筜ꆁ荓駭筜ꆇ茼馫筟ꇵ荏馒筬ꇭ荓駱筝ꆂ荬馿笰ꆅ荮馣筧ꇾ荼馥筓ꇭ荀駾筦ꆨ荡馍筗ꆵ荍駶筐ꆳ荈馫筊ꆶ荄馩筌ꆱ茰馍笏ꆎ荒馋筼ꆼ茪馉笪ꆧ荽馣筐ꆴ茼馔笳ꆠ荏馗筃ꆷ药馗筐ꆃ荎馞筍ꆾ荖駷筆ꆣ荦駭笮ꆬ茳馴笽ꇵ药馇笪ꆏ荝馫筷ꇴ荲馏筁ꆇ荔馇筇ꆋ荄駶筂ꆅ荖馷筂ꇌ荖馏筧ꇵ荁馗筀ꆄ荆馱筐ꆇ荄駲筌ꆄ荄馗筄ꆢ荿馾筒ꆮ茵駱筒ꆿ茱駶笷ꆖ荡馇策ꇾ荵馌筇ꆃ荤馾筆ꆤ茲馞笲ꆕ茵駴答ꆮ荃駱筴ꆂ茱駷筜ꆨ草馞筍ꆣ茏馤筟ꆮ茼馊筱ꆌ荡馲筧ꆕ茵馈筠ꆨ荰駰筀ꆇ茶馧筭ꆗ荝馃笱ꆗ荆馬筓ꆥ荄馯筕ꆃ荁馍笴ꆫ茮馰筶ꇶ荼馤筀ꆥ荗馉筀ꆪ荿馀筷ꆅ茵馾筭ꇾ荋馾筍ꆭ荗駌笽ꆳ荱馟筯ꆋ荟馡筭ꇶ荪馲筰ꇿ茱駾笱ꆒ荒馫筌ꆉ荊馬筬ꆯ茽馟筜ꆧ荄馰筀ꇰ草馊等ꇩ荜駾筈ꆭ茷馪筏ꇿ荍馕筵ꆢ荀馒筶ꆓ草馌筽ꆒ荦馿筧ꆌ茲馞笏ꆗ荒駰筎ꇱ荇馣筝ꆞ茽駲策ꆢ荍馶筨ꆼ茵馎筁ꆕ荨駾筄ꇳ荇馧筫ꆮ荩馳笷ꆷ荁馪筓ꇲ荄馏筀ꆾ荐馓答ꇩ荽馵筀ꆉ茵馐筧ꆠ荀駴筭ꆉ荟駵筿ꆩ茴馔筡ꇌ荑馶筜ꆃ荦馠筒ꆒ茷馣筗ꇷ荭馐筯ꆇ荴馋筎ꆷ荫馉筎ꇷ荴駭筫ꆧ荴馨筄ꆊ药駱笴ꆴ荌馎筬ꆍ荍馄筷ꆁ荖馄筡ꆾ药馎筗ꆂ荝馕筲ꆳ荇馃筳ꆜ荧首筬ꆀ茏馏笮ꆔ荐馁筎ꆔ药馭筟ꆍ荤馬筬ꆗ荧馀筧ꇵ荔馉筽ꆴ荪駰筫ꆑ荶馵筦ꆷ荦馅筳ꇩ荔馃答ꆔ荶駌笨ꇫ茨駫笨ꆃ荋馂笥ꆅ荀馔筑ꆏ荃馏筆ꆇ荑馃笨ꇫ茨駫笨ꇌ茄駶蝪駫笨ꇫ茨駫筇ꆃ荂馏筋ꇦ荆馃筗ꆒ荌馀筌ꆅ荄馒筀ꇫ茨駫笨ꇫ茏馋筌ꆏ荁馁筯ꆅ荆馇筢ꆏ荆馅答ꆅ荇馔筗ꆬ荨馍筷ꆃ荐馾筿ꆇ荋馄筢ꆭ荴馮筮ꆯ荂駿筲ꇶ荇馇答ꆵ荃馇筁ꆄ荊馋答ꆵ荲馅答ꆟ荁馐答ꆗ荂馃筲ꆌ茱駌筠ꆂ荀馊筈ꆇ荮馁筄ꇷ荐馃筆ꆇ荲馅筠ꆎ荢馾筆ꆼ荄馌筇ꆡ荋馐筇ꆇ荦馋筄ꆨ荭駲筈ꆗ荶馱筆ꆗ荜馂筓ꆗ荔馍筁ꆇ荏駲筠ꆂ荀馊筈ꆇ荮馁筄ꇷ荐馃笏ꆅ荲馱筆ꆣ荍馡筽ꆅ荿馇筏ꆄ荢馈筓ꆄ荄馋筈ꆇ荫馮笱ꆋ荆馇筝ꆂ荑馏筼ꆋ荁馋筽ꆉ荑馏筿ꆋ荑馥筿ꆋ茴馩筜ꆂ荿馏筽ꆋ药馏筲ꆋ药馏筿ꆋ药馋筽ꇌ荋馼筈ꆼ荒馬筇ꆉ荈馗筶ꆱ荆馗筜ꆂ荓馗答ꆁ荀馱筏ꇲ荠馂筀ꆊ荈馇筮ꆁ荄駷筐ꆃ荆馇筲ꆅ荠馎筢ꆾ荆馼筄ꆌ荇馡筋ꆐ荇馇筦ꆋ荄馨筭ꇲ荈馗筶ꆱ茏馅答ꆟ荁馐答ꆗ荎馂筄ꆌ茱馣筁ꆃ草馋筄ꆭ荂馇笴ꆓ荀馅筲ꆱ荆馣筍ꆡ荽馅筿ꆇ荏馄筢ꆈ荓馄筄ꆋ荈馇筫ꆮ茱馋筌ꆏ荇馏筯ꆇ荋馄筢ꆭ荴馮筮ꆯ荂駌笼ꆱ茵馄筄ꆗ荀馀筄ꆇ荊馅筄ꆗ茽馇筈ꆏ荌馄筆ꆡ荎馅筄ꆗ荀馇笳ꆭ荐馳筩ꆄ荠馟筋ꆅ荄馨答ꇰ荼馼筫ꆷ荣馨筝ꆯ荵駳筡ꆬ茳馵笼ꆎ荂馕答ꆈ荭馥笏ꇲ荃馲筳ꆪ荔馾筮ꆜ荧馬筜ꆣ荫馷笶ꇷ荓馑笱ꆶ荠馥筍ꇭ茱駲筲ꆡ荋馄筶ꆴ荩馒筰ꆰ茵馂筇ꆷ荢駴筐ꇶ茵馨筤ꆷ荦駴等ꆖ茳馏筭ꆤ荜馩筓ꆭ荿駵策ꇌ荴馧筯ꆠ荲馊筂ꆁ荌駾筵ꆄ荳馮筵ꆵ荠馐筇ꆗ荼馰筶ꆱ茴馾笷ꇵ荦馴筀ꆁ茼馶筇ꆏ荂駳笰ꇰ荋馳筶ꆊ荧馅筜ꆤ荲馾筯ꇲ荶馷筨ꇿ荫馱筌ꇱ荼馔筇ꆃ茏馎筒ꆵ荈馒策ꆗ荪馒筌ꆪ荇馓筕ꆞ荕駰策ꆮ荓駳筶ꆐ荡馩筑ꆥ荁馢等ꆢ荖馅筂ꆂ荪馋筦ꇭ茴馬筊ꆢ茼馕筧ꆫ荷馫筈ꆨ荈馏笴ꇱ荖馔笷ꆄ荊駶筷ꇩ荁駌筏ꆞ荆馭笷ꇾ荱馕筑ꆾ荄馶筜ꆁ荓駭筜ꆇ茼馫筟ꇵ荏馒筬ꇭ荓駱筝ꆂ荬馿笰ꆅ荮馣筧ꇾ荼馥筓ꇭ荀駾筦ꆨ荡馍筗ꆵ荍駶筐ꆳ荈馫筊ꆶ荄馩筌ꆱ茰馍笏ꆎ荒馋筼ꆼ茪馉笪ꆧ荽馣筐ꆴ茼馔笳ꆠ荏馗筃ꆷ药馗筐ꆃ荎馞筍ꆾ荖駷筆ꆣ荦駭笮ꆬ茳馴笽ꇵ药馇笪ꆏ荝馫筷ꇴ荲馏筁ꆇ荔馇筇ꆋ荄駶筂ꆅ荖馷筂ꇌ荖馏筧ꇵ荁馗筀ꆄ荆馱筐ꆇ荄駲筌ꆄ荄馗筄ꆢ荿馾筒ꆮ茵駱筒ꆿ茱駶笷ꆖ荡馇策ꇾ荵馌筇ꆃ荤馾筆ꆤ茲馞笲ꆕ茵駴答ꆮ荃駱筴ꆂ茱駷筜ꆨ草馞筍ꆣ茏馤筟ꆮ茼馊筱ꆌ荡馲筧ꆕ茵馈筠ꆨ荰駰筀ꆇ茶馧筭ꆗ荝馃笱ꆗ荆馬筓ꆥ荄馯筕ꆃ荁馍笴ꆫ茮馰筶ꇶ荼馤筀ꆥ荗馉筀ꆪ荿馀筷ꆅ茵馾筭ꇾ荋馾筍ꆭ荗駌笽ꆳ荱馟筯ꆋ荟馡筭ꇶ荪馲筰ꇿ茱駾笱ꆒ荒馫筌ꆉ荊馬筬ꆯ茽馟筜ꆧ荄馰筀ꇰ草馊等ꇩ荜駾筈ꆭ茷馪筏ꇿ荍馕筵ꆢ荀馒筶ꆓ草馌筽ꆒ荦馿筧ꆌ茲馞笏ꆗ荒駰筎ꇱ荇馣筝ꆞ茽駲策ꆢ荍馶筨ꆼ茵馎筁ꆕ荨駾筄ꇳ荇馧筫ꆮ荩馳笷ꆷ荁馪筓ꇲ荄馏筀ꆾ荐馓答ꇩ荽馵筀ꆉ茵馐筧ꆠ荀駴筭ꆉ荟駵筿ꆩ茴馔筡ꇌ荑馶筜ꆃ荦馠筒ꆒ茷馣筗ꇷ荭馐筯ꆇ荴馋筎ꆷ荫馉筎ꇷ荴駭筫ꆧ荴馨筄ꆊ药駱笴ꆴ荌馎筬ꆍ荍馄筷ꆁ荖馄筡ꆾ药馎筗ꆂ荝馕筲ꆳ荇馃筳ꆜ荧首筬ꆀ茏馏笮ꆔ荐馁筎ꆔ药馭筟ꆍ荤馬筬ꆗ荧馀筧ꇵ荔馉筽ꆴ荪駰筫ꆑ荶馵筦ꆷ荦馅筳ꇩ荔馃答ꆔ荶駌笨ꇫ茨駫笨ꆃ荋馂笥ꆅ荀馔筑ꆏ荃馏筆ꆇ荑馃笨ꇫ茨駫笨ꇌ茍葉\u0d81⩸\uda02쐴\uf3aeﷇ彩茂馶筤ꆢ荡馯筫ꆡ茂馶筤ꆢ荡馯筫ꆡ茂馫筤ꆲ荦馮笵ꇾ茂馫筤ꆲ荦馮笵ꇴ茈駷笽ꇶ茫駱笳ꇨ茳駶笫ꇴ茱駲茁馊答ꇫ茻茂馫筤ꆲ荦馮笵ꇲ茂馶筤ꆢ荡馯筫ꆡ茂馫筤ꆲ荦馮笵ꇱ茂馫筤ꆲ荦馮笵ꇰ茂馶筤ꆢ荡馯筫ꆡ茂馶筤ꆢ荡馯筫ꆡ茂馶筤ꆢ荡馯筫ꆡ"};
}
public static String OooO00o(long j) {
return OooO0O0.OooO0O0(j, f8180OooO00o);
}
}
就是这里,r0 这个参数根本找不到,我们直接查看 原本 smail 代码得知,直接改成下面代码就行
ss = new String[]{"xxx字符串就省略了。。。。"};
第二个地方
package o00OO;
import com.google.common.primitives.UnsignedInts;
/* compiled from: proguard-dict.txt */
/* loaded from: classes2.dex */
public class OooO0O0 {
public static long OooO00o(int i, String[] strArr, long j) {
return (strArr[i / 8191].charAt(i % 8191) << 32) ^ OooO0OO.OooO00o(j);
}
public static String OooO0O0(long j, String[] strArr) {
long OooO00o2 = OooO0OO.OooO00o(OooO0OO.OooO0OO(UnsignedInts.INT_MASK & j));
long OooO00o3 = OooO0OO.OooO00o(OooO00o2);
int i = (int) (((j >>> 32) ^ ((OooO00o2 >>> 32) & 65535)) ^ ((OooO00o3 >>> 16) & (-65536)));
long OooO00o4 = OooO00o(i, strArr, OooO00o3);
int i2 = (int) ((OooO00o4 >>> 32) & 65535);
char[] cArr = new char[i2];
for (int i3 = 0; i3 < i2; i3++) {
OooO00o4 = OooO00o(i + i3 + 1, strArr, OooO00o4);
cArr[i3] = (char) ((OooO00o4 >>> 32) & 65535);
}
return new String(cArr);
}
}
就是 return (strArr[i / 8191].charAt(i % 8191) << 32) ^ OooO0OO.OooO00o(j);
这一行代码,会导致我们代码一直运行不成功,数组下标越界异常。
需要改成 return ((long) strArr[i / 8191].charAt(i % 8191) << 32) ^ OooO0OO.OooO00o(j);
最后一个地方
是Sign.java
package cn.lacknb.test.com.proxyqwcde.core;
import cn.lacknb.test.com.proxyqwcde.core.OooO00o;
import java.util.ArrayList;
/* compiled from: proguard-dict.txt */
/* loaded from: classes2.dex */
public class Sign {
private static final int A = 1732584193;
private static final int B = -271733879;
private static final int C = -1732584194;
private static final int D = 271733878;
private static int f(int i, int i2, int i3) {
return ((~i) & i3) | (i2 & i);
}
private static int ff(int i, int i2, int i3, int i4, int i5, int i6) {
return rotateLeft(i + f(i2, i3, i4) + i5, i6);
}
private static int g(int i, int i2, int i3) {
return (i & i3) | (i & i2) | (i2 & i3);
}
private static int gg(int i, int i2, int i3, int i4, int i5, int i6) {
return rotateLeft(i + g(i2, i3, i4) + i5 + 1518565785, i6);
}
private static int h(int i, int i2, int i3) {
return (i ^ i2) ^ i3;
}
private static int hh(int i, int i2, int i3, int i4, int i5, int i6) {
return rotateLeft(i + h(i2, i3, i4) + i5 + 1859775393, i6);
}
private ArrayList<Integer> padding(byte[] bArr) {
int length = bArr.length * 8;
ArrayList<Integer> arrayList = new ArrayList<>();
for (byte b : bArr) {
arrayList.add(Integer.valueOf(b));
}
arrayList.add(128);
while (((arrayList.size() * 8) + 64) % 512 != 0) {
arrayList.add(0);
}
for (int i = 0; i < 8; i++) {
arrayList.add(Integer.valueOf((int) ((length >>> (i * 8)) & 255)));
}
return arrayList;
}
private static int rotateLeft(int i, int i2) {
return (i >>> (32 - i2)) | (i << i2);
}
public String sign(byte[] bArr) {
ArrayList<Integer> padding = padding(bArr);
int i = A;
int i2 = B;
int i3 = C;
int i4 = D;
for (int i5 = 0; i5 < padding.size() / 64; i5++) {
int[] iArr = new int[16];
for (int i6 = 0; i6 < 16; i6++) {
int i7 = (i5 * 64) + (i6 * 4);
iArr[i6] = (padding.get(i7 + 3).intValue() << 24) | padding.get(i7).intValue() | (padding.get(i7 + 1).intValue() << 8) | (padding.get(i7 + 2).intValue() << 16);
}
int[] iArr2 = {0, 4, 8, 12};
int i8 = i;
int i9 = i2;
int i10 = i3;
int i11 = i4;
int i12 = 0;
while (i12 < 4) {
int i13 = iArr2[i12];
i8 = ff(i8, i9, i10, i11, iArr[i13], 3);
int ff = ff(i11, i8, i9, i10, iArr[i13 + 1], 7);
i10 = ff(i10, ff, i8, i9, iArr[i13 + 2], 11);
i9 = ff(i9, i10, ff, i8, iArr[i13 + 3], 19);
i12++;
i11 = ff;
}
int[] iArr3 = {0, 1, 2, 3};
int i14 = i8;
int i15 = i11;
for (int i16 = 0; i16 < 4; i16++) {
int i17 = iArr3[i16];
i14 = gg(i14, i9, i10, i15, iArr[i17], 3);
i15 = gg(i15, i14, i9, i10, iArr[i17 + 4], 5);
i10 = gg(i10, i15, i14, i9, iArr[i17 + 8], 9);
i9 = gg(i9, i10, i15, i14, iArr[i17 + 12], 13);
}
int[] iArr4 = {0, 2, 1, 3};
int i18 = i14;
int i19 = 0;
while (i19 < 4) {
int i20 = iArr4[i19];
int hh = hh(i18, i9, i10, i15, iArr[i20], 3);
i15 = hh(i15, hh, i9, i10, iArr[i20 + 8], 9);
i10 = hh(i10, i15, hh, i9, iArr[i20 + 4], 11);
i9 = hh(i9, i10, i15, hh, iArr[i20 + 12], 15);
i19++;
i18 = hh;
}
i += i18;
i2 += i9;
i3 += i10;
i4 += i15;
}
return String.format(OooO00o.OooO00o(-592855683721616730L), Integer.valueOf(i), Integer.valueOf(i2), Integer.valueOf(i3), Integer.valueOf(i4));
}
}
这里
for (int i = 0; i < 8; i++) {
arrayList.add(Integer.valueOf((int) ((length >>> (i * 8)) & 255)));
}
// 需要改成
for (int i = 0; i < 8; i++) {
arrayList.add(Integer.valueOf((int) (((long)length >>> (i * 8)) & 255)));
}
精度丢失的问题
听网上的大佬说,用 jadx 1.20 的版本 反编译就没问题了。。。(听说是 M1芯片的原因的,我用的 Mac OS M1)
最后这 sign 方法最后返回的是 String.formart()
, 一看第一个返回就是 类似于 %d 的字符串,后面都为参数
经过最后测试运行,这里的值是固定的,其实我们只需要 Sign.java 这一个类就行,最后一行的代码可以改成
return String.format("%02x%02x%02x%02x", Integer.valueOf(i), Integer.valueOf(i2), Integer.valueOf(i3), Integer.valueOf(i4));
git clone https://ghproxy.com/https://github.com/skylot/jadx.git
cd jadx
./gradlew dist
按照上面的命令编译完成后
cd build/jadx/bin
./jadx-gui
就显示了工具的图形化页面。
Java 获取 sign 的测试代码
@Test
public void signTest() {
// System.out.println(OooO00o.OooO00o(-0x83a3f1a6f4c5d5aL));
Sign sign = new Sign();
String s = sign.sign(("page=11652454733").getBytes(StandardCharsets.UTF_8));
System.out.println(s);
}
在本地搭建一个获取 sign 的接口,然后最后的 Python 计算代码
#!/usr/bin/python3
# --*-- coding: utf-8 --*--
# @Author: gitsilence
# @Time: 2022/5/14 1:02 上午
import requests
import httpx
import time
client = httpx.Client(http2=True)
time_url = "https://appmatch.yuanrenxue.com/time"
data_api_url = "https://appmatch.yuanrenxue.com/app1"
headers = {
"Host": "appmatch.yuanrenxue.com",
"User-Agent": "Mozilla/5.0 (Linux; U; Android 7.1.2; zh-cn; 22011211C Build/N6F26Q) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"
}
session = requests.session()
session.headers = headers
def get_sign(page, t):
res = requests.get(f'http://localhost:8080/getSign?t=page={page}{t}')
sign = res.text
print("sign: ", sign)
return sign
def get_time():
return session.get(time_url).json()['time']
if __name__ == '__main__':
"""
Sign(page=11652454595)
page=1&sign=dbd87f06a6486cfe545a4658de03bfed&t=1652454733
page=2&sign=30b5dcbb89424531924665a44841fe71&t=1652458800
d37e65a6dde4b59f738dee69dde0249f
"""
sum = 0
for page in range(1, 101):
t = get_time()
print("t: ", t)
data = {
"page": page,
"sign": get_sign(page, str(t)),
"t": t
}
# req_url = data_api_url + f"?page={page}&sign={get_sign(page, str(t))}&t={t}"
# print(req_url)
print(data)
res = client.post(data_api_url, headers=headers, data=data)
datas = res.json()['data']
for data in datas:
sum += int(data['value'].replace(r'\r', ''))
time.sleep(0.5)
print('sum: ', sum)
pass
本文仅限供学习参考使用
其实我也搭建 ADB 的环境,通过 jadx 远程 debug 对应代码,但是这个软件禁止了远程 debug,由于本人也是现学现做的,并没有什么好的解决办法。
那些坑还是靠网上大佬提示了下,靠我这个新手,这些坑是真的不容易过;只是为了 T恤花了好长时间做了一道题;
其他题目:
后面看了大佬们的题解,第一题的算法是 MD4 的魔改算法,有大佬用 Python 进行了还原。