web端逆向經驗、分析思路


前言

以下是看了魚哥的公眾號"咸魚學python",和"網蟲spider" 之后,加上一些自己的經驗,總結出以下的js逆向的經驗。看過《誤殺》嗎,里面有句話就是:當你看過1000部以上的電影,這世界上壓根沒有什么離奇的事情。

所以多看別人的分享案例,保持學習的狀態,你可以不用自己去分析,但是一定要學習別人遇到問題時的分析思路

 

此篇博文會一直更新,把web端的爬蟲經驗分析夠覆蓋時下主流

 

1.js逆向調試流程

    1. 如果網頁有跳轉,必須勾選 preservelog 防止丟包

    2. 看一下有沒有框架 右鍵查看框架源代碼(彈出式登陸界面)

    3. 登陸盡量使用錯誤密碼 防止跳轉

    4. 查看關鍵登陸包 分析哪些參數是加密的

    5. 使用別的瀏覽器分析哪些參數是固定的值

    6. 初步猜測加密方法

    7. 搜索

      • 直接搜索參數

      • pwd=

      • pwd =

      • pwd:

      • pwd :

      • 密碼框地方右鍵 檢查 查看 id name type

    8. 找到加密的地方(重點)

    9. 調試

    10. 找出所有的加密代碼

      • 從最后一步開始寫起,缺啥找啥

      • 如果找的是函數的話 search 要帶上 function xxx

      • 如果看到加密的地方有個類,並且之后是用 prototype 把方法加在原生對象上的話,要把
        所有加在原生對象上的方法都找出來

      • 函數找多了沒關系,只要不報錯不會影響結果,但是不能找少了

 

2.rsa破解:

    • 一般的rsa加密通常會先聲明一個rsa對象

    • 本地使用公鑰加密即public key

    • 通常有Encrypt關鍵字

    • 加密后字符長度為128位或256位
      結合以上套路可以幫助我們快速判斷加密方式如何,便於我們理清解密思路。

 

rsa加密:

 

from Crypto.PublicKey import RSA  # 導入模塊
from Crypto.Cipher import PKCS1_v1_5
import base64

key = RSA.generate(2048)
with open('prkey.pem', 'wb') as f:  # 生成私鑰文件
    f.write(key.exportKey('PEM'))

public = key.publickey()
with open('pukey.pem', 'wb') as f:  # 生成公鑰文件
    f.write(public.exportKey('PEM'))


def encrypto(password):
    rsakey = RSA.importKey(open('pukey.pem').read())
    cipher = PKCS1_v1_5.new(rsakey)
    result_encode = cipher.encrypt(password.encode())
    print(result_encode)
    return result_encode


def dencrypto(password):
    prkey = RSA.importKey(open('prkey.pem').read())
    cipher = PKCS1_v1_5.new(prkey)
    result_encode = cipher.decrypt(password, 'ERROR')
    result = result_encode.decode()
    print(result)


def encrypto_test(pk, password):
    public_key = f"-----BEGIN PUBLIC KEY-----\n{pk}\n-----END PUBLIC KEY-----"
    rsakey = RSA.importKey(public_key)
    cipher = PKCS1_v1_5.new(rsakey)
    result_encode = cipher.encrypt(password.encode())
    cipher_text = base64.b64encode(result_encode)
    result = cipher_text.decode()
    print(result)
    return result


if __name__ == "__main__":
    # 加解密測試
    dencrypto(encrypto('geeker'))

    # 實際的加密邏輯案例
    password = "123456"
    pk = """MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt0TDbDiNsw8r0mNI8XPl
ZGEsElso/AzZcRcudolcoKyjs8kDixpKruiajS+/GYOGwrqhHpOgVBaQPDEHS0yi
iU37SvWJ6cCvzHQRRdZtQfdygc9JdJyPXfNw3rWoMCHqSxNx9/hNtiUujBGvnLe6
ebbCOzqsNwIbjpNhb1AZ0V7sVwk22rTJ610GWJr/5MXILyy05ziAe09pjUf/0f7U
rIEB/EG35DuvB65GDXZLjSTDs+5P1yh8rTGnFSra7OAPhnjxwmTYV2Y+RitiQYQF
yMNerI0KQNKvd3NyjHq+A9s1CzOXkCGkIK4sTsJKjC5Ok7cEOdu7+YOMLtfREzcE
MQIDAQAB"""
    encrypto_test(pk, password)

  

 

3.大廠加密都簡單,安全防護之類的完全不靠js加密,靠的是風控

 像某付{}寶,大廠高級的都是風控,加解密都是開胃菜,用一個大佬跟我說的話,當你把加解密破解之后,游戲才剛剛開始

 

4.補環境

 

1).window is not defined;

修改為: window = global或者,var window = {}

ASN1 is not define,嘗試window = global

 

2).navigator is not defined

修改為: var navigator = {}

 

3).Cannot read property 'userAgent' of undefined

navigator.userAgent = 'xxxx'

 

4).Cannot read property 'body' of undefined:

這個是 document里面的。

修改為:document.body = {xxx(具體的某個參數)}

 

5).Cannot read property 'x' of undefined

缺少函數,具體缺少什么,可根據調試來添加。

 

6).Cannot read property 'href' of undefined

是 location.href

修改為:

window.location = {
"xxxx": {},
"href": "https://www.xxxx.com/",
(其他參數保持)
}

 

 

7).Cannot read property 'length' of undefined

具體原因是取值的時候,取到的是null。。。

具體調試可得知。

 

8).Cannot read property 'cookie' of undefined

var document = {
cookie:"xxxxxx"
}

9).

Object.getOwnPropertyDescriptor

var Navigator = function() {};
Navigator.prototype = {"platform": "win32"};
navigator = new Navigator();

 

 

不能寫成:

var navigator1 = {
platform:"win32"
}

因為:

 

 

10).prototype 與 _ _ proto _ _

xxx.__proto__ == yyy.prototype

遇到不好補的直接用jsdom,補起來很繁瑣時,用jsdom處理,npm install jsdom

 

11).userAgent is not defined

 

window.navigator = {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}

 

12.補齊window.localStorage:

window.localStorage = {
    removeItem: function (key) {
        delete this[key]
    },
    getItem: function (key) {
        return this[key] ? this[key]: null;
    },
    setItem: function (key, value) {
        this[key] = "" + value;  // 將數字轉為字符串
    },
};

13.canvas補齊:

 

document = {
    createElement: function() {
        return canvas
    }
};
canvas = {
    getContext: function getContext() {
        return CanvasRenderingContext2D
    },
    toDataURL: function toDataURL() {
        return "data:image/xxxx"
    },
};
CanvasRenderingContext2D = {
    arc: function arc() {},
    stroke: function stroke() {},
    fillText: function fillText() {},
};

 

14.document補齊

 

location = {
    "href": "https://www.w3school.com.cn/jsref/prop_anchor_href.asp",
    "origin": "https://www.w3school.com.cn",
    "protocol": "https:",
}
document = {
    createElement: function () {
        var loc = {
            href: ""
        };
        var temp_href = loc.href;
        Object.defineProperty(loc, 'href', {
            // Hook loc.href,當為其賦值時,按下面的規則強制改變
            get: function () {
                return temp_href
            },
            set: function (val) {
                if (val.indexOf('http://') === 0 || val.indexOf('https://') === 0) {
                    // 1.當值為http://或https://開頭時,即為該值
                    temp_href = val;
                } else if (val.indexOf('//') === 0) {
                    // 2.當值為//開頭時,即為location.protocol加上該值
                    temp_href = location.protocol + val;
                } else if (val.indexOf('/') === 0) {
                    // 3.當值為/開頭時,即為location.origin加上該值
                    temp_href = location.origin + val;
                } else {
                    // 4.除以上3種情況,即為location.href中最后一個/之前的值加上該值
                    var s = location.href
                    temp_href = s.substring(0, s.lastIndexOf("/")+1) + val
                }
                return temp_href
            }
        });
        return loc;
    }
}

  

5.有eval語句體的,直接把eval改為console.log,在控制台輸出查看

 

6.python實現aes加密,pip3 install pycryptodome

 

ECB 加密代碼:

import base64
from Crypto.Cipher import AES

class UseAES:
    """
    AES
    除了MODE_SIV模式key長度為:32, 48, or 64,
    其余key長度為16, 24 or 32
    詳細見AES內部文檔
    CBC模式傳入iv參數
    本例使用常用的ECB模式
    """
    def __init__(self, key):
        if len(key) > 32:
            key = key[:32]
        self.key = self.to_16(key)

    @staticmethod
    def to_16(key):
        """
        轉為16倍數的bytes數據
        :param key:
        :return:
        """
        key = bytes(key, encoding="utf8")
        while len(key) % 16 != 0:
            key += b'\0'
        return key  # 返回bytes

    def aes(self):
        return AES.new(self.key, AES.MODE_ECB)  # 初始化加密器

    def encrypt(self, text):
        aes = self.aes()
        return str(base64.encodebytes(aes.encrypt(self.to_16(text))),
                   encoding='utf8').replace('\n', '')  # 加密

    def decode_bytes(self, text):
        aes = self.aes()
        return str(aes.decrypt(base64.decodebytes(bytes(
            text, encoding='utf8'))).rstrip(b'\0').decode("utf8"))  # 解密

if __name__ == '__main__':
    aes_test = UseAES("xianyuxuepython")
    a = aes_test.encrypt("Python")
    print(a)
    b = aes_test.decode_bytes(a)
    print(b)

  

cbc模式

#!/usr/bin/env python
# -*- coding=utf-8 -*-
import base64
from Crypto.Cipher import AES
import random


def pkcs7padding(text):
    """
    明文使用PKCS7填充
    最終調用AES加密方法時,傳入的是一個byte數組,要求是16的整數倍,因此需要對明文進行處理
    :param text: 待加密內容(明文)
    :return:
    """
    bs = AES.block_size  # 16
    length = len(text)
    bytes_length = len(bytes(text, encoding='utf-8'))
    # tips:utf-8編碼時,英文占1個byte,而中文占3個byte
    padding_size = length if(bytes_length == length) else bytes_length
    padding = bs - padding_size % bs
    # tips:chr(padding)看與其它語言的約定,有的會使用'\0'
    padding_text = chr(padding) * padding
    return text + padding_text


def pkcs7unpadding(text):
    """
    處理使用PKCS7填充過的數據
    :param text: 解密后的字符串
    :return:
    """
    length = len(text)
    unpadding = ord(text[length-1])
    return text[0:length-unpadding]


def encrypt(key, content):
    """
    AES加密
    key,iv使用同一個
    模式cbc
    填充pkcs7
    :param key: 密鑰
    :param content: 加密內容
    :return:
    """
    key_bytes = bytes(key, encoding='utf-8')
    iv = key_bytes
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
    # 處理明文
    content_padding = pkcs7padding(content)
    # 加密
    encrypt_bytes = cipher.encrypt(bytes(content_padding, encoding='utf-8'))
    # 重新編碼
    result = str(base64.b64encode(encrypt_bytes), encoding='utf-8')
    return result


def decrypt(key, content):
    """
    AES解密
     key,iv使用同一個
    模式cbc
    去填充pkcs7
    :param key:
    :param content:
    :return:
    """
    key_bytes = bytes(key, encoding='utf-8')
    iv = key_bytes
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
    # base64解碼
    encrypt_bytes = base64.b64decode(content)
    # 解密
    decrypt_bytes = cipher.decrypt(encrypt_bytes)
    # 重新編碼
    result = str(decrypt_bytes, encoding='utf-8')
    # 去除填充內容
    result = pkcs7unpadding(result)
    return result


def get_key(n):
    """
    獲取密鑰 n 密鑰長度
    :return:
    """
    c_length = int(n)
    source = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
    length = len(source) - 1
    result = ''
    for i in range(c_length):
        result += source[random.randint(0, length)]
    return result

en_16 = 'abcdefgj10124567'
encrypt_en = encrypt(aes_key, en_16)
print(encrypt_en)

 

PKCS7模式:

import base64
from Crypto.Cipher import AES
import random


def pkcs7padding(text):
    """
    明文使用PKCS7填充
    最終調用AES加密方法時,傳入的是一個byte數組,要求是16的整數倍,因此需要對明文進行處理
    :param text: 待加密內容(明文)
    :return:
    """
    bs = AES.block_size  # 16
    length = len(text)
    bytes_length = len(bytes(text, encoding='utf-8'))
    # tips:utf-8編碼時,英文占1個byte,而中文占3個byte
    padding_size = length if(bytes_length == length) else bytes_length
    padding = bs - padding_size % bs
    # tips:chr(padding)看與其它語言的約定,有的會使用'\0'
    padding_text = chr(padding) * padding
    return text + padding_text


def pkcs7unpadding(text):
    """
    處理使用PKCS7填充過的數據
    :param text: 解密后的字符串
    :return:
    """
    length = len(text)
    unpadding = ord(text[length-1])
    return text[0:length-unpadding]


def encrypt(key, content):
    """
    AES加密
    key,iv使用同一個
    模式cbc
    填充pkcs7
    :param key: 密鑰
    :param content: 加密內容
    :return:
    """
    key_bytes = bytes(key, encoding='utf-8')
    iv = key_bytes
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
    # 處理明文
    content_padding = pkcs7padding(content)
    # 加密
    encrypt_bytes = cipher.encrypt(bytes(content_padding, encoding='utf-8'))
    # 重新編碼
    result = str(base64.b64encode(encrypt_bytes), encoding='utf-8')
    return result


def decrypt(key, content):
    """
    AES解密
     key,iv使用同一個
    模式cbc
    去填充pkcs7
    :param key:
    :param content:
    :return:
    """
    key_bytes = bytes(key, encoding='utf-8')
    iv = key_bytes
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
    # base64解碼
    encrypt_bytes = base64.b64decode(content)
    # 解密
    decrypt_bytes = cipher.decrypt(encrypt_bytes)
    # 重新編碼
    result = str(decrypt_bytes, encoding='utf-8')
    # 去除填充內容
    result = pkcs7unpadding(result)
    return result


def get_key(n):
    """
    獲取密鑰 n 密鑰長度
    :return:
    """
    c_length = int(n)
    source = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
    length = len(source) - 1
    result = ''
    for i in range(c_length):
        result += source[random.randint(0, length)]
    return result

 

PBKDF2:

import hmac
from hashlib import sha1, md5
import base64
from Crypto.Cipher import AES
from binascii import a2b_hex, hexlify
import hashlib


def decrypt(decryptData: str, key: bytes, iv: bytes):  # 解密函數
    res = a2b_hex(decryptData)
    aes = AES.new(key, AES.MODE_CBC, iv)
    plain_text = aes.decrypt(res)
    def unpad(date): return date[0:-ord(date[-1])]
    return unpad(plain_text.decode(errors='ignore'))


def hash_hmac(key, code):
    hmac_code = hmac.new(key.encode(), code.encode(), sha1).digest()
    return base64.b64encode(hmac_code).decode()


def md5_hex(code):
    return md5(code.encode()).hexdigest()


def PBKDF2(string):
    salt = "secret".encode()
    dk = hashlib.pbkdf2_hmac('sha256', string.encode(), salt, 1000)
    return hexlify(dk).decode()


if __name__ == '__main__':
    text = '73cd58935455e66d8f9c676f7f45c88d7d27d02296f6fab0ff7c41088351ee2b08db87df48d6e7218fbac0eea8e639e0fa24ae64c6c31ece1a808d0db5b68b9c466ecf514faa4129eb661d68b012f06b5975e25eea5f381f957e71ecf3e97689d497b04f3a5bfd03e07f8682cf6480fd803c0e94173fcba5a7d3ae257f55e21d8ea822bdc589e42185e26ef145aeafabb5be0781cfa6c583622b5c8379b2a1066b173d311dffa3ebc7033e20f252c7593066899c7955efdefee904c46168dfde7d57bcb8362091907353bb0656e56c4466e5ec56b826e5fa6b857a3c6077e7755f9379ad82a17c7b3ec9b0ef40ebaff7cab21f48e4d54a8af135ba71d67ae5c5f2c6d00a3dafa8b0ff43fe30b2d62a4649ac534226c06a4d2ca4d3a4564a28eaa2958b057ae247e797f6df8552eeb3c50047998df0b0c53eeb83a2645b50b94953ab33b1370d51d43c84a955bff58ed6efb659a1dd1eda55fa8dc3f0d383303bb5d8018077870c46ed2708f7559f25a8c0ff3ced0fcd000a739e10846cc8cc437fdc022664cb63ee313cb43b53e3965bcbb77025b124ffbbf3ce49fd75f9a5afa322b65e0816b710f1f07374838cfca5e5edec2211348de61cd3acb989bda496e0e18a8569c5a39cd63c73b8fff635d853d6330e3e30a293253ac15a8b8810e5441a693e2c3b9d50afd4fb7ed673199355741a8cbbd5e9cfe8bcea2ffd6f537a24d3b6101935897de20211a4ad7404d9a5d9462276e0c422f8ac14b6b2dd6be85f12129a55fd5b648b604ed1f73c3b5d59b9ea802211dfaacb12d21f8c174fb5c0bf9476ab825a12a74fd870b19018b2fb69aecb122401ce9629e44df061eacd92ab038d5dad7671ff375c21091e7af004fda6a716a372d0b3bc500f843400f557a0f19d179b82061f82584a44542d7755e3b87e62648dde294764faebc10640ab2658dd7defff2c773140b9ea080ddca8c3691fa963ad64751b895345f4c8e827b02104e0b4c86b73be751a47fb36535305976a362b024914b31d3d39eda81128314d01f6e109880b675ea41b95720256e13a1'
    key_hex = PBKDF2("D23ABC@#56")
    iv_hex = PBKDF2("api/api3/bk/score/provide")[:32]
    print(key_hex)
    print(iv_hex)
    decrypt_text = decrypt(text, a2b_hex(key_hex), a2b_hex(iv_hex))
    print(decrypt_text)

  

 

 

AES-CBC 輸出 Hash 的示例代碼

from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex


class PrpCrypt(object):
    def __init__(self, key):
        self.key = key.encode('utf-8')
        self.mode = AES.MODE_CBC

    # 加密函數,如果text不足16位就用空格補足為16位,
    # 如果大於16當時不是16的倍數,那就補足為16的倍數。
    def encrypt(self, text):
        text = text.encode('utf-8')
        cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF')
        # 這里密鑰key 長度必須為16(AES-128),
        # 24(AES-192),或者32 (AES-256)Bytes 長度
        # 目前AES-128 足夠目前使用
        length = 16
        count = len(text)
        if count < length:
            add = (length - count)
            # \0 backspace
            # text = text + ('\0' * add)
            text = text + ('\0' * add).encode('utf-8')
        elif count > length:
            add = (length - (count % length))
            # text = text + ('\0' * add)
            text = text + ('\0' * add).encode('utf-8')
        self.ciphertext = cryptor.encrypt(text)
        # 因為AES加密時候得到的字符串不一定是ascii字符集的,輸出到終端或者保存時候可能存在問題
        # 所以這里統一把加密后的字符串轉化為16進制字符串
        return b2a_hex(self.ciphertext)

    # 解密后,去掉補足的空格用strip() 去掉
    def decrypt(self, text):
        cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF')
        plain_text = cryptor.decrypt(a2b_hex(text))
        # return plain_text.rstrip('\0')
        return bytes.decode(plain_text).rstrip('\0')


if __name__ == '__main__':
    pc = PrpCrypt('jo8j9wGw%6HbxfFn')  # 初始化密鑰 key
    e = pc.encrypt('{"code":200,"data":{"apts":[]},"message":"","success":true}')  # 加密
    d = pc.decrypt("lXgLoJQ3MAUdzLX+ORj5/pJlkRAU423JfyUKVd5IwfCSxw6d1mHwBdHV9p3kmKCYwNRmAIEWeb/9ypLCqTZ1FA==")  # 解密
    print("加密:", e)
    print("解密:", d)

 

AES-CBC 輸出 Base64 的示例代碼

from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import base64

class PrpCrypt(object):
    def __init__(self, key):
        self.key = key.encode('utf-8')
        self.mode = AES.MODE_CBC

    # 加密函數,如果text不足16位就用空格補足為16位,
    # 如果大於16當時不是16的倍數,那就補足為16的倍數。
    def encrypt(self, text):
        text = text.encode('utf-8')
        cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF')
        # 這里密鑰key 長度必須為16(AES-128),
        # 24(AES-192),或者32 (AES-256)Bytes 長度
        # 目前AES-128 足夠目前使用
        length = 16
        count = len(text)
        if count < length:
            add = (length - count)
            # \0 backspace
            # text = text + ('\0' * add)
            text = text + ('\0' * add).encode('utf-8')
        elif count > length:
            add = (length - (count % length))
            # text = text + ('\0' * add)
            text = text + ('\0' * add).encode('utf-8')
        self.ciphertext = cryptor.encrypt(text)
        return base64.b64encode(self.ciphertext).decode()

    # 解密后,去掉補足的空格用strip() 去掉
    def decrypt(self, text):
        cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF')
        decryptByts = base64.b64decode(text)
        plain_text = cryptor.decrypt(decryptByts)
        return bytes.decode(plain_text).rstrip('\0')


if __name__ == '__main__':
    pc = PrpCrypt('jo8j9wGw%6HbxfFn')  # 初始化密鑰 key
    e = pc.encrypt('{"code":200,"data":{"apts":[]},"message":"","success":true}')  # 加密
    d = pc.decrypt("lXgLoJQ3MAUdzLX+ORj5/pJlkRAU423JfyUKVd5IwfCSxw6d1mHwBdHV9p3kmKCYwNRmAIEWeb/9ypLCqTZ1FA==")  # 解密
    print("加密:", e)
    print("解密:", d)

 

 

 更多的加密算法,有個老哥都實現了,git地址:https://github.com/Eeyhan/R-A-M-D-D3-S-M-H

 

7.css偽元素破解:

CSS中,::before 創建一個偽元素,其將成為匹配選中的元素的第一個子元素。常通過 content 屬性來為一個元素添加修飾性的內容。此元素默認為行內元素。

 

8.發現有加密,搜索encrypt,JSON.parse,JSON.stringify,CryptoJS 等相關的

 

 

9.斷點后的變量保存到全局

    • 選中變量, 右鍵 Evalute in console
    • 在 console 中選中輸出的內容, 右鍵 store as global variable

 

10.JSFuck 是使用 []()! 和 + 六種字符來表示原有的字符的

就像下面這樣的對應關系:

false       =>  ![]
true        =>  !![]
undefined   =>  [][[]]
NaN         =>  +[![]]
0           =>  +[]
1           =>  +!+[]
2           =>  !+[]+!+[]
10          =>  [+!+[]]+[+[]]
Array       =>  []
Number      =>  +[]
String      =>  []+[]
Boolean     =>  ![]

JSFuck 的處理方法有以下幾種:

document.write(xxx)
alert(xxx)
console.log(xxx)

11.eval加密

把一段字符串當做js代碼去執行

eval(function(){alert(100);return 200})()

 

例子: 漫畫櫃,空中網 之后會單獨寫一篇漫畫櫃的解密。

12.變量名混淆

  1. 把變量名、函數名、參數名等,替換成沒有語義,看着又很像的名字。

_0x21dd83、_0x21dd84、_0x21dd85

  

 

  1. 用十六進制文本去表示一個字符串

\x56\x49\x12\x23

 

  1. 利用JS能識別的編碼來做混淆
    JS是Unicode編碼,本身就能識別這種編碼。類似的一些變量名,函數名都可以用這個表示,並且調用。

類似:

 \u6210\u529f表示中文字符(成功)。
 
 類似:
 
 \u0053\u0074\u0072\u0069\u006e\u0067.\u0066\u0072\u006f\u006d\u0043\u0068\u0061\u0072\u0043\u006f\u0064\u0065就代表String.fromCharCode
 
 類似:

('')['\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72']['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'];效果等同於String.fromCharCode

 

  1. 把一大堆方法名、字符串等存到數組中,這個數組可以是上千個成員。然后調用的時候,取數組成員去用

var arr = ["Date","getTime"];
var time = new window[arr[0]]()[arr[1]]();
console.log(time);

 

  1. 字符串加密后發送到前端,然后前端調用對應的函數去解密,得到明文

var arr = ['xxxx']

// 定義的解密函數
function dec(str){
  return 'push'
}
test[dec(arr[0])](200);

  

13.控制流平坦化

將順序執行的代碼混淆成亂序執行,並加以混淆

以下兩段代碼的執行結果是相同的:

 

// 正常形態
function test(a){
  var b = a;
  b += 1;
  b += 2;
  b += 3;
  b += 4;
  return a + b
}

// 亂序形態
//(這里比較簡單,在很多加密網站上case 后面往往不是數字或字符串,而是類似 YFp[15][45][4]這樣的對象,相當惡心)
function test1(a){
  var arr = [1,2,3,4,5,6]
  for(var i = 0, i < arr.lenght, i++){
    switch (arr[i]) {
      case 4:
        b += 3;
        break;
      case 2:
        b += 1;
      break;
      case 1:
        var b = a;
      break;
     case 3:
        b += 2;
      break;
      case 6:
        return a + b
      case 5:
        b += 4;
      break;
    }
  }
}
// 結果都是30 但是test1看着費勁
console.log(test1(10));
console.log(test(10));

  

 

14.壓縮代碼

把多行代碼壓縮成一行

function test(a){
  var b = a;
  var c = b + 1;
  var d = b + 2;
  var e = b + 3;
  var f = b + 4;
  return e + f
}

// 壓縮一下
function test1(a){
  var b,c,d,e,f
  return f = (e = (d = ( c = (b = a,b + 1),b + 2),b + 3),b + 4),e + f
}

  

 

15.長得像base64的字符串,但是解密失敗的,要嘛aes/des,rsa,如果不是,嘗試用lzstring庫加解密

 

 

16.有關atob相關的

 

在瀏覽器中base64編碼轉換使用的是

_0x1c0cdf = _0xcbc80b['atob'](_0x1c0cdf),

在nodejs調試的時候使用的是

Buffer.from(_0x1c0cdf,"base64").toString()

 

17.判斷數據是不是由js生成或異步加載的。

 

  • 第一種,右鍵查看「網頁源代碼」,之后在打開的網頁源碼的界面搜索我們想要的數據是否在其中就可以判斷了。

  • 第二種,關閉網頁的js加載功能,查看網頁我們需要的數據是否能夠順利加載或者查看數據是否完整,步驟也非常簡單

第二種:

chrome瀏覽器訪問某網站,點擊哪個鎖圖片

 

 選擇網站設置,然后把js那一欄改為禁止

 

 刷新頁面即可驗證

 

18.node環境調試

 

用 Python 調用的 Node 環境不支持 document 這類瀏覽器屬性,在調試的時候需要將它去除或在 Node 下執行不報錯即可

 

19.找加密字段時

如果直接搜搜不到或者搜出來結果很多,可以搜跟這個加密字段相關的其他參數,因為一般情況下它們都是一起提交的,所以一般都會寫在一塊

20.在堆棧里,發現找不到js文件時,

 

 

參考鏈接:https://stackoverflow.com/questions/60369755/could-not-load-content-for-webpack-source-file-in-chrome-sources-tab這個應該是 webpack 的最小化生產模式導致在devtool模式的時候找不到文件映射

I was getting exactly the same problem, same error message etc when trying to debug typescript / html in Google Chrome.

The solution is to empty your cache.

Press Control + H to load up your browser history, and press the Clear Data button.

The try pressing Control + O or Control + P to load/select a source file again

 

 

通過快捷鍵 ctrl + p 重新加載文件

 

 

21.hook eval

window.__cr_eval = window.eval;
var myeval = function (src) {
    console.log('eval:', src);
    return window.__cr_eval(src)
};
var _myeval = myeval.bind(null);
_myeval.toString = window.__cr_eval.toString;
Object.defineProperty(window, 'eval', {value: _myeval});

 

 

 

 

22.去除無限debug

//去除無限debugger
Function.prototype.__constructor_back = Function.prototype.constructor;
Function.prototype.constructor = function() {
    if(arguments && typeof arguments[0]==='string'){
        //alert("new function: "+ arguments[0]);
        if("debugger" === arguments[0]){
            //arguments[0]="console.log(\"anti debugger\");";
            //arguments[0]=";";
            return
        }
    }
   return Function.prototype.__constructor_back.apply(this,arguments);
}

 

23.ob混淆,99%的加密結果都在代碼結尾

 

 

 

結語

沒有結束,會持續更新,同時app端的逆向也會出一個同類型的經驗博文持續更新

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM