TTS 网站加密请求 / 响应体逆向分析:基于 WebAssembly 的加密解密全流程

TTS 网站加密请求 / 响应体逆向分析:基于 WebAssembly 的加密解密全流程

一、背景:从明文到加密的逆向困境

之前使用某TTS网站时,请求体都是明文传输;近期网站升级后,请求/响应均被加密,首次接触加密接口逆向时毫无头绪,最终借助调试工具+逻辑分析,理清了基于WebAssembly的加密解密流程。

二、逆向核心:定位encrypt_req为请求体加密函数

要破解加密逻辑,首先需确定哪个函数负责请求体加密。通过「函数语义+参数特征+代码逻辑+Wasm桥接规则+抓包验证」5个维度,最终锁定encrypt_req是核心加密函数。

1. 从函数名语义锁定方向

encrypt_reqencrypt(加密)+req(request,请求)组成,字面含义就是“对请求进行加密”,结合“请求体是HTTP加密核心”的常识,初步判断其作用是加密请求体。

2. 从参数特征确认加密对象

函数定义为export function encrypt_req(body) { ... }

  • Web开发中,body是“请求体”的标准命名(如fetch/XMLHttpRequest的请求体参数);
  • 函数唯一入参是body,说明加密对象仅为请求体,与请求头/URL无关。

3. 代码逻辑:JS→Wasm的加密桥接

逐行解析encrypt_req代码,验证其“加密请求体”的核心行为:

代码行代码内容解析依据
1const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);调用Wasm栈管理函数,预留16字节空间存储加密结果,准备执行Wasm逻辑
2const ptr0 = passStringToWasm0(body, ...);通过wasm-bindgen工具,将JS请求体字符串转为Wasm可读取的内存格式(Wasm无法直接读取JS字符串)
3const len0 = WASM_VECTOR_LEN;获取请求体转内存后的字节长度,Wasm通过“指针+长度”访问内存数据
4wasm.encrypt_req(retptr, ptr0, len0);调用Wasm层的encrypt_req(JS仅为桥接层,真正加密逻辑在Wasm中)
5var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);从预留栈空间读取Wasm返回结果:r0是加密后的数据(含密文+密钥)
6return takeObject(r0);将Wasm内存中的结果转回JS对象,最终返回加密后的请求体密文+密钥

4. Wasm桥接规则:返回复合加密结果

wasm-bindgen不支持Wasm直接返回多值,但可返回复合对象

  • 调试发现takeObject(r0)先返回“堆索引(数字)”,最终解析出包含encrypted_body(请求体密文)和encrypt-key(解密密钥)的对象;
  • 证明encrypt_req不仅加密请求体,还生成对应的解密密钥。

5. 抓包验证:闭环匹配

  1. 抓包发现请求体是密文、请求头含encrypt-key
  2. 调用encrypt_req(原始请求体)后,返回结果与抓包的encrypted_body+encrypt-key完全一致;
  3. 按抓包格式发送这两个值,接口调用成功——最终确认encrypt_req是“加密请求体+生成密钥”的核心函数。

三、加密解密整体架构

该TTS应用采用“WebAssembly+Node.js+Python”混合架构,核心加密逻辑封装在Wasm中:

  • WebAssembly:存储核心加密/解密算法(XXX_wasm_bg.wasm),对外暴露encrypt_req/decrypt_resp`函数;
  • Node.js:作为桥接层,实现Python与Wasm的跨语言调用;
  • Python:业务层,调用加密/解密接口,发送HTTP请求。

四、请求体加密流程

1. Python加密入口(TTS_generating.py

defencrypt_request(body):# 构造加密请求数据 input_data ={'action':'encrypt','data': json.loads(body)}# 调用Node.js脚本执行加密 result = subprocess.run(['node', encrypt_js_path],input=json.dumps(input_data), encoding='utf-8', capture_output=True)# 返回:{'encrypted_body': 密文, 'encrypt_key': 密钥}return json.loads(result.stdout)['data']

2. Node.js桥接逻辑(encrypt_wasm.js

if(inputObj.action ==='encrypt'){const plainStr =JSON.stringify(inputObj.data);// 调用Wasm加密函数const encrypted =encrypt_req(plainStr);// 返回加密结果outputResult(true,{encrypt_key: encrypted.encrypt_key,encrypted_body: encrypted.encrypted_body },'');}

3. Wasm核心加密

加密算法封装在XXX_wasm_bg.wasm中,通过encrypt_req暴露给JS,推测采用对称加密算法(如AES),密钥由Wasm动态生成。

五、响应体解密流程

1. Python解密入口(TTS_generating.py

defdecrypt_response(encrypted_data, encrypt_key):# 构造解密请求数据 input_data ={'action':'decrypt','encrypted_body': encrypted_data,'encrypted_key': encrypt_key }# 调用Node.js脚本执行解密 result = subprocess.run(['node', encrypt_js_path],input=json.dumps(input_data), encoding='utf-8', capture_output=True)# 返回解密后的明文return json.loads(result.stdout)['data']['decrypted_data']

2. Node.js桥接逻辑(encrypt_wasm.js

elseif(inputObj.action ==='decrypt'){const encrypted_body = inputObj.encrypted_body;const encrypted_key = inputObj.encrypted_key;// 调用Wasm解密函数const decrypted =decrypt_resp(encrypted_body, encrypted_key);// 返回解密结果outputResult(true,{decrypted_data: decrypted },'');}

3. Wasm核心解密

解密算法同样封装在XXX_wasm_bg.wasm中,通过decrypt_resp暴露,与encrypt_req配对使用。

六、服务端:请求解密+响应加密逻辑

1. 请求体解密(服务端侧)

服务器收到请求后,按“先解密钥,再解内容”的逻辑处理:

  1. 提取请求体密文+请求头encrypt-key
  2. 服务器私钥解密encrypt-key,得到原始对称密钥(如AES密钥);
  3. 用对称密钥解请求体密文,得到明文请求体;
  4. 解析明文,处理业务逻辑(如生成TTS音频)。

服务端解密伪代码(Java)

// 提取请求头/请求体String encryptKey = request.getHeader("encrypt-key");String encryptedBody = request.getBody();// 私钥解密encrypt-key,得到AES密钥String aesKey =RSAUtils.decrypt(encryptKey,"服务器RSA私钥");// AES解密请求体String originalBody =AESUtils.decrypt(encryptedBody, aesKey);// 处理业务JSONObject body =JSONObject.parseObject(originalBody);String content = body.getString("content");

2. 响应体加密(服务端侧)

服务器处理完业务后,加密响应体再返回:

  1. 生成原始响应明文(如音频URL、时长);
  2. 随机生成新的对称密钥,加密响应明文得到密文;
  3. 客户端公钥加密新密钥,生成响应头encrypt-key
  4. 返回“响应体密文+响应头encrypt-key”。

七、技术特点与优化建议

1. 现有方案特点

  • 安全性:核心算法封装在Wasm中,难以逆向;密钥通过非对称加密传输;
  • 跨平台性:Node.js桥接实现Python与Wasm的跨语言调用;
  • 性能:Wasm提供接近原生的执行效率,避免Python GIL限制。

2. 优化方向

  • 减少进程开销:使用长连接Node.js进程,避免频繁创建/销毁子进程;
  • 增强错误处理:添加详细日志+自动重试机制;
  • 性能提升:将加密逻辑移植到Python,减少进程间通信开销;
  • 安全增强:实现密钥轮换+请求签名验证,防止中间人攻击。

八、总结

该TTS网站的加密解密是“客户端加密请求→服务端解密请求→服务端加密响应→客户端解密响应”的闭环流程,encrypt-key是贯穿全程的解密凭证,Wasm则是保护核心算法的关键载体。

这次逆向过程让我体会到:技术接口的加密并非“黑盒”,通过“函数语义分析+代码逻辑拆解+抓包验证”的组合方式,能逐步理清加密流程。

九、最后整理出程序,生成TTS。

完整Python代码的整体执行流程,包括各函数的功能、函数间的调用关系、核心业务逻辑(加密请求、发送请求、轮询音频、下载音频)以及不同执行分支的处理逻辑。下面我会按“模块拆解→完整流程→核心细节”的思路,把整个代码逻辑讲清楚。

一、代码整体功能总览

完整的TTS接口交互工具,专门对接 网站 的语音合成接口,核心能力是:

  1. 对请求体进行加密(依赖Node.js调用Wasm模块);
  2. 发送加密后的HTTP请求到接口;
  3. 轮询服务器获取音频生成结果(处理加密响应的解密);
  4. 下载生成好的音频文件;
  5. 支持单独的“响应解密测试”(命令行传参)。

二、核心函数模块拆解

先理清每个函数的定位和作用,这是理解流程的基础:

函数名核心作用关键逻辑
encrypt_request(body)加密请求体1. 拼接Node.js脚本路径;
2. 构造加密入参(action=encrypt);
3. 调用subprocess.run执行Node.js脚本;
4. 解析返回的加密结果(encrypted_body + encrypt_key)
decrypt_response(encrypted_data, encrypt_key)解密响应体1. 拼接Node.js脚本路径;
2. 构造解密入参(action=decrypt);
3. 调用Node.js脚本执行解密;
4. 返回解密后的明文
send_encrypted_request(url, body, ...)发送加密请求1. 调用encrypt_request加密请求体;
2. 构造包含encrypt-key的请求头;
3. 发送POST请求;
4. 处理响应(判断是否需要解密,调用decrypt_response);
5. 返回响应数据(解密后/原始)
poll_for_audio_result(shot_id, ...)轮询音频结果1. 循环发送GET请求查询音频状态;
2. 处理加密响应(调用decrypt_response);
3. 根据状态(GENERATING/COMPLETED/FAILED)决定继续轮询/返回结果/终止;
4. 最大重试30次,间隔2秒
download_audio(audio_url, ...)下载音频1. 构造请求头(带授权信息);
2. 流式下载音频(stream=True);
3. 显示下载进度,保存到本地(按URL文件名/时间戳命名)
get_auth_info()读取授权信息从指定路径的auth_info.json读取authorizationcookies,转换为请求可用的格式

三、完整执行流程(正常调用分支)

当直接运行脚本(无额外命令行参数/仅传1个请求体参数)时,执行流程如下:

步骤1:初始化请求体
  • 若命令行传入参数(sys.argv[1]),则用该参数作为请求体;
  • 否则使用默认请求体:{"content":"我们都是中国人...","toneId":45,...}
步骤2:加密请求体

调用encrypt_request(body)

  • 执行Node.js脚本encrypt_wasm.js,传入action=encrypt+原始请求体;
  • 若加密成功,返回encrypted_body(加密后的请求体)和encrypt_key(密钥);
  • 若加密失败,打印错误并退出脚本。
步骤3:读取授权信息

调用get_auth_info()

  • E:\Projects\my_app\utils\auth_info\auth_info.json读取authorization(认证令牌)和cookies
  • 若读取失败(文件不存在/解析错误),打印错误并退出。
步骤4:发送加密请求

调用send_encrypted_request(url, body, ...)

  • 构造请求头:包含authorizationclientidencrypt-key(步骤2的encrypt_key)等;
  • 发送POST请求,请求体为encrypted_body
  • 接收响应:
    • 若响应头有encrypt-key,调用decrypt_response解密响应体;
    • 若无需解密,直接解析JSON;
  • 返回响应数据(解密后/原始)。
步骤5:轮询音频生成结果
  • 从请求URL中提取shot_id
  • 调用poll_for_audio_result(shot_id, ...)
    • 循环发送GET请求到结果查询接口;
    • 每次请求后判断音频状态:
      • GENERATING:继续轮询(等待2秒后重试);
      • COMPLETED/GENERATING_COMPLETED:返回音频结果;
      • FAILED:打印失败原因并返回;
    • 若超过30次重试仍未获取结果,打印“超时”并返回None。
步骤6:下载音频(若成功获取结果)
  • 从轮询结果中提取audioUrl(音频URL);
  • 调用download_audio(audio_url, ...)
    • 流式下载音频文件,显示下载进度;
    • 保存到脚本所在目录(文件名优先用URL中的名称,无则用时间戳命名,如audio_20260114_153000.mp3)。

四、单独解密测试分支

当脚本传入2个命令行参数python 44.py <encrypted_body> <encrypt_key>)时,执行独立的解密逻辑:

  1. 读取命令行参数:encrypted_body(加密的响应体)、encrypt_key(解密密钥);
  2. 调用decrypt_response解密;
  3. 打印解密结果(若为JSON则格式化输出);
  4. 解密失败则打印错误并退出。

五、关键细节补充

  1. 跨语言调用:加密/解密依赖Node.js脚本,Python通过subprocess.run调用,本质是“Python→Node.js→Wasm”的桥接;
  2. 错误处理:每个核心函数都有完善的异常捕获(JSON解析错误、子进程执行失败、网络请求异常等),并打印详细错误日志;
  3. 请求头适配:所有请求头严格模拟浏览器(User-Agent、Referer、sec-*等),保证接口兼容性;
  4. 授权处理authorization自动补全Bearer 前缀,cookies按需添加,适配接口的鉴权规则。

总结

这段代码的核心执行逻辑是**“加密请求→发送请求→轮询结果→解密响应→下载音频”的闭环**,关键要点:

  1. 加密/解密是核心依赖:通过Node.js调用Wasm模块实现,Python仅作为业务层封装;
  2. 轮询机制解决音频异步生成问题:最多30次重试,间隔2秒,保证能获取最终生成结果;
  3. 双执行分支设计:既支持完整的“请求-生成-下载”流程,也支持单独的解密测试;

完善的兼容性处理:请求头模拟浏览器、授权信息自动适配、错误日志详细,保证稳定性。成品如下:

在这里插入图片描述


在这里插入图片描述](https://i-blog.ZEEKLOGimg.cn/direct/820c6471d45840cb9263467ff655ea6b.png#pic_center)

在这里插入图片描述

Read more

【无人机避障算法核心技术】:揭秘五种主流算法原理与实战应用场景

第一章:无人机避障算法概述 无人机避障算法是实现自主飞行的核心技术之一,其目标是在复杂环境中实时感知障碍物,并规划安全路径以避免碰撞。随着传感器技术和计算能力的提升,避障系统已从简单的距离检测发展为融合多源信息的智能决策体系。 避障系统的基本组成 典型的无人机避障系统包含以下关键模块: * 感知模块:利用激光雷达、超声波、立体视觉或RGB-D相机获取环境数据 * 数据处理模块:对原始传感器数据进行滤波、特征提取和障碍物识别 * 决策与规划模块:基于环境模型生成避障轨迹,常用算法包括A*、Dijkstra、RRT和动态窗口法(DWA) 常见避障算法对比 算法优点缺点适用场景A*路径最优,搜索效率高高维空间计算开销大静态环境全局规划DWA实时性强,适合动态避障局部最优风险室内低速飞行RRT*渐进最优,适应复杂空间收敛速度慢三维未知环境 基于深度学习的避障方法示例 近年来,端到端神经网络被用于直接从图像生成控制指令。以下是一个简化的行为克隆模型推理代码片段: import torch import torchvision.transforms as tran

飞书 × OpenClaw 接入指南:不用服务器,用长连接把机器人跑起来

你想在飞书里用上一个能稳定对话、能发图/收文件、还能按规则在群里工作的 AI 机器人,最怕两件事:步骤多、出错后不知道查哪里。这个项目存在的意义,就是把“飞书接 OpenClaw”这件事,整理成一套对非技术也友好的配置入口,并把官方文档没覆盖到的坑集中写成排查清单。 先说清楚它的角色:OpenClaw 现在已经内置官方飞书插件 @openclaw/feishu,功能更完整、维护也更及时。这是好事,说明飞书 + AI 的接入已经走通。这个仓库并不是要替代官方插件,而是继续为大家提供: * 新用户:从零开始的新手教程(15–20 分钟) * 老用户:从旧版(独立桥接或旧 npm 插件)迁移到官方插件的保姆级路线 * 常见问题答疑 & 排查清单(最常见的坑优先) * 进阶场景:独立桥接模式依然可用(需要隔离/定制时再用) 另外,仓库也推荐了一个新项目

FAIR plus 机器人全产业链接会,链动全球智能新机遇

FAIR plus 机器人全产业链接会,链动全球智能新机遇

本文声明:本篇内容为个人真实体验分享,非商业广告,无强制消费引导。所有推荐仅代表个人感受,仅供参考,按需选择。 过往十年,中国机器人产业蓬勃发展。中国出品的核心部件得到了产业规模化的验证,机器人产品的整体制造能力也开始向全球输出。与此同时,机器人产业正在更加紧密地与人工智能融合,机器人从专用智能走向通用智能。 在此背景下,深圳市机器人协会打造了“FAIR plus机器人全产业链接会”,FAIR plus是一个专注于机器人全产业链技术和开发资源的平台,也是全球首个机器人开发技术展,以供应链和创新技术为切入点,推动全球具身智能机器人产业的发展。通过学术会议、技术标准、社区培育、供需对接等方式,创造人工智能+机器人各产业链环节的开发、产品、工程、方案等技术人员,以及有意引入机器人的场景方相关工艺、设备、信息技术人员线下见面的机会,达成合作,以有效促进机器人向智能化方向发展,连同提升产业整体能力的建设和配置。 2025年4月,首届“FAIR plus机器人全产业链接会”(FAIR plus 2025)以“智启未来链动全球”为主题,汇聚全球顶尖专家、企业领袖,

机器人坐标系详解

机器人坐标系详解

笔者虽然从事自动化工作十几年,但是对于机器人坐标系的理解始终是一知半解,最近认为吃透了坐标系的事,和广大同仁分享一下。 工业机器人的坐标系的五个坐标系:1、世界坐标系;2、机器人足部坐标系;3、基坐标系;4、法兰坐标系;5、工具坐标系 这五个坐标系是工业机器人空间位置和姿态的数学基础。可以把它们想象成一套从宏观到微观的定位系统。 为了让你更直观地理解,可以把整个机器人工作站想象成一个房间,把机器人想象成人的手臂。以下是详细的解释: 1. 世界坐标系 —— 房间的地标 * 定义:这是一个固定不变的绝对坐标系,通常定义在整个工作站(房间)的某个角落。 * 用途:用来描述房间里所有东西的绝对位置。比如:机器人站在哪里、传送带放在哪里、工件放在哪里,都是相对于世界坐标系的。 * 理解:它相当于你房间里的经纬度或者墙角。无论你怎么移动,这个点的位置是固定不变的。 2. 机器人足部坐标系 —— 机器人脚下的地 * 定义:这是一个位于机器人安装底座正下方的坐标系。通常Z轴垂直向上,指向机器人的身体。 * 用途:在安装机器人时,我们需要把机器人足部坐标系校准到世界坐标系中去。