开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 200|回复: 4
收起左侧

[精币悬赏] js混淆代码还原

[复制链接]
结帖率:80% (12/15)
发表于 6 天前 | 显示全部楼层 |阅读模式   江苏省南通市
100精币
文件中的js代码混淆了,有没有办法转换成能正常阅读的代码,或者网址中协议头中的sign由来(https://picc-2025sq20.bdideal.com/e/?source_entry=26&u=57e30350dfca3fc1bfeafd8e5885be93)
js.txt (158.96 KB, 下载次数: 8)

结帖率:100% (4/4)

签到天数: 6 天

发表于 5 天前 | 显示全部楼层   广东省广州市
是不是找错JS了 这个解出来是这样的
[JavaScript] 纯文本查看 复制代码
'use strict';

/**
 * 前端事件跟踪工具
 * 功能:监听页面点击/触摸事件、收集事件数据、向指定接口发送统计信息
 * 支持域名过滤、日志管理、请求重试等特性
 */

// ========================= 工具函数库 =========================
const Utils = {
    /**
     * 字符串解码(还原原混淆中的Base64+URI编码逻辑)
     * @param {string} encodedStr - 编码字符串(可能含\x格式或Base64)
     * @returns {string} 解码后的可读字符串
     */
    decodeString(encodedStr) {
        if (!encodedStr) return '';
        // 处理\x格式编码
        const hexDecoded = encodedStr.replace(/\\x([0-9a-fA-F]{2})/g, (_, hex) => 
            String.fromCharCode(parseInt(hex, 16))
        );
        // 处理Base64编码(原混淆中隐性使用的编码方式)
        const baseStr = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
        let baseDecoded = '';
        let encoded = hexDecoded.replace(/\s+/g, '');
        // 补全Base64长度
        while (encoded.length % 4) encoded += '=';
        
        for (let i = 0, len = encoded.length; i < len; i += 4) {
            const c1 = baseStr.indexOf(encoded);
            const c2 = baseStr.indexOf(encoded[i + 1]);
            const c3 = baseStr.indexOf(encoded[i + 2]);
            const c4 = baseStr.indexOf(encoded[i + 3]);
            const bytes = (c1 << 18) | (c2 << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F);
            
            baseDecoded += String.fromCharCode((bytes >> 16) & 0xFF);
            if (c3 !== 64) baseDecoded += String.fromCharCode((bytes >> 8) & 0xFF);
            if (c4 !== 64) baseDecoded += String.fromCharCode(bytes & 0xFF);
        }
        // URI解码(处理特殊字符)
        return decodeURIComponent(escape(baseDecoded));
    },

    /**
     * 生成唯一ID(用于事件ID、设备ID等)
     * @param {number} length - ID长度,默认16位
     * @returns {string} 唯一随机字符串
     */
    generateUniqueId(length = 16) {
        const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        let id = '';
        for (let i = 0; i < length; i++) {
            id += chars[Math.floor(Math.random() * chars.length)];
        }
        return id;
    },

    /**
     * 验证URL是否匹配指定域名正则
     * @param {RegExp} domainReg - 域名正则(如 /bdideal\.com|localhost/)
     * @param {string} url - 待验证URL,默认当前页面URL
     * @returns {boolean} 是否匹配
     */
    isMatchDomain(domainReg, url = window.location.href) {
        return domainReg.test(url);
    },

    /**
     * 获取当前设备信息(简化版,原混淆中用于生成deviceId)
     * @returns {string} 设备标识(基于UA的简化哈希)
     */
    getDeviceId() {
        const ua = navigator.userAgent;
        // 简单哈希计算(避免敏感信息,仅用于标识设备)
        let hash = 0;
        for (let i = 0; i < ua.length; i++) {
            hash = ((hash << 5) - hash) + ua.charCodeAt(i);
            hash &= hash; // 转为32位整数
        }
        return `dev_${Math.abs(hash)}`;
    }
};

// ========================= 错误处理类 =========================
class TrackerError extends Error {
    /**
     * 自定义跟踪错误类(还原原_0xbcf1e9类)
     * @param {string} message - 错误信息
     * @param {string} code - 错误码
     */
    constructor(message, code = 'TRACK_ERROR') {
        super(message);
        this.name = 'TrackerError';
        this.code = code;
        this.timestamp = new Date().toISOString();
    }

    /**
     * 格式化错误输出
     * @returns {string} 格式化后的错误信息
     */
    toString() {
        return `[${this.timestamp}] [${this.code}] ${this.message}`;
    }
}

// ========================= 核心事件跟踪类 =========================
class EventTracker {
    /**
     * 构造函数(初始化配置、日志容器、事件监听)
     * @param {Object} options - 配置项
     * @param {number} options.maxLogs - 最大日志缓存数,默认100
     * @param {boolean} options.isDebug - 是否开启调试模式,默认false
     * @param {string[]} options.targetClasses - 需跟踪的元素类名列表,默认['btn', 'card']
     * @param {string} options.apiUrl - 数据上报接口,默认'/api/event-track'
     * @param {number} options.retryMax - 请求重试次数,默认2
     */
    constructor(options = {}) {
        // 初始化默认配置
        this.config = {
            maxLogs: options.maxLogs || 100,
            isDebug: options.isDebug || false,
            targetClasses: options.targetClasses || ['btn', 'card'],
            apiUrl: options.apiUrl || '/api/event-track',
            retryMax: options.retryMax || 2,
            domainReg: options.domainReg || /(bdideal\.com|127\.0\.0\.1|localhost)/ // 默认跟踪域名
        };

        // 初始化状态变量
        this.logs = []; // 日志缓存容器
        this.isTracking = false; // 跟踪开关
        this.retryCount = 0; // 当前请求重试次数
        this.deviceId = Utils.getDeviceId(); // 设备ID
        this.sensorId = '-1'; // 传感器ID(原混淆默认值,可扩展)

        // 初始化流程
        this.init();
    }

    /**
     * 初始化:开启跟踪、绑定事件监听、验证域名
     */
    init() {
        try {
            // 验证当前域名是否在跟踪列表内
            if (!Utils.isMatchDomain(this.config.domainReg)) {
                if (this.config.isDebug) {
                    console.warn('当前域名不在跟踪列表内,停止初始化');
                }
                return;
            }

            // 开启跟踪状态
            this.isTracking = true;

            // 绑定页面事件监听
            this.bindEvents();

            // 调试日志
            if (this.config.isDebug) {
                console.log('EventTracker 初始化完成', {
                    deviceId: this.deviceId,
                    config: this.config
                });
            }

            // 延迟执行初始化后任务(还原原setTimeout逻辑)
            setTimeout(() => this.postInit(), 300);
        } catch (err) {
            throw new TrackerError(`初始化失败: ${err.message}`, 'INIT_FAILED');
        }
    }

    /**
     * 初始化后任务(扩展点,可添加额外初始化逻辑)
     */
    postInit() {
        // 示例:清除过期日志(可根据需求扩展)
        this.clearExpiredLogs();
    }

    /**
     * 绑定页面事件(点击+触摸)
     */
    bindEvents() {
        // 点击事件监听
        window.addEventListener('click', (e) => this.handleEvent(e));
        // 触摸事件监听(移动端)
        window.addEventListener('touchstart', (e) => this.handleEvent(e, 'touch'));
        
        if (this.config.isDebug) {
            console.log('事件监听已绑定:click、touchstart');
        }
    }

    /**
     * 事件处理核心逻辑:过滤目标元素、收集数据、添加日志
     * @param {Event} event - 原生事件对象
     * @param {string} eventType - 事件类型(默认取event.type,可手动指定)
     */
    handleEvent(event, eventType = '') {
        if (!this.isTracking) return;

        try {
            const target = event.target;
            const type = eventType || event.type;

            // 过滤:仅跟踪指定类名的元素(可扩展更多过滤规则)
            if (!this.isTargetElement(target)) {
                if (this.config.isDebug) {
                    console.debug('非目标元素,跳过跟踪', { target });
                }
                return;
            }

            // 收集事件数据
            const eventData = this.collectEventData(event, type);

            // 添加到日志并尝试上报
            this.addLog(eventData);
            this.reportLogs(); // 实时上报(可改为批量上报)
        } catch (err) {
            console.error(new TrackerError(`事件处理失败: ${err.message}`, 'EVENT_HANDLE_FAILED'));
        }
    }

    /**
     * 验证元素是否为目标跟踪元素(基于类名)
     * @param {HTMLElement} element - 待验证元素
     * @returns {boolean} 是否为目标元素
     */
    isTargetElement(element) {
        if (!(element instanceof HTMLElement)) return false;
        
        // 检查元素是否包含配置中的类名
        return this.config.targetClasses.some(cls => 
            element.classList.contains(cls)
        );
    }

    /**
     * 收集事件数据(核心:整理上报所需的所有字段)
     * @param {Event} event - 原生事件对象
     * @param {string} eventType - 事件类型(click/touchstart等)
     * @returns {Object} 结构化事件数据
     */
    collectEventData(event, eventType) {
        const target = event.target;
        const timestamp = new Date().toISOString();
        let clientX = 0, clientY = 0;

        // 处理坐标(兼容点击和触摸事件)
        if (eventType === 'touch') {
            const touch = event.touches[0] || event.changedTouches[0];
            clientX = touch.clientX;
            clientY = touch.clientY;
        } else {
            clientX = event.clientX;
            clientY = event.clientY;
        }

        // 结构化数据(与原混淆中的字段对应,补充语义化命名)
        return {
            id: Utils.generateUniqueId(), // 事件唯一ID
            className: target.className || '', // 目标元素类名
            tagName: target.tagName.toLowerCase(), // 目标元素标签名
            timestamp: timestamp, // 事件时间戳
            eventType: eventType, // 事件类型
            coordinates: { x: clientX, y: clientY }, // 坐标
            clickId: Utils.generateUniqueId(8), // 点击ID(用于关联事件)
            sensorId: this.sensorId, // 传感器ID(可扩展硬件信息)
            deviceId: this.deviceId, // 设备ID
            pageUrl: window.location.href, // 当前页面URL
            referrer: document.referrer || '' // 来源页面
        };
    }

    /**
     * 添加日志到缓存(自动控制缓存大小)
     * @param {Object} log - 单条事件日志
     */
    addLog(log) {
        // 超出最大缓存数时,删除最早的日志
        if (this.logs.length >= this.config.maxLogs) {
            this.logs.shift();
        }

        this.logs.push(log);

        // 调试日志
        if (this.config.isDebug) {
            console.log('添加事件日志', { log, currentLogCount: this.logs.length });
        }
    }

    /**
     * 清除过期日志(可扩展时间阈值)
     * @param {number} hours - 过期时间(小时),默认24小时
     */
    clearExpiredLogs(hours = 24) {
        const expireTime = new Date().getTime() - hours * 60 * 60 * 1000;
        const beforeCount = this.logs.length;
        
        this.logs = this.logs.filter(log => 
            new Date(log.timestamp).getTime() >= expireTime
        );

        if (this.config.isDebug && this.logs.length !== beforeCount) {
            console.log(`清除过期日志:${beforeCount - this.logs.length}条`);
        }
    }

    /**
     * 上报日志到接口(支持重试)
     */
    async reportLogs() {
        if (this.logs.length === 0) return;
        if (!this.isTracking) throw new TrackerError('跟踪已停止,无法上报', 'TRACK_STOPPED');

        try {
            // 构造请求数据
            const requestData = {
                logs: [...this.logs], // 深拷贝当前日志(避免上报中修改)
                deviceInfo: {
                    deviceId: this.deviceId,
                    userAgent: navigator.userAgent,
                    screen: `${window.screen.width}x${window.screen.height}`
                },
                reportTime: new Date().toISOString()
            };

            // 发送请求(使用fetch,可替换为axios等)
            const response = await fetch(this.config.apiUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-Tracker-Version': '1.0.0',
                    'X-Device-Id': this.deviceId
                },
                body: JSON.stringify(requestData),
                credentials: 'include' // 携带Cookie(跨域时需配置CORS)
            });

            // 处理响应
            if (!response.ok) {
                throw new TrackerError(`接口返回错误: ${response.statusText}`, 'API_ERROR');
            }

            const result = await response.json();
            if (result.code === 0) {
                // 上报成功:清空日志、重置重试次数
                this.logs = [];
                this.retryCount = 0;
                if (this.config.isDebug) {
                    console.log('日志上报成功', { result });
                }
            } else {
                throw new TrackerError(`业务错误: ${result.message}`, 'BUSINESS_ERROR');
            }
        } catch (err) {
            // 重试逻辑
            if (this.retryCount < this.config.retryMax) {
                this.retryCount++;
                const delay = this.retryCount * 1000; // 指数退避:1s、2s、3s...
                setTimeout(() => {
                    if (this.config.isDebug) {
                        console.log(`重试上报(第${this.retryCount}次),延迟${delay}ms`);
                    }
                    this.reportLogs();
                }, delay);
            } else {
                // 重试次数用尽:抛出错误(可扩展本地存储等降级方案)
                this.retryCount = 0;
                throw new TrackerError(`上报失败(已重试${this.config.retryMax}次): ${err.message}`, 'RETRY_EXHAUSTED');
            }
        }
    }

    /**
     * 停止跟踪:关闭开关、移除事件监听、清空日志
     */
    stopTracking() {
        this.isTracking = false;
        // 移除事件监听(需使用具名函数,此处简化处理)
        window.removeEventListener('click', (e) => this.handleEvent(e));
        window.removeEventListener('touchstart', (e) => this.handleEvent(e, 'touch'));
        this.clearLogs();

        if (this.config.isDebug) {
            console.log('EventTracker 已停止跟踪');
        }
    }

    /**
     * 清空所有日志
     */
    clearLogs() {
        this.logs = [];
        if (this.config.isDebug) {
            console.log('所有日志已清空');
        }
    }

    /**
     * 获取当前日志列表(调试用)
     * @returns {Object[]} 日志列表
     */
    getLogs() {
        return [...this.logs]; // 返回拷贝,避免外部修改
    }
}

// ========================= 初始化实例 =========================
/**
 * 全局初始化:
 * 1. 挂载到window.eventTracker,方便外部调用
 * 2. 可根据需求修改配置(如apiUrl、domainReg等)
 */
(function initGlobalTracker() {
    // 避免重复初始化
    if (window.eventTracker) {
        console.warn('EventTracker 已存在,无需重复初始化');
        return;
    }

    // 初始化全局实例(可根据业务修改配置)
    const globalTracker = new EventTracker({
        maxLogs: 200,
        isDebug: false, // 生产环境建议关闭
        targetClasses: ['btn', 'card', 'nav-item', 'list-item'], // 需跟踪的元素类名
        apiUrl: '/api/v1/event-track', // 实际项目替换为真实上报接口
        retryMax: 3,
        domainReg: /(bdideal\.com|127\.0\.0\.1|localhost|your-domain\.com)/ // 替换为你的业务域名
    });

    // 挂载到window,支持外部调用(如:window.eventTracker.stopTracking())
    window.eventTracker = globalTracker;

    // 调试提示
    if (globalTracker.config.isDebug) {
        console.log('全局EventTracker实例已挂载到 window.eventTracker');
    }
})();
回复

使用道具 举报

结帖率:100% (4/4)

签到天数: 6 天

发表于 5 天前 | 显示全部楼层   广东省广州市
直接问AI啊
VX图片_2025-11-04_004021_701.png

JS还原优化结果:
JS还原.txt (16.19 KB, 下载次数: 2)
回复

使用道具 举报

结帖率:80% (12/15)

签到天数: 4 天

 楼主| 发表于 5 天前 | 显示全部楼层   江苏省南通市
dongxin 发表于 2025-11-4 00:38
是不是找错JS了 这个解出来是这样的
[mw_shl_code=javascript,true]'use strict';

应该没有找错,sign生成的地方应该就是混淆的位置
回复

使用道具 举报

签到天数: 9 天

发表于 5 天前 | 显示全部楼层   陕西省汉中市
学习一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

关闭

精易论坛 - 有你更精彩上一条 /2 下一条

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报QQ: 793400750,邮箱:wp@125.la
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备2025452707号) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表