Experience of cracking No. 1 store

1. Pea pod downloads the latest version of No. 1 store, version 7.0.3. (downloading the old version seems to be a forced upgrade).

2. Through fiddler, I caught a package that searches for products according to keywords.

The request header and the request body are roughly the same. By sending the http request, it is found that the returned json will be invalid within a few minutes. At this time, it is thought that there are time-related encryption parameters to verify the request. In the case of changing the parameters, the influencing parameters are found. It is found that the suffix of the url has a sign. At this time, the parameter is found. Then look at the source code through jadx GUI software. You want to find out how to encrypt this parameter. Because the parameters affecting the results are related to sign, search for the methods related to sign and debug them through vs code to see if the whole process has taken this method.

It's written in the previous blog to hook through frida. I won't say it here. The following is the code of hook

function hook1(){
     * .overload()
        .overload('[B', '[B')
        .overload('java.util.Map', 'java.lang.String', 'java.lang.String')
    var sign = Java.use('com.jingdong.jdsdk.network.toolbox.GatewaySignatureHelper');//Class name
    sign.signature.implementation= function(a,b,c){
        console.log('Before encryption:'+a)
        console.log('Before encryption b: '+b)
        console.log('Before encryption c: '+c)
        var res = this.signature(a,b,c)
        console.log('After encryption:'+res);
        console.log('                    ')
        console.log('                    ')
        return res;

function main(){


Here are a few points to note. There will be many methods with the same name in a class, but when we hook, we need to hook a specific method. Therefore, if there are more than two methods with the same name, we need to overload and refer to the code in the comment; In addition, the method passes several parameters in the source code. If you hook here, you need to pass several parameters.

Finding the desired method in the source code also requires skills. Generally speaking, if we search sign directly, there may be thousands of codes related to this, so we can add a double quotation mark, which will greatly screen the results and facilitate us to go to hook. The search results can be found by copying the code of the top ten categories to the console, and then the search results can be found by clicking hook. (command frida -U com.thestore.main-l Hook.js)

Then it's hard to find that all the methods in it don't go Later, I searched through & sign and finally found the encryption method. It was found that three parameters affect the encryption result. Further analysis found that the secretKey is a fixed value. All decisions are that only url and body are encrypted.


Through hook, it is determined that when searching for products through keywords, this method is indeed used for encryption, but it needs to be further confirmed that whether I finally get the returned data is the same as the request structure when I capture the package, whether I can get the real data by sending a request, and whether it is the same as the data displayed in the APP search. So at this time, I need to call it remotely, and then write a test class locally to see if the result output from the console is what I want. The python script is as follows (script name rpc2.py)

from flask import Flask
from flask import request
import frida
import hashlib
import requests
import time
import json
import chardet

app = Flask(__name__)

def on_message(message, data):
    if message['type'] == 'send':

script = None

def begin():
    global script
    process = frida.get_remote_device().attach('com.thestore.main')
    # process = frida.get_device_manager().get_device("").attach('com.thestore.main')
    with open("rpc2.js",'r',encoding='utf-8') as js:
    script = process.create_script(jscode)
    script.on('message', on_message)
    script.load()#Finished loading script
    print('1. Finished loading script,Successfully obtained script object.....')
    app.run(debug=True, port=8004)# Start service

@app.route('/sign', methods=['GET'])
def waimai_function():
    p1 = request.args.get("p1")#Several parameters are determined according to the encryption method
    p2 = request.args.get("p2")
    print("p1 yes"+p1)
    print("p2 yes"+p2)
    res = script.exports.wirelesscode(p1,p2)#Pass the value here, and the rest is to open the service
    # res = '{wirelesscode:"'+res+'"}'
    return res

if __name__ == "__main__":

js code is as follows (the name is rpc2.js)

rpc.exports = {
    wirelesscode: function (p1,p2) {
        var result = ''
        Java.perform(function () {
            var sign = Java.use('com.jingdong.jdsdk.network.toolbox.GatewaySignatureHelper');//Class name
            console.log('Here we are, brother---'+p1+'-------'+p2);
            console.log('Parameters passed in:'+p1);
            console.log('Parameters passed in:'+p2);
            var c = 'f9b37e4b28e84c169f9d503baaa23b6c';//Fixed value
            result = sign.signature(p1,p2,c);
        return result;

The local test class code is as follows

public class TestKeyword {
    public static void main(String[] args) throws Exception {
    	String keyword  = "Facial Cleanser";
    	int page = 1;
    	String p2 = URLEncoder.encode("{\"addrFilter\":\"1\",\"apolloId\":\"b3fbf56db4484f42bb8464b94374d5a0\","
    			+ "\"apolloSecret\":\"af200ce75e1a4e188eca5fa90907f4a7\",\"articleEssay\":\"1\","
    			+ "\"deviceidTail\":\"\",\"insertArticle\":\"1\",\"insertScene\":\"1\","
    			+ "\"insertedCount\":\"0\",\"isCorrect\":\"1\",\"keyword\":\""+keyword+"\","
    			+ "\"latitude\":\"0.0\",\"longitude\":\"0.0\",\"newMiddleTag\":\"1\","
    			+ "\"newVersion\":\"3\",\"oneBoxMod\":\"1\",\"orignalSearch\":\"1\","
    			+ "\"orignalSelect\":\"1\",\"page\":\""+page+"\",\"pageEntrance\":\"1\","
    			+ "\"pagesize\":\"10\",\"pvid\":\"\",\"sdkClient\":\"plugin_android\","
    			+ "\"sdkName\":\"search\",\"sdkVersion\":\"1.0.0\",\"searchVersionCode\":\"0\","
    			+ "\"showShopTab\":\"yes\",\"showStoreTab\":\"1\",\"stock\":\"1\"}","utf-8");
    	String res = "http://localhost:8004/sign?p1="+DecipherUtil.key(keyword, page)+"&p2="+p2;
    	String url = HttpBase.get(res, "utf-8").getResult();
    	String body = "body="+p2+"&";
    	Map<String,String> header = new HashMap();
		header.put("Charset", "UTF-8");
		header.put("Connection", "keep-alive");
		header.put("Cache-Control", "no-cache");
		header.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		header.put("Content-Length", "927");
		header.put("Host", "api.m.jd.com");
		header.put("User-Agent", "okhttp/3.12.1");
		try {
			String result = PostUtil.post(url, header, body);
		} catch (ConnectException e) {
			// TODO Auto-generated catch block

The util class code is as follows

public class DecipherUtil {
    public static  String key(String keyword,int page) throws Exception {
        String time = System.currentTimeMillis()+"";
        String p1 = URLEncoder.encode("http://api.m.jd.com/api?appid=member_yhd&functionId=yhd_nsearch"
                + "&t="+time+"&clientVersion=7.0.3&build=703&client=yhd_android&d_brand=Coolpad"
                + "&d_model=N3C&osVersion=7.1.1&screen=1344*720&partner=jingdong"
                + "&lang=zh_CN&uuid=352118197740800-00281a339ed5&area=2_2825_0_0"
                + "&networkType=wifi&wifiBssid=unknown","utf-8");
        String p2 = URLEncoder.encode("{\"addrFilter\":\"1\",\"apolloId\":\"b3fbf56db4484f42bb8464b94374d5a0\","
                + "\"apolloSecret\":\"af200ce75e1a4e188eca5fa90907f4a7\",\"articleEssay\":\"1\","
                + "\"deviceidTail\":\"\",\"insertArticle\":\"1\",\"insertScene\":\"1\","
                + "\"insertedCount\":\"0\",\"isCorrect\":\"1\",\"keyword\":\""+keyword+"\","
                + "\"latitude\":\"0.0\",\"longitude\":\"0.0\",\"newMiddleTag\":\"1\","
                + "\"newVersion\":\"3\",\"oneBoxMod\":\"1\",\"orignalSearch\":\"1\","
                + "\"orignalSelect\":\"1\",\"page\":\""+page+"\",\"pageEntrance\":\"1\","
                + "\"pagesize\":\"10\",\"pvid\":\"\",\"sdkClient\":\"plugin_android\","
                + "\"sdkName\":\"search\",\"sdkVersion\":\"1.0.0\",\"searchVersionCode\":\"0\","
                + "\"showShopTab\":\"yes\",\"showStoreTab\":\"1\",\"stock\":\"1\"}","utf-8");
        return p1;

In fact, you can know through the hook method that the keywords involved in encryption are nothing more than search keywords. At most, one page turning parameter is added to the time, which mainly depends on how it is spliced before encryption. Generally, when you see many% in the body, you will naturally think of encoding and decoding. The encoding and decoding encountered before is that only Chinese characters are encoded, but No. 1 store is all involved in the encoding.

Several points to pay attention to in the whole process:

      1. During the whole hook process and local test, the real machine or simulator must be connected to the computer, and the APP of No. 1 store needs to be opened. If an error about frida is reported in the hook process, it may be that the highest authority is not given or there is no forwarding. At this time, you can re-establish these two steps and start frida again.

      2. For the above python script, if there are dependencies that are not downloaded, the startup will also report an error. Import the dependent command pip install package name.

      3. Sometimes when frida is started, the APP of store 1 is also opened, but an error will be reported when executing the script, saying frida Invalidargumenterror: device not found, that is, we process = frida get_ devices_ The manager () line of code is wrong. Just replace it with the above line. This is not that you can't write it in this method. The main reason is that sometimes you can't connect the first time, and then the second and third time. To be on the safe side, use the line above.

     4. The service will be started and the python script can also be executed, but the APP will flash back and cannot be opened again. At this time, you need to restart the mobile phone or simulator, then re forward it, start frida, open the APP of No. 1 store, and then start the script.


Posted by LooieENG on Wed, 18 May 2022 05:26:39 +0300