目的
个人业余项目研究(非盈利用途)
写本文目的是单纯将平台用作不限量云盘存储用途
样本版本
aHR0cHM6Ly9zai5xcS5jb20vYXBwZGV0YWlsL2NvbS5sZWlzdS5zcG9ydHM=
样本版本差异
6.5.0 版本检测反调试,但不影响静态分析。使用frida_dex_dump.js脱壳,dex文件10个
5.5.1 版本无检测反调试,但不影响静态分析。使用frida_dex_dump.js脱壳,dex文件12个
请求参数分析
:method: GET
:path: /v1/app/match/football/match_live?auth_key=1661915993-0-0-db9fd07d3adfa8310d76992ac50d126c
:authority: app-gateway.leisuapi.com
:scheme: https
ver: 5.5.1
cdid: 4f857114-41fa-3d83-bbcf-5bb1a614264d
device_id:
user-agent: leisu/5.5.1/Android/9/28/google/Pixel 3/arm64-v8a/armeabi-v7a/armeabi/10
sign: a695973cdf56ec90f64936fac29fb7b0
start: 1661912164
channel: Ali
sn: unknown
time: 1661915983
aid: 62d33b5544bc26a4
platform: 1
devicetoken: Tk9SSUQuMSNhMT****dG1RUT09
accept-encoding: gzip
主要分析参数
-
devicetoken
-
aid
-
sign
-
device_id
-
auth_key
参数纯静态分析
device_token 来源
net.security.device.api.SecurityDevice
private native SecuritySession getSessionRaw()
sign
auth_key
cdid
cdid: 4f857114-41fa-3d83-bbcf-5bb1a614264d
device_id:
user-agent: leisu/5.5.1/Android/9/28/google/Pixel 3/arm64-v8a/armeabi-v7a/armeabi/10 channel: Ali
sn: unknown
aid: 62d33b5544bc26a4
固定疑似与设备绑定
数据解密
解密入口 com.**.http.net.JsonResponseBodyConverter
private Reader decrypt(String str) {
DecryptResult decryptResult = (DecryptResult) this. gson.fromJson(str, (Class) DecryptResult.class) ;
if (decryptResult.getCode() == 1) {
String obj = decryptResult.getData().toString();
if (TextUtils.isEmpty(obj)) {
return new StringReader(str);
}
Object parse = JSON.parse(AESUtils.decrypt(Base64.decode(obj, 0), KeyConstant.Companion.m57939a()).trim(), Feature.OrderedField);
LinkedHashMap linkedHashMap = new LinkedHashMap();
linkedHashMap.put("code", 0);
linkedHashMap.put("msg", decryptResult.getMsg());
linkedHashMap.put("data", parse);
return new StringReader(this. gson.toJson(linkedHashMap));
} else if (decryptResult.getCode() <= 100 || decryptResult.getCode() > 126) {
return new StringReader(str);
} else {
String obj2 = decryptResult.getData().toString();
if (TextUtils.isEmpty(obj2)) {
return new StringReader(str);
}
String caesarDecrypt = AESUtils.caesarDecrypt(obj2, decryptResult.getCode() - 100);
C8283w.m57162b("接口凯撒解密:" + caesarDecrypt);
Object parse2 = JSON.parse(caesarDecrypt, Feature.OrderedField);
LinkedHashMap linkedHashMap2 = new LinkedHashMap();
linkedHashMap2.put("code", 0);
linkedHashMap2.put("msg", decryptResult.getMsg());
linkedHashMap2.put("data", parse2);
return new StringReader(this. gson.toJson(linkedHashMap2));
}
}
AES密钥运算
public static String CreateSkey() {
String AUTH_AES = "c4GJx$jeFK@v*P#t";
// c4GJx$jeDK@v*P#t
if (AUTH_AES.length() <= 8) {
return AUTH_AES;
}
Charset charset = Charset.forName("UTF-8");
StringBuilder sb = new StringBuilder();
String str = AUTH_AES;
int length =AUTH_AES.length() - 8;
if (str != null) {
String substring = str.substring(0, length);
sb.append(substring);
sb.append(new String("D".getBytes(charset)));
String str2 =AUTH_AES;
int length2 = AUTH_AES.length() - 7;
int length3 = AUTH_AES.length();
if (str2 != null) {
String substring2 = str2.substring(length2, length3);
sb.append(substring2);
return sb.toString();
}
}
return "";
}
凯撒解密
package com.leisux;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.zip.GZIPInputStream;
public class Leisux {
public static String decrypt(byte[] bArr, String sKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Charset charset = Charset.forName("UTF-8");
SecretKeySpec skeySpec = new SecretKeySpec(sKey.getBytes(charset), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
// System.out.println("Base64 decoded: "+Base64.decode(encData.getBytes()).length);
byte[] original = cipher.doFinal(bArr);
return new String(original, Charset.defaultCharset()).trim();
}
public static String CreateSkey() {
String AUTH_AES = "c4GJx$jeFK@v*P#t";
// c4GJx$jeDK@v*P#t
if (AUTH_AES.length() <= 8) {
return AUTH_AES;
}
Charset charset = Charset.forName("UTF-8");
StringBuilder sb = new StringBuilder();
String str = AUTH_AES;
int length =AUTH_AES.length() - 8;
if (str != null) {
String substring = str.substring(0, length);
sb.append(substring);
sb.append(new String("D".getBytes(charset)));
String str2 =AUTH_AES;
int length2 = AUTH_AES.length() - 7;
int length3 = AUTH_AES.length();
if (str2 != null) {
String substring2 = str2.substring(length2, length3);
sb.append(substring2);
return sb.toString();
}
}
return "";
}
public static final String caesarDecrypt(String sb) {
String str;
byte[] decode = Base64.decode(sb, 0);
byte[] uncompress = uncompress(decode);
try {
if (uncompress != null) {
Charset defaultCharset = Charset.defaultCharset();
str = new String(uncompress, defaultCharset);
} else if (decode != null) {
Charset defaultCharset2 = Charset.defaultCharset();
str = new String(decode, defaultCharset2);
} else {
str = null;
return str;
}
return str;
} catch (Exception unused) {
return "";
}
}
public static byte[] uncompress(byte[] bArr) {
if (bArr == null) {
return null;
}
if (bArr.length == 0) {
return null;
}
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
GZIPInputStream gZIPInputStream = new GZIPInputStream(new ByteArrayInputStream(bArr));
byte[] bArr2 = new byte[256];
while (true) {
int read = gZIPInputStream.read(bArr2);
if (read < 0) {
return byteArrayOutputStream.toByteArray();
}
byteArrayOutputStream.write(bArr2, 0, read);
}
} catch (Exception unused) {
return null;
}
}
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
StringBuilder sbs = new StringBuilder();
String data = sbs.toString();
System.out.println(data);
Integer code = 118; // json中的code
String sb = Carser.decrypt(data, code-100); // 重组base64
String s = caesarDecrypt(sb);
System.out.println(s);
}
}