[Hundreds of JS Reverse Cases] The fourth question of the anti-crawling practice platform for netizens: JSFuck encryption

Pay attention to the WeChat public account: Brother K crawler, continue to share technical dry goods such as advanced crawler, JS/Android reverse!

statement

All the content in this article is for learning and communication only. The captured content, sensitive URLs, and data interfaces have been desensitized. Commercial and illegal uses are strictly prohibited. Otherwise, all consequences arising therefrom have nothing to do with the author. If there is any infringement , please contact me to delete immediately!

reverse goal

  • Goal: Anti-anti-reptile practice platform for net losers. Question 4: JSFuck encryption
  • Link: http://spider.wangluozhe.com/challenge/4
  • Introduction: This question still requires collecting all the numbers of 100 pages and calculating the sum of all the data. It is necessary to extract the source code for calculation, mainly using JSFuck encryption

01.png

Introduction to JSFuck

JSFuck, AAEncode, JJEncode are all by the same author. JSFuck was created by Yosuke HASEGAWA in Japan in 2010. It can encode arbitrary JavaScript into an obfuscated form using only 6 symbols []()!+. In 2012, Martin Kleppe created a jsfuck project on GitHub and a JSFuck.com website that contains web applications implemented using the encoder. JSFuck can be used to bypass detection of malicious code submitted on websites, such as cross-site scripting (XSS) attacks. Another potential use of JSFuck is code obfuscation. Currently jQuery already has a fully functional version obfuscated by JSFuck.

Online experience address: https://utf-8.jp/public/jsfuck.html http://www.jsfuck.com/

A normal piece of JS code:

alert(1)

The code after JSFuck obfuscation looks like:

[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]])+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]])()((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[!+[]+!+[]+!+[]]]+[+!+[]]+([+[]]+![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[!+[]+!+[]+[+[]]])

The common elements, numbers, and symbol conversions in JSFuck are as follows. For more elements, please refer to JSFuck official GitHub or JSFuck Wikipedia :

Value JSFuck
false ![]
true !![] or !+[]
NaN +[![]]
undefined [][[]]
Infinity +(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]])
Array []
Number +[]
String []+[]
Boolean ![]
Function []["filter"]
eval []["filter"]["constructor"]( CODE )()
window []["filter"]["constructor"]("return this")()
+ (+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]])+[])[!+[]+!+[]]
. (+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]
0 +[]
1 +!![]or+!+[]
2 !![]+!![]or!+[]+!+[]
3 !![]+!![]+!![]or!+[]+!+[]+!+[]
a (![]+[])[+!+[]]
d ([][[]]+[])[!+[]+!+[]]
e (!![]+[])[!+[]+!+[]+!+[]]
f (![]+[])[+[]]

Let's take the letter a as an example to demonstrate its obfuscation process:

  1. "false"[1]: The letter a is taken from the string false, and in false, the index value of a is 1;
  2. (false+[])[1]: false can be written as false+[], that is, the boolean constant false plus an empty array;
  3. (![]+[])[1]: false can also be written as ![], that is, negation is applied to an empty array;
  4. (![]+[])[+true]: 1 is a number, we can write it as +true;
  5. (![]+[])[+!![]]: Since false is ![], true is !![], resulting in the final obfuscated code.

JSFuck deobfuscation method

JSFuck usually executes the method in the form of Function(xxx)() and eval(xxx) when calling a method, so the common deobfuscation methods of JSFuck are as follows:

  1. Decrypt directly using online tools, such as: https://lelinhtinh.github.io/de4js/ ;
  2. For the case of Function, copy the content in the penultimate parenthesis in the outermost layer of the code, put it in the browser and execute it directly to see the source code;
  3. For the case of eval, copy the content in the last parenthesis in the outermost layer of the code, put it in the browser and execute it directly to see the source code;
  4. Using Hook, Hook Function and eval respectively, print out the source code;
  5. Use AST for deobfuscation. Brother K will also write the AST tutorial in the future. This article will not introduce it in detail.

As in alert(1)the obfuscated code, copy the content in the last outermost bracket to the browser, and you can see the source code:

02.png

Inverse parameter

The target of the reverse is mainly the page-turning interface _signatureparameters . The encryption method of the call is still window.get_sign()the same as the previous questions. This article will not repeat them.

03.png

Continue to follow up, you will find that it is a JSFuck obfuscation:

04.png

We copy this code and put it in the editor. Take PyCharm as an example. Since we want to select the content in the matching brackets, we can set the PyCharm bracket matching highlight to red, which is convenient for us to find. Click File in turn. - Settings - Editor - Color Scheme - General - Code - Matched brace, set the Background to a prominent color:

05.png

At this point, we select the last bracket and look up, we can clearly see another bracket that matches it, as shown in the following figure:

06.png

We copy the content in the brackets (you can include the brackets or not), put it in the browser console and run it, you can see the source code:

07.png

In addition to this method, we can also use the Hook method to directly capture the source code and then print the output. Note that there are no ()parentheses , that is, the eval method is executed. We write the Hook eval code as follows:

eval_ = eval;
eval = function (a){
    debugger;
    return eval_()
}


// 另外提供一个 Hook Function 的代码
// Function.prototype.constructor_ = Function.prototype.constructor;
// Function.prototype.constructor = function (a) {
//     debugger;
//     return Function.prototype.constructor_(a);
// };

Refresh the web page and disconnect it directly. At this time, the value of a is the source code:

08.png

Copy the source code and analyze it locally:

(function () {
    let time_tmp = Date.now();
    let date = Date.parse(new Date());
    window = {};
    let click = window.document.onclick;
    let key_tmp;
    let iv_tmp;
    if (!click) {
        key_tmp = date * 1234;
    } else {
        key_tmp = date * 1244;
    }
    if (time_tmp - window.time < 1000) {
        iv_tmp = date * 4321;
    } else {
        iv_tmp = date * 4311;
    }
    const key = CryptoJS.enc.Utf8.parse(key_tmp);
    var iv = CryptoJS.enc.Utf8.parse(iv_tmp);
    (function tmp(date, key, iv) {
        function Encrypt(word) {
            let srcs = CryptoJS.enc.Utf8.parse(word);
            let encrypted = CryptoJS.AES.encrypt(srcs, key, {
                iv: iv,
                mode: CryptoJS.mode.CBC,
                padding: CryptoJS.pad.Pkcs7
            });
            return encrypted.ciphertext.toString().toUpperCase();
        }

        window.sign = Encrypt(date);
    })(date, key, iv);
})();

It can be seen that it is an AES encryption. The main attention here is that there are two if-else statements. The first is to judge whether it exists window.document.onclick, and the second is to judge the time difference. We can try to get the window.document.onclicksum window.timesee what is going on. Whether it is if or else, you can also complete these two values ​​locally. In fact, after the test by Brother K, it window.document.onclickis null, and then you can get the result whether you go if or else, so for this question, the two The window object doesn't matter, just remove it directly, key_tmpand you can take iv_tmpany value.

Since the analysis of this question has been completed and rewritten locally, the data of each page is calculated one by one with the Python code carrying the _signature, and the final submission is successful:

09.png

full code

GitHub pays attention to Brother K's crawler and continues to share crawler-related code! Welcome star! https://github.com/kgepachong/

The following only demonstrates some key codes and cannot be run directly! Complete code repository address: https://github.com/kgepachong/crawler/

JavaScript encryption code

/* ==================================
# @Time    : 2021-12-13
# @Author  : 微信公众号:K哥爬虫
# @FileName: challenge_4.js
# @Software: PyCharm
# ================================== */

var CryptoJS = require('crypto-js')

let date = Date.parse(new Date());
window = {};

let key_tmp = date * 1234;
// let key_tmp = date * 1244;
let iv_tmp = date * 4321;
// let iv_tmp = date * 4311;

const key = CryptoJS.enc.Utf8.parse(key_tmp);
var iv = CryptoJS.enc.Utf8.parse(iv_tmp);
(function tmp(date, key, iv) {
    function Encrypt(word) {
        let srcs = CryptoJS.enc.Utf8.parse(word);
        let encrypted = CryptoJS.AES.encrypt(srcs, key, {
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return encrypted.ciphertext.toString().toUpperCase();
    }

    window.sign = Encrypt(date);
})(date, key, iv);

function getSign() {
    return window.sign
}

// 测试输出
// console.log(getSign())

Python calculation key code

# ==================================
# --*-- coding: utf-8 --*--
# @Time    : 2021-12-13
# @Author  : 微信公众号:K哥爬虫
# @FileName: challenge_4.py
# @Software: PyCharm
# ==================================


import execjs
import requests


challenge_api = "http://spider.wangluozhe.com/challenge/api/4"
headers = {
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Cookie": "将 cookie 值改为你自己的!",
    "Host": "spider.wangluozhe.com",
    "Origin": "http://spider.wangluozhe.com",
    "Referer": "http://spider.wangluozhe.com/challenge/4",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
    "X-Requested-With": "XMLHttpRequest"
}


def get_signature():
    with open('challenge_4.js', 'r', encoding='utf-8') as f:
        ppdai_js = execjs.compile(f.read())
    signature = ppdai_js.call("getSign")
    print("signature: ", signature)
    return signature


def main():
    result = 0
    for page in range(1, 101):
        data = {
            "page": page,
            "count": 10,
            "_signature": get_signature()
        }
        response = requests.post(url=challenge_api, headers=headers, data=data).json()
        for d in response["data"]:
            result += d["value"]
    print("结果为: ", result)


if __name__ == '__main__':
    main()

{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4585873/blog/5376628