记录一次体体现前端工具仔综合实力的实际操作
作者:互联网
起因
我们公司在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
完成配网并成功发现设备,大功告成
结尾
这篇文章主要是记录这次操作中的思路,以及抓包、改包、反编译等技能的实践操作,真正做到学以致用,将我们所学的知识,运用到实际操作当中去。
标签:fog2,记录,实际操作,前端,paramAnonymousString,ret,模块,paramUZModuleContext,Fog2sdk 来源: https://blog.51cto.com/u_15182950/2736159