前言
分析算法,这个事情...我发现了。是真上瘾...
(PS:从某米应用商店下载了一整页的APP...)
工具
-
fiddler(抓网络数据包用)
-
jadx-gui(APP反编译用)
-
易语言(复现用)
-
算法助手(可用也可不用,xp模块,需root使用)
0x1 抓包
直接手机设置代{过}{滤}理,打开APP,竟然能抓到数据包。【也可以用Drony端口转发抓包、小黄鸟等】
登录下发验证码的接口为/v3/getVerCode.msp
,codeParam值为32位长度,猜测是md5加密
还有另外一个/v3/getVericodek.msp
的接口返回的内容为json格式
复制代码 隐藏代码{"resultMsg":"请求成功","resultCode":"1","vericodek":"f2G8x42F57UT"}
0x2 分析
jadx搜接口(不用助手)
直接搜/v3/getVericodek.msp
找到cn.thepaper.paper.ui.mine.registerNew.b
类中的a函数。
查看调用堆栈(用助手)
直接上算法助手搜fiddler数据中codeParam值6280CE5F15B9BCC2CD0AA9C73D0A3046
,出现一条数据记录
复制代码 隐藏代码明文为F028407907FB062579FEE0D33D155F94C27D4A1DBB53F4DC33402F13BE590D7175FFB8EBB425208A1CB86F151398D955
但是好像并没有再助手和fiddler中搜到相关的数据,猜测明文也是经过处理的,我们看调用堆栈。
找到cn.thepaper.paper.ui.mine.registerNew.b
类中的a函数。
复制代码 隐藏代码public void a(String str, String str2, String str3, String str4, String str5) {
String str6;
String str7;
if (TextUtils.isEmpty(str5)) {
str6 = str3 + "0000";
str7 = "0000";
} else {
str6 = str3 + str5;
str7 = str5;
}
this.f2371c.a(str, str2, str7, EncryptUtils.encryptMD5ToString(EncryptUtils.encryptAES2HexString(("verType=" + str + "mail=" + str2 + "gCode=" + str7).getBytes(), str6.getBytes())), str4).a(new c<BaseInfo>() {
/* 此处省略N多处理代码 */ });
}
简单看一下,根据fiddler的参数,可以得出"verType=" + str + "mail=" + str2 + "gCode=" + str7
中
str | str2 | str7 |
---|---|---|
a函数的参数1 | 手机号 | 变量str7 |
6 | 18396555555 | 0000 |
查看哪里调用a函数
在a函数处右键,查找用例。有很多,但是根据上门的a函数的第一个参数str=6,可找到本次调用的位置。
双击进去查看。
复制代码 隐藏代码public void t(View view) {
if (!cn.thepaper.paper.lib.c.a.a(view)) {
if (!PaperApp.isNetConnected()) {
ToastUtils.showShort((int) R.string.network_fail);
return;
}
cn.thepaper.paper.lib.b.a.a("294");
String trim = this.e.getText().toString().trim();
this.w = trim;
if (!RegexUtils.isMobileSimple(trim)) {
ToastUtils.showShort((int) R.string.phone_incorrect);
return;
}
String str = this.v;
if (str == null || str.length() != 12) {
this.r.d();
return;
}
this.r.a("6", this.w, this.v, "1", "");/* 此处为调用a函数 */ this.g.requestFocus();
m(this.g);
}
}
由上述f函数的代码可得出a函数所有的参数(String str, String str2, String str3, String str4, String str5)
str | str2 | str3 | str4 | str5 |
---|---|---|---|---|
a函数的参数1 | this.w=手机号 | this.v | 变量str4 | 变量str5 |
6 | 18396555555 | 未知 | 1 | '' |
出现一个未知的this.v ,既然有调用,那就肯定有赋值,我们再右键查this.v的查找用例
果然找到一个,
复制代码 隐藏代码this.v = vericodek.getVericodek();public String getVericodek() {
return this.vericodek;
}
this.vericodek这不巧了吗这不是,这不就是/v3/getVericodek.msp
中得到的吗?
又根据
复制代码 隐藏代码if (TextUtils.isEmpty(str5)) {
str6 = str3 + "0000";
str7 = "0000";
} else {
str6 = str3 + str5;
str7 = str5;
}
str5为空,所以得出:
复制代码 隐藏代码str6 = str3 + "0000";str7 = "0000";
str | str2 | str3 | str4 | str5 | str6 | str7 |
---|---|---|---|---|---|---|
a函数的参数1 | this.w=手机号 | this.v=getVericodek.msp中的vericodek | 变量str4 | 变量str5 | str6=str3+"0000" | str7="0000" |
6 | 18396555555 | f2G8x42F57UT | 1 | '' | f2G8x42F57UT0000 | 0000 |
得出所有参数和变量之后,查看处理过程,现实encryptAES2HexString,然后再用encryptMD5ToString。(PS:那就是先AES加密,在用MD5加密,得出的6280CE5F15B9BCC2CD0AA9C73D0A3046
)
分析
明文经过处理,得到md5值
复制代码 隐藏代码EncryptUtils.encryptAES2HexString(("verType=" + str + "mail=" + str2 + "gCode=" + str7).getBytes(), str6.getBytes())
也就等于
复制代码 隐藏代码EncryptUtils.encryptAES2HexString(("verType=" + "6" + "mail=" + "18396555555" + "gCode=" + "0000").getBytes(), str6.getBytes())
先看encryptAES2HexString
复制代码 隐藏代码public static String encryptAES2HexString(byte[] bArr, byte[] bArr2) {
return bytes2HexString(encryptAES(bArr, bArr2));/* 看样子应该是AES加密,编码为hex而不是base64 */}
再看下encryptAES
复制代码 隐藏代码private static final String AES_Algorithm = "AES";
public static String AES_Transformation = "AES/ECB/PKCS5Padding";
public static byte[] encryptAES(byte[] bArr, byte[] bArr2) {
return desTemplate(bArr, bArr2, AES_Algorithm, AES_Transformation, true);/* AES_Algorithm= */ }
public static byte[] desTemplate(byte[] bArr, byte[] bArr2, String str, String str2, boolean z) {
if (!(bArr == null || bArr.length == 0 || bArr2 == null || bArr2.length == 0)) {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(bArr2, str);
Cipher instance = Cipher.getInstance(str2);
instance.init(z ? 1 : 2, secretKeySpec, new SecureRandom());
return instance.doFinal(bArr);
} catch (Throwable th) {
th.printStackTrace();
}
}
return null;
}
由desTemplate可得出AES/ECB算法参1为明文,参2为秘钥
所以用在线AES加密网站测试
加密结果为:F028407907FB062579FEE0D33D155F94C27D4A1DBB53F4DC33402F13BE590D7175FFB8EBB425208A1CB86F151398D955
再MD5结果为:6280CE5F15B9BCC2CD0AA9C73D0A3046
,正好是fiddler里面的codeParam值
0x3 需要注意的事项
-
秘钥的一部分this.v=f2G8x42F57UT 并不是固定的,而是每一次下发验证码之前就要先获取的,
-
AES加密的结果中的字母必须为大写,小写的话直接MD5,结果会不一样哦
-
请求的时候,记得要添加协议头哦,要不然的话会提示
没找到uuid
0x4 易语言实现下发短信
因为vericodek不一样,所以易语言之后的codeParam值也和之前fiddler抓到的不一样了。
本文始发于微信公众号(网络侦查研究院):某湃新闻APP之登录验证码下发短信分析
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论