Entering the path

Caught analysis

tool

Charles – Network packet capture

Download it at www.charlesproxy.com/

(Prerequisite: Charles certificate should be installed on mobile phone and COMPUTER)

Certificate of installation and support caught HTTPS set guidelines refer to: blog.csdn.net/victory0943…

Postman – Interface debugging tool

Download it at www.postman.com/

You can import cURL, which is convenient and efficient, as shown in the following figure

RE File Manager – Android file export tool (requires root permission)

Download: m-k73-com.sm-tc.cn/c/m.k73.com…

Runtime environment

Huawei P9 Android 6.0

(by default, the packet capture tool on android7.0 or higher cannot catch HTTPS requests because 7.0 or higher only trusts system level certificates and Charles certificates are installed in user level directories.

Solution: You can upgrade the Charles certificate to the system certificate, that is, install the Charles certificate to the system certificate directory.

Specific operation may refer to connect: www.pianshen.com/article/972.)

Analyzing the packet capture interface

Grab the interface to get stores by latitude and longitude

Operate the widget on your phone, find a location where you can relocate and click to trigger a request for a nearby store. Charles then captures the relevant interface request

Right-click the relevant request and copy the data in cURL format to Postman for debugging analysis

CURL data analysis

It was found that it was a POST request, and the request body was URL encoded, so it was not easy to read. We decoded the URL

CURL cURL cURL cURL cURL cURL cURL cURL cURL cURL cURL cURL cURL cURL cURL cURL cURL

curl -H 'Host: yx.feiniu.com' -H 'content-type: application/x-www-form-urlencoded' -H 'the user-agent: Mozilla / 5.0 (iPhone; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, Like Gecko) Mobile/15E148 MicroMessenger/8.0.7(0x18000731) NetType/WIFI Language/zh_CN' -H 'Referer: https://servicewechat.com/wx08cc6bd15fabfa53/83/page-frame.html' --data-binary "Data = 22% % 7 b % 22 apiversion % 3 a % 22 t141%22% 2 c % 22 appversion % 22% % 3 a 221.5.1 22% % 22% 2 c % 22 areacode % 3 a % 22 cs000016%22% 2 c % 22 channel % 2 2%3A%22online%22%2C%22clientid%22%3A%22a7ea53059fc868e2e3e2dd7c04027035%22%2C%22device_id%22%3A%22tv179yrhs3kv9RXjJv6uJN mdkN6kTbmaUHQE%22%2C%22time%22%3A1626080760465%2C%22reRule%22%3A%224%22%2C%22token%22%3A%227ae362df162da5ffbfc408ed8e3d4 ff3%22%2C%22viewSize%22%3A%22720x1184%22%2C%22networkType%22%3A%22wifi%22%2C%22isSimulator%22%3Afalse%2C%22osType%22%3A% 224%22%2C%22scopeType%22%3A1%2C%22businessType%22%3A2%2C%22businessId%22%3A%2217210001%22%2C%22deliveryCircleType%22%3A% 221%22%2C%22body%22%3A%7B%22longitude%22%3A%22MTIwLjE1NDc3NQ%3D%3D%22%2C%22latitude%22%3A%22MzAuMzA1ODIy%22%7D%7D&h5=yx_ touch&paramsMD5=iOWz8O%2BxL9r9GX4k5Te%2F2U5HGTRk1GQ6YqLnMErWrAI%3D" --compressed 'https://yx.feiniu.com/member-yxapp/location/homeStoreList/t141'
Copy the code

The following is the cURL interface data decoded from the URL

Curl -h 'Host: yx.feiniu.com' -h 'Content-Type: Application/X-www-form-urlencoded' -h 'user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, Like Gecko) Mobile/15E148 MicroMessenger/8.0.7(0x18000731) NetType/WIFI Language/zh_CN' -h 'Referer: https://servicewechat.com/wx08cc6bd15fabfa53/83/page-frame.html' --data-binary "Data = {" apiVersion" : "t141", "appVersion" : "1.5.1", "areaCode" : "CS000016", "channel" : "online", "clientid" : "a7ea53059fc868e2e3e 2dd7c04027035","device_id":"tv179yrhs3kv9RXjJv6uJNmdkN6kTbmaUHQE","time":1626080760465,"reRule":"4","token":"7ae362df162 da5ffbfc408ed8e3d4ff3","viewSize":"720x1184","networkType":"wifi","isSimulator":false,"osType":"4","scopeType":1,"busine ssType":2,"businessId":"17210001","deliveryCircleType":"1","body":{"longitude":"MTIwLjE1NDc3NQ==","latitude":"MzAuMzA1OD Iy"}}&h5=yx_touch&paramsMD5=iOWz8O+xL9r9GX4k5Te/2U5HGTRk1GQ6YqLnMErWrAI=" --compressed 'https://yx.feiniu.com/member-yxapp/location/homeStoreList/t141'Copy the code

Data, H5, and paramsMD5 are displayed as follows:

data: {"apiVersion":"t141"."appVersion"1.5.1"."areaCode":"CS000016"."channel":"online"."clientid":"a7ea53059fc868e2e3e2dd7c04027035"."device_id":"tv179yrhs3kv9RXjJv6uJNmdkN6kTbmaUHQE"."time": 1626080760465."reRule": "4"."token":"7ae362df162da5ffbfc408ed8e3d4ff3"."viewSize":"720x1184"."networkType":"wifi"."isSimulator":false."osType": "4"."scopeType": 1.."businessType": 2."businessId": "17210001"."deliveryCircleType": "1"."body":{"longitude":"MTIwLjE1NDc3NQ=="."latitude":"MzAuMzA1ODIy"}}
h5: yx_touch
paramsMD5: iOWz8O+xL9r9GX4k5Te/2U5HGTRk1GQ6YqLnMErWrAI=
Copy the code

The mobile phone repeated the operation, and after calling the interface for packet capture for many times, the comparison found that:

H5 is fixed to yx_touch

ParamsMD5 is a literal encryption parameter, but its data format is different from that of MD5. It is assumed that MD5 is used and then another encryption is performed

{“longitude”:” longitude”:”MTIwLjE1NDc3NQ==”,”latitude”:”MzAuMzA1ODIy”}

Cracking goals

  1. ParamsMD5 Encryption logic
  2. Latitude and longitude encryption logic

In the early brought wonderful way

The reverse trip

Get wechat small program package wxapkg

The tools required

The RE file manager app mentioned earlier

Small program main subpackage judgment basis

Now, the size of a single package of wechat small programs cannot exceed 4M (except the basic dependent package of small programs). If the project content is too large, the developer will use the subcontracting mode

For example (the small package shown below is for other applications, not the case to be analyzed in this article)

Among them:

_2124598774_821. Wxapkg 3.3 M master package

_ – 588782754 _76. Wxapkg 1.5 M package

_152740959_13. Wxapkg 89 k package

_1123949441_552. wxAPkg 14M base dependency package

operation

After opening the small program, the system automatically downloads and generates the corresponding package in the directory where the small program package is stored

Direct access to wechat small program package path through RE file manager: / data/data/com. Tencent. Mm/MicroMsg / $user MD5 “/ appbrand/PKG / _ * _xxx wxapkg by re into zip file manager sent to individual nailing or QQ, WeChat, etc., received the computer for the file

Tip: if you open more than one small program before, you can first enter the directory to delete all, so as to distinguish the small program package

decompiling

tool

wxUnpacker

Download: gitee.com/guo49227377… Install the Node environment before running the tool. This tool requires several Node dependent libraries. Installation instructions are available in the readme. md document linked to this tool

The principle of

I understand ~, have a classmate can refer to this mp.weixin.qq.com/s/4BerA1Ij3…

The author too dish, see not quite understand ~

Specific commands

#Main package decompilationnode wxWxapkg.js .. /.. /wxapkg/xxxx/_-2094256841_77.wxapkg#Subpackage decompilationnode wxWxapkg.js -s=/Users/toretto/crack/wxapkg/xxxx/_-2094256841_77 .. /.. /wxapkg/xxxx/_571009734_77.wxapkg ....#Partial decompilation may cause an error, but it does not affect the subsequent encryption analysis process
Copy the code

get

Encryption analysis

tool

Wechat developer tools

Download address: developers.weixin.qq.com/miniprogram…

For reading code, code jump tracking

Analytical environment preparation

  1. Import decompile main package directory

  1. Give a name, click the test number to generate an AppID, create a small program

Static analysis

ParamsMD5 analysis

ParamsMD5 = paramsMD5 = paramsMD5 = paramsMD5 = paramsMD5

  1. Key position positioning

Well, if I go to 2, my gut tells me to go to getHmacSha256(n) in Request.js. Look at the data structure, including data, H5 and paramMD5. It is consistent with the conclusion of the previous interface analysis, and the general format is excellent

  1. GetHmacSha256 (n)
function getHmacsha256(e) {
    var n = JSON.stringify(e) + e.isSimulator + e.viewSize + e.networkType + e.time, t = _common2.default.environment === _config.ENVIRONMENTS.BETA ? "@yx789*&^DKJ##CC" : "@653yx#*^&HrTy99";
    console.log("request.js@32 n: " + n);
    return _encBase2.default.stringify((0, _hmacSha2.default)(n, t));
}
Copy the code

Variable n: We can guess from json.stringify (e) that parameter E is the data in the interface data and is a JSON object. The logic of n can basically lock the string of data itself and concatenate several values corresponding to data’s keys

T =” @653YX #*^&HrTy99″, is a fixed salt value.

Copy and paste the parameter data from the interface analysis above, change the code, and add a print statement to debug and look at the result:

var a = {"apiVersion":"t141"."appVersion":"1.5.1."."areaCode":"CS000016"."channel":"online"."clientid":"a7ea53059fc868e2e3e2dd7c04027035"."device_id":"tv179yrhs3kv9RXjJv6uJNmdkN6kTbmaUHQE"."time":1626080760465."reRule":"4"."token":"7ae362df162da5ffbfc408ed8e3d4ff3"."viewSize":"720x1184"."networkType":"wifi"."isSimulator":false."osType":"4"."scopeType":1."businessType":2."businessId":"17210001"."deliveryCircleType":"1"."body": {"longitude":"MTIwLjE1NDc3NQ=="."latitude":"MzAuMzA1ODIy"}};


function getHmacsha256(e) {
    // var n = JSON.stringify(e) + e.isSimulator + e.viewSize + e.networkType + e.time, t = _common2.default.environment === _config.ENVIRONMENTS.BETA ? "@yx789*&^DKJ##CC" : "@653yx#*^&HrTy99";
    var n = JSON.stringify(e) + e.isSimulator + e.viewSize + e.networkType + e.time, t = "@653yx#*^&HrTy99";
    console.log("request.js@32 n: " + n);
    return _encBase2.default.stringify((0, _hmacSha2.default)(n, t));
}

console.log(getHmacsha256(a));
Copy the code
RegeneratorRuntime is not defined in comment.jsCopy the code

Baidu found a solution to this error: blog.csdn.net/sinat_33184…

Small programs using async appear regeneratorRuntime is not defined error says fewer dependent libraries, download it

# generated package. Json
npm init 
Download the missing packageNPM install [email protected]Move the missing runtime.js to the project
cd node_modules/regenerator-runtime/
# same directory as common.js
cp runtime.js /Users/toretto/crack/wxapkg/darunfa/_-2094256841_77/service/
Copy the code

Modify the common.js code to introduce the package:

// Add it at the top
import regeneratorRuntime from './runtime.js'
Copy the code
Noderequest.js: can notimport modules fromOutside # can not import files from outside, there is no JS base I blind guess may be wechat small program does not have this syntax (because the code global searchimportThere is no match after the keyword.Copy the code

I saw this snippet in the applet code:

var _wepy = require(". /.. /npm/wepy/lib/wepy.js"),
Copy the code

That looks like the way to get in, so I learned a little bit and wrote this:

var regeneratorRuntime = require('./runtime.js');
Copy the code

Run again:

node reuqest.js
iOWz8O+xL9r9GX4k5Te/2U5HGTRk1GQ6YqLnMErWrAI=
// It can be run successfully
// The encryption of the printed output is the same as that obtained by the interface
Copy the code

Continue analyzing its generation logic, go back to the relevant code, and add a print statement:

f.Base64 = {
            stringify: function(r) {
                console.log("\nenc-base64@21 function(r):" + r);
                console.log("\nenc-base64@22 rObj:" + JSON.stringify(r));
                var e = r.words, t = r.sigBytes, o = this._map;
                r.clamp();
                for (var n = [], f = 0; f < t; f += 3) for (var i = e[f >>> 2] > > >24 - f % 4 * 8 & 255, a = e[f + 1 >>> 2] > > >24 - (f + 1) % 4 * 8 & 255, c = e[f + 2 >>> 2] > > >24 - (f + 2) % 4 * 8 & 255, p = i << 16 | a << 8 | c, s = 0; s < 4 && f + 75. * s < t; s++) n.push(o.charAt(p >>> 6 * (3 - s) & 63));
                var u = o.charAt(64);
                if (u) for(; n.length %4;) n.push(u);const ret = n.join("");
                console.log('\nenc-base64.js@27 n.join(""): ' + ret);
                return ret;
            }
Copy the code

R is a Base64 object and uses its words and sigBytes attributes:

toString(r): 
88e5b3f0efb12fdafd197e24e537bfd94e47193464d4643a62a2e7304ad6ac02

rObj:
{"words": [-1998212112, -273600550, -48660956, -449331239.1313282356.1691640890.1654843184.1255582722]."sigBytes":32}
Copy the code

Continuing the analysis of r’s build logic, add a few lines of print statements:

_createHmacHelper: function(t) {
                return function(n, e) {
                    console.log("libs/core.js@155 function(n, e) n:" + n);
                    console.log("libs/core.js@156 function(n, e) e:" + e);
                    console.log("libs/core.js@156 t:" + JSON.stringify(t));
                    const ret = new h.HMAC.init(t, e).finalize(n);
                    console.log("\nlibs/core.js@159 h.HMAC.init(t, e).finalize(n): " + JSON.stringify(ret))
                    return ret;
                };
            }
Copy the code

Add a few print statements to execute look:

/ / parameter n:
n: {"apiVersion":"t141"."appVersion":"1.5.1."."areaCode":"CS000016"."channel":"online"."clientid":"a7ea53059fc868e2e3e2dd7c04027035"."device_id":"tv179yrhs3kv9RXjJv6uJNmdkN6kTbmaUHQE"."time":1626080760465."reRule":"4"."token":"7ae362df162da5ffbfc408ed8e3d4ff3"."viewSize":"720x1184"."networkType":"wifi"."isSimulator":false."osType":"4"."scopeType":1."businessType":2."businessId":"17210001"."deliveryCircleType":"1"."body": {"longitude":"MTIwLjE1NDc3NQ=="."latitude":"MzAuMzA1ODIy"}}false720x1184wifi1626080760465
/ / parameter e:
e:
@653yx#*^&HrTy99
Copy the code

Hmac-sha256 hMAC-sha256 hMAC-sha256 hMAC-sha256 hMAC-sha256 hMAC-sha256 hMAC-sha256

It seems that the author also needs a systematic study of cryptography ~

Yuan god with certain

Encryption translation

The front end can encrypt, the back end must have the corresponding decryption. After reviewing the encryption logic of the above analysis, write a test demo in Java or Python to verify it

// The result is consistent with the previous js source code execution:
88e5b3f0efb12fdafd197e24e537bfd94e47193464d4643a62a2e7304ad6ac02
iOWz8O+xL9r9GX4k5Te/2U5HGTRk1GQ6YqLnMErWrAI=
Copy the code

Another way to think about it

The obfuscation code is not easy to read, and the code quantity is also complicated, so it may be difficult to realize encryption translation. Then we change our thinking, from “decipher” to “use” to sort out the above encryption process, sort out the code involved in encryption, copy it to a JS file as a tool library to get the final encryption result: specific process:

  1. A search for HMAC-SHA256 in the code shows that it comes from the crypto-js file

Crypto – js for the front end, see an encryption library blog.csdn.net/caoyan0829/…

# download
npm install crypto-js
# copy the library
cp 'node_modules/crypto-js/crypto-js'  crypto-js 

Copy the code
  1. Analyze the encrypted processing code in the small program, add the following logic at the back of the new crypto-js file
function stringify (r) {
    var e = r.words, t = r.sigBytes, o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    r.clamp();
    for (var n = [], f = 0; f < t; f += 3) for (var i = e[f >>> 2] >>> 24 - f % 4 * 8 & 255, a = e[f + 1 >>> 2] >>> 24 - (f + 1) % 4 * 8 & 255, c = e[f + 2 >>> 2] >>> 24 - (f + 2) % 4 * 8 & 255, p = i << 16 | a << 8 | c, s = 0; s < 4 && f + .75 * s < t; s++) n.push(o.charAt(p >>> 6 * (3 - s) & 63)); var u = o.charAt(64); if (u) for (; n.length % 4; ) n.push(u); // Const const Expected an operand but found const // console.log("\nenc-base64.js@40 n.join(\"\"): "+ ret); return n.join(""); } function getSignStr (str) { var hash = CryptoJS.HmacSHA256(str, key); // let hashInHex= CryptoJS.enc.Hex.stringify(hash); //base64_str return stringify(hash); }Copy the code

Test the data in the interface. If it works, this file can be used as a tool library to get encrypted signatures. Suitable for front-end development without back-end foundation of the students to use.

Of course, the backend students with Java or other languages to achieve encryption translation is difficult, you can also directly use this JS file, the following idea:

As an external js resource file is ready, the relevant reference: blog.csdn.net/u014174048/… Let Java execute js code by calling a script engine to get encrypted results:

  1. Put the crypto-js file under resource/js/
  2. Java complicit JS script interface:
public interface JavaScriptInterface {
    public String getSignStr(String str);
}

Copy the code
  1. A functional test
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.FileReader;

public class ExecuteScript {

    public static void main(String[] args) {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");
        String key = "{\" apiVersion \ ": \" t141 \ ", \ "appVersion \" : \ "1.5.1 \", \ "areaCode \" : \ "CS000016 \", \ "the channel \" : \ "online \", \ "clientid \" : \ "a7ea5 3059fc868e2e3e2dd7c04027035\",\"device_id\":\"tv179yrhs3kv9RXjJv6uJNmdkN6kTbmaUHQE\",\"time\":1626080760465,\"reRule\":\ "4\",\"token\":\"7ae362df162da5ffbfc408ed8e3d4ff3\",\"viewSize\":\"720x1184\",\"networkType\":\"wifi\",\"isSimulator\":f alse,\"osType\":\"4\",\"scopeType\":1,\"businessType\":2,\"businessId\":\"17210001\",\"deliveryCircleType\":\"1\",\"body \":{\"longitude\":\"MTIwLjE1NDc3NQ==\",\"latitude\":\"MzAuMzA1ODIy\"}}";
        try {
            String path = Thread.currentThread().getContextClassLoader().getResource("").getPath(); // Get the targe path
            System.out.println(path);
            // The argument to FileReader is the path to the js file to execute
            engine.eval(new FileReader(path+ "js/crypto-js.js"));
            if (engine instanceofInvocable) { Invocable invocable = (Invocable) engine; JavaScriptInterface executeMethod = invocable.getInterface(JavaScriptInterface.class); System.out.println(executeMethod.getSignStr(key)); }}catch(Exception e) { e.printStackTrace(); }}}Copy the code
// Execute result: consistent
iOWz8O+xL9r9GX4k5Te/2U5HGTRk1GQ6YqLnMErWrAI=
Copy the code

So be it, that’s a solution; If not for crawlers, it would be too much work to completely reproduce the Java version of the encryption logic

Longitude and latitude encryption analysis

{“longitude”:”MTIwLjE1NDc3NQ==”,”latitude”:”MzAuMzA1ODIy”}

The latitude and longitude encryption is much simpler than paramsMD5.

Static analysis
  1. Decode (e.latitude) = _base2.default.decode(e.latitude
  2. By observing the encryption result format and combining with the code context, it is found that there are base64-related codes, so it may be base64 encryption
  3. MzAuMzA1ODIy -> 30.305822, is 6 decimal digits, its value is in line with the value range of China’s dimension, should be correct
  4. Direct Java write section demo reverse verification, with Base64 encryption try
public static void main(String[] args) {
        String ret = Base64.getEncoder().encodeToString("30.305822".getBytes());
        System.out.println(ret);
    }
Copy the code
# result always MzAuMzA1ODIyCopy the code
  1. Conclusion: It is pure Base64 encryption

Wonderful brought the cat

Result:

  1. Reverse-engineering requires patience as well as bold guesses and assumptions to keep trying. Some print debugging as described in the text is verified after making bold guesses with the code
  2. A lot of useful tools used in reverse work, usually pay attention to collect some useful tools or blog to get twice the result with half the effort, the tools used in this article and related extended knowledge points are posted links, convenient reader collection ~
  3. The purpose of this article is to share some reverse skills and ideas, the sensitive case mentioned in this article has been omitted, readers can not use the content described in this article to obtain illegal business interests, if the legal responsibility will be borne by readers themselves.