Knowledgeset is a team official account, mainly targeting at the mobile development field, sharing mobile development technology, including iOS, Android, applets, mobile front end, React Native, WEEX, etc. Original articles will be shared every week, and our articles will be published on our official account. Stay tuned for more.

The original link

In the last article “micro channel small program” decompile actual combat (A) : unpack “, we introduced in detail how to obtain a small program. Wxapkg package, and analyzed the structure of the. Wxapkg package, and finally obtained the files in the package through the script decompression: The “compiled” code files and resource files of the applets, but since most of these files are confused and poorly readable, this article will go further and try to restore the contents of the.wxapkg package as much as possible to the “compiled” content.

Note: This article contains part of the source code analysis, due to the small screen of the mobile phone, the reading experience may not be good, it is recommended to browse on the computer.

Special thanks: The restoration tool used below is from the open source project wxappUnpacker on GitHub. Special thanks to the original author for his selfless contribution.

An overview of

As we know, front-end Web page programming is a combination of HTML + CSS + JS, in which HTML is used to describe the structure of the page, CSS is used to describe the appearance of the page, JS is usually used to deal with the page logic and user interaction. Similarly, there is a similar role for applets. A applets project consists mainly of the following types of files:

  • .jsonJSON configuration file with suffix
  • .wxmlThe suffix WXML template file
  • .wxssSuffix WXSS style file
  • .jsSuffixed JavaScript script logic file

For example, “knowledge set” small program source engineering structure is as follows:

However, as described in the previous article, unpacking the.wxapkg of the “knowledge set” applet resulted in the following file:

Json, app-service.js, page-frame. HTML, *. HTML, resource files, etc., but these files have been “scrambled” and reintegrated and compressed, and wechat developer tools cannot identify them. We can’t debug/compile them directly.

Therefore, we first try to analyze the structure and purpose of each file content extracted from.wxapkg, and then introduce how to use scripting tools to restore them to the source code before “compilation”, and run in wechat developer tools.

File analysis

This section mainly analyzes the source file after unpacking the.wxapkg of the “knowledge set” small program as an example.

You can skip the analysis in this section and go straight to the next section on decompiling the script to restore the source code.

app-config.json

Small program engineering mainly includes tool configuration project.config.json, global configuration app.json and page configuration page.json three types of JSON configuration files. Among them:

Project.config. json is used to personalize developer tools and include basic configuration for applets projects, so it will not be “compiled” into the.wxapkg package;

App. json is the global configuration of the current applet, including all the page path of the applet, interface performance, network timeout, bottom TAB, etc.

Page. json is used to configure the window representation of each page. The configuration items in the page overwrite the same configuration items in the window of app.json.

Therefore, the “compiled” file app-config.json is actually a summary of app.json and configuration files of each page, which is roughly as follows:

{" page ": {/ / each page configuration" pages/index/index. The HTML ": {/ / a page address" window ": {/ / a specific configuration page" navigationBarTitleText ": EnablePullDownRefresh: true}}, // omit... }, "entryPagePath": "pages/index/index.html", ["pages/index/index", "pages/detail/detail", "pages/search/search"], // page list "global": {// global page configuration "window": {" navigationBarTextStyle ":" black ", "navigationBarTitleText" : "small knowledge set", "navigationBarBackgroundColor" : "#F8F8F8", "backgroundColor": "#F8F8F8" } } }Copy the code

By comparing with the original project app.json and page. Json content of each page configuration, we can get the simple integration rule of app-config.json summary file, which can be easily divided into the corresponding JSON files before “compilation”.

app-service.js

In the small program project, JS files are responsible for interaction logic, mainly including app.js, page.js for each page, developer’s custom JS files and imported third-party JS files. After “compilation”, all these JS files will be summarized into the app-service.js file. Its structure is as follows:

// Declarations of some global variables
var __wxAppData = {};
var __wxRoute;
var __wxRouteBegin;
var __wxAppCode__ = {};
var global = {};
var __wxAppCurrentFile__;
var Component = Component || function(){};
var definePlugin = definePlugin || function(){};
var requirePlugin = requirePlugin || function(){};
var Behavior = Behavior || function(){};

// Applets compile base library versions
/ * v0.6 vv_20180125_fbi * /
global.__wcc_version__='v0.6 vv_20180125_fbi';
global.__wcc_version_info__={"customComponents":true."fixZeroRpx":true."propValueDeepCopy":false};

// Project third party or custom some JS source code
define("utils/util.js".function(require, module, exports, window,document,frames,self,location,navigator,localStorage,history,Caches,screen,alert,confirm,prompt,XMLHttpRequest,We bSocket,Reporter,webkit,WeixinJSCore) {
  "use strict";
  / /... Specific source code content
});

// ...

// app.js source code definition
define("app.js".function(.) {
  "use strict";
  / /... App.js source code content
});
require("app.js");

// Each page corresponds to the JS source definition
__wxRoute = 'pages/index/index'; // Page routing address
__wxRouteBegin = true;
define("pages/index/index.js".function(.){
  "use strict";
  / /... Page. Js source code content
});
require("pages/index/index.js");

Copy the code

In this file, each JS file in the original applet project is declared by the define method definition, which contains the path and contents of the JS file, as follows:

define("path/to/xxx.js".function(...). {"use strict"; / /... Xxx.js source code content});Copy the code

Therefore, it is also easy to extract the source of these JS files and restore them to the appropriate path location. Of course, the contents of these JS files have been obfuscated and compressed, and we can use tools like UglifyJS to beautify them, but it is still difficult to restore some original variable names, but it basically does not affect normal reading and use.

page-frame.html

In applets, WXML files are used to describe the structure of the page and WXSS files are used to describe the style of the page. There is an app.wxss file in the project that defines some global styles that are automatically imported into individual pages; In addition, each page also contains page.wxml and page.wXSS, respectively, to describe the structure and style of its page; WXSS style files and public xxxtemplate. WXML template files will be used by some pages, usually in the page. WXSS and page.

When the applet is “compiled”, all.wxml files and app.wxss and public xxxcommon.wxss style files are consolidated into page-frame. HTML files, and the page.wxss style files for each page, A page.html file will be generated separately in their respective paths.

The content structure of the page-frame. HTML file is as follows:


      
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width =device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
    <link rel="icon" href="data:image/ico; base64,aWNv">
    <script>
      // Declarations of some global variables
      var __pageFrameStartTime__ = Date.now();
      var __webviewId__;
      var __wxAppCode__ = {};
      var __WXML_GLOBAL__ = {
        entrys: {},
        defines: {},
        modules: {},
        ops: [].wxs_nf_init: undefined.total_ops: 0
      };
      
      // Applets compile base library versions
      / * v0.6 vv_20180125_fbi * /
      window.__wcc_version__ = 'v0.6 vv_20180125_fbi';
      window.__wcc_version_info__ = {
        "customComponents": true."fixZeroRpx": true."propValueDeepCopy": false
      };
      
      var $gwxc
      var $gaic = {}
      $gwx = function(path, global) {
        // $GWX method definition (core)
      }
      
      var BASE_DEVICE_WIDTH = 750;
      var isIOS = navigator.userAgent.match("iPhone");
      var deviceWidth = window.screen.width || 375;
      var deviceDPR = window.devicePixelRatio || 2;
      function checkDeviceWidth() {
        // checkDeviceWidth method definition
      }
      checkDeviceWidth()
      
      var eps = 1e-4;
      function transformRPX(number, newDeviceWidth) {
        // transformRPX method definition
      }
      
      var setCssToHead = function(file, _xcInvalid) {
        // setCssToHead method definition
      }
      setCssToHead([])(); // Clear the CSS in HeadsetCssToHead([...] );// Set the contents of app.wxss to Head, where... It is the content of app.wXSS in the small program project
      var __pageFrameEndTime__ = Date.now()
    </script>
  </head>
  <body>
    <div></div>
  </body>
</html>
Copy the code

Compared with other files, page-frame. HTML is more complex. Wechat directly “compiles”.wxml and part of.wxss and confuses them into JS codes into the above files, and then calls these JS codes to construct virtual-dom and render the page.

At the heart of these are the $GWX and setCssToHead methods.

$GWX is used to generate all.wxml files in JS code, where the content structure of each.wxml file is defined and confused in the $GWX method. We can get the contents of each.wxml by passing it the.wxml path parameter to the page. With a little more work, it’s back to where it was before “compilation.”

In $GWX there is an x array to store the.wxml files of the current applets. For example, the x value of the “knowledge set” applets is as follows:

var x = ['./pages/detail/detail.wxml'.'/towxml/entry.wxml'.'./pages/index/index.wxml'.'./pages/search/search.wxml'.'./towxml/entry.wxml'.'/towxml/renderTemplate.wxml'.'./towxml/renderTemplate.wxml'];
Copy the code

To retrieve the contents of index.wxml, open the page-frame. HTML file in Chrome and type the following command in Console:

$gwx("./pages/index/index.wxml")
Copy the code

The setCssToHead method is used to generate.wxSS code from an array of split style strings and set it into the HTML Head. It also inserts an array of styles corresponding to all the.wxss files referenced by import (the common xxxcommon.wxss style file) into the _C variable in the method and marks which files refer to the _C data. In addition, at the end of the page-frame. HTML file, this method is called to generate the contents of the global app.wxss set into the Head.

Therefore, we can extract and restore the contents of the corresponding.wxss at each place where the setCssToHead method is called.

See this article for a more detailed analysis of the $GWX and setCssToHead methods in the page-frame.html file.

In addition, the checkDeviceWidth method is used to detect the screen width, which is used to convert RPX units to PX pixels in the transformRPX method.

RPX, or Responsive Pixel, is a size unit defined by the small program itself that can be adapted to the current screen width of the device. The applet states that the screen width of all devices is 750rpx, and the actual pixel value of 1rpx will vary depending on the actual screen width of the device.

*.html

As mentioned above, the page.wxSS style file for each page is “compiled” to generate a page.html file in its own path. Each page.html file has the following structure:

<style></style>
<page></page>
<script>
  var __setCssStartTime__ = Date.now(); setCssToHead([...] ) ()// Set the contents of search.wxss
  var __setCssEndTime__ = Date.now();
  document.dispatchEvent(new CustomEvent("generateFuncReady", {
    detail: {
      generateFunc: $gwx('./pages/search/search.wxml')}}))</script>
Copy the code

In this file, the.wxSS style content is set into the Head by calling the setCssToHead method, so similarly, we can extract the page.wxss for each page based on the setCssToHead call parameters.

Resource file

Source files such as images and audio files from applets are copied directly to the.wxapkg package after being “compiled”, and their original path remains unchanged, so we can use them directly.

“Decompile”

In the previous section, we completed a brief analysis of almost all the file contents of the.wxapkg package. Now let’s take a look at how to restore the source of the small program through node.js script.

Thanks again to the wxappUnpacker authors for the restore tools that allow us to “stand on the shoulders of giants” and “decompile” with ease. Its use is as follows:

  • Node wuconfig. js : Split the contents of app-config.json into the corresponding page.

  • Nodewujs. js : Split app-service.js into a series of original independent JS files, and use uglip-es beauty-tool to restore the code as much as possible before “compilation”;

  • Nodewuwxml.js [-m] : Extract and restore.wxml and app.wxss and public.wxss style files from page-frame.html;

  • Nodewuwxss. js : The command parameter is.wxapkg unpacked directory, it will analyze and extract from each page.

In addition, the author also provides a one-click unpack and restore script, you just need to provide a small program.wxapkg file, and then execute the following command:

node wuWxapkg.js [-d] <path/to/.wxapkg>
Copy the code

The script will automatically unpack the.wxapkg file and automatically restore any files in the package that have been “compiled/obfuscated” (including directory structures).

PS: This tool relies on ugliy-es, vm2, esprima, cssBeautify, CSS-tree, etc. Node.js packages, so you may need NPM install XXX to install these dependencies to perform correctly.

For more details on usage and related questions, see the GitHub repo for the open source project.

Finally, we create an empty applet project in the wechat developer tool, and import the relevant directory files after the above restoration into the project, and then compile and run. The following picture shows the code project after the.wxapkg package restoration of the “Knowledge set” applet:

Above, done!

conclusion

This paper analyzes the file structure of.wxapkg unpacked in detail, and introduces how to get the source code of any small program through script “one-button restore”.

For some simple and use WeChat official introduction of primary development way of small procedures, can use the tool basic direct reduction got the source code to run, but for some complex logic, or use WePY, Vue some frameworks such as the development of small procedures, after reduction of the source code may have a little problem, need us to solving human flesh.

subsequent

In this paper, the source code of the small program “compiled” after the analysis of the content structure and use of the file is relatively scattered, and there is no dependency of the file and the loading logic to study, we will write some articles on wechat client is how to parse the loading small program. Wxapkg package and run.

Refer to the link

  • wxappUnpacker
  • wechat-app-unpack