创建或修改目录:/www/wwwroot/104.219.215.234/data 失败!
拳交 扩张 微信小法子源码阅读札记1 - 偷偷撸改

偷偷撸改

拳交 扩张 微信小法子源码阅读札记1

发布日期:2024-10-30 20:04    点击次数:184

在这里阅读的是,微信安卓653.980版的反编译后的代码。很剖析的不错看到,小法子在代码中被称为appbrand,主要逻辑放在包com.tencent.mm.plugin.appbrand底下(部分抽出的ui控件之外);另外助用了3个js资源,均在/assets/wxa_library/下。固然很大部分代码被污辱过的,关联词符合的反编译后,咱们还是能看出绝大部分东西。包整理步骤整理com.tencent.mm.plugin.appbrand下的内容,按包分裂:a:似乎是单例和依赖注入的容器appcache:微信小法子打包为wxapkg文献,这里处理的是下载解包考据和后续处理逻辑appstorage:在数据库中存取AppBrandKVData的逻辑b:在数据库中存取AppBrandLauncherLayoutItem的逻辑,是微信小法子列表缓存c:通过安卓的canvas终流露一套完满的js的canvasapi,提供给小法子中canvas控件使用config:小法子模块环境变量惩处,其中数据不错通过互联网下发更新contact:把app添加为微信商酌东谈主,似乎和聊天置顶关联d:InputStream关系器用类e:灌音功能关系器用类f:隔邻的东谈主的小法子关系器用类g:应该是AppBrandNetworkUtil,小法子模块用到的汇集部分的器用类h:权限惩处器用类,包括小法子权限惩处和jsapi权限惩处,同期也不错通过汇集更新i:小法子sd卡操作器用类ipc:ipc即程度间通讯。小法子通过新开程度来保险独处运行的,独处程度的启动与微信执行的通讯依赖这个包的代码完成。其中AppBrandMainProcessService是最主要运行做事,而AppBrandProcessProxyUI是小法子程度持有性质activity。j:AppBrandConversionExtension拳交 扩张,似乎是多个小法子切换流程中的扶直类jsapi:微信小法子通过浏览器泄露给js环境的api的进口基本上皆在这儿了拳交 扩张,包括组件部分和api部分。终末AppBrandJSInterface把这些进口团员在一谈。k:似乎是一些零星的器用类l:js中WebSocketapi的native终了launching:微信小法子加载逻辑的终了。主如若处理了好多加载准备流程中的逻辑和失实监测m:微信小法子列表搜索功能关系逻辑netscene:好像是对webview发起的特殊申请的处理和中断page:页面部分,包括微信小法子列表页等,主要皆是各个activity和使用的自界说view。其中l.class值得贯注,应该是中枢使用的webview了,h.class是这个webview的容器,也作念了好多操作。report:仅仅数据上报关系的东西task:一些杂七杂八的异步责任放这儿了ui:和page差未几,亦然各式万般的activity和view。微信小法子执行的容器页面(5个)和各式功能与相配页面widget:统统泄露给js的native控件皆在这儿了。其实并未几其他文献中值得神态的一些东西:a.class即AppBrandBridge是小法子主路由适度器,持有着刻下统统小法子f.class看起来是AppBrandService,持有后台运行的jscore面前不错得回的信息粗鄙知谈每个包皆饶恕一些什么代码之后,咱们就不错对微信小法子进行一些挖掘了。wxapkg解包通过合手包咱们不错发现,每次投入小法子列表后,就融会过汇蚁合手下来统统小法子的wxapkg包,然后统统需要的东西皆在内部了。那这个wxapkg在哪儿解包的呢?经过搜索,咱们发现是appcache/f.class即AppBrandWxaPkg完成的这段责任。由于污辱得一塌混沌,因此我分析执行wxapkg之后我方终流露一次解码(python):
#!/usr/bin/python

# lrdcq
# usage python wxapkg_unpack.py filename, unpack at filename.unpack

import sys,os
import struct

class WxapkgFile:
  nameLen = 0
  name = ""
  offset = 0
  size = 0

with open(sys.argv[1], "rb") as f:

  root = os.path.dirname(os.path.realpath(f.name))
  name = os.path.basename(f.name)

  #read header

  firstMark = struct.unpack('B', f.read(1))[0]
  print 'first header mark = ' + str(firstMark)

  info1 = struct.unpack('>L', f.read(4))[0]
  print 'info1 = ' + str(info1)

  indexInfoLength = struct.unpack('>L', f.read(4))[0]
  print 'indexInfoLength = ' + str(indexInfoLength)

  bodyInfoLength = struct.unpack('>L', f.read(4))[0]
  print 'bodyInfoLength = ' + str(bodyInfoLength)

  lastMark = struct.unpack('B', f.read(1))[0]
  print 'last header mark = ' + str(lastMark)

  if firstMark != 190 or lastMark != 237:
    print 'its not a wxapkg file!!!!!'
    exit()

  fileCount = struct.unpack('>L', f.read(4))[0]
  print 'fileCount = ' + str(fileCount)

  #read index

  fileList = []

  for i in range(fileCount):

    data = WxapkgFile()
    data.nameLen = struct.unpack('>L', f.read(4))[0]
    data.name = f.read(data.nameLen)
    data.offset = struct.unpack('>L', f.read(4))[0]
    data.size = struct.unpack('>L', f.read(4))[0]

    print 'readFile = ' + data.name + ' at Offset = ' + str(data.offset)

    fileList.append(data)

  #save files
  
  for d in fileList:
    d.name = '/' + name + '.unpack' + d.name
    path = root + os.path.dirname(d.name)

    if not os.path.exists(path):
      os.makedirs(path)

    w = open(root + d.name, 'w')
    f.seek(d.offset)
    w.write(f.read(d.size))
    w.close()

    print 'writeFile = ' + root + d.name

  f.close()
另外执行文献结构如图:點擊在新視窗中瀏覽此圖片看起来很剖析的解包代码,通过这些代码,咱们就不错把微信下载下来的wxapkg手动进行解包了,进而不错络续分析其终了旨趣。页面加载一驱动的小法子列表界面是ui/AppBrandLauncherUI.class,然后通过AppBrandProcessProxyUI启动了小法子的AppBrandUI。投入法子后,咱们整理出最要道的activity和view:ui/AppBrandUI.class 小法子主activitypage/f.class AppBrandPageContainerpage/e.class SwipeBackLayout的收受,每一个当个侧滑页page/h.class AppBrandWebView的逻辑容器,耦合webview和其他控件的逻辑page/l.class AppBrandWebView,主逻辑webviewAppBrandUI->f页面->e页面->h页面->l页面,通过这一条界面链条传到webview里最要道的东西,即是刻下法子的appId和版块号。然后webview就加载了这么的东西:
//h.class
    if (paramString.dOS == null) {
      paramString.dOS = (paramString.RA() + "page-frame.html");
    }
    paramString.loadUrl(paramString.dOS);
//l.class
  final String RA()
  {
    if (this.dOR == null) {
      this.dOR = ("https://servicewechat.com/" + this.dzg + "/" + com.tencent.mm.plugin.appbrand.a.mr(this.dzg).dDB.dBs + "/");
    }
    return this.dOR;
  }
执行在webview中加载了形为https://servicewechat.com/{appid}/{version}/page-frame.html的页面。这个页面其实被定向到wxapkg中的page-frame.html,它通过jsbridge再调用到代码其余部分。另外一边,还启动了一个f.class即AppBrandService。启动AppBrandService的代码中会开一个jscore,如下:
this.dWV = new AppBrandJSInterface(this);
    if (com.tencent.smtt.sdk.aa.fM(com.tencent.mm.sdk.platformtools.aa.getContext()))
    {
      this.dzh = new i(com.tencent.mm.sdk.platformtools.aa.getContext(), this.dWV, "WeixinJSCore");
      g.iuh.a(434L, 2L, 1L, false);
      v.i("MicroMsg.AppBrandService", "Using X5 Javascript Engine");
      g.iuh.a(434L, 0L, 1L, false);
      OJ();
      paramContext = com.tencent.mm.plugin.appbrand.appcache.b.aq(this.dzg, "WAService.js");
      g.iuh.a(370L, 5L, 1L, false);
      if (!be.kS(paramContext)) {
        break label258;
      }
      v.e("MicroMsg.AppBrandService", "get Null Or Nil service js");
      g.iuh.a(370L, 6L, 1L, false);
    }
    for (;;)
    {
      paramContext = com.tencent.mm.plugin.appbrand.appcache.b.aq(this.dzg, "app-service.js");
      g.iuh.a(370L, 9L, 1L, false);
      if (!be.kS(paramContext)) {
        break label281;
      }
      v.e("MicroMsg.AppBrandService", "get Null Or Nil app-service js");
      g.iuh.a(370L, 10L, 1L, false);
      return;
      this.dzh = new h(com.tencent.mm.sdk.platformtools.aa.getContext(), this.dWV, "WeixinJSCore");
      g.iuh.a(434L, 1L, 1L, false);
      v.i("MicroMsg.AppBrandService", "Using WebView Based Javascript Engine");
      break;
      label258:
      com.tencent.mm.plugin.appbrand.k.c.a(this.mContext, this.dzh, paramContext, new c.a()
      {
        public final void OK()
        {
          v.e("MicroMsg.AppBrandService", "service inject library js fail");
          g.iuh.a(370L, 6L, 1L, false);
          com.tencent.mm.plugin.appbrand.report.a.S(f.this.dzg, 24);
        }
        
        public final void onSuccess()
        {
          f.this.dzh.evaluateJavascript("wx.version", new u() {});
          g.iuh.a(370L, 7L, 1L, false);
        }
      });
    }
反编译得稍乱,不外这其实即是两种情况的逻辑。使用X5 Javascript Engine并实例化出一个i.class或者使用WebView Based Javascript Engine并实例化出一个h.class。i.class封装调用的是腾讯的x5js引擎,而i.class是一个不会自大的webview,他们皆终流露沟通的接口b.class,内部两个步调,第一个赫然是onDestroy,第二个即是最要道的evaluateJavascript了。这么一来,咱们就不错画出统统这个词微信小法子的运行构架和链条了:點擊在新視窗中瀏覽此圖片页面路由比如js路由界面掀开是jsapi/an.class,咱们跟踪一下代码。它从a.class即AppBrandBridge的map:Map<String, com.tencent.mm.plugin.appbrand.page.f> dyQ中取出了刻下期骗(dzg)的f页面AppBrandPageContainer。然后在f中新建了一个e并完成了动画,何况不错看到f领有两个数组来持有不同掀开方法的e页面。不错得到的信息是:a(AppBrandBridge)持有了刻下每一个掀开的小法子的主界面f(AppBrandPageContainer),之是以不持有每一个activity也许是为了浅近搬动容器位置或者缓存关系的问题吧;每一个小法子有一个f,其掀开的每一个页面是一个e(SwipeBackLayout),天然每一个e配有一个l(AppBrandWebView)来呈现界面。因此不错交融为,每一个程度(AppBrandProcessProxyUI)启动一个微信小法子,领有一个AppBrandUI,它的最中枢的是AppBrandPageContainer,内部最多饶恕5个界面(e)。这么咱们就不错画出微信小法子的界面结构了:點擊在新視窗中瀏覽此圖片筹商到通常代码中不错看出,有5个AppBrandProcessProxyUI即微信最多不错启动5个小法子,而每个小法子最多有5个页面即5层SwipeBackLayout即5个webview,统统这个词小法子部分最坏情况会领有5x5+1系数26个jscore。回到界面路由,由于当个小法子皆在一个AppBrandPageContainer中,因此统统的路由操作只需要定位到这个f界面,作念界面动画就不错了——事实上即是这么作念的,除了动画,AppBrandPageContainer持有两个数组来惩处不同掀开方法的SwipeBackLayout,路由操作同期是在对这两个数组进行操作。而执行具体SwipeBackLayout实例化的终了,是把柄传入的JSONObject内容详情的了。其他路由方法均同理。native控件咱们了解到微信小法子每一个界面即是一个webview,那统统界面皆是h5的咯?似乎并不是,开着安卓的界面界限自大咱们就不错发现部分view是native的控件,事实上掀开WAWebview.js咱们就不错看到,有特意的behavior:wx-native来标柱一个view是否是纯native的控件,就算没标注,比如wx-input控件,也在部分情状下用native来终了的。咱们用wx-input例如子望望它是怎样交互的。最初看到控件内监听器,注册:"input.input": "_inputKey",当输入的本事,回调到_inputKey,而_inputKey的代码是:
        _inputKey: function(e) {
            var t = e.target.value;
            if (this._value = t, this._checkPlaceholderStyle(t), this.bindinput) {
                var n = {
                    id: this.$$.id,
                    dataset: this.dataset,
                    offsetTop: this.$$.offsetTop,
                    offsetLeft: this.$$.offsetLeft
                };
                WeixinJSBridge.publish("SPECIAL_PAGE_EVENT", {
                    eventName: this.bindinput,
                    data: {
                        ext: {
                            setKeyboardValue: !0
                        },
                        data: {
                            type: "input",
                            timestamp: Date.now(),
                            detail: {
                                value: e.target.value,
                                cursor: this.$.input.selectionStart
                            },
                            target: n,
                            currentTarget: n,
                            touches: []
                        },
                        eventName: this.bindinput
                    }
                })
            }
            return ! 1
        },
这就很有兴趣兴趣了,js代码把刻下input的id,所极端据和在页面中的坐标通过JSBridge发送给了native。关于在java中的代码是jsapi/a/a.class即AppBrandJsApiInputBase,接下来的事情家喻户晓谈了,无非是把柄传入的json中的面孔绘图native控件,然后接着处理。上头这么的js代码在WAWebview.js中有好多出,咱们不错完满的回想出到底有哪些native控件何况在native中的代码对应:input,textarea : jsapi/a包 widget/input包终了datepicker : jsapi/b包 widget/b包终了map : jsapi/map包 widget/AppBrandMapView.class终了canvas : c包 widget/AppBrandDrawableView.class终了video : x5原生终了,不是小法子完成的其中有兴趣兴趣的是这些native终了的view出面前了文档scroll-view的tips中:“请勿在 scroll-view 中使用 textarea、map、canvas、video 组件”。思思照实不错交融,如果是在web第一层塞入的native控件,不错很浅近的让native控件和网页一谈转念;而scroll-view赫然仅仅个html的div终了的,native很难监听到div内部的转念,天然也没发让这些native的控件一谈滚,因此就gg了。待续 淫乱电影

 




Powered by 偷偷撸改 @2013-2022 RSS地图 HTML地图

Copyright Powered by站群系统 © 2013-2024

创建或修改目录:/www/wwwroot/104.219.215.234/data 失败!
JzEngine Create File False