【JS逆向百例】某盾 Blackbox 逆向分析

在这里插入图片描述

声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!

逆向目标

目标:某盾 Blackbox 算法逆向分析

网站:aHR0cHM6Ly93d3cuanVuZXlhb2Fpci5jb20v

本文只对某盾 Blackbox 的其中一种算法进行逆向分析,不涉及指纹风控、环境部分。

逆向分析

在这里插入图片描述

通过搜索 blackBox 即可定位到如下位置:

在这里插入图片描述

往上跟栈,发现是由此函数生成的:

在这里插入图片描述

进入到该函数内,重新下断点刷新网站,单步往下跟,定位到最后 return 处:

在这里插入图片描述

发现 Blackbox 值是由 5WPH173561408225WrZh6Cf 经过 QOoooO 函数生成的 ,搜索发现该值是

profile.json 接口返回的:

在这里插入图片描述

在这里插入图片描述

我们的重点就是 profile.json 接口的这些请求参数,非常之多,但是不要怕,慢慢来。

查看堆栈,发现和 Blackbox 值最终生成的 js 文件一样,都是 fm.js 文件,也就是 Blackbox 值生成的核心文件,点进去发现有一堆 oQ0Qo0 大数组混淆,定位到 ooQGOO 的生成位置 oQ0Qo0 = ooQGOO(oQ0Qo0);

在这里插入图片描述

oQ0Qo0 就是传入的长字符串, 通过 ooQGOO 函数就生成了 oQ0Qo0 的大数组,可以把 ooQGOO 给扣下来,非常容易,也可以分析 ooQGOO 函数,对这类混淆熟悉的可以直接秒,基本都是一套逻辑:

// 传入的长字符串
en_txt = '';

// ooQGOO 函数部分
oQ0Qo0 = decodeURIComponent(atob(en_txt))['split']('##');

traverse(ast, {
    MemberExpression(path){
        let {object, property} = path.node;
        if (!t.isIdentifier(object) && !t.isNumericLiteral(property)) return;
        if (object.name !== "oQ0Qo0") return;
        let _v = oQ0Qo0[property.value]
        path.replaceWith(t.valueToNode(_v))

    }
});

然后再通过工具替换代码,这边选用 ReRes 工具进行替换,写好规则保存勾选就好了:

https://github.com/annnhan/ReRes

在这里插入图片描述

刷新网站没有任何问题,然后我们再从头再来:

先解决 QOoooO 函数,其传入接口返回的 tokenId 参数,生成最终的 Blackbox 值,进入该函数,逻辑非常清晰:

在这里插入图片描述

可以直接扣下来,或者分析还原,代码如下:

import random

def get_blackbox(token_id):
    chars = "ghijklmnopqrstuv"
    all_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    return chars[int(token_id[0], 16)] + token_id[1:4] + random.choice(all_chars) + token_id[4:14] + random.choice(all_chars) + token_id[14:22] + random.choice(all_chars) + token_id[22]

然后就是 profile.json 接口的这些请求参数分析:

  • partner:写死;
  • app_name:写死;
  • token_id:搜索即可定位到:
    在这里插入图片描述

由 partner、时间戳、随机值组成:

import time
import random

token_id = (
    partner
    + "-"
    + str(int(time.time() * 1000))
    + "-"
    + "".join(random.choices("0123456789abcdef", k=12))
)

剩下的不太好搜索定位,我们用 idf 搜索来定位,发现有五处生成位置,我们全部打上断点:

在这里插入图片描述

断到如上位置,可以发现:

  • v:是 version 在 js 文件中是写死的:

在这里插入图片描述

  • idf:目前生成的明显不是最终请求的参数;
  • w:通过 O0QOOQ 函数 对版本 v 进行 加密生成,我们跟进去:

在这里插入图片描述

然后再跟进到 QOoo0Q 函数中,单步走,就定位到如下 return 的位置,发现关键字 TripleDES

在这里插入图片描述

这个可能有些小伙伴不太熟悉,直接百度或者 ai 就会发现是 3DES 加密:

在这里插入图片描述

  • 浏览器生成:

在这里插入图片描述

  • 标准:

在这里插入图片描述

发现浏览器生成的,和标准的不太一样,不过又非常相似,我们其实也能看到一些特征,比如大小写互换,然后我们可以自己处理成一样的:

import base64
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad, unpad


def replace_characters(input_str):
    return input_str.replace('+', '~')

def swap_characters_3DES2(s):
    # 使用字典映射实现字符互换
    swap_map = {
        'i': 'j',
        'j': 'i',
        'I': 'J',
        'J': 'I'
    }
    # 使用列表推导式逐个字符替换
    swapped_s = ''.join([swap_map.get(char, char) for char in s])
    return swapped_s

def encrypt_3des_cbc(data, key):
    iv = '12345678'  # 3DES 使用8字节IV
    block_size = DES3.block_size

    # 对数据进行填充
    data = pad(data.encode('latin-1'), block_size)

    cipher = DES3.new(key.encode('latin-1'), DES3.MODE_CBC, iv.encode('latin-1'))
    encrypted = cipher.encrypt(data)

    return replace_characters(swap_characters_3DES2(base64.b64encode(encrypted).decode('latin-1').swapcase()))


if __name__ == '__main__':
    data = 'JZuFK8iZfzhZG+BaqcUjAgNuPh8lFrtHCX3Ev7uGAGTj9gLkI0nL5bb/QS7zhKew'
    key = '1735627982523-1142600494'
    encrypted_data = encrypt_3des_cbc(data, key)
    print(encrypted_data)

key Q0oQ0o["timestamp"]["substring"](0, 24)

通过搜索,可以定位到 Q0oQ0o["timestamp"] 的生成位置:

在这里插入图片描述

也是由时间戳、随机数组成,可以重新刷新,我们看看还有什么参数是走的这个算法。

断住后,往上跟值,可以发现是哪个参数:

在这里插入图片描述

在这里插入图片描述

发现:

  • abcdgfct 都是由这个算法生成,明文就是加密的值,key 都是同一个值如上;

idf

然后跳断点,又来到了我们断 idf 的地方:

在这里插入图片描述

Q0oQ0o["timestamp"] 就是我们截取生成 key 的初始值,上面已经分析了。又发现关键字 setPublicKey

可能猜到是 RSA 加密,PublicKey 搜索发现 在 js 文件中是写死的,经过测试是标准的 RSA 加密:

在这里插入图片描述

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

def RSA_Public_Encrypt(plain_text):
    # RSA 公钥
    public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuR3+MuPOVYuAKOS6O+J/ds+JAesgyFforFupDiDBBMTItdXyMrG6gUPFxj/pT/9uQSq8Zxl7BrdiKdi0G2ppEn4Nym+VRLTv2+lNa3kvlrj25Lop7wDZkVRecK5oDvdaQHrm4KKiF7jZNbHEreWGsINLpGvzBMRNztRtOJ6+XEQIDAQAB"

    # 加载公钥
    key = RSA.import_key(base64.b64decode(public_key))

    # 使用 PKCS1_v1_5 进行加密
    cipher = PKCS1_v1_5.new(key)
    encrypted_data = cipher.encrypt(plain_text.encode('utf-8'))

    # 返回 Base64 编码的加密结果
    return base64.b64encode(encrypted_data).decode('utf-8')

e

直接暴力搜索 ["e"],发现有 20 多个位置,不过非常容易定位到其生成的位置:

在这里插入图片描述

Q0o0o0 函数生成,进入后发现也是随机生成的:

在这里插入图片描述

import random

def generate_random_string():
    # 字符集
    characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    # 随机生成 127 长度的字符串
    random_string = "".join(random.choice(characters) for _ in range(108))
    # 在随机位置插入一个反斜杠
    insert_position = random.randint(0, len(random_string))
    random_string = random_string[:insert_position] + "\\" + random_string[insert_position:]
    return random_string

h

搜索 _callback 或者 h= 可以定位到目标位置, 就在生成 idf 的下面:

在这里插入图片描述

将前面的请求参数,拼接成字符串,然后再进行 O00O0o["hash128"] 函数的加密:

query_string = "?" + urllib.parse.urlencode(params)
h = oo0OOQ.hash128(query_string)

hash128 可以直接扣 js 代码,不多,或者直接用 python 还原:

在这里插入图片描述

python 算法的源码,会分享到知识星球当中,需要的小伙伴自取,仅供学习交流。

结果验证

在这里插入图片描述

关于同BlackBox相关的逆向工程方法或破解手段,此类话题涉及安全性和合法性问题,在许多国家和地区可能违反法律法规以及道德准则。从技术角度探讨合法合规的安全测试与防护措施是有意义的。 对于软件系统的安全性评估通常采用多种技术和工具来检测潜在漏洞并加强防御机制。这包括但不限于静态分析、动态分析、模糊测试等正规途径来进行安全研究[^1]。 ### 合规的安全测试实践 #### 静态应用安全测试 (SAST) 通过解析源代码或二进制文件而不需执行程序本身即可识别安全隐患的一种方式。这种方法有助于发现编码阶段引入的问题。 ```python import bandit def check_insecure_functions(codebase): findings = [] # 使用Bandit库扫描Python项目中的不安全函数调用 results = bandit.main._main(['bandit', '-r', codebase]) for result in results: finding = { "filename": result.fname, "issue_severity": result.issue_sev, "line_number": result.lineno, "code_snippet": result.text } findings.append(finding) return findings ``` #### 动态应用安全测试 (DAST) 在应用程序运行时对其进行黑盒测试,模拟攻击者的行为尝试找出可利用的缺陷。这种方式能够捕捉到实际环境中可能出现的风险点。 ```bash # 使用OWASP ZAP进行自动化渗透测试 zap.sh -daemon -port 8090 \ -config api.key=your_api_key_here \ -open-url http://target-application.com/ ``` #### 模糊测试(Fuzzing) 输入异常数据给目标系统以触发未预见行为的技术,可以有效挖掘未知类型的错误和弱点。 ```c #include <fuzzer/FuzzedDataProvider.h> extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { FuzzedDataProvider provider(data, size); // 对接收到的数据做进一步处理... } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值