超星學習通逆向介面引數加密分析 - 課程頁面切換tab介面
超星的介面分析了很久,分析到這個介面的時候才想到寫篇部落格,之前的一些介面和分析就沒寫下來
先開倆坑在這裡,等以後再填
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個結果,lucky,看了下第一個沒看出啥,看第二個,很明顯對應的是課程介面的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
先看這兩行
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()
最後根據以上的分析,編寫出對應的程式碼,驗證分析結果
和抓包時得到的引數一致。
完美收場。