[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G

Time:2022-5-8

[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G

Follow wechat official account: brother K crawler, QQ communication group: 808574309, and continue to share advanced crawler, js/ Android reverse and other technical dry goods!

statement

All contents in this article are only for learning and communication. The packet capturing content, sensitive website and data interface have been desensitized. It is strictly prohibited to use them for commercial and illegal purposes, otherwise all the consequences have nothing to do with the author. If there is infringement, please contact me and delete them immediately!

Reverse target

  • Goal: G log in to a game
  • Home page:aHR0cHM6Ly93d3cuZ205OS5jb20v
  • Interface:aHR0cHM6Ly9wYXNzcG9ydC5nbTk5LmNvbS9sb2dpbi9sb2dpbjM=
  • Reverse parameters:
    Query String Parameters:

    password: kRtqfg41ogc8btwGlEw6nWLg8cHcCW6R8JaeM......

Reverse process

Packet capture analysis

Go to the home page, enter an account and password casually, click login, grab the package and locate the login interface asaHR0cHM6Ly9wYXNzcG9ydC5nbTk5LmNvbS9sb2dpbi9sb2dpbjM=In the get request, query string parameters, the password is encrypted.

[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G

Encryption entry

If you search the keyword password directly, you will find that there are too many results that are difficult to locate. It is easier to locate the encryption entry using XHR breakpoint. For XHR breakpoint debugging, you can see the previous tutorials of brother K:[JS reverse hundred examples] XHR breakpoint debugging, steam login reverse, as shown in the figure below, at home You can see the key statements in min.jsa.encode(t.password, s)t.passwordIt’s a plaintext password,sIt’s a timestamp.

[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G

follow-upa.encode()Function, which is still in home In min.js, by observing this part of the code, we can find that jsencrypt is used and setpublickey is used to set the public key. From this, we can see that it should be RSA encryption. The specific steps are to combine the plaintext password and timestamp into a | combination, and then encode the URL after RSA encryption to get the final result, as shown in the figure below:

[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G

When RSA encryption finds the public key, you can directly use Python’s cryptodome module to implement the encryption process. The code is as follows:

import time
import base64
from urllib import parse
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_v1_5


password = "12345678"
timestamp = str(int(time.time() * 1000))
encrypted_object = timestamp + "|" + password
public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB"
rsa_ key = RSA. import_ Key (Base64. B64decode (public_key)) # import the read public key
cipher = PKCS1_ v1_ 5. New (rsa_key) # generate object
encrypted_password = base64.b64encode(cipher.encrypt(encrypted_object.encode(encoding="utf-8")))
encrypted_password = parse.quote(encrypted_password)
print(encrypted_password)

Even if we don’t use python, we can also reference jsencrypt module to implement this encryption process (the usage method of this module can be referred to)JSEncrypt GitHub), as follows:

/*
Reference the jsencrypt encryption module. If you directly use require in pycharm to reference the latest version of jsencrypt,
Running may prompt jsencrypt JS window is not defined, and VaR window = this is defined directly in this file; Just,
You can also use the same version 2.3.1 as the website: https://npmcdn.com/jsencrypt @2.3.1/bin/jsencrypt. js
You can also set jsencrypt JS is directly pasted into this script. If the prompt is not defined, it can be defined directly in this script.
*/

JSEncrypt = require("jsencrypt")

function getEncryptedPassword(t, e) {
    var jsEncrypt = new JSEncrypt();
    jsEncrypt.setPublicKey('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB');
    var i = e ? e + "|" + t : t;
    return encodeURIComponent(jsEncrypt.encrypt(i));
}

var password = "12345678";
var timestamp = (new Date).getTime();
console.log(getEncryptedPassword(password, timestamp));

Webpack rewrite

The title of this article is the actual battle of webpack rewriting, so it is obvious that the purpose of this article is to practice the rewriting of JavaScript modular programming webpack code. Now most sites use this writing method. However, not all sites, like the sites encountered in this article, can be easily implemented by other methods. Often, most sites need you to remove their source code to restore the encryption process, For JavaScript modular programming, i.e. webpack, we have described it in detail in previous articles of brother K:Crawler reverse foundation, understand JavaScript modular programming, webpack

A standard webpack as a whole is an Iife immediate call function expression, in which there is a module loader, that is, the function calling the module, which generally hasfunction.call()perhapsfunction.apply()Method. The parameter passed by Iife is a list or dictionary, which contains some modules that need to be called. The writing method is similar to:

!function (allModule) {
    function useModule(whichModule) {
        allModule[whichModule].call(null, "hello world!");
    }
}([
    function module0(param) {console.log("module0: " + param)},
    function module1(param) {console.log("module1: " + param)},
    function module2(param) {console.log("module2: " + param)},
]);

Observe the encryption code of this site and you will find that all encryption methods are at home In min.js, you can see at the beginning of this file that the whole is an Iife immediate call function expression,function eThere are key methods.call()Therefore, it can be judged that the function is a module loader. The parameters passed later are a dictionary, which contains object methods, that is, the module functions to be called. This is a typical webpack writing method, as shown in the following figure:

[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G

Next, we complete the rewriting of the webpack code in four steps, and pick up the original code to realize the encryption process.

1. Find Iife

Iife immediately calls function expressions, also known as immediate execution functions. Self executing functions pull out the Iife framework in the source code, and then put useful code into it:

!function (t) {
    
}({
    
})

2. Module loader found

As we have said before, withfunction.call()perhapsfunction.apply()Method is the module loader, that is, the method of calling the module. In this example,function eIt’s the module loader. Just pull it down. Other redundant codes can be deleted directly. Note that they are used in iti, so defineiThe sentences should also be cut down:

!function (t) {
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
            n.loaded = !0,
            n.exports
    }
    var i = {};
}({
    
})

3. Find the calling module

Back to the place of encryption, the first module is 3,nInsideencodeThe final result returned by the method is the encrypted result, as shown in the following figure:

[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G

The second module is 4. You can see the information in module 3this.jsencrypt.encrypt(i)Method is actually the method called in line 3340. This method is located in module 4. You can place the mouse cursor in front of the function on the browser developer tool source page and slide it up until the beginning of the module. You can also use editors such as vs code to edit the whole home Paste the min.js code, then choose to collapse all the codes, and then search this function to quickly locate the module.

[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G

After confirming that modules 3 and 4 are used, all the codes of these two modules can be deducted. The general code structure is as follows (the specific code of module 4 is too long and has been deleted):

!function (t) {
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
            n.loaded = !0,
            n.exports
    }
    var i = {};
}(
    {
        4: function (t, e, i) {},
        3: function (t, e, i) {
            var s;
            s = function (t, e, s) {
                function n() {
                    "undefined" != typeof r && (this.jsencrypt = new r.JSEncrypt,
                        this. jsencrypt. Setpublickey ("------ begin public key ----- omitted ----- end public key -----")
                }

                var r = i(4);
                n.prototype.encode = function (t, e) {
                    var i = e ? e + "|" + t : t;
                    return encodeURIComponent(this.jsencrypt.encrypt(i))
                },
                    s.exports = n
            }.call(e, i, e, t),
                !(void 0 !== s && (t.exports = s))
        }
    }
)

One thing we need to understand here is that there is a line in the code of module 3var r = i(4);, hereiyes3: function (t, e, i) {}, passed oniModule 3 is called by the module loader, i.e.call(n.exports, n, n.exports, e)One of the parameters isi, as I said earlier when I explained the basics,.callThe first parameter of specifies the point of this object in the function body and does not represent the real parameter, so the first parametern.exportsNot a parameter, from the second parameter, i.enStart counting, theniActually.call(n.exports, n, n.exports, e)Insidee, sovar r = i(4);It’s actually a module loaderfunction eModule 4 is called. Since module 4 here is an object, it’s best to write it asvar r = i("4");, here is a number, so it can run successfully. If the name of module 4 becomes func4 or other names, it must be quoted when calling.

4. Export encryption function

At present, the key encryption code has been stripped. The last step is to export the encryption function for us to call. First define a global variable, such as effunc, and then use the statement behind the module loadereFunc = e, export the module loader:

var eFunc;

!function (t) {
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
            n.loaded = !0,
            n.exports
    }
    var i = {};
    eFunc = e
}(
    {
        4: function (t, e, i) {},
        3: function (t, e, i) {}
    }
)

Then define a function to pass in the plaintext password and return the encrypted password:

function getEncryptedPassword(password) {
    var timestamp = (new Date).getTime();
    var encryptFunc = eFunc("3");
    var encrypt = new encryptFunc;
    return encrypt.encode(password, timestamp)
}

Among them, timestamp is the timestamp, because what we finally need to call is the timestamp in module 3n.prototype.encodeFor this method, first call module 3 and return the n function in module 3 (you can run the code in the browser and view the results step by step), then new it, call the encode method of N and return the encrypted results.

Since then, the encryption code of the webpack has been stripped. Finally, debugging will find that the navigator and window are undefined. Define them as follows:

var navigator = {};
var window = global;

Here’s an extension. In the browser, window is actually global. There is no window in nodejs, but there is a global, which is similar to the window object type of the browser and is a globally accessible object. Therefore, in the nodejs environment, window can be defined as global. If it is empty, it may cause other errors.

Complete code

GitHub pays attention to brother K crawler and continues to share crawler related codes! Welcome, star!https://github.com/kgepachong/

The following only demonstrates some key codes, which cannot be run directly!Full code warehouse address:https://github.com/kgepachong…

JavaScript encryption key code architecture

Method 1: rewrite the source code of webpack to realize RSA encryption:

var navigator = {};
var window = global;
var eFunc;

!function (t) {
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
            n.loaded = !0,
            n.exports
    }

    var i = {};
    eFunc = e;
}(
    {
        4: function (t, e, i) {},
        3: function (t, e, i) {}
    }
)

function getEncryptedPassword(password) {
    var timestamp = (new Date).getTime();
    var encryptFunc = eFunc("3");
    var encrypt = new encryptFunc;
    return encrypt.encode(password, timestamp)
}

//Test sample
// console.log(getEncryptedPassword("12345678"))

Method 2: directly use jsencrypt module to realize RSA encryption:

/*
Reference jsencrypt encryption module, which is suitable for running in nodejs environment.
1. Use the require statement to reference, provided that NPM has been installed;
2. Jsencrypt JS is pasted directly into this script for use. At the same time, the end exports JSEncrypt = JSEncrypt;  Change to JE = jsencrypt export method.
PS: VAR navigator = {} needs to be defined; var window = global;, Otherwise, the prompt is undefined.
*/

//========================================================= 1. Reference by require=========================
// var je = require("jsencrypt")

//Encrypt =================================================================== JS copy===================
/*! JSEncrypt v2.3.1 | https://npmcdn.com/[email protected]/LICENSE.txt */
var navigator = {};
var window = global;

//This is jsencrypt JS code

function getEncryptedPassword(t) {
    var jsEncrypt = new je();
    jsEncrypt.setPublicKey('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB');
    var e = (new Date).getTime();
    var i = e ? e + "|" + t : t;
    return encodeURIComponent(jsEncrypt.encrypt(i));
}

//Test sample
// console.log(getEncryptedPassword("12345678"));

Python login key code

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


import re
import json
import time
import random
import base64
from urllib import parse

import execjs
import requests
from PIL import Image
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_v1_5

login_ Url = 'desensitization processing, full code attention GitHub: https://github.com/kgepachong/crawler '
verify_ image_ Url = 'desensitization processing, full code attention GitHub: https://github.com/kgepachong/crawler '
check_ code_ Url = 'desensitization processing, full code attention GitHub: https://github.com/kgepachong/crawler '

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
session = requests.session()


def get_jquery():
    jsonp = ''
    for _ in range(21):
        jsonp += str(random.randint(0, 9))
    jquery = 'jQuery' + jsonp + '_'
    return jquery


def get_dict_from_jquery(text):
    result = re.findall(r'\((.*?)\)', text)[0]
    return json.loads(result)


def get_encrypted_password_by_javascript(password):
    #Two JavaScript scripts, both methods
    with open('gm99_encrypt.js', 'r', encoding='utf-8') as f:
    # with open('gm99_encrypt_2.js', 'r', encoding='utf-8') as f:
        exec_js = f.read()
    encrypted_password = execjs.compile(exec_js).call('getEncryptedPassword', password)
    return encrypted_password


def get_encrypted_password_by_python(password):
    timestamp = str(int(time.time() * 1000))
    encrypted_object = timestamp + "|" + password
    public_ Key = "desensitization processing, pay attention to GitHub with complete code: https://github.com/kgepachong/crawler "
    rsa_ key = RSA. import_ Key (Base64. B64decode (public_key)) # import the read public key
    cipher = PKCS1_ v1_ 5. New (rsa_key) # generate object
    encrypted_password = base64.b64encode(cipher.encrypt(encrypted_object.encode(encoding="utf-8")))
    encrypted_password = parse.quote(encrypted_password)
    return encrypted_password


def get_verify_code():
    response = session.get(url=verify_image_url, headers=headers)
    with open('code.png', 'wb') as f:
        f.write(response.content)
    image = Image.open('code.png')
    image.show()
    Code = input ('Please input the picture verification code: ')
    return code


def check_code(code):
    timestamp = str(int(time.time() * 1000))
    params = {
        'callback': get_jquery() + timestamp,
        'ckcode': code,
        '_': timestamp,
    }
    response = session.get(url=check_code_url, params=params, headers=headers)
    result = get_dict_from_jquery(response.text)
    if result['result'] == 1:
        pass
    else:
        Raise exception ('incorrect input of verification code! ')


def login(username, encrypted_password, code):
    timestamp = str(int(time.time() * 1000))
    params = {
        'callback': get_jquery() + timestamp,
        'encrypt': 1,
        'uname': username,
        'password': encrypted_password,
        'remember': 'checked',
        'ckcode': code,
        '_': timestamp
    }
    response = session.get(url=login_url, params=params, headers=headers)
    result = get_dict_from_jquery(response.text)
    print(result)


def main():
    #Test account: 15434947408, password: [email protected] @VwV
    Username = input ('Please enter login account: ')
    Password = input ('Please enter login password: ')

    #Obtain the encrypted password, which can be implemented by Python or JavaScript
    encrypted_password = get_encrypted_password_by_javascript(password)
    # encrypted_password = get_encrypted_password_by_python(password)

    #Get verification code
    code = get_verify_code()

    #Verification code
    check_code(code)

    #Login
    login(username, encrypted_password, code)


if __name__ == '__main__':
    main()

[JS reverse hundred examples] webpack rewrites the actual combat, and RSA encryption of a game in G