前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >某音创作者平台视频、图文作品上传发布逆向分析(支持百M以上视频分片上传)

某音创作者平台视频、图文作品上传发布逆向分析(支持百M以上视频分片上传)

原创
作者头像
用户8988577
发布2024-03-18 21:57:56
3011
发布2024-03-18 21:57:56
举报
文章被收录于专栏:言云纪言云纪

## 概要

本文仅作为技术分享交流,切勿用于非法用途。附完整签名算法还原实例代码!

为避免文中代码过多,导致文章不方便阅读,所以请求代码全换成了curl请求格式,请自行粘贴后使用工具进行转换成python代码进行调用!

#### 获取资源上传授权

curl 请求格式

代码语言:sh
复制
curl --location 'https://creator.douyin.com/web/api/media/upload/auth/v5/' \
--header 'Cookie:{这儿是你自己账号的登录cooies}'

响应体

代码语言:json
复制
{
    "ak": "AKLTYjdjYTUwZWQwZDU0NDRmMmEwNWU5NmE1MTdiYzUyZTg",
    "auth": "{\"AccessKeyID\":\"AKTPNzAyMGQ2YTgxYj*******YjY\",\"SecretAccessKey\":\"tr3i*****4x\",\"SessionToken\":\"STS2eyJMVEFj*********WJhNiJ9\",\"ExpiredTime\":\"2024-03-20T18:18:36+08:00\",\"CurrentTime\":\"2024-03-18T18:18:36+08:00\"}",
    "extra": {
        "logid": "2024031818*********0",
        "now": 1710757116000
    },
    "status_code": 0
}
// 这儿需要保存ak与auth字段,这两个参数会在后续加密和获取资源分配请求中用到

#### 获取图文资源上传分配地址

代码语言:sh
复制
curl --location 'https://imagex.bytedanceapi.com/?Action=ApplyImageUpload&Version=2018-08-01&ServiceId=jm8ajry58r&app_id=2906&user_id=&s=cbdzimvyprv' \
--header 'accept: */*' \
--header 'authorization: {通过加密算法生成,会做加密分析还原}' \
--header 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0' \
--header 'x-amz-date: 20240318T095316Z' \
--header 'x-amz-security-token: STS2eyJMVEFj*********WJhNiJ9'

响应体

代码语言:json
复制
{
    "ResponseMetadata": {
        "RequestId": "202403181********FCC",
        "Action": "ApplyImageUpload",
        "Version": "2018-08-01",
        "Service": "imagex", 
        "Region": "cn-north-1" 
    },
    // 如果签名请求成功,会返回Result对象,失败则返回Error对象
    "Result": {
        // 内容太多,此处省略。主要取SessionKey, UploadHosts, StoreUri, Auth参数
    }
}

该段请求主要针对headers中的authorization参数加密,x-amz-date为当前ios8601格式的时间,x-amz-security-token 参数为上文获取资源上传授权请求中获取 3. authorization 参数逆向分析 authorization 参数为AWS4-HMAC-SHA256进行加密 格式:AWS4-HMAC-SHA256 Credential={上文获取的ak参数}/{ios8601格式的时间前8位}/{资源分配桶地址}/{资源分配服务名}/aws4_request, SignedHeaders=x-amz-date;x-amz-security-token, Signature={加密参数}

通过上述加密格式可分析出主要需要获取并还原出资源分配桶地址, 资源分配服务名,以及最后的Signature生成规则。 全局搜索AWS4-HMAC-SHA256得到资源分配桶地址资源分配服务名分别为固定值cn-north-1imagex

Signature参数为: this.signature(e, t), 继续深入发现一直再调用a函数,a函数为AWS4-sha256标准加密

python 加密过程还原代码

代码语言:python
复制
import datetime, hashlib, hmac
from urllib.parse import urlencode

def getSignatureKey(key, date_stamp, regionName, serviceName):
    kDate = hmac.new(('AWS4' + key).encode('utf-8'), date_stamp.encode("utf-8"), hashlib.sha256).digest()
    kRegion = hmac.new(kDate, regionName.encode("utf-8"), hashlib.sha256).digest()
    kService = hmac.new(kRegion, serviceName.encode("utf-8"), hashlib.sha256).digest()
    kSigning = hmac.new(kService, 'aws4_request'.encode("utf-8"), hashlib.sha256).digest()
    return kSigning

def buildStrParams(params):
    url = ""
    for key, value in params.items():
        url += key + "=" + str(value) + "&"
    return url[:-1]  # 去除最后一个多余的"&"

def random_s():
    digits = '0123456789'
    ascii_letters = 'abcdefghigklmnopqrstuvwxyz'
    l = digits + ascii_letters
    str_list = [random.choice(l) for i in range(11)]
    random_str = ''.join(str_list)
    return random_str

def generateAuthorization(secretAccessKey, region, service, canonical_querystring, amz_date, SessionToken, date_stamp, AccessKeyID):
        signing_key = getSignatureKey(secretAccessKey, date_stamp, region, service)
        canonical_headers = 'x-amz-date:' + amz_date + '\n' + 'x-amz-security-token:' + SessionToken + '\n'
        canonical_request = "GET" + '\n' + "/" + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + 'x-amz-date;x-amz-security-token' + '\n' + hashlib.sha256("".encode("utf-8")).hexdigest()
        algorithm = 'AWS4-HMAC-SHA256'
        credential_scope = date_stamp + '/' + region + '/' + service + '/' + 'aws4_request'
        string_to_sign = algorithm + '\n' +  amz_date + '\n' +  credential_scope + '\n' +  hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()
        Signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
        data = f"AWS4-HMAC-SHA256 Credential={AccessKeyID}/{date_stamp}/{region}/{service}/aws4_request, SignedHeaders=x-amz-date;x-amz-security-token, Signature={Signature}"
        return data

if __name__ == "__main__":
    auth = {
        "accessKeyId": "AKTPZjAzMDR******NmNlMDE",
        "secretAccessKey": "AuISVb8*******PlyYEK3L2",
        "sessionToken": "STS2eyJ*******ZCJ9"
    }

    times = datetime.datetime.utcnow()
    amz_date = times.strftime('%Y%m%dT%H%M%SZ')
    date_stamp = times.strftime('%Y%m%d') 
    region = 'cn-north-1'
    service = 'imagex'

    params = {
        "Action": "ApplyImageUpload",
        "ServiceId": "jm8ajry58r",
        "Version": "2018-08-01",
        "app_id": "2906",
        "s": random_s,
        "user_id": ""
    }

    canonical_querystring = buildStrParams(params)
    SessionToken = auth.get('sessionToken')
    AccessKeyID = auth.get('accessKeyId')
    secretAccessKey = auth.get('secretAccessKey')

    Authorization = generateAuthorization(secretAccessKey, region, service, canonical_querystring, amz_date, SessionToken, date_stamp, AccessKeyID)
    print(Authorization)

至此Authorization参数还原分析完成.加密都规则都是比较规范,没什么好继续说的.拼接headers请求头后拿到响应体中的SessionKeyUploadHostsStoreUriAuth参数,其中上传地址为:https://{UploadHosts}/upload/v1/{storeUri},需要对上传地址进行动态拼接.

#### 上传图片

代码语言:sh
复制
curl --location 'https://tos-lf-x.snssdk.com/upload/v1/*****' \
--header 'Authorization: SpaceKey/jm*******' \
--header 'Content-CRC32: ff3ceced' \
--header 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'
--data '{你要上传的文件内容}'

其中url为上文拼接的url地址, Authorization为上文请求获取得到的Auth参数,Content-CRC32通过计算文件内容获取.python读取文件内容并且计算crc32代码如下.

代码语言:python
复制
with open(filePath,"rb")as f:
    data = f.read()
    crc32 = hex(zlib.crc32(data) & 0xFFFFFFFF)[2:]

响应体

代码语言:json
复制
{
 "code":2000,  // 如果返回2000则上传成功
 "apiversion":"v1",
 "message":"Success",
 "data":{
 "crc32":"ff3ceced"
        }
}

#### 发布图文作品

代码语言:sh
复制
curl --location 'https://creator.douyin.com/web/api/media/aweme/create/' \
--header 'cookie: {你的登录授权cookie信息}' \
--header 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0' \
--header 'Content-Type: text/plain' \
--data 'text={标题}&text_extra=[]&activity=[]&challenges=[]&hashtag_source=""&mentions=[]&ifLongTitle=true&hot_sentence=&visibility_type=0&download=1&poster={storeUri}&timing=-1&images=[{"uri":"{storeUri}"]&creation_id=1hz6lvsn1710767057933'

主要修改--data中的参数,text为标题,images里面是你要发布的图文storeUri地址的数组,poster是封面图片的storeUri地址

#### 视频切片上传

视频资源上传规则和图文资源上传规则大致相同,唯一的区别在于获取分配地址的params参数以及加密过程中的service参数需要做修改,变动如下.

代码语言:python
复制
service = 'vod'
params = {
    'Action': 'ApplyUploadInner', 
    'FileSize': fileSize, ## 文件总大小
    'FileType': 'video', 
    'IsInner': '1', 
    'SpaceName': 'aweme', 
    'Version': '2020-11-19', 
    'app_id': '2906', 
    's': random_s, 
    'user_id': ''
}

最后post进行请求即可完成视频上传,视频切片python代码实现如下:

代码语言:python
复制
def videoSplit(filePath, chunk_size=3):
    chunk_size_bytes = chunk_size * 1024 * 1024
    with open(filePath, 'rb') as file:
        file_data = file.read()

    total_slices = (len(file_data) + chunk_size_bytes - 1) // chunk_size_bytes
    slices = []
    chunks = {}
    uploadid = str(uuid.uuid4())
    for i in tqdm(range(total_slices), desc='切片'):
        start = i * chunk_size_bytes
        end = min((i + 1) * chunk_size_bytes, len(file_data))
        data = file_data[start:end]
        # 每一段视频的请求参数信息
        slice_info = {
            "uploadid": uploadid, # 上传uuid,一个完整的视频切片后的uuid需要一致
            'part_number': i + 1, # 当前视频切片的顺序
            'part_offset': start, # 上传文件的写入地址
            "phase": "transfer",
        }  
        chunks[start] = data
        slices.append(slice_info)
    return slices, chunks

至此,视频切片上传结束,至于视频发布我这儿就不做继续分析了,换汤不换药都是一个流程.还原过程中如果如遇到什么问题或文中有什么错误欢迎评论区留言补充,看到就回复.

#### 最终效果

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档