本次分析针对米游社 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);
@d
public final native String a2222(@d String str);
@d
public 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
方法,看到里面的内容我笑出了声,这一大堆数字看起来貌似在告诉我它就是关键要保护的东西。
@d
public 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 log
iArr = [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 看下吧,那个活儿更累嘞。