首页 > 技术文章 > 记录一次体体现前端工具仔综合实力的实际操作

liujingjiu 2021-02-27 10:47 原文

起因

我们公司在17年的时候有个在手机端设备控制的项目,当时Android端和iOS端是使用apicloud打包而成。当时有款需要控制的设备用到了庆科的WiFi模组,所以项目中使用了庆科在apicloud的模块Store中提供的模块。
在这个项目上线后,很长一段时间都属于停滞状态。直到最近项目重启,再去看,庆科的模块已经全被下架了,而其它满足需求的模块需要付钱。
虽然庆科的官网中有原生android和iOS开发的文档,但是通过我自定义模块编译的APP甚至官方文档中的APP均无法完成配网和设备发现。
在这里插入图片描述

过程

通过用Fiddler抓包观察apicloud添加模块的流程,我发现在apicloud中每个模块都有一个唯一的模块ID,而添加模块的操作是针对模块ID进行的。虽然庆科所有的模块均已被下架,但我估计模块的数据依旧存在于apicloud的数据库中,而只是将数据的状态置为搜索不可见。通过apicloud论坛,我得知了庆科在apicloud上架的模块有两个—mico和fog2。
随后我再在百度中搜索apicloud mico,找到属于它的百度快照。通过百度快照,找到了mico模块的模块ID—8647
再通过添加其它模块,得到添加模块的接口与数据、cookie(我这里是直接用的新版本的fiddler直接抓包,修改,请求)。然后将数据中的模块ID改成mico模块的模块ID—8647,最后执行接口请求。
在这里插入图片描述
在这里插入图片描述

mico躺在已添加模块中。
在这里插入图片描述

在加完mico模块后,我才注意到这个模块居然是只支持Android,并且我打包后的APP依旧无法完成配网和设备发现。

接着我再在百度中搜索apicloud fog2,找到属于它的百度快照,不过与mico模块不同,通过百度快照无法得知fog2的模块ID。
在这里插入图片描述

在这里插入图片描述
随后我尝试再用其它的搜索引擎,通过Google,找到了模块ID—24853
在这里插入图片描述
在这里插入图片描述
最后按照添加mico模块的办法添加fog2模块到项目中。

看似到这一步一切已经完成了,其实并没有。因为fog2模块的开发文档失效了。
在这里插入图片描述
又回到了原点。

这时我想到,不如打个Android的包,再将这个包反编译,不就可以得到fog2模块的源码了吗?

祭出我的反编译三件套

在这里插入图片描述

首先将apk文件解压到文件夹
在这里插入图片描述

然后在当前页面启动命令行模式,输入 java -jar apktool_2.3.4.jar d -f app.apk -o app
在这里插入图片描述

随后使用VSCode打开apktool反编译apk的输出文件夹,搜索fog2,得知fog2模块代码存在于classes20.dex文件中。
在这里插入图片描述

将classes20.dex文件复制到dex2jar-2.0文件夹中
在这里插入图片描述

随即在命令行中定位到dex2jar-2.0目录下,输入 d2j-dex2jar classes20.dex,得到classes20-dex2jar.jar包

在这里插入图片描述

在这里插入图片描述
经过分析代码和转化其它需要的dex文件,得到以下方法


  public void jsmethod_getSSID(UZModuleContext paramUZModuleContext)
  {
    this.mJsCallback = paramUZModuleContext;
    paramUZModuleContext = this.micodev.getSSID();
    execCallBack("success", this.errorCode.setSuccJson("{\"ssid\":\"" + paramUZModuleContext + "\"}"), true);
  }
  
  public void jsmethod_init(UZModuleContext paramUZModuleContext)
  {
    this.mJsCallback = paramUZModuleContext;
    paramUZModuleContext = paramUZModuleContext.optString("host");
    if (checkAndCallBack(true, new String[] { paramUZModuleContext })) {
      MiCO.init(paramUZModuleContext);
    }
  }
  
  public void jsmethod_startEasyLink(UZModuleContext paramUZModuleContext)
  {
    this.mJsCallback = paramUZModuleContext;
    String str1 = paramUZModuleContext.optString("ssid");
    String str2 = paramUZModuleContext.optString("password");
    int j = paramUZModuleContext.optInt("runSecond");
    int k = paramUZModuleContext.optInt("sleeptime");
    paramUZModuleContext = paramUZModuleContext.optString("extraData");
    int i = j;
    if (j == 0) {
      i = 60000;
    }
    j = k;
    if (k == 0) {
      j = 20;
    }
    if ((checkAndCallBack(true, new String[] { str1 })) && (i > 0) && (j > 0)) {
      this.micodev.startEasyLink(str1, str2, i, j, new EasyLinkCallBack()
      {
        public void onFailure(int paramAnonymousInt, String paramAnonymousString)
        {
          Fog2sdk.this.execCallBack("error", Fog2sdk.this.errorCode.setFailureJsonCode(paramAnonymousInt, paramAnonymousString), true);
        }
        
        public void onSuccess(String paramAnonymousString)
        {
          if ("success".equals(paramAnonymousString))
          {
            Fog2sdk.this.execCallBack("keep", Fog2sdk.this.errorCode.setSuccJson("{\"message\":\"" + paramAnonymousString + "\"}"), false);
            return;
          }
          Fog2sdk.this.execCallBack("keep", Fog2sdk.this.errorCode.setSuccJson("{\"message\":\"" + paramAnonymousString + "\"}"), true);
        }
      }, paramUZModuleContext);
    }
  }
  
  public void jsmethod_startSearchDevices(UZModuleContext paramUZModuleContext)
  {
    this.mNDSCallBack = paramUZModuleContext;
    this.micodev.startSearchDevices("_easylink._tcp.local.", new SearchDeviceCallBack()
    {
      public void onDevicesFind(JSONArray paramAnonymousJSONArray)
      {
        if (Fog2sdk.this.mNDSCallBack != null) {
          Fog2sdk.this.mNDSCallBack.success(Fog2sdk.this.errorCode.setSuccJson("{\"devices\":" + paramAnonymousJSONArray.toString() + "}"), false);
        }
      }
      
      public void onFailure(int paramAnonymousInt, String paramAnonymousString)
      {
        Fog2sdk.this.mNDSCallBack.error(null, Fog2sdk.this.errorCode.setFailureJsonCode(paramAnonymousInt, paramAnonymousString), true);
      }
      
      public void onSuccess(String paramAnonymousString)
      {
        Fog2sdk.this.mNDSCallBack.success(Fog2sdk.this.errorCode.setSuccJson("{\"message\":\"" + paramAnonymousString + "\"}"), false);
      }
    });
  }
  
  public void jsmethod_stopEasyLink(UZModuleContext paramUZModuleContext)
  {
    this.mJsCallback = paramUZModuleContext;
    this.micodev.stopEasyLink(new EasyLinkCallBack()
    {
      public void onFailure(int paramAnonymousInt, String paramAnonymousString)
      {
        Fog2sdk.this.execCallBack("error", Fog2sdk.this.errorCode.setFailureJsonCode(paramAnonymousInt, paramAnonymousString), true);
      }
      
      public void onSuccess(String paramAnonymousString)
      {
        Fog2sdk.this.execCallBack("success", Fog2sdk.this.errorCode.setSuccJson("{\"message\":\"" + paramAnonymousString + "\"}"), true);
      }
    });
  }
  
  public void jsmethod_stopSearchDevices(UZModuleContext paramUZModuleContext)
  {
    this.mJsCallback = paramUZModuleContext;
    this.micodev.stopSearchDevices(new SearchDeviceCallBack()
    {
      public void onFailure(int paramAnonymousInt, String paramAnonymousString)
      {
        Fog2sdk.this.execCallBack("error", Fog2sdk.this.errorCode.setFailureJsonCode(paramAnonymousInt, paramAnonymousString), true);
        Fog2sdk.this.mNDSCallBack = null;
      }
      
      public void onSuccess(String paramAnonymousString)
      {
        Fog2sdk.this.execCallBack("success", Fog2sdk.this.errorCode.setSuccJson("{\"message\":\"" + paramAnonymousString + "\"}"), true);
        Fog2sdk.this.mNDSCallBack = null;
      }
    });
  }
package com.mxchip.helper;

public class MiCO
{
  public static void init(String paramString)
  {
    Configuration._APIHOST = paramString;
  }
}

public static String _APIHOST = "https://v2.fogcloud.io";

最终得出的js代码

let fog2 = null;
let easyLinkService = {
    hasInit: false,
    init: function() {
        if(fog2 == null){
            fog2 = api.require('fog2')
        }
        if (!this.hasInit) {
            this.initEasyLink()
            this.hasInit = true
        }
    },
    initEasyLink: function() {
        fog2.init({
            host: "https://v2.fogcloud.io"
        })
    },
    getSSID: function() {
        return new Promise ( function(resolve, reject) {
            fog2.getSSID(function(ret, err) {
                if (ret) {
                    resolve(ret.ssid)
                } else {
                    reject(err)
                }
            });
        })
    },

    startEasyLink: function(ssid_val, psw_val) {
        return new Promise ( function(resolve, reject) {
            let param = {
                ssid: ssid_val,
                password: psw_val
            };
            fog2.startEasyLink(param, function(ret, err) {
                if (ret) {
                    resolve(ret.message)
                } else {
                    reject(err.message)
                }
            });
        })
    },
    stopEasyLink: function() {
        return new Promise ( function(resolve, reject) {
            fog2.stopEasyLink(function(ret, err) {
                if (ret) {
                    console.log(ret.message);
                    resolve(ret.message)
                } else {
                    console.log(err.message);
                    reject(err.message)
                }
            });
        })
    },
    startSearchDevices: function() {
        return new Promise ( function(resolve, reject) {
            fog2.startSearchDevices(function(ret, err) {
                if (ret) {
                    let deviceList = [];
                    if (null != ret.devices && ret.devices.length > 0) {
                        deviceList = ret.devices
                        resolve(deviceList)
                    }
                } else {
                    reject(err)
                }
            });
        })
    },
    stopSearchDevices: function() {
        return new Promise ( function(resolve, reject) {
            fog2.stopSearchDevices(function(ret, err) {
                if (ret) {
                    resolve(ret)
                } else {
                    reject(err)
                }
            });
        })
    },
}
window.easyLinkService = easyLinkService
export default easyLinkService

完成配网并成功发现设备,大功告成
在这里插入图片描述

结尾

这篇文章主要是记录这次操作中的思路,以及抓包、改包、反编译等技能的实践操作,真正做到学以致用,将我们所学的知识,运用到实际操作当中去。

推荐阅读