Initial commit
This commit is contained in:
206
README_REVERSE_ENGINEERING.md
Normal file
206
README_REVERSE_ENGINEERING.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# Tencent Hunyuan 3D API Reverse Engineering Document
|
||||
|
||||
## Project Overview
|
||||
|
||||
This project reverse-engineers the frontend signing algorithm of Tencent Hunyuan 3D (https://3d.hunyuan.tencent.com/), enabling **pure Python HTTP calls** without a browser environment for features like image-to-3D generation and quota queries.
|
||||
|
||||
---
|
||||
|
||||
## Core Achievements
|
||||
|
||||
### 1. Signing Algorithm Cracked
|
||||
|
||||
**Algorithm Location**: webpack Chunk 3057, Module 47436
|
||||
|
||||
**Signing Flow**:
|
||||
```
|
||||
1. nonce generation: 16 iterations of Math.random(), selecting from 62-char set (A-Za-z0-9)
|
||||
2. timestamp: Math.floor(Date.now() / 1000) (second-level timestamp)
|
||||
3. key derivation: hardcoded byte array → XOR → circular left shift → permutation → truncation
|
||||
4. signature: HMAC-SHA256(sorted query param string, derived key) → Hex
|
||||
```
|
||||
|
||||
**Key Constants**:
|
||||
```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] # left shift bits
|
||||
M = [14, 11, 13, 9, 15, 10, 12, 8, 6, 3, 5, 1, 7, 2, 4, 0] # permutation table
|
||||
```
|
||||
|
||||
**Derived Key**: `Hf6d6KFB3D` (10 characters)
|
||||
|
||||
### 2. Signing Scope (Important Finding)
|
||||
|
||||
⚠️ **The signature only covers URL query parameters, NOT the request body**
|
||||
|
||||
Actual browser request:
|
||||
```
|
||||
POST /api/3d/creations/generations?timestamp=xxx&nonce=yyy&sign=zzz
|
||||
Body: {"sceneType":"playGround3D-2.0",...}
|
||||
```
|
||||
|
||||
Signature computation:
|
||||
```python
|
||||
# Only sign query params (timestamp + nonce)
|
||||
param_str = "nonce=yyy×tamp=xxx"
|
||||
sign = HMAC-SHA256(param_str, key="Hf6d6KFB3D")
|
||||
```
|
||||
|
||||
### 3. Image URL Format
|
||||
|
||||
Must use Tencent's internal resource format:
|
||||
```
|
||||
https://3d.hunyuan.tencent.com/api/3d/resource/download?resourceId=<32-digit-hex>
|
||||
```
|
||||
|
||||
You cannot directly use a COS URL; you must upload through the browser to obtain a resourceId.
|
||||
|
||||
---
|
||||
|
||||
## File Reference
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `hunyuan3dweb/sign.py` | Signing algorithm in pure Python |
|
||||
| `hunyuan3dweb/api.py` | Pure Python API client |
|
||||
| `hunyuan3dweb/browser/login.py` | Browser automation login tool |
|
||||
| `doc/api.md` | API endpoint documentation |
|
||||
|
||||
---
|
||||
|
||||
## Usage Flow
|
||||
|
||||
### 1. Login to Obtain Cookie
|
||||
|
||||
```bash
|
||||
hunyuan3dweb-login
|
||||
# Follow prompts to enter email and verification code
|
||||
# Login state is automatically saved to ~/.config/hunyuan3dweb/profile
|
||||
```
|
||||
|
||||
### 2. Pure Python 3D Generation
|
||||
|
||||
```python
|
||||
from hunyuan3dweb import Hunyuan3DAPI
|
||||
|
||||
api = Hunyuan3DAPI()
|
||||
|
||||
# Check quota
|
||||
quota = api.get_quota_info()
|
||||
|
||||
# Generate 3D model
|
||||
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"
|
||||
)
|
||||
|
||||
# Query status
|
||||
status = api.get_generation_status(result["creationsId"])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Feature | Method | Endpoint | Signature Scope |
|
||||
|---------|--------|----------|-----------------|
|
||||
| User info | GET | `/getuserinfo` | Query params |
|
||||
| Quota query | POST | `/quotainfo` | Query params |
|
||||
| Generate 3D | POST | `/creations/generations` | Query params |
|
||||
| Query status | GET | `/creations/detail` | Query params |
|
||||
|
||||
---
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Signing Algorithm Implementation
|
||||
|
||||
```python
|
||||
def derive_key(c: bytes) -> str:
|
||||
"""Derive signing key from hardcoded constants"""
|
||||
# 1. XOR with D
|
||||
t = bytearray(16)
|
||||
for i in range(16):
|
||||
t[i] = c[i] ^ D[i]
|
||||
|
||||
# 2. Circular left shift
|
||||
o = bytearray(16)
|
||||
for i in range(16):
|
||||
n = U[i]
|
||||
val = t[i]
|
||||
o[i] = (val << n | val >> (8 - n)) & 0xFF
|
||||
|
||||
# 3. Permutation
|
||||
n = bytearray(16)
|
||||
for i in range(16):
|
||||
n[i] = o[M[i]]
|
||||
|
||||
# 4. Truncate (find first zero byte)
|
||||
try:
|
||||
r = n.index(0)
|
||||
except ValueError:
|
||||
r = 16
|
||||
|
||||
return n[:r].decode('utf-8')
|
||||
```
|
||||
|
||||
### Request Signing
|
||||
|
||||
```python
|
||||
def sign(params: dict) -> dict:
|
||||
result = dict(params)
|
||||
result["timestamp"] = int(time.time())
|
||||
result["nonce"] = generate_nonce(16)
|
||||
|
||||
# Sort and join (JSON format for lists/dicts)
|
||||
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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verification Results
|
||||
|
||||
| Test Item | Browser Signature | Python Signature | Match |
|
||||
|-----------|-------------------|------------------|-------|
|
||||
| Fixed params | `2214e55a...` | `2214e55a...` | ✅ |
|
||||
| Quota query | Works | Works | ✅ |
|
||||
| Generate request | Works | Works | ✅ |
|
||||
| Status query | Works | Works | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Limitations and Notes
|
||||
|
||||
1. **Image Upload**: Still requires a browser environment to upload images and obtain resourceId (Tencent COS requires temporary signatures)
|
||||
2. **Cookie Expiration**: Login sessions expire and need periodic re-login
|
||||
3. **Quota Limit**: Each account has a generation quota limit (default 20/day)
|
||||
4. **Rate Limiting**: Frequent calls may trigger anti-bot measures
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
```
|
||||
requests
|
||||
cloakbrowser (for login and upload)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Legal Notice
|
||||
|
||||
This project is for educational and research purposes only. Use of this code is subject to Tencent Hunyuan 3D's Terms of Service. Do not use for commercial purposes or large-scale automated calling.
|
||||
Reference in New Issue
Block a user