文件的解密入口定义在 WebViewClient中的 shouldInterceptRequest方法
在apiCloud中对应的类为 com.uzmap.pkg.uzcore.h.d 对应的方法定义如下

public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if (!this.b) {
return super.shouldInterceptRequest(view, url);
}
String d = b.d(url);
if (!b.e(d)) {
return b(url, d);
}
WebResourceResponse a = a(url, d);
return a == null ? super.shouldInterceptRequest(view, url) : a;
}

其中 this.b 的值决定了 是否使用解密
(this.b的值对应于 compile.Properties.smode() 具体可以参考 com.uzmap.pkg.uzcore.h.f.y()方法 如下

public void y() {
setNetworkAvailable(true);
d B = B();
boolean z = B.q;        ===>  这个值决定了是否进行资源文件的解密
String j = B.j();
com.uzmap.pkg.a.k.e.a((WebView) this, z);
a a = a.a(this.f);
a.a((b) this);
setWebChromeClient(a);
setWebViewClient(c.a(this.f, z, j));
this.g = new com.uzmap.pkg.uzcore.uzmodule.c(this);
this.g.a(z, j);
}

B.q的值在 com.uzmap.pkg.uzcore.b.e.a(InputStream , boolean) 和 com.uzmap.pkg.uzcore.r.y()
这里两个方法中进行设置
通过分析得出最终取决于 compile.Properties.smode()的值
当 this.b = false 时候不使用解密 即此时对应的资源文件没有加密
否则 则判断是否为 html,js,css的文件类型再进行相应的解密处理

从已知的分析来看, apicloud使用的加密算法是RC4, 而且密钥的长度为 20
只不过在不同版本中使用的RC4算法略有不同
descriptor属性为 "sdk" 或者 uz_version在 1.2.0以后的(包括1.2.0) 使用 com.uzmap.pkg.uzcore.external.Enslecb.ohs方法进行解密
这个方法在目前的分析来看使用的都是通用的RC4算法
没有uz_version属性 或者 uz_version 在 1.2.0 以前的 则使用变种的RC4算法 这个算法定义在java层 而不是在jni层
这个RC4的state大小只有20字节(通用的RC4的state大小由256字节)

关于这个的判断逻辑可以参考下边的代码逻辑(属性k为true 则调用ohs方法解密, 否则使用变种的rc4算法解密)

​
if ("sdk".equals(b.q())) {    // 这里对应的是 compile.Properties.descriptor 方法的返回值
    k = true;
    return;
}
String v = this.v.metaData.getString("uz_version");
if (!TextUtils.isEmpty(v)) {
    String[] vs = v.split("\\.");
    if (vs != null && vs.length >= 3) {
        String v1 = vs[0];
        String v2 = vs[1];
        int ver1 = Integer.valueOf(v1).intValue();
        int ver2 = Integer.valueOf(v2).intValue();
        if ((ver1 == 1 && ver2 >= 2) || ver1 > 1) {   // uz_version>=1.2.x 则 i.k = True
            k = true;
        }
    }
}
​

当然这里 ohs 的实现逻辑不一定是rc4算法
保险的话可以考虑通过 unicorn/AndroidNativeEmu/Unidbg 之类的工具来直接调用得到解密结果

对于变种的rc4算法,密钥则来源于 Enslecb.oc 方法 和 compile.Properties.cloudKey
密钥具体构造如下
1、提取compile.Properties.cloudKey 中的10个字符
如果 cloudKey 长度为10 则直接返回 ; 否则 每4个字符取前两个字符拼接成长度为10的字符串 2、Enslecb.oc() + 第1步中的字符串
对于上述的两种解密方法都涉及到对 jni的调用 而且jni里边有对apk签名的校验
签名的校验过程是:
先对apk的签名字节进行rc4加密
接着对加密的apk签名字节进行base64编码 然后对 base64字符串进行 md5 得到长度为 32 的 hex字符串最后将这个字符串与jni中的字符串常量进行比对, 相等则通过校验, 否则校验失败apk签名串的初始化过程在 Enslecb.sm 中调用 这个方法会在application的onCreate方法中先调用
所以如果使用 AndroidNativeEmu之类的工具的话需要先手动调用 Enslecb.sm 方法, 传入apk对应的签名字节
保证后续的调用能通过校验

如果觉得我的文章对你有用,可以赞助本站,使本站更好的发展