当前位置: 首页 > news >正文

关于 js:8. 反调试与混淆识别

一、常见反调试手段识别

1. debugger 死循环(阻塞调试器)

样例代码:

while (true) {debugger;
}

原理:

  • 每次执行到 debugger 语句,如果 DevTools 打开,将自动触发断点

  • 如果在死循环中,调试器会被频繁打断,卡死页面或无法操作

特征识别:

  • 出现在自执行函数中 (function(){...})(),或者 setInterval、setTimeout 里。

  • 常与加密代码混合,隐藏在核心逻辑附近。

应对方法:

  • 打开 Chrome DevTools → 设置 → 关闭 "暂停于异常" 和自动断点。

  • 手动删除 debugger,或用 Babel/AST 脚本批量清除:

traverse(ast, {DebuggerStatement(path) {path.remove();}
});

2. 时间延迟检测(检测调试耗时)

样例代码:

const start = Date.now();
for (let i = 0; i < 1e8; i++) {}
const end = Date.now();
if (end - start > 500) {alert("你调试我了!");
}

原理:

  • 调试器中手动打断点,会暂停脚本执行

  • 利用 Date.now()performance.now() 计算耗时,如果超过阈值,说明你在调试。

特征识别:

  • Date.now()performance.now() 出现多次用于比对时间差。

  • 常用于函数入口、加密函数前后。

应对方法:

  • 重写时间函数,返回恒定时间:

Date.now = () => 123456789;
performance.now = () => 100;
  • 或删除时间差判断代码段(使用 AST 或脚本)

3. 函数串扰检测(检测函数是否被 hook)

样例代码:

const realAlert = alert;
alert = function () {console.log("你调试了吗?");return realAlert.apply(this, arguments);
};

原理:

  • 检测是否篡改了系统函数,例如 alert、console、eval 等。

  • 调试器经常 hook 函数,攻击者利用此逻辑检测调试行为。

特征识别:

  • 检测 alert, eval, console.log 等函数是否被改写。

  • Function.prototype.toString() 经常联合使用,判断函数体内容是否 [native code]

应对方法:

  • 恢复原始函数

alert = window.__proto__.alert;
console.log = window.__proto__.console.log;
  • 用 Proxy 包装函数,同时伪装 toString() 输出。

4. Function.prototype.toString 检测(伪装函数原型)

样例代码:

if (alert.toString().indexOf('[native code]') === -1) {throw new Error('你修改了 alert 函数!');
}

原理:

  • JS 中原生函数 toString() 会返回 [native code]

  • 一旦你对 alert 之类做了 hook 或包装,这一特征就消失。

反制手段:

  • 伪装 toString 输出:

alert = new Proxy(alert, {apply: function(target, thisArg, argumentsList) {return target.apply(thisArg, argumentsList);}
});
alert.toString = function() {return "function alert() { [native code] }";
};

5. window.console 检测

样例代码:

if (!window.console || typeof console.log !== "function") {throw new Error("console 被篡改!");
}

原理:

  • 某些调试工具会临时修改 console 行为。

  • 检测 console 存在性和完整性也是一种反调试手段。

解决方式:

  • 恢复原始 console 对象。

  • 或伪造 console 对象结构(手动定义全套方法)。

6. 异常捕获干扰调试

样例代码:

try {throw new Error("调试干扰");
} catch (e) {debugger;
}

原理:

  • 在 try-catch 中故意嵌入 debugger、死循环或跳转逻辑,扰乱调试节奏。

  • 有的框架会在异常栈中判断调试器是否存在。

应对方案:

  • 修改 try-catch 中间代码,绕开 debugger。

  • 用 AST 替换整个异常处理段。

7. 堆栈跟踪干扰(检测调试器存在)

样例代码:

function checkStack() {try {throw new Error();} catch (e) {if (e.stack.indexOf("Debugger") !== -1) {alert("发现调试器");}}
}

原理:

  • 抛异常时,Error.stack 会包含调用堆栈信息。

  • 如果你在 Chrome DevTools 设置了断点,可能会在 stack 中体现。

应对:

  • 重写 Error 构造函数或其 stack 属性,返回空堆栈。

8. requestAnimationFrame 反调试

样例代码:

let lastTime = performance.now();
function checkDebugger() {let now = performance.now();if (now - lastTime > 100) {alert("调试器卡住了浏览器");}lastTime = now;requestAnimationFrame(checkDebugger);
}
requestAnimationFrame(checkDebugger);

原理:

  • requestAnimationFrame 频率非常高(约每16ms执行一次),调试器会明显卡顿,时间差变大。

应对方法:

  • 重写 requestAnimationFrame,屏蔽检测逻辑。

  • 或 hook performance.now() 伪造时间。

9. 全局函数自毁 / 还原干扰

样例代码:

(function(){Function = null;
})();

原理:

  • 故意销毁 JS 全局函数,阻止我们运行 eval / Function 等调试代码。

应对方法:

  • 在中断点处提前 window.Function = Function 备份

  • 或直接改写函数覆盖逻辑,让其失效

总结

技术名检测方式应对手段
debugger 死循环debugger 频繁触发AST 移除 / DevTools 设置
时间延迟检测Date.now() / performance.now()Hook 时间函数 / 删除判断
函数串扰检查 alert、console、eval 是否被 hook还原函数 / Proxy + toString 伪装
toString 检测判断函数是否为 [native code]改写 toString 方法
console 检测是否存在 console 方法伪造完整 console 对象结构
异常捕获干扰try-catch 嵌入 debugger替换整个代码块
堆栈跟踪调试检测分析 Error.stack 内容重写 Error / 清空 stack
requestAnimationFrame 检测检测浏览器执行频率重写 rAF / 时间伪造

二、JavaScript 混淆手法

混淆的目标是让代码变得:

  • 难读(降低可读性)

  • 难调试(隐藏执行流程)

  • 难还原(阻碍逆向)

1. 字符串拆分拼接

原始代码:

var key = "secretKey";

混淆后代码示例:

var _0x1a2b = "sec" + "ret" + "Key";

甚至更复杂:

var a = "s";
var b = "e";
var c = b + "c";
var d = a + c + "ret" + "Key";  // 最终是 "secretKey"

混淆目的:

  • 隐藏字符串字面量,防止关键词命中(如 w、sign、token 等)。

识别与还原方法:

  • 手动打断点查看变量值(或用 console.log 打印)

  • 或者用 AST 脚本静态还原拼接结果(字符串折叠优化):

traverse(ast, {BinaryExpression(path) {if (path.node.operator === "+" &&t.isStringLiteral(path.node.left) &&t.isStringLiteral(path.node.right)) {path.replaceWith(t.stringLiteral(path.node.left.value + path.node.right.value));}}
});

2. base64 编码隐藏字符串

混淆代码示例:

var data = atob("c2VjcmV0S2V5");  // "secretKey"

原理:

  • 用 Base64 编码字符串后解码执行,达到隐藏真实内容的目的。

  • 通常与 eval, Function, new Image() 等组合使用。

混淆目的:

  • 防止明文暴露关键字(如 UA、token、cookie、sign 等)

识别特征:

  • atob()btoa()Buffer.from(...).toString(...) 出现

  • 明文字符串为 4 的倍数长度,末尾常有 = 填充符

还原方式:

  • 浏览器或脚本执行:

console.log(atob("c2VjcmV0S2V5"));

3. eval / Function 动态执行

示例 1(eval):

eval("console." + "log('hello')");

示例 2(Function):

var code = "return 5 + 5;";
var fn = new Function(code);
console.log(fn()); // 输出 10

原理:

  • 动态执行字符串拼接后的代码,防止静态分析

  • 通常与字符串拼接、base64 一起使用。

特征识别:

  • 出现 eval(), new Function(), setTimeout(code, 0) 等动态执行语句。

  • 动态生成的代码中常含混淆函数调用、加密入口、hook 代码。

还原与处理:

1)打补丁替换 evalconsole.log

eval = console.log;  // 打印出真实代码

2)拦截 Function:

window.Function = function(code) {console.log("[HOOKED FUNCTION]:", code);return () => {};
};

3)使用 AST 替换 eval:

traverse(ast, {CallExpression(path) {if (path.node.callee.name === 'eval') {path.node.callee.name = 'console.log';}}
});

4. 数组 + 索引跳转(Control Flow Flattening)

混淆代码示例:

var _0xabc = ["log",         // 索引 0"Hello",       // 索引 1"console",     // 索引 2
];(function(arr) {var a = arr[2]; // "console"var b = arr[0]; // "log"var c = arr[1]; // "Hello"window[a][b](c);  // => console.log("Hello")
})(_0xabc);

或者极端一点:

var arr = ["\x63\x6f\x6e\x73\x6f\x6c\x65", "\x6c\x6f\x67"];
window[arr[0]][arr[1]]("hi");

原理:

  • 字符串存入数组,索引读取,打乱顺序。

  • 控制流 flatten:真实执行路径隐藏在数组索引组合里。

特征识别:

  • 有大数组存放字符串

  • 数组通过索引访问,变量命名毫无意义(如 _0xabc[1]

  • 出现 “mapping 函数”:例如 _0xabc = function(i){ return arr[i]; }

还原方法:

  • 手动记录数组内容 → 替换索引值

  • 使用 Babel AST 扫描,把数组取值还原成字符串

  • 工具推荐

    • de4js:https://lelinhtinh.github.io/de4js/

    • 自写还原脚本处理全局映射数组

总结

混淆类型特征应对手段
字符串拼接多个字符串拼成关键字AST 静态还原 / 打断点查看
Base64 编码出现 atob(), 字符串有 =解码查看 / Python 辅助
动态执行eval, Function, setTimeoutHook 动态函数 / AST 替换打印
数组+索引跳转大数组 + 随机索引访问还原数组映射 / 替换所有访问语句

三、AST 抽象语法树分析

AST(抽象语法树) 是程序源代码的结构化、树状表示。

在 JavaScript 中,一段代码:

var a = "hello";

会被转换为一个 AST 树结构,描述这段代码的结构,比如:VariableDeclaration -> VariableDeclarator -> Identifier + Literal

它并不是运行代码,而是「代码结构本身」的抽象。

在 JS 混淆还原、定位加密函数、批量清理垃圾逻辑时,AST 是最强的静态分析工具:

任务AST 作用
还原混淆(字符串拼接、数组索引)静态提取还原拼接结果
删除垃圾代码(无用判断等)删除某些结构的语句(如 if (false)
替换函数调用eval() 改为 console.log()
查找加密入口、核心参数生成定位函数名和依赖链,追踪代码调用路径

Babel 是 JS 编译领域的核心工具,它能:

  •  解析 JS 源码为 AST(@babel/parser

  •  遍历和修改 AST(@babel/traverse

  •  将 AST 重新生成代码(@babel/generator

1. Babel AST 操作的基本流程

安装依赖(Node 环境)

npm install @babel/parser @babel/traverse @babel/generator

1)将代码解析成 AST

const parser = require('@babel/parser');
const code = 'var a = "he" + "llo";';const ast = parser.parse(code, {sourceType: 'module'
});

2)遍历 AST 并修改

const traverse = require('@babel/traverse').default;
const t = require('@babel/types');traverse(ast, {BinaryExpression(path) {if (path.node.operator === '+' &&t.isStringLiteral(path.node.left) &&t.isStringLiteral(path.node.right)) {// 替换拼接表达式为结果字符串path.replaceWith(t.stringLiteral(path.node.left.value + path.node.right.value));}}
});

3)生成新代码

const generate = require('@babel/generator').default;
const output = generate(ast);
console.log(output.code); // var a = "hello";

2. 实战:还原混淆数组+索引跳转代码

示例混淆代码:

var _0xabc = ["se", "cret", "Key"];
var key = _0xabc[0] + _0xabc[1] + _0xabc[2];

还原目标:把 _0xabc[0] 直接替换成 "se" 等,变成:

var key = "secretKey";

解法思路:

  1. 找出数组声明内容,建立索引映射

  2. 遍历代码中所有的 MemberExpression(属性访问)

  3. 如果是 _0xabc[0],直接替换成 "se" 的字符串字面量

Babel 脚本:

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');const code = `
var _0xabc = ["se", "cret", "Key"];
var key = _0xabc[0] + _0xabc[1] + _0xabc[2];
`;const ast = parser.parse(code);let mapping = {};traverse(ast, {VariableDeclarator(path) {if (t.isIdentifier(path.node.id) &&t.isArrayExpression(path.node.init)) {const arrName = path.node.id.name;const elements = path.node.init.elements;mapping[arrName] = elements.map(e => e.value);}},MemberExpression(path) {const obj = path.node.object;const prop = path.node.property;if (t.isIdentifier(obj) &&mapping[obj.name] &&t.isNumericLiteral(prop)) {const value = mapping[obj.name][prop.value];path.replaceWith(t.stringLiteral(value));}}
});const output = generate(ast);
console.log(output.code);

3. 辅助工具推荐

工具说明
AST Explorer可视化查看 AST 结构,非常适合新手理解
Babel + Node 脚本实际静态还原代码
Chrome DevTools配合调试、打断点验证逻辑是否还原成功

总结

AST 是在面对 JS 混淆与参数还原时,最强的“静态分析武器”,一旦掌握,就能自动还原大量加密、反调试逻辑,让 JS 逆向效率质变!


四、定位核心参数生成函数

在爬虫、逆向场景中,服务端通常要求提交一些“加密参数”:

  • 常见名称有:wsigntokenauthxyzmh

  • 这些参数通过 JS 中隐藏/混淆的函数生成,是反爬的关键一环

我们的任务是定位并还原这些函数!

1. 典型例子

例如某请求:

POST /api/check
headers:w: "e72fa5b18d320...(加密值)"

需要搞清楚:

  • 谁生成了 w

  • w 用了哪些参数(时间戳、cookie、UA、行为数据)?

  • 生成函数是否被混淆?

  • 是否用了动态执行(eval、Function)?

  • 是否跑在 WebWorker 或 iframe 中?

2. 定位思路总览

方法原理
1. 关键词搜索搜索 w=, sign=, headers, FormData, .w, .sign
2. hook XMLHttpRequest / fetch拦截请求参数,看 w 的生成前有哪些代码执行
3. 打断点(XHR/fetch/send)手动调试,寻找传输逻辑、函数调用栈
4. 控制台 hook 全局函数重定义 CryptoJS.MD5btoa(),打印入参与结果
5. 格式化 + 搜索函数调用格式化 JS 源码,搜索可疑函数调用
6. DOM 元素关联有些加密数据来源于点击、坐标、行为序列
7. AST 分析静态查找函数依赖链、追踪返回值
8. Blob / Worker 调试查看是否把加密逻辑放在独立线程或动态 blob JS 里

3. 最常用方式详解

【方法 1】关键字搜索法(适用于未严重混淆)

搜索:

"w="
"sign="
"form.append"
"headers"
"return {"

例子:

var t = get_w(UA, timestamp);
formData.append("w", t);

通过定位 get_w(),再深入分析。

【方法 2】hook fetch / XMLHttpRequest 拦截入参

// hook fetch
window.fetch = new Proxy(window.fetch, {apply(target, thisArg, args) {console.log("[fetch]", args);return Reflect.apply(target, thisArg, args);}
});// hook XHR
const open = XMLHttpRequest.prototype.open;
const send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function () {this._url = arguments[1];return open.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function (body) {console.log("[XHR]", this._url, body);return send.apply(this, arguments);
};

作用:

  • 拦截请求,打印出 w, sign 等参数值

  • 分析是在哪段逻辑设置的这些参数

  • 可结合堆栈 console.trace() 查看是谁生成的

【方法 3】打断点(最直接有效)

位置推荐:

  • fetchXMLHttpRequest.prototype.send 上打断点

  • document.cookie 被读取时(可用 Monitor Events

  • CryptoJS.MD5()btoa()encodeURIComponent() 等加密函数调用处

  • eval()Function() 调用处,观察执行前的参数

技巧:

  • 打断点后,切换到 Call Stack,顺藤摸瓜,追函数栈

  • 使用 Chrome DevTools「黑盒」方式隐藏无用框架代码

【方法 4】hook 加密函数打印入参

常见加密函数有:

CryptoJS.MD5(xxx)
CryptoJS.AES.encrypt
btoa()
encodeURIComponent()

可以这样 hook:

CryptoJS.MD5 = function (arg) {console.log("[MD5]", arg);return originalMD5(arg); // 原函数
}

或者 hook 所有函数:

Function.prototype.call = new Proxy(Function.prototype.call, {apply(target, thisArg, args) {console.log("[CALL]", thisArg, args);return Reflect.apply(target, thisArg, args);}
});

【方法 5】格式化搜索函数调用

使用 Pretty Print 格式化混淆代码,再查找形如:

var w = a.b(c, d);  // 参数生成函数
  • 重点关注:a.b 这种链式调用,常是封装后的加密函数

  • a.b 替换成打印函数,输出参数和返回值

【方法 6】AST 静态追踪核心函数

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const fs = require("fs");const code = fs.readFileSync("./encrypt.js").toString();
const ast = parser.parse(code);traverse(ast, {CallExpression(path) {const { callee } = path.node;if (callee.type === "Identifier" &&callee.name === "get_w"  // 可替换成你猜测的函数名) {console.log("Found w generator:", path.toString());}}
});

也可静态追踪返回的字符串是否带有 w=...

4. 实战案例简化版

例子:

function gen_w(ts, cookie, ua) {var str = ts + "|" + cookie + "|" + ua;return btoa(str);
}let w = gen_w(Date.now(), document.cookie, navigator.userAgent);

分析流程:

  1. 搜索 w=,发现 gen_w()

  2. 跟进 gen_w(),看到参数组成

  3. 分析加密逻辑 btoa(str)

  4. 结论:w 是 base64(ts|cookie|ua)

就可以写脚本还原它。

5. W 参数常见特征

特征解读
固定长度多为 32、64、128 位(MD5、SHA1、AES 编码)
每次不同含时间戳、行为 ID、cookie 等
与滑动验证/行为交互相关w 中可能包含点击坐标、移动轨迹、session_id、lot_number 等
通常通过层层封装多层函数嵌套,常混淆关键函数名

6. 辅助工具推荐

工具名用途
Charles/Fiddler抓包查看真实参数
DevTools Source Map调试压缩源码前的真实结构
Babel Parser + Traverse静态定位函数/AST 跟踪
mitmproxy + JS hook手机端逆向生成参数
Obfuscator-IO-Deobfuscator一键还原混淆代码

总结

定位加密函数 = 抓到“w 参数生成”的函数,并拆解其中逻辑(参数输入、算法过程、输出)

通常会结合这些手段:

  • 抓包 + 调试断点 + 函数 hook + AST 分析

  • 同时注意 Worker / iframe / 动态 eval 场景

相关文章:

关于 js:8. 反调试与混淆识别

一、常见反调试手段识别 1. debugger 死循环&#xff08;阻塞调试器&#xff09; 样例代码&#xff1a; while (true) {debugger; }原理&#xff1a; 每次执行到 debugger 语句&#xff0c;如果 DevTools 打开&#xff0c;将自动触发断点。 如果在死循环中&#xff0c;调试…...

深度Q网络(DQN)的基本概念

一、深度Q网络(DQN)的基本概念 深度Q网络(Deep Q-Network,DQN)是将强化学习中的Q学习(Q-Learning)与深度学习相结合的算法,由DeepMind在2013年提出,并在2015年发表于《Nature》杂志。它通过神经网络近似动作价值函数(Q函数),解决传统Q学习在高维状态空间下的计算难…...

uniapp+vue3中自动导入ref等依赖

前言&#xff1a; 在我们使用uni-appvue3创建项目&#xff0c;开发的过程中&#xff0c;老是需要导入我们的ref、onshow等&#xff0c;那么能不能自动导入&#xff0c;不用我们每个页面都写呢&#xff1f;是没问题的&#xff0c;这里让他的小帮手来帮你减轻负担&#xff1a;他就…...

合肥SMT贴片加工核心优势与工艺升级

内容概要 在电子制造领域&#xff0c;工艺精度与生产效率的平衡始终是企业关注的核心命题。本文将系统呈现合肥SMT贴片加工产业的技术演进图谱&#xff0c;为寻求制造升级的企业提供可落地的决策参考。 作为长三角电子制造集群的重要节点&#xff0c;合肥SMT贴片加工产业通过持…...

Ansible安装与核心模块实战指南

Ansible安装与核心模块实战指南 自动化运维入门:从安装到模块化任务配置 Ansible作为一款无代理自动化工具,通过模块化设计实现高效管理,尤其适用于快速部署、配置和维护大规模系统。本文将从安装、核心模块使用到实际案例,全面解析其核心功能与最佳实践。 一、Ansible安装…...

TDengine 做为 Spark 数据源

简介 Apache Spark 是开源大数据处理引擎&#xff0c;它基于内存计算&#xff0c;可用于批、流处理、机器学习、图计算等多种场景&#xff0c;支持 MapReduce 计算模型及丰富计算操作符、函数等&#xff0c;在大超大规模数据上具有强大的分布式处理计算能力。 通过 TDengine …...

Codeforces Round 997 (Div. 2)

A. Shape Perimeter 题目大意 给你一个m*m的正方形&#xff0c;再给你n个坐标表示每次在xy移动的距离&#xff08;第一个坐标是初始位置正方形左下角&#xff09;&#xff0c;问路径图形的周长 解题思路 记录好第一次的位置之后一直累加最后求总移动距离的差值即可 代码实…...

WSL 安装 Debian 12 后,Linux 如何安装 nginx ?

在 WSL 的 Debian 12 中安装 Nginx 的步骤如下&#xff1a; 1. 更新系统软件包 sudo apt update && sudo apt upgrade -y2. 安装 Nginx sudo apt install nginx -y3. 管理 Nginx 服务 ▶ 启动 Nginx sudo service nginx start # 如果使用 systemd 可能需改用&…...

目标检测任务 - 数据增强

目标检测任务 - DETR &#xff1a; 数据预处理/数据增强 算法源码实例 import datasets.transforms as Tnormalize T.Compose([T.ToTensor(),T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ])scales [480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800]…...

java的switch case

import java.util.Scanner;public class Hello {public static void main(String[] args) {Scanner in new Scanner(System.in);int type in.nextInt();switch(type){case 1:case 2:System.out.println("你好");break;case 3:System.out.println("晚上好"…...

基于亚博K210开发板——LCD触摸屏读取坐标数据测试

开发板 亚博K210开发板 实验目的 主要学习 K210 通过 I2C 读取触摸屏的坐标&#xff0c;并打印出来&#xff0c;显示在 LCD上。 实验准备 实验元件 LCD 显示屏触摸板 元件特性 K210 开发板自带 2.0 寸触摸屏&#xff0c;其实是 LCD 显示屏上贴一个触摸板组成&#xf…...

coze平台实现文生视频和图生视频(阿里云版)工作流

工作流全貌 开始 首先从入参开始&#xff1a; api_key&#xff1a;来自阿里云百炼平台&#xff0c;自行去申请 prompt&#xff1a;生成视频的文本提示词。支持中英文&#xff0c;长度不超过800个字符&#xff0c;每个汉字/字母占一个字符&#xff0c;超过部分会自动截断。 …...

python酒店健身俱乐部管理系统

目录 技术栈介绍具体实现截图系统设计研究方法&#xff1a;设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理&#xff0c;难度适中&#xf…...

QtGUI模块功能详细说明,图标和光标(七)

目录 一.窗口和屏幕管理 二. 绘图和渲染 三. 图像处理 四. 字体和文本 五. 事件和输入处理 六. OpenGL 和硬件加速 七. 颜色和外观 八. 图标和光标 1、QIcon: 图标管理 1.1、QIcon 简介 1.2、图标的来源与创建 1.3、多分辨率与 DPI 支持 1.4、图标的状态管理 2、…...

【图像处理基石】如何入门OCR技术?

入门OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术需要结合理论学习、工具实践和项目实战&#xff0c;以下是分步骤的学习指南&#xff0c;适合零基础学习者&#xff1a; 一、明确OCR技术的核心概念 OCR的基本原理 核心流程&#xf…...

数据库知识沉浸式游戏化学习设计研究

数据库知识沉浸式游戏化学习设计研究 摘要: 本研究旨在设计一款以数据库知识为主题的沉浸式游戏化学习系统。通过对数据库知识体系的深入剖析,结合游戏化学习理论,构建了一个多层次、多任务的游戏架构。玩家在游戏过程中需完成构建数据库结构、编写 SQL 查询等任务来解锁关…...

大疆无人机

在大疆上云API中&#xff0c;​​DRC 链路​​通常指 ​​Device-Cloud Remote Control Link&#xff08;设备-云端远程控制链路&#xff09;​​&#xff0c;它是无人机&#xff08;或设备&#xff09;与云端服务之间建立的​​实时控制与数据传输通道​​&#xff0c;用于实现…...

撤回不了一点 v1.0.2,支持微信QQ钉钉飞书等消息防撤回

如今生活节奏快得飞起&#xff0c;社交软件和工作通讯软件成了咱日常交流的核心阵地。大家肯定都有过这些闹心事儿&#xff1a;和朋友聊得正嗨&#xff0c;对方突然撤回一条消息&#xff0c;好奇心瞬间爆棚&#xff0c;却怎么也看不到撤回的内容&#xff1b;工作群里关键信息刚…...

什么是Git?

“Git”是目前非常火、广泛使用的版本控制系统&#xff0c;尤其在软件开发领域中扮演着核心角色。 一、什么是Git&#xff1f;它到底是什么&#xff1f; Git 是一种版本控制系统&#xff08;Version Control System, VCS&#xff09;。它的主要作用是帮助开发者管理“代码的不…...

微信小程序 自定义图片分享-绘制数据图片以及信息文字

一 、需求 从数据库中读取头像&#xff0c;姓名电话等信息&#xff0c;当分享给女朋友时&#xff0c;每个信息不一样 二、实现方案 1、先将数据库中需要的头像姓名信息读取出来加载到data 数据项中 data:{firstName:, // 姓名img:, // 头像shareImage:,// 存储临时图片 } 2…...

langchain提示词的使用

一、概述 提示词是指向人工智能大模型提供的输入信息&#xff0c;通常包含关键词、问题或指令&#xff0c;可以引导大模型生成与用户期望相符的回应。我们在豆包&#xff0c;DeepSeek等大模型中输入的问题都可以认为一个简单的提示词&#xff0c;不过为了真正得到我们需要的结…...

C语言| extern的用法作用

C语言| 局部变量、全局变量 extern定义的变量&#xff0c;只对全局变量有用。 掌握extern的用法及其作用。extern主要用于在不同.c文件间扩展全局变量的作用范围。 扩展全局变量的使用范围&#xff0c;操作方法&#xff1a; 1 在一个文件内扩展全局变量的使用范围 全局变量…...

Rust 环境变量管理秘籍:从菜鸟到老鸟都爱的 dotenv 教程

前言 写代码的你,是否遭遇过这些灵魂拷问: “我现在在哪个环境?开发?测试?还是直接在生产线上裸奔?”“少写一个 .env,测试脚本在数据库里上演清空大法,客户当场破防。”“每次手动设置 RUST_ENV,命令敲到一半就开始怀疑人生,还怕输错一个字符引发灭世级事故。”别慌…...

Leetcode (力扣)做题记录 hot100(49,136,169,20)

力扣第49题&#xff1a;字母异位词分组 49. 字母异位词分组 - 力扣&#xff08;LeetCode&#xff09; 遍历数组&#xff0c;将每一个字符串变成char数组 然后排序&#xff0c;如果map里面有则将他的值返回来&#xff08;key是排序好的字符串&#xff09; class Solution {pu…...

Slitaz 系统深度解析

Slitaz 系统深度解析&#xff1a;从系统架构到设计哲学 一、系统定位与核心目标 Slitaz&#xff08;Simplified Lightweight IT Automatic Zen&#xff09;是一个基于 Linux 的超轻量级发行版&#xff0c;设计目标是极致轻量化、快速启动、低资源消耗&#xff0c;专为老旧硬件…...

Deepseek+Xmind:秒速生成思维导图与流程图

deepseekxmind&#xff0c;快速生成思维导图和流程图 文章目录 思维导图deepseek笔记本 txt文件xmind 流程图deepseekdraw.io 思维导图 deepseek 笔记本 txt文件 将deep seek的东西复制到文本文件中&#xff0c;然后将txt文件拓展名改成md xmind 新建思维导图----左上角三…...

理解计算机系统_并发编程(5)_基于线程的并发(二):线程api和基于线程的并发服务器

前言 以<深入理解计算机系统>(以下称“本书”)内容为基础&#xff0c;对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定 引入 接续上一篇理解计算机系统_并发编程(4)_基于线程的并发(一…...

java刷题基础知识

List<int[]> merged new ArrayList<int[]>(); return merged.toArray(new int[merged.size()][]); 表示一个存储 int[] 类型元素的列表&#xff0c;list灵活支持扩展&#xff0c;因为不知道最后有几个区间&#xff0c;所以用list&#xff0c;最后toArray返回成数组…...

MATLAB语音情感识别神经网络方法

在MATLAB中使用神经网络进行语音情感识别通常涉及以下步骤&#xff1a;数据准备、特征提取、神经网络模型构建、训练与评估。以下是详细说明和示例代码&#xff1a; 1. 数据准备 数据集&#xff1a;推荐使用公开情感语音数据集&#xff08;如RAVDESS、CREMA-D、EMODB等&#x…...

PostgreSQL 服务器信号函数

PostgreSQL 服务器信号函数 PostgreSQL 提供了一组服务器信号函数&#xff08;Server Signaling Functions&#xff09;&#xff0c;允许数据库管理员向 PostgreSQL 服务器进程发送特定信号以控制服务器行为。这些函数提供了对数据库服务器的精细控制能力。 一、核心信号函数…...

流动式起重机Q2的培训内容有哪些?

流动式起重机 Q2 的培训内容主要分为理论知识和实际操作两部分&#xff0c;具体如下&#xff1a; 理论知识 基础理论知识&#xff1a;涵盖机械原理、液压原理、电气原理等内容&#xff0c;帮助学员理解起重机的基本工作原理。例如&#xff0c;通过机械原理知识&#xff0c;学员…...

虹科应用 | 探索PCAN卡与医疗机器人的革命性结合

随着医疗技术的不断进步&#xff0c;医疗机器人在提高手术精度、减少感染风险以及提升患者护理质量方面发挥着越来越重要的作用。医疗机器人的精确操作依赖于稳定且高效的数据通信系统&#xff0c;虹科提供的PCAN四通道mini PCIe转CAN FD卡&#xff0c;正是为了满足这一需求而设…...

Linux系统编程---Signal信号集

0、前言 在上一篇博客笔记文章中&#xff0c;对Linux进程间通信的信号进行了讲解&#xff0c;本章将接着上一篇文章的内容&#xff0c;继续对Linux进程间通信中信号部分的信号集这个小知识点进行梳理。 如果有对Linux系统编程有不了解的地方&#xff0c;欢迎查阅博主的Linux系统…...

上电单次复位触发电路

SA1相当于是另外一个触发信号&#xff0c;S2A是手动触发信号&#xff0c;当S1A和S2A开关都断开时,示波器A入口所连接线路为上拉状态&#xff0c;高电平为3V。 当S2A闭合&#xff0c;相当于手动拉低&#xff0c;可以用于唤醒单片机之类的。 当S1A闭合&#xff0c;模拟电源接入&…...

talk-linux 不同用户之间终端通信

好的&#xff01;下面是一个完整的指南和脚本&#xff0c;用于在两台 Linux 主机上配置并使用 talk 聊天功能&#xff08;假设它们在同一个局域网内&#xff09;。 ⸻ &#x1f9fe; 一、需求说明 我们需要在两台主机上&#xff1a; 1. 安装 talk 和 talkd 2. 启用 talkd 服…...

QGIS 将 Shapefile 导入 PostGIS 数据库

一、背景介绍&#xff1a;QGIS、PostgreSQL 和 PostGIS 的关系和用途 在开始动手操作之前&#xff0c;我们先简单了解一下 QGIS、PostgreSQL 和 PostGIS 之间的关系及其用途。 QGIS&#xff08;Quantum GIS&#xff09;&#xff1a;一款开源免费的桌面地理信息系统&#xff0…...

《内网渗透测试:绕过最新防火墙策略》

内网渗透测试是检验企业网络安全防御体系有效性的核心手段&#xff0c;而现代防火墙策略的持续演进&#xff08;如零信任架构、AI流量分析、深度包检测&#xff09;对攻击者提出了更高挑战。本文系统解析2024年新型防火墙的防护机制&#xff0c;聚焦协议隐蔽隧道、上下文感知绕…...

CSS结构性伪类、UI伪类与动态伪类全解析:从文档结构到交互状态的精准选择

一、结构性伪类选择器&#xff1a;文档树中的位置导航器 结构性伪类选择器是CSS中基于元素在HTML文档树中的层级关系、位置索引或结构特征进行匹配的一类选择器。它们无需依赖具体的类名或ID&#xff0c;仅通过文档结构即可精准定位元素&#xff0c;是实现响应式布局和复杂文档…...

【大模型LLM学习】MiniCPM的注意力机制学习

【大模型LLM学习】MiniCPM的注意力机制学习 前言1 Preliminary1.1 MHA1.2 KV-cache 2 GQAGQA的MiniCPM实现 3 MLAMLA的MiniCPM-3-4b的实现 TODO 前言 之前MiniCPM3-4B是最早达到gpt-3.5能力的端侧小模型&#xff0c;其注意力机制使用了MLA。本来想借着MiniCPM从MHA过到MLA的&am…...

stm32之PWR、WDG

目录 1.PWR1.1 简介1.2 电源框图1.3 上电复位和掉电复位1.4 可编程电压监测器1.5 低功耗模式1.5.1 模式选择1.5.2 睡眠模式1.5.3 停止模式1.5.4 待机模式 1.6 实验1.6.1 修改主频1.6.2 睡眠模式串口发送接收1.6.3 停止模式对射式红外传感器计次1.6.4 待机模式实时时钟 2.看门狗…...

分布式任务调度XXL-Job

​ XXL-Job 是一款轻量级、分布式的任务调度平台&#xff0c;其核心设计解决了传统任务调度&#xff08;如Quartz&#xff09;在分布式场景下的‌任务分片‌、‌高可用‌、‌可视化管控‌等痛点。以下从原理、核心架构、应用场景、代码示例及关联中间件展开详解 一、主流任务…...

内存泄漏与OOM崩溃根治方案:JVM与原生内存池差异化排查手册

内存泄漏与OOM崩溃根治方案&#xff1a;JVM与原生内存池差异化排查手册 一、问题描述与快速解决方案 1. 核心问题分类 内存泄漏&#xff08;Memory Leak&#xff09; 现象&#xff1a;应用运行时间越长&#xff0c;内存占用持续攀升&#xff0c;GC回收效率下降&#xff0c;最…...

火山引擎发展初始

火山引擎是字节跳动旗下的云计算服务品牌&#xff0c;其云服务业务的启动和正式商业化时间线如下&#xff1a; 1. **初期探索&#xff08;2020年之前&#xff09;** 字节跳动在早期为支持自身业务&#xff08;如抖音、今日头条等&#xff09;构建了强大的基础设施和技术中…...

使用光标测量,使用 TDR 测量 pH 和 fF

时域反射计 &#xff08;TDR&#xff09; 是一种通常用于测量印刷电路板 &#xff08;PCB&#xff09; 测试试样和电缆阻抗的仪器。TDR 对于测量过孔和元件焊盘的电感和电容、探针尖端电容和电感&#xff0c;甚至寄生电感收发器耦合电容器也非常有用。这也是验证仿真或提取您自…...

mybatisplus 集成逻辑删除

一开始&#xff0c;没去查资料&#xff0c;后面要被AI气死了&#xff0c;先看它的的话 一开始&#xff0c;看ai的描述&#xff0c;我还以为&#xff0c;不需要改数据库&#xff0c;mybatis-puls自动拦截集成就可以实现逻辑删除&#xff0c;c&#xff0c;最后还是要给数据库加一…...

ABAP+旧数据接管的会计年度未确定

导资产主数据时&#xff0c;报错旧数据接管的会计年度未确定 是因为程序里面使用了下列函数AISCO_CALCULATE_FIRST_DAY&#xff0c;输入公司代码&#xff0c;获取会计年度&#xff0c;这个数据是在后台表T093C表中取数的&#xff0c;通过SE16N可以看到后台表数据没有数&#xf…...

KT148A语音芯片发码很难播放_将4脚对地一下再发正常,什么原因?

问题描述如下&#xff1a;您好&#xff0c;遇到一点问题请帮忙支持一下&#xff1a; KT148A 这颗芯片&#xff0c; 我们上电后发码很难触发播放&#xff0c; 但用镊子将4pin PB0对地短接触发一下&#xff0c;再发码就很正常&#xff0c;这是什么原因&#xff1f; 根据现象来看…...

【大模型】DeepResearcher:通用智能体通过强化学习探索优化

DeepResearcher&#xff1a;通过强化学习在真实环境中扩展深度研究 一、引言二、技术原理&#xff08;一&#xff09;强化学习与深度研究代理&#xff08;二&#xff09;认知行为的出现&#xff08;三&#xff09;模型架构 三、实战运行方式&#xff08;一&#xff09;环境搭建…...

SpringBoot 3.X 开发自己的 Spring Boot Starter 和 SpringBoot 2.x 的区别

SpringBoot 2.x 在模块中创建 src/main/resources/META-INF/spring.factories 文件 文件内容如下&#xff1a; org.springframework.boot.autoconfigure.EnableAutoConfiguration\com.xxx.xxx.yourfilejava1,\com.xxx.xxx.yourfilejava2 SpringBoot 3.x 在模块中创建 src/m…...

NY164NY165美光固态闪存NY166NY172

美光NY系列固态闪存深度解析&#xff1a;技术、体验与行业洞察 一、技术架构与核心特性解析 美光NY系列&#xff08;NY164/NY165/NY166/NY172&#xff09;作为面向企业级市场的固态闪存产品&#xff0c;其技术设计聚焦高可靠性与性能优化。从架构上看&#xff0c;该系列可能采…...