本帖最后由 spcspcspcspcspc 于 2021-3-9 14:12 编辑
还是先感谢热心网友分享的APP,这几天有空就又出了一篇帖子,和上篇的思路基本相同。
程序中所有地址及数据均经过修改,不作为真实数据!仅提供分析方法!。
程序分析第一步 抓包。
请求内容类似{"data":"nrDugWses删除一大段BdbYTixA5MQ==","handshake":"v20200610"}
返回的内容为乱码,经仔细辨认十六进制中包含1F8B0800,这是gzip格式压缩。
直接解压出来类似{"code":200,"message":"操作成功","data":"ObzEZUE4删除一大段sJUQo0RI","handshake":"v20200610"}
可以看到来回的信息里面data都经过加密了,一看就是很火的AES加密!假如你看不出来是什么加密方式,一步步来分析他。
JADX打开app,搜索"data",发现出来200多条信息,我们换个关键词"handshake",结果只有一条。
[Java] 纯文本查看 复制代码 public static final String f26955g = "handshake";
继续以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();
}
上面果然出现了"data",后面的AESUtils.m40156b就是加密函数了,CTRL再单击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"是不是很激动,但这不是加密方式,f28855c才是真正的加密方式,CTRL再单击f28855c
[Java] 纯文本查看 复制代码 private static String f28855c = "AES/ECB/PKCS7Padding";
所以真正的加密方式是"AES/ECB/PKCS7Padding",返回再跟进EncryptUtils.m15560k看看:
[Java] 纯文本查看 复制代码 public static byte[] m15560k(byte[] bArr, byte[] bArr2, String str, byte[] bArr3) {
return m15513b(m15556j(bArr, bArr2, str, bArr3));
}
CTRL再单击m15556j
[Java] 纯文本查看 复制代码 public static byte[] m15556j(byte[] bArr, byte[] bArr2, String str, byte[] bArr3) {
return m15504a(bArr, bArr2, "AES", str, bArr3, true);
}
CTRL再单击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);
secretKey就是密码,这一步中str为上面的"AES",所以bArr2就是关键密码。
一路反推回去其实就是EncryptUtils.m15560k(str.getBytes(), f28856d.getBytes(), f28855c, null);中的f28856d。
CTRL再单击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是调用的系统"security"的模块,并没法直接看到明文。 继续往下分析:直接用压缩软件把app解压,文件夹中搜索security,出现两个libsecurity.so,一个在\lib\arm64-v8a中,一个在lib\armeabi-v7a。 打开IDA软件,把libsecurity.so拖进去,左侧列表就出现了Java_com_niming_weipa_utils_TestUtil_getSecret等函数,点击进去看看,右侧窗口F5,转为JAVA代码[Java] 纯文本查看 复制代码 __int64 __fastcall Java_com_niming_weipa_utils_TestUtil_getSecret(__int64 a1)[/font][/font]
{
return (*(__int64 (__fastcall **)(__int64, const char *))(*(_QWORD *)a1 + 1336LL))(a1, "0MDQRQgYI4a9e3Zns");
} 以此类推,一共有"A7D90#83B1o6!d1F6","4rKFwocME2SIp4Anftc","E8yC1EncqQ3ZrfWQg","0MDQRQgYI4a9e3Zns"四种密码。 直接一个个试试吧。其中有一个就是密码。 把所有发送请求的数据解压成明文,还是采用JSON数据, 其中list/hot的链接返回内容直接包含视频地址,“is_free”标签有的是0有的是1,不知道是不是收费和免费的意思,如果是那收费的也就都可以看了。 api/user/info链接返回的数据应该是用户信息,其中"coins":0和"is_vip":"n"感觉可以伪造一下数据破解一下本地VIP。 留给感兴趣的同学去研究吧。
当我们再次去请求数据的时候显示认证失败!!!看来还是有坑。 仔细观察发现请求的头部参数里有个X-TOKEN: 6rb+/wSXpc删除一大段S1JJZNQ30g7RvMmNJQE (下面关于X-TOKEN的分析有错误,正确方法见文章末尾) 再仔细观察发现在auth/login/device链接中返回的数据中包含有TOKEN的参数, 所以可以先请求auth/login/device获取X-TOKEN的参数后,再加到协议头里,再请求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"}
所以可以先请求auth/login/device获取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,可以累计叠加,永久会员不是梦
|