前言

最近,当我在知识星球上观看小组聊天时,我发现一些朋友正在讨论与酷音乐有关的问题。以前,一些行星成员还发送了私人消息来询问此情况。 K兄弟一直尽力满足粉丝的需求。本文将在该网站上进行反向研究。这个案例是相对新颖的,不仅满足了粉丝的需求,而且还可以补充并改善了WASM反向案例:

反向目标数据包捕获分析

输入主页,随机输入您的手机号码,单击以发送验证代码,验证代码的弹出窗口将弹出并抓住数据包,并且会有很多响应。经过分析后,有用的接口将被send_mobile和get_verfy_info:

在第一个send_mobile接口之后,SSA代码将在响应协议标题中返回:

同时,此参数将在get_verfy_info接口上携带:

最后,通过此界面返回sessionID,这意味着会话已创建,并且是全球唯一的标识符:

然后,通过yidun单击/滑块验证代码,发现它将通过v4/verify_user_info进行验证:

该界面中有许多参数,还有与WASM相关的单词:

md5js解密_md5.js_md5.js怎么调用

最后,再次调用send_mobile接口,状态:1表示发送成功:

在数据包捕获分析之后,我们需要反向的参数为:中,UUID,签名,参数,PK,SID,EDT。

中和UUID参数的反向分析

单击发送按钮,然后查看发送堆栈并从第一个输入:

然后搜索中间:我发现有一些可疑的地方,在这些地方分开切断,最后在以下地方成功崩溃:

md5.js_md5.js怎么调用_md5js解密

我们输入getKgmid方法,发现它已在cookie中采用kg_mid,并且该值与我们刚刚看到的值相同。如果此参数在cookie中不存在,则将调用以下方法以获取浏览器的指纹信息,并使用MD5算法生成此值:

md5.js_md5js解密_md5.js怎么调用

因此,我们直接使用v_jstools钩住了如何生成cookie参数。挂钩脚本如下:

(function () {
  'use strict';
  var cookieTemp = '';
  Object.defineProperty(document, 'cookie', {
    set: function (val) {
      if (val.indexOf('kg_mid') != -1) {
        debugger;
      }
      console.log('Hook捕获到cookie设置->', val);
      cookieTemp = val;
      return val;
    },
    get: function () {
      return cookieTemp;
    },
  });
})();

清除浏览器高速缓存,刷新并发现向下已成功切断,遵循堆栈并找到生成参数的位置如下:

根据分析,该参数是通过生成UUID然后使用MD5算法生成的。它遵循UUID生成功能,其生成逻辑如下:

Guid: function() {
        function S4() {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        }
        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }

在这一点上,已经分析了MID和UUID参数。

签名参数

签名参数与全局搜索签名相同。最后,它在这个地方成功中断了。一代逻辑如下:

用数据参数将PARM参数拼写为parm参数,然后分别调用k.unshift(y)和k.push(y),以在数组的开始和结尾插入固定的字符串,最后将阵列拼接到字符串中通过加入MD5加密生成签名参数。

参数,PK参数

参数是在MID参数下生成的,逻辑如下:

通过将要加密的OBJ对象传递到AES函数中,键和EncryptedStr参数最终返回。我们输入AES函数以查看其生成逻辑:

md5.js怎么调用_md5js解密_md5.js

经过分析后,可以看出t是随机生成的,然后通过指定的处理逻辑将t处理到键和IV中,最后,加密参数与t一起返回,并以下复制:

function AES_Encrypt(data) {
    // 将输入数据转换为JSON字符串
    const jsonString = JSON.stringify(data);
    // 生成随机密钥(Key)
    const generateRandomKey = (length) => {
        const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        let randomKey = '';
        for (let i = 0; i < length; i++) {
            randomKey += chars.charAt(Math.floor(Math.random() * chars.length));
        }
        return randomKey;
    };
    // 如果未提供密钥,则生成一个16字符的随机密钥
    key = generateRandomKey(16);
    // 使用MD5对密钥进行编码,并截取前32字符作为实际密钥
    const md5Key = md5_encode(key).substring(0, 32);
    // 如果未提供向量(IV),则使用密钥的最后16字符
    iv = md5Key.substring(md5Key.length - 16);
    // 将密钥和向量转换为CryptoJS的Utf8对象
    const cryptoKey = CryptoJS.enc.Utf8.parse(md5Key);
    const cryptoIv = CryptoJS.enc.Utf8.parse(iv);
    // 使用AES算法进行加密
    const encrypted = CryptoJS.AES.encrypt(jsonString, cryptoKey, {
        iv: cryptoIv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    // 将加密结果转换为Hex字符串
    const encryptedHexStr = CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(encrypted.toString()));
    return {
        key: key,
        encryptedStr: encryptedHexStr
    };
}

然后继续下降,发现PK是由RSA生成的,主要是对密钥进行加密:

输入RSA.Encrypt函数,并发现它是带有10001的公共密钥索引的RSA加密和类型的nopadding:

md5.js怎么调用_md5js解密_md5.js

每个加密的结果具有一个独特的值。通过引用库或WT-JS重现它后,我们发现最终生成的加密值与其不同。最后,我们拿走了所有代码,并将其放入nodepad:

md5js解密_md5.js_md5.js怎么调用

我发现它是在一个大模块中,我们将其重写为自我执行的功能,并以模块的形式导入它:

const RSA = require('./rsa'); // 引入保存的rsa.js文件
function rsa_encode(word){
    word = JSON.stringify(word)
    // 使用的公钥
    const publicKey = "B1B1EC76A1BBDBF0D18E8CD9A87E53FA3881E2F004C67C9DDA2CA677DBEFA3D61DF8463FE12D84FF4B4699E02C9D41CAB917F5A8FB9E35580C4BDF97763A0420A476295D763EE10174E6F9EBF7DF8A77BA5B20CDA4EE705DEF5BBA3C88567B9656E52C9CD5CD95CA735FF2D25F762B133273EEEB7B4F3EA8B6DA29040F3B67CD";
    
    // 使用 encrypt 函数进行加密
    const encryptedMessage = RSA.encrypt(word);
    return encryptedMessage
    
    }

最后,结果与网页一致:

SID,EDT参数

求解上述参数后,我们最终来到SID和EDT参数,并使用堆栈和搜索快速找到以下位置:

md5js解密_md5.js_md5.js怎么调用

生成的逻辑如下:

var t = new wasm_bindgen.EData;
e.sid = t.get_sid(),
e.edt = c

我发现我在wasm_bindgen下首先有一个新的edata对象。我们去了Edata查看它,逻辑是:

md5js解密_md5.js_md5.js怎么调用

我们在全球搜索WASM_BINDGEN,以查找分配变量的下一个断点,清除缓存,单击发送以成功地在初始化位置上打破:

md5.js怎么调用_md5js解密_md5.js

然后,我逐步跟进,发现该方法初始化后,WASM文件开始在以下位置加载:

之后,我准备与WebAssembly(WASM)模块进行交互,具体来说,开始为WebAssembly实例配置导入对象。当然,这也是本文中最令人恶心的部分,并且在互动部分进行了许多检测。

原型链的检测:

md5.js怎么调用_md5.js_md5js解密

DOM层相关检测:

md5.js怎么调用_md5.js_md5js解密

WebGL原型链检测:

md5.js_md5.js怎么调用_md5js解密

md5.js怎么调用_md5.js_md5js解密

与WebGL相关的API操作检测:

md5.js_md5js解密_md5.js怎么调用

如果我们仍然像以前一样使用WebAssembly将WASM加载到节点中,则不可避免地会出现错误。因为我们缺乏相应的环境,所以我们需要将所有验证code.js拉到当地,如下所示:

md5js解密_md5.js怎么调用_md5.js

然后,我们仍然使用Mixue的代理框架:最新的Snow King Type__1286参数反向分析,K兄弟K将带您免费饮料〜。

将我们所有的陈词滥调文档,窗户,导航器,画布,位置等挂在代理上。

_instanceOf分析

原始代码如下:

function _instanceof(left, right) {
  if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
    return !!right[Symbol.hasInstance](left);
  } else {
    return left instanceof right;
  }
}

如果未满足以前的条件(即,正确或没有符号。Hasinstance方法),则使用JavaScript的内置实例操作员执行类型检查。

因此,在补充时,您需要注意原型链的继承关系,例如窗口,导航器,画布等。以下是一些例子:

HTMLCanvasElement = function HTMLCanvasElement (){
}
canvas.__proto__=HTMLCanvasElement.prototype
function WebGLRenderingContext() {}
// 为 WebGLRenderingContext 添加 Symbol.hasInstance
 Object.defineProperty(WebGLRenderingContext, Symbol.hasInstance, {
  value: function (obj) {
    return obj && typeof obj === 'object' && obj.drawingBufferWidth !== undefined && obj.drawingBufferHeight !== undefined;
  }
}); 

补充时,您可以转到检测场所打印相关信息,也可以直接修改RET = true(前提是您必须知道检测点在哪里):

md5js解密_md5.js_md5.js怎么调用

或者,您可以大胆地尝试修改_instanceOf函数。没有影响WASM加载,这不是使其检测返回的一部分的一种方法(当然,您必须知道要检测到什么)。返回不带大脑的真实可能会导致虚假价值或无法使用。

md5.js怎么调用_md5.js_md5js解密

整个代码完成后,我们将其运行并在网页上调用它:

var t = new wasm_bindgen.EData;
console.log(t.get_sid())
console.log(t.get_edt())

发现以下错误:

提示:此模块在我们的WASM下不存在,但是当我们打印WASM时,我们发现WASM确实存在并且负载已完成。经过进一步的分析,我们发现WASM是通过fetch加载的,而获取是一种异步形式,因此,当我们直接称其为单位时,它绝对不会被调用。我们还需要写一个异步呼叫:

setTimeout(() => {
             var t = new wasm_bindgen.EData;
            console.log(t.get_sid())
            console.log(t.get_edt())
             setTimeout = function(){}
}, 1000);

最后,我们使用节点导出异步结果:

const express = require('express');
const app = express();
const port = 3000;
// 定义一个接口来获取get_sid和get_edt的值
app.get('/getValues', async (req, res) => {
    // 模拟延时并获取值
    setTimeout(() => {
        try {
            var t = new wasm_bindgen.EData(); 
            const get_sid = t.get_sid();
            const get_edt = t.get_edt();
        res.json({ get_sid, get_edt });
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
}, 1000);
});
app.listen(port, () => {
    console.log(`Server is running on http://localhost:${port}`);
});

有关Yidun的相关说明,您可以参考以前的文章:[验证代码识别列] Tongkill空间推理验证验证代码培训和识别。

结果验证

最终的实施过程如下:

本网站每日更新互联网创业教程,一年会员只需98,全站资源免费下载点击查看会员权益

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注