头图
Pay attention to WeChat public account: K brother crawler, QQ exchange group: 808574309, continue to share advanced crawler, JS/Android reverse engineering and other technical dry goods!

statement

All the content in this article is for learning and communication only. The captured content, sensitive URLs, and data interfaces have been desensitized, and it is strictly forbidden to use them for commercial or illegal purposes. Otherwise, all the consequences arising therefrom will have nothing to do with the author. Infringement, please contact me to delete it immediately!

Reverse target

  • Target: cnki academic translation AES encryption
  • Homepage: aHR0cHM6Ly9kaWN0LmNua2kubmV0L2luZGV4
  • Interface: aHR0cHM6Ly9kaWN0LmNua2kubmV0L2Z5enMtZnJvbnQtYXBpL3RyYW5zbGF0ZS9saXRlcmFsdHJhbnNsYXRpb24=
  • Reverse parameters: Request Payload: words: "kufhG_UJw_k3Sfr3j0BLAA=="

Reverse process

The reverse material of this issue comes from the help of a group of friends in the K reptile exchange group. The goal is cnki academic translation. Fans want to achieve two functions: 1. Break the limit of 1000 characters in English; 2. Reverse encryption process.

01.png

Go to the translation homepage, capture the package and locate the translation interface, you can see that the text to be translated will be encrypted in the Request Payload, as shown in the following figure:

02.png

If you directly search for the keyword words here, you will find that there are many results, which are not easy to find. Note that there is a translateType in the Payload parameter, then you can directly search for translateType, because these two parameters are usually next to each other, of course. You can use XHR breakpoints to find it, but it’s a bit more troublesome. The search results are all in app.9fb42bb0.js. Notice that there is encryption in the last result, which means encryption, which is basically the place of encryption:

03.png

The console prints (0, h.encrypto)(this.inputWord) , which is the encryption result:

04.png

Continue to follow up on h.encrypto . Obviously, AES encryption is n = "4e87183cfd3a45fe" , where n is the key, the mode is ECB, and Pkcs7 is filled. Finally, some string replacements are performed, as shown in the following figure:

05.png

Know the encryption algorithm, key and other key parameters, then directly refer to the crypto-js module to implement it. The JavaScript code is as follows:

// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js')

function s(t) {
    var n = "4e87183cfd3a45fe"
    var e = {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    }
      , i = CryptoJS.enc.Utf8.parse(n)
      , s = CryptoJS.AES.encrypt(t, i, e)
      , r = s.toString().replace(/\//g, "_");
    return r = r.replace(/\+/g, "-"),
    r
}

console.log(s("测试"))

// kufhG_UJw_k3Sfr3j0BLAA==

A small demo translated using Python:

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


import execjs
import requests


token_url = "https://dict.cnki.net/fyzs-front-api/getToken"
translation_api = "https://dict.cnki.net/fyzs-front-api/translate/literaltranslation"
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"

session = requests.session()


def get_token():
    headers = {"User-Agent": UA}
    response = session.get(url=token_url, headers=headers).json()
    token = response["data"]
    return token


def get_encrypted_word(word):
    with open('cnki_encrypt.js', 'r', encoding='utf-8') as f:
        cnki_js = f.read()
    encrypted_word = execjs.compile(cnki_js).call('s', word)
    return encrypted_word


def get_translation_result(encrypted_word, token):
    payload = {
        "translateType": None,
        "words": encrypted_word
    }
    headers = {
        "Token": token,
        "User-Agent": UA
    }
    response = session.post(url=translation_api, headers=headers, json=payload).json()
    result = response["data"]["mResult"]
    return result


def main():
    word = input("请输入待翻译字符串: ")
    token = get_token()
    encrypted_word = get_encrypted_word(word)
    result = get_translation_result(encrypted_word, token)
    print("翻译结果为: ", result)


if __name__ == "__main__":
    main()

Fans still have a problem with the character limit. See if it can be broken. The actual test limit is 1000 characters for English and 500 characters for Chinese, as shown in the figure below:

06.png

In fact, this restriction is not only a front-end restriction, but also a restriction on the server. We can bring more than 500 Chinese characters to request. The first character is "Test 1", and the last three characters are "Test 2". "At this time, there are more than 500 characters, and we see that Test 2 does not appear in the translation results, so if we want to translate a lot of strings, we can only divide them into several parts for processing.

07.png


K哥爬虫
166 声望148 粉丝

Python网络爬虫、JS 逆向等相关技术研究与分享。