xyjwfn 发表于 2019-10-4 12:40

淘宝系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)

免责声明: 本文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请读者自负。

kmp6780 发表于 2020-4-24 15:30

请教下,mtopsdk怎么反编译出来,需要脱壳什么的吗?
我是用dex2jar-2.0 反 apk里的classes.dex,然后用gui看这个mtopsdk没编译出来~~。 是空的,


木ID 发表于 2019-10-4 13:30

看不懂哦哦

soulmutou 发表于 2019-10-4 13:36

感谢分享~~~

倾注你的笑sf 发表于 2019-10-4 21:21

学习了,十分感谢

白菜 发表于 2019-10-4 22:10

有些地方不太懂,可否交流一下

xyjwfn 发表于 2019-10-5 08:18

白菜 发表于 2019-10-4 22:10
有些地方不太懂,可否交流一下

欢迎一起交流的

Disk4mat 发表于 2019-10-5 11:39

感谢楼主分享,学习了

明日清晨 发表于 2019-10-5 19:06

支持一下!楼主辛苦!

爱你一辈子 发表于 2019-10-5 23:00

看看,不错,正在研究中心

babyq2019 发表于 2019-10-24 22:32

感谢分享
页: [1] 2
查看完整版本: 淘宝系MtopSDK逆向分析(一)