前言
我又来了。今天的主角是某浪新闻APP
工具
- fiddler(抓包工具)
- Drony(习惯用了,不用去手机设置里面填写代{过}{滤}理地址和端口。。)
- jadx-gui(反编译app)
- root环境(我这是另类的分析,要用到hook)
- e4a(java小白,只能用这个编写xposed模块了)
0x1 抓包
fiddler下关键词sendsms
断点(省的浪费人家的短信额度。。。)
分别用2个不同的后机会抓2次包,分析不同的信息。
mobile |
GAuth |
SN-REQID |
15600000000 |
newsapp:1629519735:5be3ae91fd334a78b91d893d0de7853b:46100b5f78fd8ad4163a10da7ce7f9bd9cc24953fadf732795b65544f91b553b |
162951973462938c4670a9754 |
15699999999 |
newsapp:1629519762:483b210ec35f4e4090ab4ccc8f147ee2:1c7eacc96f5bbe42f6e0ccff425efadef0b82e28a17f71124304bb2bfad6dab4 |
162951976242538c4670a1271 |
经测试,协议头不带SN-REQID可以正常发送,但是不带GAuth下发就会失败。
所以接下来分析GAuth的值是怎么得来的
0x2 分析+hook
jadx-gui
搜"GAuth"
打开jadx,分析app,搜索"GAuth"
,一共3处调用。
(无用功)查看第一处调用
我们先看第一处调用:
addRequestHeader("GAuth", HttpSignUtils.e("newsapp", serverTime, UUID.randomUUID().toString().replaceAll("\\-", "")));
右键跳到HttpSignUtils.e
HttpSignUtils.e
public static String e(String str, long j, String str2) {
if (SNTextUtils.f(str)) {
str = "newsapp";
}
return str + ":" + j + ":" + str2 + ":" + HttpSignHelper.financeSecretKey2(str2, j);
}
HttpSignHelper.financeSecretKey2
public static native String financeSecretKey2(String str, long j);
竟然是native,需要分析so文件。。那我这能力,我直接就放弃了。。
查看第二处调用
addRequestHeader("GAuth", HttpSignUtils.e(str, j, replaceAll));
/* 全文是下面这样的 */
public void addThirdAppSignHeader(String str, long j, boolean z) {
String replaceAll = UUID.randomUUID().toString().replaceAll("\\-", "");
if (z) {
addRequestHeader("GAuth", HttpSignUtils.e(str, j, replaceAll));/* 如果z为true */
} else {
addRequestHeader("GAuth", HttpSignUtils.d(str, j, replaceAll));/* 如果z为false */
}
addRequestHeader("User-Agent", ApiManager.f().e().p());
addRequestHeader("DeviceId", ApiManager.f().e().c());
}
我们可以通过xposed模块hook,把addThirdAppSignHeader的参数z设置为false,让其执行HttpSignUtils.d函数
HttpSignUtils.d
看样子 就是str:j:str2:g(str2 + j,a.get(str))
public static String d(String str, long j, String str2) {
if (SNTextUtils.f(str)) {
str = "newsapp";
}
StringBuilder sb = new StringBuilder();
sb.append(str);
sb.append(":");
sb.append(j);
sb.append(":");
sb.append(str2);
sb.append(":");
sb.append(g((str2 + j).getBytes(), a.get(str).getBytes()));
return sb.toString();
}
str |
j |
str2 |
本次为'newsapp' |
十位时间戳 |
randomUUID替换'-'为'' |
'newsapp' |
十位时间戳 |
UUID.randomUUID().toString().replaceAll("\-", "") |
a
这个a.get(str),就是取出hashMap中'newsapp'的值,也就是f()
a = hashMap;
hashMap.put("newsapp", f());
这个f()应该也是通过so得出的,技术有限,所以不分析他了。直接从g加密函数入手,hook出明文和秘钥。
g
HmacSHA256加密操作,bArr为明文,bArr2为秘钥
private static synchronized String g(byte[] bArr, byte[] bArr2) {
SecretKeySpec secretKeySpec = new SecretKeySpec(bArr2, "HmacSHA256");
Mac instance = Mac.getInstance("HmacSHA256");
instance.init(secretKeySpec);
return a(instance.doFinal(bArr));
}
易安卓写hook g
XposedHelpers.findAndHookMethod("com.XXX.XXXX.HttpSignUtils", lpparam.classLoader, "g" , byte[].class , byte[].class , new XC_MethodHook() //g(byte[] bArr, byte[] bArr2) {
{
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("某浪新闻 g【HmacSHA256加密】参数1--->> " + 转换操作.字节到文本((byte[])param.args[0],"utf-8"));
XposedBridge.log("某浪新闻 g【HmacSHA256加密】参数2--->> " + 转换操作.字节到文本((byte[])param.args[1],"utf-8"));
}
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("某浪新闻 g【HmacSHA256加密】结果--->> " + (String)param.getResult());
}
});
拿到明文和秘钥、加密结果
(PS:经过多次测试,秘钥为固定值。所以可以直接编写GAuth值的构造程序)
多次测试
(PS:经过测试,uuid的值为任意数均可,不影响)
0X3 易语言模拟
0x4 最后的建议
增加人机验证,比如图片验证码或者是滑块验证码等方式,加大破解的难度