程序中所有地址及数据均经过修改,不作为真实数据!仅提供分析方法!。
程序分析第一步 抓包。
请求内容类似
[color=]{"data":"nrDugWses删除一大段BdbYTixA5MQ==","handshake":"v20200610"}
返回的内容为乱码,经仔细辨认十六进制中包含
[color=]1F8B0800
,这是
[color=]gzip
格式压缩。
直接解压出来类似
[color=]{"code":200,"message":"操作成功","data":"ObzEZUE4删除一大段sJUQo0RI","handshake":"v20200610"}
可以看到来回的信息里面data都经过加密了,一看就是很火的AES加密!假如你看不出来是什么加密方式,一步步来分析他。
JADX打开app,搜索"data",发现出来200多条信息,我们换个关键词"handshake",结果只有一条。
[Java] 纯文本查看 复制代码 public static final String f26955g = "handshake";
继续以
[color=]f26955g
为关键字搜索,出来2条。我们进另外一条看看
[Java] 纯文本查看 复制代码 if (sVar.mo33077c() != 0) { String a = JSONUtil.m36637a(new JSONObject(hashMap2));
LogUtils.m14031b("===ParamsString: " + a);
hashMap.put("data", AESUtils.m40156b(a));
}
hashMap.put(AbstractC4663a.f26955g, "v20200610");
String a2 = JSONUtil.m36637a(hashMap);
LogUtils.m14031b("===realParamsJson: " + a2);
return b0Var.mo32465f().mo32478a(b0Var.mo32467h()).mo32473a(f26933d, RequestBody.m46225a(this.f26934a, String.valueOf(a2))).mo32479a();
}
上面果然出现了
[color=]"data"
,后面的
[color=]AESUtils.m40156b
就是加密函数了,CTRL再单击
[color=]m40156b
,跟进去看看:
[Java] 纯文本查看 复制代码 public static String m40156b(String str) { if (f28855c.equals("AES/ECB/NoPadding")) {
while (str.getBytes().length % 16 != 0) {
str = str + ' ';
}
}
byte[] k = EncryptUtils.m15560k(str.getBytes(), f28856d.getBytes(), f28855c, null);
return k != null ? new String(k) : "";
}
}
看到"AES/ECB/NoPadding"是不是很激动,但这不是加密方式,
[color=]f28855c
才是真正的加密方式,CTRL再单击
[color=]f28855c
[Java] 纯文本查看 复制代码 private static String f28855c = "AES/ECB/PKCS7Padding";
所以真正的加密方式是"AES/ECB/PKCS7Padding",返回再跟进
[color=]EncryptUtils.m15560k
看看:
[Java] 纯文本查看 复制代码 public static byte[] m15560k(byte[] bArr, byte[] bArr2, String str, byte[] bArr3) {
return m15513b(m15556j(bArr, bArr2, str, bArr3));
}
CTRL再单击
[color=]m15556j
[Java] 纯文本查看 复制代码 public static byte[] m15556j(byte[] bArr, byte[] bArr2, String str, byte[] bArr3) {
return m15504a(bArr, bArr2, "AES", str, bArr3, true);
}
CTRL再单击
[color=]m15504a
[Java] 纯文本查看 复制代码 private static byte[] m15504a(byte[] bArr, byte[] bArr2, String str, String str2, byte[] bArr3, boolean z) {
SecretKey secretKey;
if ("DES".equals(str)) {
secretKey = SecretKeyFactory.getInstance(str).generateSecret(new DESKeySpec(bArr2));
} else {
secretKey = new SecretKeySpec(bArr2, str);
}
Cipher instance = Cipher.getInstance(str2);
[color=]secretKey
就是密码,这一步中
[color=]str
为上面的
[color=]"AES"
,所以
[color=]bArr2
就是关键密码。
一路反推回去其实就是
[color=]EncryptUtils.m15560k(str.getBytes(), f28856d.getBytes(), f28855c, null);
中的
[color=]f28856d
。
CTRL再单击
[color=]f28856d
[Java] 纯文本查看 复制代码 private static String f28856d;
static {
String str;
if (TextUtils.equals("release", "debug")) {
str = TestUtil.getSecret2();
} else {
str = TextUtils.equals("release", "staging") ? TestUtil.getSecretPre() : TestUtil.getSecret();
}
f28856d = str;
}这一步就是判断APP是测试版还是正式版使用不同密码,随便跟一个进去,例如CTRL再单击TestUtil.getSecretPre[Java] 纯文本查看 复制代码public class TestUtil {
static {
System.loadLibrary("security");
}
public static native String getSecret();
public static native String getSecret2();
public static native String getSecret3();
public static native String getSecretPre();
public static native String getSecretVP();
}loadLibrary是调用的系统"
[color=]security
"的模块,并没法直接看到明文。继续往下分析:直接用压缩软件把app解压,文件夹中搜索
[color=]security
,出现两个
[color=]libsecurity.so
,一个在\lib\arm64-v8a中,一个在lib\armeabi-v7a。打开IDA软件,把libsecurity.so拖进去,左侧列表就出现了
[color=]Java_com_niming_weipa_utils_TestUtil_getSecret
等函数,点击进去看看,右侧窗口F5,转为JAVA代码[Java] 纯文本查看 复制代码__int64 __fastcall Java_com_niming_weipa_utils_TestUtil_getSecret(__int64 a1)
{
return (*(__int64 (__fastcall **)(__int64, const char *))(*(_QWORD *)a1 + 1336LL))(a1, "0MDQRQgYI4a9e3Zns");
}以此类推,一共有
[color=]"A7D90#83B1o6!d1F6","4rKFwocME2SIp4Anftc","E8yC1EncqQ3ZrfWQg","0MDQRQgYI4a9e3Zns"
四种密码。直接一个个试试吧。其中有一个就是密码。把所有发送请求的数据解压成明文,还是采用JSON数据,其中
[color=]list/hot
的链接返回内容直接包含视频地址,
[color=]“is_free”
标签有的是0有的是1,不知道是不是收费和免费的意思,如果是那收费的也就都可以看了。
[color=]api/user/info
链接返回的数据应该是用户信息,其中
[color=]"coins":0和"is_vip":"n"
感觉可以伪造一下数据破解一下本地VIP。留给感兴趣的同学去研究吧。
当我们再次去请求数据的时候显示认证失败!!!看来还是有坑。仔细观察发现请求的头部参数里有个
[color=]X-TOKEN: 6rb+/wSXpc删除一大段S1JJZNQ30g7RvMmNJQE
[color=](下面关于
X-TOKEN的分析有错误,正确方法见文章末尾)再仔细观察发现在
[color=]auth/login/device
链接中返回的数据中包含有
[color=]TOKEN
的参数,所以可以先请求
[color=]auth/login/device
获取
[color=]X-TOKEN
的参数后,再加到协议头里,再请求
[color=]list/hot
链接就正常了。 至此app的加密分析就结束了。
因为没找到易语言"AES/ECB/PKCS7Padding"加密解密的模块或者算法,所以就没有深入研究,也没有成品。(即使有也不可能发布的!) 如果有易语言"AES/ECB/PKCS7Padding"加密解密的模块或者算法的请分享交流,谢谢!
X-TOKEN的参数解密后数据为{"device_no":"e509-a93d-3e02-b39-205b6","device_type":"A","token":"eyJ0eXAiOiJKV1删除一大段QiLre1visa1s","version":"1.0.0"}
所以可以先请求
[color=]auth/login/device
获取
[color=]TOKEN
的参数后,替换掉上面的“
token
”参数,加密后数据给到X-TOKEN,再加到协议头里,再请求list/hot链接就正常了。邀请码得会员流程:伪造device_no(8个随机数-3个随机数-12个随机数),替换下列行中的999999999,[Asm] 纯文本查看 复制代码{"channel":"","code":"","device_no":"999999999","device_type":"A","version":"1.0.1"}加密后的数据替换下列行中的999999999,[Asm] 纯文本查看 复制代码{"data":"999999999","handshake":"v20200610"}附加协议头后发送 ***/app/api/auth/login/device,返回数据提取data数据解密,提取token数据,替换下列行中的999999999,device_no替换下列行中的88888888[Asm] 纯文本查看 复制代码{"device_no":"88888888","device_type":"A","token":"999999999","version":"1.0.1"}加密后的数据替换下列行中的999999999,[Asm] 纯文本查看 复制代码Accept-Language: zh-CN,zh;q=0.8
User-Agent: Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleDart/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17
Accept: application/json
X-TOKEN: 999999999
Content-Type: application/json; charset=utf-8
Connection: Keep-Alive
Accept-Encoding: gzip上面作为协议头,邀请码替换下行的666666作为数据[Asm] 纯文本查看 复制代码{"code":"666666"}发送**/app/api/user/bindcode返回信息提取message为“操作成功”就是成功邀请了一个账户。每邀请一个可以得3天VIP,可以累计叠加,永久会员不是梦