超星的接口分析了很久,分析到这个接口的时候才想到写篇博客,之前的一些接口和分析就没写下来
先开俩坑在这里,等以后再填
1.如何抓安卓APP上HTTPS的包(需ROOT)
2.如何逆向安卓APP
本次分析的接口是这个
http://data.xxt.aichaoxing.com/analysis/course/tab
参数 u=224217004&sign=task&description=%E4%BB%BB%E5%8A%A1&enc=E783557848978DAFBC36732F63E554E9&personid=243104286&classid=49650050&courseid=220816469
这个接口在课程页面点击tab切换时会被调用一次
先看参数
参数名 | 值 |
---|---|
u | 224217004 |
sign | task |
description | 任务 |
enc | E783557848978DAFBC36732F63E554E9 |
personid | 243104286 |
classid | 49650050 |
courseid | 220816469 |
根据之前抓包的内容可以得到除了enc以外的内容,再看enc长度是32位,可以猜一手MD5
反编译看下代码
反编译用了MT管理器
脱壳用了Arm Pro
都是要付费的,怎么操作就省略,相信你们都会
用MT管理器搜索接口关键字analysis/course/tab
,只搜索到一个结果,好的开头是成功的一半
点进去看下,反编译成,java代码很明显代码被混淆了,
包名都变成了单个的英文字母,先不管,试试继续分析下去
看到方法上的注解,返回参数还用了泛型,很明显是Retrofit2框架了,enc参数在这里
手机上截图有点小,把代码粘出来
@f(value="analysis/course/tab") public b<String> a( @t(value="u") String var1, @t(value="sign") String var2, @t(value="description") String var3, @t(value="enc") String var4, @t(value="personid") String var5, @t(value="classid") String var6, @t(value="courseid") String var7 );
已经找到源头,那看看哪里会调用这个接口就行了
搜索调用这个类的代码,看这个类的包名和类名方法名分别是e.g.u.h2.b、d和a
有好几个同名的重载方法,先不管,搜索smali调用的代码e/g/u/h2/b;->a
找到了20多个结果,不好办
看一下这个方法有7个String类型的参数,超过4个参数smali里面就会用invoke-interface/range
调用
用正则来搜索一下代码invoke-interface/range.*?e/g/u/h2/b/d;->a
结果没减少多少,还是有21个
不过我们知道参数有7个,看哪里有调用7个参数的方法好了,range后面大括号里的就是参数,v1-v6就是6个参数,快速找一下
还是没法找出来,不过还有别的方法,搜一下字符串任务
完全匹配,这个是抓包抓到的参数
运气不错只搜索到2个结果,看了下第一个没看出啥,看第二个,很明显对应的是课程界面的tab,里面还有接口的域名
public void run() throws Throwable { String string; String string2; if (Objects.equals("任务", this.a)) { string2 = "task"; string = "任务"; } else if (Objects.equals("章节", this.a)) { string2 = "chapters"; string = "章节"; } else if (Objects.equals("更多", this.a)) { string2 = "more"; string = "更多"; } else { string2 = ""; string = ""; } if (g.b((CharSequence)string)) { return; } String string3 = URLEncoder.encode(string, "utf-8"); string3 = b.a((b)this.f, (String)this.b, (String)string2, (String)string3, (String)this.c, (String)this.d, (String)this.e); ((d)s.a((String)"http://data.xxt.aichaoxing.com/").a(d.class)).a(this.b, string2, string, string3, this.c, this.d, this.e).a((o.d)new a(this)); }
前面的代码就是接口参数里的sign和description,string2就对应参数里的sign了,string对应参数里的description
先看这两行
String string3 = URLEncoder.encode(string, "utf-8"); string3 = b.a( (b)this.f, (String)this.b, (String)string2, (String)string3, (String)this.c, (String)this.d, (String)this.e );
看前面代码可以知道这里string是tab的名字,就是任务、章节、更多
这三个其中一个
随后对string进行了一次url编码
最后调用了b.a
方法,传入了7个参数,上下文并不存在名称为b的对象,因此可以断定b是一个类名
查看import,定位到了e.g.k.e.b
这个类
点进去查看一下
public static String a(b b2, String string, String string2, String string3, String string4, String string5, String string6) { return b2.a(string, string2, string3, string4, string5, string6); } private String a(String string, String string2, String string3, String string4, String string5, String string6) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(string5); stringBuilder.append(string6); stringBuilder.append(string3); stringBuilder.append(string4); stringBuilder.append(string2); stringBuilder.append(string); stringBuilder.append("qK`b3XjC"); return m.a((String)stringBuilder.toString()).toUpperCase(); }
调用了b2.a
方法,b2的类型是b,其实就是自身了,传递了6个参数,也就是调用了下面的a方法
可以看到就是按 5 6 3 4 2 1的顺序将参数进行拼接,最后拼上一个盐,最后调用一个m.a
方法
m.a
其实就是一个md5的方法
根据参数顺序,最后可以分析出 string3 = md5(this.e + this.d + string3 + this.c + string2 + this.b + salt)
,其中salt是一个字符串qK`b3XjC
查看代码发现下面调用了接口
((d)s.a((String)"http://data.xxt.aichaoxing.com/").a(d.class)).a(this.b, string2, string, string3, this.c, this.d, this.e).a((o.d)new a(this));
根据接口定义的参数顺序就可以得到这样一个参数对应表
变量名 | 接口参数名 |
---|---|
this.b | u |
string2 | sign |
string | description |
string3 | enc |
this.c | personid |
this.d | classid |
this.e | courseid |
那么可以得到伪代码enc = md5(classid + courseid + URLEncoder.encode(description) + personid + sign + u + salt).toUpperCase()
最后根据以上的分析,编写出对应的代码,验证分析结果
和抓包时得到的参数一致。
完美收场。