米游社接口分析记录
本次分析针对米游社 app2.6.0 版本
学逆向的基础知识的时候一般都用的爆破的方法,无非改几个跳转和 0x1,0x0 而已,每次看到别人分析算法都非常羡慕。之前早有耳闻米游社 api 接口有一个经常变动的效验字段,所以今天就索性试了试。
MT 管理器提取安装包,没有加固。
点查看,粗略看了看,代码量挺大的,所以打算先定位到签到的 activity。
用 MT 管理器的 Activity 记录功能,定位到签到的 activity 是com.mihoyo.hyperion.web.MiHoYoWebActivity(看起来并没有什么用)
还是直接入手 apk 吧,用 Dex 编辑器++打开所有的 dex(MultiDex)。
因为在网上有一些讨论,所以大概知道效验的字段叫DS,直接搜索。
找到 809 个结果,不过也没啥,明显android.xxx、com.google.xxx之类的应该没啥关系,直接看com.mihoyo.xxx的就行。不太清楚为啥 MT 管理器搜索代码的时候就不能全字匹配,不过也无所谓,人工全字匹配也罢。
简单的几次尝试可以发现找到了想要的东西 (这名字取得也是非常文艺:达摩克里斯?)。

点进去反编译之。
static{ System.loadLibrary("dddd");}public DamoclesInterceptor(){}private final native String a();private final native String a1();private final native String a11();private final native String a2();private final native String a22();private final native String a222(String str);@dpublic final native String a2222(@d String str);@dpublic e0 intercept(@d w.a aVar){ RuntimeDirector runtimeDirector = m__m; if(runtimeDirector == null || !runtimeDirector.isRedirect(0)) { k0.e(aVar, "chain"); return aVar.a(aVar.request().l().a("DS", a2222(AManager.INSTANCE.k2())).a()); } return(e0) runtimeDirector.invocationDispatch(0, this, new Object[] { aVar });}有loadLibrary的native方法,看来等下得分析分析 so 文件。
注:
loadLibrary是读取 lib 文件夹下的 libxxxx.so 文件,是用 c++之类的写的,叫做 native 编程。
先稳一手,看下下面那一串方法,我不会安卓/java 开发,不知道这个方法名字叫啥?e0 后面又有 intercept。干脆搜一下这个文件的名字DamoclesInterceptor看下调用的地方。
除了定义的地方,有两个地方调用了。

下面那个我没看懂在干什么,看上面那个。 反编译后容易看到里面的关键代码:
webViewJsCallbackBean.getData().put("DS", new DamoclesInterceptor().a2222(AManager.INSTANCE.lk2()));是在请求数据之类的?总之调用了 DamoclesInterceptor() 里面刚刚看到 native 的 a2222() 函数,传参是AManager.INSTANCE.lk2()先看下这个传参是何方神圣,翻到最上面看 import,这个 AManager 是从com.mihoyo.hyperion.manager导入的。
浏览一下这个AManage的IK2方法,看到里面的内容我笑出了声,这一大堆数字看起来貌似在告诉我它就是关键要保护的东西。
@dpublic final String lk2(){ int i; RuntimeDirector runtimeDirector = m__m; if(runtimeDirector != null && runtimeDirector.isRedirect(1)) { return(String) runtimeDirector.invocationDispatch(1, this, a.a); } int[] iArr = { -120, -14348907, 192, -6561, 192, -1594323, -6561, 192, -14348907, -112, -100, 204, -120, 156, -1594323, 180, 174, -2187, -112, -98, -14348907, -2187, -19683, 168, 186, -100, -114, -2187, -108, -59049, 204, 156 }; StringBuilder sb = new StringBuilder(); ArrayList < Number > arrayList = new ArrayList < > (iArr.length); for(int i2: iArr) { if(i2 < 0) { double d = (double) 6; i = ((double)(-i2)) >= Math.pow(3.0 d, d) ? (int)(((Math.log(-((double) i2)) / Math.log(3.0 d)) - d) + ((double) 48)) : ~i2; } else { i = (i2 / 3) + 48; } arrayList.add(Integer.valueOf(i)); } ArrayList arrayList2 = new ArrayList(y.a(arrayList, 10)); for(Number intValue: arrayList) { sb.append((char) intValue.intValue()); arrayList2.add(sb); } String sb2 = sb.toString(); k0.d(sb2, "sb.toString()"); return sb2;}不会 java,用 python 照猫画虎写了个:
from math import logiArr = [204, 180, -108, -122, -102, -118, -102, -114, -1594323, 162, -102, 174, -4782969, 210, 204, 222, -106, 204, 204, -6561, -531441, -122, 180, -6561, -59049, -108, -116, -120, 198, -104, -110, -177147]arrayList = []sb = ""for i2 in iArr: if i2 < 0: d = 6 if - i2 >= 3 ** 6: i = int((log(float(-i2)) / log(3.0) - d) + float(48)) else: i = ~i2 else: i = (i2 // 3) + 48 arrayList.append(chr(i))print("".join(arrayList))运行之,得到结果tlkyeueq7fej8vtzitt26yl24kswrgm5。
用 ida 反编译了下 so 文件发现这就是加密 DS 的salt。懒得分析后面的了,直接用别人现成的算了 (ps:现成指的是网上看到的用的是 web 的 salt,我改成安卓的 salt)。
def get_ds(): n = 'tlkyeueq7fej8vtzitt26yl24kswrgm5' #n = 'hfiki8qvnuai95p2845psdo9ydcmsrc0' #这是 web 端的 i = str(int(time.time())) r = ''.join(random.sample(string.ascii_lowercase + string.digits, 6)) c = hexdigest('salt=' + n + '&t=' + i + '&r=' + r) return '{},{},{}'.format(i, r, c)至于抓包啥啥的我就懒得搞了,知道这个 DS 怎么来就行了,万一实在没办法了就跟进 ida 看下吧,那个活儿更累嘞。