起因

我们公司在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 = easyLinkServiceexport default easyLinkService

完成配网并成功发现设备,大功告成

结尾

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

©著作权归作者所有:来自51CTO博客作者wx60877cc7b61d6的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 210406 类数组 获取遍历DOM元素 向元素添加文本 获取元素的自定
  2. PHP第一课
  3. PHP:实例演示PHP模块加载和JavaScript和PHP中for/forEach两种语
  4. CSS的基本语法/选择器优先级/实例演示前端组件样式模块化原理与
  5. 已安装nginx动态添加模块
  6. 自动化运维Ansible
  7. IIS7设置http跳转到https重定向的方法
  8. JavaScript:数学对象,随机生成数字验证码并且随机添加字体颜色
  9. 留言板实战与添加字数实时统计功能

随机推荐

  1. Glide源码分析(四)——Registry机制
  2. 通过Android软件ZAX实时查看Zabbix监控
  3. Android低版本使用ActionBar导入v7-appco
  4. 将XML元素反序列化为Java Map
  5. 推荐一个Emoji框架
  6. Suggestion: use tools:overrideLibrary=
  7. 仪表测试自定义视图
  8. 如何设置webview的初始缩放/宽度
  9. android中easeui 环信3.2.3 昵称 头像 设
  10. android语音识别和合成第三方