Open Bpazy opened 5 years ago
最近在研究微爱这款应用的请求时,发现每一条请求都携带了sig这个参数,并且sig随着每一次登录都会变化,不同的行为触发的HTTP请求所携带的sig也都不相同。
微爱
sig
图片中的sig是经过URLEecode的,我把他Decode一下得到gO5EnwNaGxqEWk/uyGWQn6+sktk=。
gO5EnwNaGxqEWk/uyGWQn6+sktk=
这显然就是一个经过了Base64编码的字符串,但在对该字符串Base64解码的时候发现结果是乱码,这说明该串是被加密的。
这里我注意到sig是28位的base64,所以我猜测是不是对某些字符串做了MD5的16位编码之后再base64编码,测试了几个字符串结果都与sig不同,只能作罢。
base64
MD5
要弄明白加密算法是什么,只剩下了一条路,反编译APK并分析了。
把手机上的APK com.welove520.welove.apk 拷贝到电脑中,使用dex2jar:
com.welove520.welove.apk
d2j-dex2jar.bat com.welove520.welove.apk
得到com.welove520.welove-dex2jar.jar,接着使用JD-GUI就可以查看jar的代码了,因为被混淆过,所以阅读非常困难。
com.welove520.welove-dex2jar.jar
要想从茫茫的被混淆代码中找到自己需要的,是不可能的事情,所以只能另辟蹊径。
打开Android Studio,打开logcat,把手机连上电脑,选择监视welove的log信息,随意在APP中做一些操作,观察logcat窗口,果然出现了有效的信息。
Android Studio
logcat
welove
log
这里包含了SigUtils,相比这是生成sig的类吧,在代码中搜索SigUtils和sig,发现sig注入的代码块和SigUtils的逻辑: 具体算法则在com.welove520.welove.l.e.a(String, String, Map)方法中,查看之:
SigUtils
com.welove520.welove.l.e.a(String, String, Map)
public static String a(String paramString1, String paramString2, Map<String, String> paramMap) { return encode(paramString1, paramString2, sloveMapData(paramString1, paramString2, paramMap).getBytes()); } public static String encode(String paramString1, String paramString2, byte[] paramArrayOfByte) { try { paramString1 = Mac.getInstance("HmacSHA1"); paramString1.init(new SecretKeySpec("8b5b6eca8a9d1d1f".getBytes(), "HmacSHA1")); paramString1 = Base64.encodeToString(paramString1.doFinal(paramArrayOfByte), 0).replaceAll("\r", "").replaceAll("\n", "").trim(); return paramString1; } catch (NoSuchAlgorithmException paramString1) { Log.e("SigUtils:", String.valueOf(paramString1.toString())); return ""; } catch (InvalidKeyException paramString1) { for (;;) { Log.e("SigUtils:", String.valueOf(paramString1.toString())); } } }
找到加密的算法了! HmacSHA1,且密钥是写死在代码中的8b5b6eca8a9d1d1f,接下来找到被加密的字段就可以了,还是在这个被混淆的类中:
HmacSHA1
8b5b6eca8a9d1d1f
private static String sloveMapData(String paramString1, String paramString2, Map<String, String> paramMap) { Object localObject = new String[paramMap.size()]; paramString2 = new StringBuilder(paramString2); StringBuilder localStringBuilder = new StringBuilder(); LinkedHashMap localLinkedHashMap = new LinkedHashMap(); Iterator localIterator = paramMap.entrySet().iterator(); int i = 0; while (localIterator.hasNext()) { localObject[i] = ((String)((Map.Entry)localIterator.next()).getKey()); i += 1; } Arrays.sort((Object[])localObject, String.CASE_INSENSITIVE_ORDER); int j = localObject.length; i = 0; while (i < j) { localIterator = localObject[i]; localLinkedHashMap.put(localIterator, a((String)paramMap.get(localIterator))); i += 1; } paramMap = localLinkedHashMap.entrySet().iterator(); while (paramMap.hasNext()) { localObject = (Map.Entry)paramMap.next(); localStringBuilder.append((String)((Map.Entry)localObject).getKey()).append("=").append((String)((Map.Entry)localObject).getValue()).append("&"); } paramString2.append("&").append(a(paramString1)).append("&").append(a(localStringBuilder)); Log.d("SigUtils", "SigUtils#" + paramString2.toString()); return paramString2.toString(); }
配合Logcat信息了解到加密的字段是{GET|POST}&{url}&{content}并且url和content都是经过Base64编码的,POST、url 都是固定的,content则是请求的信息出除去sig字段,对这一构造得到的字符串进行HmacSHA1加密之后再进行Base64编码就是请求中需要的sig了!!
Logcat
{GET|POST}&{url}&{content}
url
content
Base64
POST
这里有一个坑就是Java自带的Base64编码的的结果是小写的,比如=编码之后是%3d,而微爱请求的则是%3D,这里需要转换大小写。
=
%3d
%3D
测试一下算法是否正确(我在这里使用了Golang):
package main import ( "crypto/hmac" "crypto/sha1" "encoding/base64" "fmt" "net/url" ) func main() { key := []byte("8b5b6eca8a9d1d1f") mac := hmac.New(sha1.New, key) method := "POST" u := "http://api.welove520.com/v1/game/house/home" content := "access_token=562949961343086-*****9974dd0&love_space_id=8444*****15867" mac.Write([]byte(method + "&" + url.QueryEscape(u) + "&" + url.QueryEscape(content))) result := mac.Sum(nil) s := base64.StdEncoding.EncodeToString(result) fmt.Println(s) }
执行得到的sig为gO5EnwNaGxqEWk/uyGWQn6+sktk=
与Fiddler截包获得的sig一致:
access_token=562949961343086-*****9974dd0&love_space_id=8444*****15867&sig=gO5EnwNaGxqEWk%2FuyGWQn6%2Bsktk%3D
只不过这里的sig也经过了URLEncode。
有了sig就方便各种模拟HTTP请求了。
感谢提供思路,不过新版似乎换了皮,secret也换了 http://imtt.dd.qq.com/16891/apk/6A6B1EFDB16F6ABE1756386BEF5C1448.apk?fsname=com.welove520.qqsweet_3.1.2_53.apk&hsr=4d5s
最近在研究
微爱
这款应用的请求时,发现每一条请求都携带了sig
这个参数,并且sig
随着每一次登录都会变化,不同的行为触发的HTTP请求所携带的sig也都不相同。图片中的
sig
是经过URLEecode的,我把他Decode一下得到gO5EnwNaGxqEWk/uyGWQn6+sktk=
。这显然就是一个经过了Base64编码的字符串,但在对该字符串Base64解码的时候发现结果是乱码,这说明该串是被加密的。
这里我注意到
sig
是28位的base64
,所以我猜测是不是对某些字符串做了MD5
的16位编码之后再base64
编码,测试了几个字符串结果都与sig
不同,只能作罢。要弄明白加密算法是什么,只剩下了一条路,反编译APK并分析了。
把手机上的APK
com.welove520.welove.apk
拷贝到电脑中,使用dex2jar:得到
com.welove520.welove-dex2jar.jar
,接着使用JD-GUI就可以查看jar的代码了,因为被混淆过,所以阅读非常困难。要想从茫茫的被混淆代码中找到自己需要的,是不可能的事情,所以只能另辟蹊径。
打开
Android Studio
,打开logcat
,把手机连上电脑,选择监视welove
的log
信息,随意在APP中做一些操作,观察logcat
窗口,果然出现了有效的信息。这里包含了
SigUtils
,相比这是生成sig的类吧,在代码中搜索SigUtils
和sig
,发现sig
注入的代码块和SigUtils
的逻辑: 具体算法则在com.welove520.welove.l.e.a(String, String, Map)
方法中,查看之:找到加密的算法了!
HmacSHA1
,且密钥是写死在代码中的8b5b6eca8a9d1d1f
,接下来找到被加密的字段就可以了,还是在这个被混淆的类中:配合
Logcat
信息了解到加密的字段是{GET|POST}&{url}&{content}
并且url
和content
都是经过Base64
编码的,POST
、url
都是固定的,content则是请求的信息出除去sig
字段,对这一构造得到的字符串进行HmacSHA1
加密之后再进行Base64
编码就是请求中需要的sig
了!!这里有一个坑就是Java自带的
Base64
编码的的结果是小写的,比如=
编码之后是%3d
,而微爱
请求的则是%3D
,这里需要转换大小写。测试一下算法是否正确(我在这里使用了Golang):
执行得到的
sig
为gO5EnwNaGxqEWk/uyGWQn6+sktk=
与Fiddler截包获得的
sig
一致:只不过这里的
sig
也经过了URLEncode。有了
sig
就方便各种模拟HTTP请求了。