# 腾讯混元3D API 逆向工程文档 ## 项目概述 本项目通过逆向工程破解了腾讯混元3D(https://3d.hunyuan.tencent.com/)的前端签名算法,实现了**纯 Python HTTP 调用**,无需浏览器环境即可使用图生3D、查询配额等功能。 --- ## 核心成果 ### 1. 签名算法破解 **算法位置**: webpack Chunk 3057, Module 47436 **签名流程**: ``` 1. nonce 生成: 16次 Math.random(),从 62 字符集 (A-Za-z0-9) 选取 2. timestamp: Math.floor(Date.now() / 1000)(秒级时间戳) 3. 密钥派生: 硬编码字节数组 → XOR → 循环左移 → 置换 → 截断 4. 签名: HMAC-SHA256(排序后的查询参数字符串, 派生密钥) → Hex ``` **关键常量**: ```python C = bytes([122, 59, 92, 165, 30, 79, 166, 139, 142, 129, 139, 89, 219, 131, 101, 204]) D = bytes([122, 59, 92, 45, 30, 79, 106, 139, 156, 13, 46, 63, 74, 91, 108, 125]) U = [3, 5, 2, 7, 1, 4, 6, 2, 5, 3, 1, 4, 2, 6, 3, 5] # 左移位数 M = [14, 11, 13, 9, 15, 10, 12, 8, 6, 3, 5, 1, 7, 2, 4, 0] # 置换表 ``` **派生密钥**: `Hf6d6KFB3D`(10字符) ### 2. 签名范围(重要发现) ⚠️ **签名只包含 URL 查询参数,不包含请求体数据** 浏览器实际请求: ``` POST /api/3d/creations/generations?timestamp=xxx&nonce=yyy&sign=zzz Body: {"sceneType":"playGround3D-2.0",...} ``` 签名计算: ```python # 只签查询参数(timestamp + nonce) param_str = "nonce=yyy×tamp=xxx" sign = HMAC-SHA256(param_str, key="Hf6d6KFB3D") ``` ### 3. 图片URL格式 必须使用腾讯内部资源格式: ``` https://3d.hunyuan.tencent.com/api/3d/resource/download?resourceId=<32位十六进制> ``` 不能直接上传 COS URL,需要通过浏览器上传获取 resourceId。 --- ## 文件说明 | 文件 | 说明 | |------|------| | `hunyuan3d_sign.py` | 签名算法纯 Python 实现 | | `hunyuan3d_api.py` | 纯 Python API 客户端 | | `hunyuan3d_login.py` | 浏览器自动化登录工具 | | `get_resource_id.py` | 获取图片 resourceId 工具 | | `cookies.txt` | Cookie 存储文件 | | `uploaded_image_url.txt` | 上传后的图片 URL | --- ## 使用流程 ### 1. 登录获取 Cookie ```bash python hunyuan3d_login.py # 按提示输入邮箱和验证码 # 登录状态自动保存到 ./hunyuan3d_profile ``` ### 2. 提取 Cookie ```bash python get_cookie_persistent.py # 生成 cookies.txt ``` ### 3. 上传图片获取 resourceId ```bash python get_resource_id_v2.py # 生成 uploaded_image_url.txt ``` ### 4. 纯 Python 生成3D模型 ```python from hunyuan3d_api import Hunyuan3DAPI api = Hunyuan3DAPI("hunyuan_user=xxx; hunyuan_token=yyy") # 查询配额 quota = api.get_quota_info() # 生成3D模型 result = api.generate_3d( image_url="https://3d.hunyuan.tencent.com/api/3d/resource/download?resourceId=...", scene_type="playGround3D-2.0", model_type="image2ModelV3.1" ) # 查询状态 status = api.get_generation_status(result["creationsId"]) ``` --- ## API 端点 | 功能 | 方法 | 端点 | 签名范围 | |------|------|------|----------| | 用户信息 | GET | `/getuserinfo` | 查询参数 | | 配额查询 | POST | `/quotainfo` | 查询参数 | | 生成3D | POST | `/creations/generations` | 查询参数 | | 查询状态 | GET | `/creations/detail` | 查询参数 | --- ## 技术细节 ### 签名算法实现 ```python def derive_key(c: bytes) -> str: """从硬编码常量派生签名密钥""" # 1. XOR with D t = bytearray(16) for i in range(16): t[i] = c[i] ^ D[i] # 2. 循环左移 o = bytearray(16) for i in range(16): n = U[i] val = t[i] o[i] = (val << n | val >> (8 - n)) & 0xFF # 3. 置换 n = bytearray(16) for i in range(16): n[i] = o[M[i]] # 4. 截断(找到第一个0字节) try: r = n.index(0) except ValueError: r = 16 return n[:r].decode('utf-8') ``` ### 请求签名 ```python def sign(params: dict) -> dict: result = dict(params) result["timestamp"] = int(time.time()) result["nonce"] = generate_nonce(16) # 排序并拼接(JSON格式用于列表/字典) sorted_items = sort_params(result) param_str = join_params(sorted_items) # HMAC-SHA256 key = derive_key(C) signature = hmac.new( key.encode('utf-8'), param_str.encode('utf-8'), hashlib.sha256 ).hexdigest() result["sign"] = signature return result ``` --- ## 验证结果 | 测试项 | 浏览器签名 | Python 签名 | 匹配 | |--------|-----------|-------------|------| | 固定参数 | `2214e55a...` | `2214e55a...` | ✅ | | 配额查询 | 可用 | 可用 | ✅ | | 生成请求 | 可用 | 可用 | ✅ | | 状态查询 | 可用 | 可用 | ✅ | --- ## 限制与注意事项 1. **图片上传**: 仍需浏览器环境上传图片获取 resourceId(腾讯 COS 需要临时签名) 2. **Cookie 有效期**: 登录状态会过期,需要定期重新登录 3. **配额限制**: 每个账号有生成配额限制(默认20次/天) 4. **风控检测**: 频繁调用可能触发风控 --- ## 依赖 ``` requests cloakbrowser (用于登录和上传) ``` --- ## 法律声明 本项目仅供学习和研究使用。使用本代码需遵守腾讯混元3D的服务条款。请勿用于商业用途或大规模自动化调用。