淘宝系MtopSDK逆向分析(一)
经过上一篇文章分析ANetwork框架的基础运行方式后,本篇文章准备分析一下MtopSDK的初始化流程,如果大家还不知道Mtop在移动端App里面干啥的建议先读一下[《移动API网关》](https://user-gold-cdn.xitu.io/2019/10/4/16d943874737b715)这篇文章简单了解MtopSDK。
话不多说,直接开始分析先将文件定位到`Lmtopsdk/mtop/intf/Mtop;`这个类上:
```
.field protected static final instanceMap:Ljava/util/Map;
.field final initTask:Lmtopsdk/mtop/global/init/IMtopInitTask;
.field volatile instanceId:Ljava/lang/String;
.field final mtopConfig:Lmtopsdk/mtop/global/MtopConfig;
```
里面有几个重要的实例属性:
* instanceMap(存放Mtop实例的)
* initTask(初始化任务)
* instanceId(实例ID可能为: OPEN、INNER、PRODUCT)
* mtopConfig(MTOP配置信息)
那Mtop这个类是如何构造的呢?细看之下会发现Mtop只有一个私有的构造方法:
```
.method private constructor <init>(Ljava/lang/String;Lmtopsdk/mtop/global/MtopConfig;)V
```
翻译成Java代码大概就是这样:
```java
private Mtop(String instancceId, MtopConfig config){
...
}
```
MtopConfig稍后再来分析,再继续往下分析Mtop类还有个私有init方法和几个静态instance的方法:
```
.method private declared-synchronized init(Landroid/content/Context;Ljava/lang/String;)V
.method public static instance(Landroid/content/Context;)Lmtopsdk/mtop/intf/Mtop;
.method public static instance(Landroid/content/Context;Ljava/lang/String;)Lmtopsdk/mtop/intf/Mtop;
.method public static instance(Ljava/lang/String;Landroid/content/Context;)Lmtopsdk/mtop/intf/Mtop;
.method public static instance(Ljava/lang/String;Landroid/content/Context;Ljava/lang/String;)Lmtopsdk/mtop/intf/Mtop;
```
因为init方法是个私有的,不太可能从外部调用,所以直接先看下几个instance方法。虽然instance有好几个重载形式,但最终都还是调用的`instance(Ljava/lang/String;Landroid/content/Context;Ljava/lang/String;)`,简单的翻译成Java代码如下:
```java
public static instance(Context ctx){
instanec(ctx, null, null);
}
public static instance(Context ctx,String ttid){
instanec(null, ctx, ttid);
}
public static instance(String instanceId, Context ctx){
instanec(instanceId, ctx, null);
}
public static instance(String instanceId, Context ctx,String ttid){
}
```
知道最终的走向后,咱们就直接分析第四个instance方法就行啦,smali代码就不贴了直接转成Java方便阅读:
```java
public static instance(String instanceId, Context ctx,String ttid){
if(instanceId == null){
instanceId = "INNER";
}
Mtop mtop = instanceMap.get(instanceId); //获取mtop实例
if(mtop == null){
synchronized (Mtop.class){
mtop = instanceMap.get(instanceId); //获取mtop实例
if(mtop == null){
Map<String, MtopConfig> mtopConfigs = MtopSetting.mtopConfigMap;
MtopConfig config= mtopConfigs.get(instanceId);
if(config == null){
config = new MtopConfig(instanceId);
}
mtop = new MTop(instanceId, config);
config.mtopInstance = mtop;
//MtopSetting.mtopConfigMap.put(instanceId, config);
instanceMap.put(instanceId, mtop);
}
}
}
if(mtop.isInit){
return mtop;
}
mtop.init(ctx,ttid);
return mtop;
}
```
上面的instance方法差不多就是创建Mtop实例、调用init方法,所以再来看一个Mtop的构造方法:
```
.method private constructor <init>(Ljava/lang/String;Lmtopsdk/mtop/global/MtopConfig;)V
...
iput-object p2, p0, Lmtopsdk/mtop/intf/Mtop;->mtopConfig:Lmtopsdk/mtop/global/MtopConfig;
invoke-static {p1}, Lmtopsdk/mtop/global/init/MtopInitTaskFactory;->getMtopInitTask(Ljava/lang/String;)Lmtopsdk/mtop/global/init/IMtopInitTask;
move-result-object v0
iput-object v0, p0, Lmtopsdk/mtop/intf/Mtop;->initTask:Lmtopsdk/mtop/global/init/IMtopInitTask;
....
.end method
```
Mtop构造方法做了一些实例属性的初始化工作,需要注意的是`initTask`这个实例属性的获取是从`MtopInitTaskFactory`里面获取的,跟过去看一下,是如何获取`IMtopInitTask`的实例的:
```java
public static IMtopInitTask getMtopInitTask(String instanceId){
switch{
case "INNER":
default:
return InnerMtopInitTask();
case "OPEN":
returnn OpenMtopInitTask();
case "PRODUCT":
return ProductMtopInitTask();
}
}
```
大概意思就是通过不同的`instancceId`获取对应的初始化任务。
有了`IMtopInitTask`实例后在哪里执行呢?继续分析Mtop的init方法会发现有一段运行`IMtopInitTask`的代码:
```
new-instance v0, Lmtopsdk/mtop/intf/Mtop$1;
invoke-direct {v0, p0}, Lmtopsdk/mtop/intf/Mtop$1;-><init>(Lmtopsdk/mtop/intf/Mtop;)V
invoke-static {v0}, Lmtopsdk/mtop/util/MtopSDKThreadPoolExecutorFactory;->submit(Ljava/lang/Runnable;)Ljava/util/concurrent/Future;
```
在分析`IMtopInitTask`的几个实现类之前,先去分析一下比较重要的类:`MtopSetting`,看名字知道专门用来配置Mtop和MtopConfig的,它有个静态属性和几个方法来设置一些配置:
```
protected static final Map<String, MtopConfig> mtopConfigMap;
public static MapConfig getMtopConfigByID(String instanceId){ }
...
```
`getMtopConfigByID`这个方法会通过instanceId获取MtopConfig的实例,如果没有的话会创建一个新的并且将它放入到`mtopConfigMap`中,方便下次获取。其他的方法都是通过`getMtopConfigByID`获取Mtop或MtopConfig实例后调用相应的设置项。
经过上面的一翻分析,猜测以下类的主要作用:
* MtopSettings (设置工具类)
* MtopConfig (存在Mtop配置类)
* Mtop (Mtop核心功能类)
* IMtopInitTask (Mtop初始化任务)
现在有人`instanceId`就能知道对应的`IMtopInitTask`实例来初始化Mtop,下一篇文章再来分析`IMtopInitTask`实例,最终完成爬包功能!!
最后欢迎大家关注我的公众号,获取最新的进展。
![](https://user-gold-cdn.xitu.io/2019/10/3/16d90c28f2befa48?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
免责声明: 本文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请读者自负。 请教下,mtopsdk怎么反编译出来,需要脱壳什么的吗?
我是用dex2jar-2.0 反 apk里的classes.dex,然后用gui看这个mtopsdk没编译出来~~。 是空的,
看不懂哦哦 感谢分享~~~ 学习了,十分感谢
有些地方不太懂,可否交流一下 白菜 发表于 2019-10-4 22:10
有些地方不太懂,可否交流一下
欢迎一起交流的 感谢楼主分享,学习了 支持一下!楼主辛苦! 看看,不错,正在研究中心 感谢分享
页:
[1]
2